From 3a92c4f7989dc6e643ef01a8c65b26a75a07572a Mon Sep 17 00:00:00 2001 From: JimmFly Date: Sat, 5 Aug 2023 08:15:17 +0800 Subject: [PATCH] feat: modify sidebar floating logic and header responsive style (#3550) --- .../blocksuite/workspace-header/header.tsx | 118 ++++++++------- .../blocksuite/workspace-header/index.tsx | 8 +- .../blocksuite/workspace-header/styles.css.ts | 142 ++++++++++++------ .../src/components/app-sidebar/index.css.ts | 35 ++--- .../src/components/app-sidebar/index.tsx | 15 +- .../page-list/view/collection-list.css.ts | 13 +- 6 files changed, 189 insertions(+), 142 deletions(-) diff --git a/apps/core/src/components/blocksuite/workspace-header/header.tsx b/apps/core/src/components/blocksuite/workspace-header/header.tsx index a9fbfc9c38..af989d8842 100644 --- a/apps/core/src/components/blocksuite/workspace-header/header.tsx +++ b/apps/core/src/components/blocksuite/workspace-header/header.tsx @@ -8,6 +8,7 @@ import { isDesktop } from '@affine/env/constant'; import { CloseIcon, MinusIcon, RoundedRectangleIcon } from '@blocksuite/icons'; import type { Page } from '@blocksuite/store'; import { headerItemsAtom } from '@toeverything/infra/atom'; +import clsx from 'clsx'; import { useAtom, useAtomValue } from 'jotai'; import type { FC, HTMLAttributes, PropsWithChildren, ReactNode } from 'react'; import { @@ -38,8 +39,6 @@ export type BaseHeaderProps< export enum HeaderRightItemName { EditorOptionMenu = 'editorOptionMenu', - // some windows only items - WindowsAppControls = 'windowsAppControls', } type HeaderItem = { @@ -63,59 +62,54 @@ const HeaderRightItems: Record = { ); }, }, - [HeaderRightItemName.WindowsAppControls]: { - Component: () => { - const handleMinimizeApp = useCallback(() => { - window.apis?.ui.handleMinimizeApp().catch(err => { - console.error(err); - }); - }, []); - const handleMaximizeApp = useCallback(() => { - window.apis?.ui.handleMaximizeApp().catch(err => { - console.error(err); - }); - }, []); - const handleCloseApp = useCallback(() => { - window.apis?.ui.handleCloseApp().catch(err => { - console.error(err); - }); - }, []); - return ( -
- - - -
- ); - }, - availableWhen: () => { - return isDesktop && globalThis.platform === 'win32'; - }, - }, }; export type HeaderProps = BaseHeaderProps; +const WindowsAppControls = () => { + const handleMinimizeApp = useCallback(() => { + window.apis?.ui.handleMinimizeApp().catch(err => { + console.error(err); + }); + }, []); + const handleMaximizeApp = useCallback(() => { + window.apis?.ui.handleMaximizeApp().catch(err => { + console.error(err); + }); + }, []); + const handleCloseApp = useCallback(() => { + window.apis?.ui.handleCloseApp().catch(err => { + console.error(err); + }); + }, []); + return ( +
+ + + +
+ ); +}; const PluginHeader = () => { const rootRef = useRef(null); @@ -165,7 +159,7 @@ export const Header = forwardRef< const appSidebarFloating = useAtomValue(appSidebarFloatingAtom); const mode = useAtomValue(currentModeAtom); - + const isWindowsDesktop = globalThis.platform === 'win32' && isDesktop; return (
- {!open && } - {props.leftSlot} +
{!open && }
+
+ {props.leftSlot} +
{props.children} -
+
{useMemo(() => { return Object.entries(HeaderRightItems).map( @@ -227,6 +232,7 @@ export const Header = forwardRef< ); }, [props])}
+ {isWindowsDesktop ? : null}
); diff --git a/apps/core/src/components/blocksuite/workspace-header/index.tsx b/apps/core/src/components/blocksuite/workspace-header/index.tsx index ef368a836f..e29d64bedd 100644 --- a/apps/core/src/components/blocksuite/workspace-header/index.tsx +++ b/apps/core/src/components/blocksuite/workspace-header/index.tsx @@ -65,7 +65,7 @@ export const BlockSuiteEditorHeader: FC< }} /> -
+
{isEditable ? (
) : ( - + {title || 'Untitled'} )} diff --git a/apps/core/src/components/blocksuite/workspace-header/styles.css.ts b/apps/core/src/components/blocksuite/workspace-header/styles.css.ts index 15d9fbe48c..e1013c5df7 100644 --- a/apps/core/src/components/blocksuite/workspace-header/styles.css.ts +++ b/apps/core/src/components/blocksuite/workspace-header/styles.css.ts @@ -1,5 +1,7 @@ import type { ComplexStyleRule } from '@vanilla-extract/css'; -import { style } from '@vanilla-extract/css'; +import { createContainer, style } from '@vanilla-extract/css'; + +export const headerVanillaContainer = createContainer(); export const headerContainer = style({ height: 'auto', @@ -27,35 +29,45 @@ export const headerContainer = style({ } as ComplexStyleRule); export const header = style({ + containerName: headerVanillaContainer, + containerType: 'inline-size', flexShrink: 0, - height: '52px', + minHeight: '52px', width: '100%', - padding: '0 20px', - display: 'flex', - justifyContent: 'space-between', + padding: '8px 20px', + display: 'grid', + gridTemplateColumns: '1fr auto 1fr', alignItems: 'center', background: 'var(--affine-background-primary-color)', zIndex: 99, position: 'relative', selectors: { - '&[data-is-edgeless="true"]': { + '&[data-is-page-list="true"], &[data-is-edgeless="true"]': { borderBottom: `1px solid var(--affine-border-color)`, }, }, + '@container': { + [`${headerVanillaContainer} (max-width: 900px)`]: { + alignItems: 'start', + }, + }, }); export const titleContainer = style({ width: '100%', height: '100%', - margin: 'auto', - position: 'absolute', - inset: 'auto auto auto 50%', - transform: 'translate(-50%, 0px)', display: 'flex', justifyContent: 'center', alignItems: 'center', alignContent: 'unset', fontSize: 'var(--affine-font-base)', + ['WebkitAppRegion' as string]: 'no-drag', + '@container': { + [`${headerVanillaContainer} (max-width: 900px)`]: { + alignItems: 'start', + paddingTop: '2px', + }, + }, }); export const title = style({ @@ -75,9 +87,26 @@ export const title = style({ }, }, } as ComplexStyleRule); - +export const pageTitle = style({ + maxWidth: '600px', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + transition: 'width .15s', + cursor: 'pointer', + '@container': { + [`${headerVanillaContainer} (max-width: 1920px)`]: { + maxWidth: '800px', + }, + [`${headerVanillaContainer} (max-width: 1300px)`]: { + maxWidth: '400px', + }, + [`${headerVanillaContainer} (max-width: 768px)`]: { + maxWidth: '220px', + }, + }, +}); export const titleWrapper = style({ - height: '100%', position: 'relative', display: 'flex', justifyContent: 'center', @@ -86,10 +115,28 @@ export const titleWrapper = style({ export const headerLeftSide = style({ display: 'flex', alignItems: 'center', - width: '150px', - '@media': { - '(max-width: 900px)': { - width: 'auto', + transition: 'all .15s', + '@container': { + [`${headerVanillaContainer} (max-width: 900px)`]: { + flexDirection: 'column', + alignItems: 'flex-start', + height: '68px', + }, + }, +}); +export const headerLeftSideItem = style({ + '@container': { + [`${headerVanillaContainer} (max-width: 900px)`]: { + position: 'absolute', + left: '0', + bottom: '8px', + }, + }, +}); +export const headerLeftSideOpen = style({ + '@container': { + [`${headerVanillaContainer} (max-width: 900px)`]: { + marginLeft: '20px', }, }, }); @@ -99,7 +146,21 @@ export const headerRightSide = style({ alignItems: 'center', gap: '12px', zIndex: 1, + marginLeft: '20px', justifyContent: 'flex-end', + transition: 'all .15s', + '@container': { + [`${headerVanillaContainer} (max-width: 900px)`]: { + position: 'absolute', + height: 'auto', + right: '0', + bottom: '8px', + marginRight: '18px', + }, + }, +}); +export const headerRightSideWindow = style({ + marginRight: '140px', }); export const browserWarning = style({ @@ -131,22 +192,12 @@ export const closeButton = style({ }); export const switchWrapper = style({ - position: 'absolute', - right: '100%', - top: 0, - bottom: 0, - margin: 'auto', display: 'flex', justifyContent: 'center', alignItems: 'center', }); export const searchArrowWrapper = style({ - position: 'absolute', - left: 'calc(100% + 4px)', - top: 0, - bottom: 0, - margin: 'auto', display: 'flex', justifyContent: 'center', alignItems: 'center', @@ -164,16 +215,13 @@ export const allPageListTitleWrapper = style({ color: 'var(--affine-text-primary-color)', display: 'flex', alignItems: 'center', - '::after': { - content: '""', - display: 'block', - width: '100%', - height: '1px', - background: 'var(--affine-border-color)', - position: 'absolute', - bottom: 0, - left: 0, - margin: '0 1px', + width: '100%', + height: '100%', + '@container': { + [`${headerVanillaContainer} (max-width: 900px)`]: { + alignItems: 'flex-start', + marginTop: '8px', + }, }, }); export const pageListTitleIcon = style({ @@ -220,30 +268,36 @@ export const windowAppControlsWrapper = style({ gap: '2px', transform: 'translateX(8px)', height: '100%', + position: 'absolute', + right: '14px', }); export const windowAppControl = style({ WebkitAppRegion: 'no-drag', cursor: 'pointer', display: 'inline-flex', - width: '42px', - height: 'calc(100% - 10px)', - paddingTop: '10px', + width: '51px', alignItems: 'center', justifyContent: 'center', borderRadius: '0', selectors: { '&[data-type="close"]': { width: '56px', - paddingRight: '14px', - marginRight: '-14px', + paddingRight: '5px', + marginRight: '-12px', }, '&[data-type="close"]:hover': { - background: 'var(--affine-error-color)', - color: '#FFFFFF', + background: 'var(--affine-windows-close-button)', + color: 'var(--affine-pure-white)', }, '&:hover': { - background: 'var(--affine-background-tertiary-color)', + background: 'var(--affine-hover-color)', + }, + }, + '@container': { + [`${headerVanillaContainer} (max-width: 900px)`]: { + height: '50px', + paddingTop: '0', }, }, } as ComplexStyleRule); diff --git a/packages/component/src/components/app-sidebar/index.css.ts b/packages/component/src/components/app-sidebar/index.css.ts index a48ea6bccb..ba5086208e 100644 --- a/packages/component/src/components/app-sidebar/index.css.ts +++ b/packages/component/src/components/app-sidebar/index.css.ts @@ -17,23 +17,18 @@ export const navWrapperStyle = style({ paddingBottom: '8px', backgroundColor: 'transparent', '@media': { - [`(max-width: ${floatingMaxWidth}px)`]: { - position: 'absolute', - width: `calc(${navWidthVar})`, - zIndex: 4, - backgroundColor: 'var(--affine-background-primary-color)', - selectors: { - '&[data-open="false"]': { - marginLeft: `calc((10vw + ${navWidthVar}) * -1)`, - }, - }, - }, print: { display: 'none', zIndex: -1, }, }, selectors: { + '&[data-is-floating="true"]': { + position: 'absolute', + width: `calc(${navWidthVar})`, + zIndex: 4, + backgroundColor: 'var(--affine-background-primary-color)', + }, '&[data-open="false"]': { marginLeft: `calc(${navWidthVar} * -1)`, }, @@ -93,17 +88,15 @@ export const sidebarFloatMaskStyle = style({ right: '100%', bottom: 0, background: 'var(--affine-background-modal-color)', - '@media': { - [`(max-width: ${floatingMaxWidth}px)`]: { - selectors: { - '&[data-open="true"]': { - opacity: 1, - pointerEvents: 'auto', - right: '0', - zIndex: 3, - }, - }, + selectors: { + '&[data-open="true"][data-is-floating="true"]': { + opacity: 1, + pointerEvents: 'auto', + right: '0', + zIndex: 3, }, + }, + '@media': { print: { display: 'none', }, diff --git a/packages/component/src/components/app-sidebar/index.tsx b/packages/component/src/components/app-sidebar/index.tsx index 89179f88cd..3925f45f49 100644 --- a/packages/component/src/components/app-sidebar/index.tsx +++ b/packages/component/src/components/app-sidebar/index.tsx @@ -59,18 +59,22 @@ export function AppSidebar(props: AppSidebarProps): ReactElement { useEffect(() => { function onResize() { - const { matches } = window.matchMedia( + const isFloatingMaxWidth = window.matchMedia( `(max-width: ${floatingMaxWidth}px)` - ); + ).matches; + const isOverflowWidth = window.matchMedia( + `(max-width: ${appSidebarWidth / 0.4}px)` + ).matches; + const isFloating = isFloatingMaxWidth || isOverflowWidth; if ( open === undefined && localStorage.getItem(APP_SIDEBAR_OPEN) === null ) { // give the initial value, // so that the sidebar can be closed on mobile by default - setOpen(!matches); + setOpen(!isFloating); } - setAppSidebarFloating(matches && !!open); + setAppSidebarFloating(isFloating && !!open); } onResize(); @@ -78,7 +82,7 @@ export function AppSidebar(props: AppSidebarProps): ReactElement { return () => { window.removeEventListener('resize', onResize); }; - }, [open, setAppSidebarFloating, setOpen]); + }, [appSidebarWidth, open, setAppSidebarFloating, setOpen]); // disable animation to avoid UI flash const enableAnimation = useEnableAnimation(); @@ -99,6 +103,7 @@ export function AppSidebar(props: AppSidebarProps): ReactElement { })} data-open={open} data-is-macos-electron={isMacosDesktop} + data-is-floating={appSidebarFloating} data-enable-animation={enableAnimation && !isResizing} >