diff --git a/apps/core/src/components/pure/workspace-slider-bar/WorkspaceSelector/styles.ts b/apps/core/src/components/pure/workspace-slider-bar/WorkspaceSelector/styles.ts index a64c8da32e..ceabd79481 100644 --- a/apps/core/src/components/pure/workspace-slider-bar/WorkspaceSelector/styles.ts +++ b/apps/core/src/components/pure/workspace-slider-bar/WorkspaceSelector/styles.ts @@ -6,7 +6,6 @@ export const StyledSelectorContainer = styled('div')(() => { display: 'flex', alignItems: 'center', padding: '0 6px', - margin: '0 -6px', borderRadius: '8px', color: 'var(--affine-text-primary-color)', ':hover': { diff --git a/apps/core/src/components/pure/workspace-slider-bar/collections/collections-list.tsx b/apps/core/src/components/pure/workspace-slider-bar/collections/collections-list.tsx index 69e0fd4f4d..6f33be68c2 100644 --- a/apps/core/src/components/pure/workspace-slider-bar/collections/collections-list.tsx +++ b/apps/core/src/components/pure/workspace-slider-bar/collections/collections-list.tsx @@ -211,7 +211,7 @@ const CollectionRenderer = ({ } >
- +
} @@ -228,8 +228,8 @@ const CollectionRenderer = ({
{collection.name}
- -
+ +
{pagesToRender.map(page => { return ( {page.title || t['Untitled']()} - -
- {referencesToRender.map(id => { - return ( - - ); - })} -
+ + {referencesToRender.map(id => { + return ( + + ); + })} ); diff --git a/apps/core/src/components/pure/workspace-slider-bar/collections/styles.css.ts b/apps/core/src/components/pure/workspace-slider-bar/collections/styles.css.ts index 1623b553b4..b9fc05d9db 100644 --- a/apps/core/src/components/pure/workspace-slider-bar/collections/styles.css.ts +++ b/apps/core/src/components/pure/workspace-slider-bar/collections/styles.css.ts @@ -1,4 +1,4 @@ -import { globalStyle, style } from '@vanilla-extract/css'; +import { globalStyle, keyframes, style } from '@vanilla-extract/css'; export const wrapper = style({ userSelect: 'none', @@ -29,8 +29,9 @@ export const more = style({ display: 'flex', alignItems: 'center', justifyContent: 'center', - borderRadius: 4, - padding: 4, + borderRadius: 2, + fontSize: 16, + color: 'var(--affine-icon-color)', ':hover': { backgroundColor: 'var(--affine-hover-color)', }, @@ -52,3 +53,34 @@ export const menuDividerStyle = style({ height: '1px', background: 'var(--affine-border-color)', }); + +const slideDown = keyframes({ + '0%': { + height: '0px', + }, + '100%': { + height: 'var(--radix-collapsible-content-height)', + }, +}); + +const slideUp = keyframes({ + '0%': { + height: 'var(--radix-collapsible-content-height)', + }, + '100%': { + height: '0px', + }, +}); + +export const collapsibleContent = style({ + overflow: 'hidden', + marginTop: '4px', + selectors: { + '&[data-state="open"]': { + animation: `${slideDown} 0.2s ease-out`, + }, + '&[data-state="closed"]': { + animation: `${slideUp} 0.2s ease-out`, + }, + }, +}); diff --git a/apps/core/src/components/pure/workspace-slider-bar/favorite/styles.css.ts b/apps/core/src/components/pure/workspace-slider-bar/favorite/styles.css.ts index e8f8a176cd..be889f6b87 100644 --- a/apps/core/src/components/pure/workspace-slider-bar/favorite/styles.css.ts +++ b/apps/core/src/components/pure/workspace-slider-bar/favorite/styles.css.ts @@ -11,11 +11,13 @@ export const label = style({ export const favItemWrapper = style({ display: 'flex', flexDirection: 'column', - gap: '4px', selectors: { '&[data-nested="true"]': { - marginLeft: '12px', - width: 'calc(100% - 12px)', + marginLeft: '20px', + width: 'calc(100% - 20px)', + }, + '&:not(:first-of-type)': { + marginTop: '4px', }, }, }); @@ -40,6 +42,7 @@ const slideUp = keyframes({ export const collapsibleContent = style({ overflow: 'hidden', + marginTop: '4px', selectors: { '&[data-state="open"]': { animation: `${slideDown} 0.2s ease-out`, @@ -53,5 +56,4 @@ export const collapsibleContent = style({ export const collapsibleContentInner = style({ display: 'flex', flexDirection: 'column', - gap: '4px', }); diff --git a/apps/core/src/components/root-app-sidebar/index.tsx b/apps/core/src/components/root-app-sidebar/index.tsx index 1e202203f2..4804783b9b 100644 --- a/apps/core/src/components/root-app-sidebar/index.tsx +++ b/apps/core/src/components/root-app-sidebar/index.tsx @@ -51,14 +51,14 @@ export type RootAppSidebarProps = { }; const RouteMenuLinkItem = React.forwardRef< - HTMLDivElement, + HTMLButtonElement, { currentPath: string; // todo: pass through useRouter? path: string; icon: ReactElement; children?: ReactElement; isDraggedOver?: boolean; - } & React.HTMLAttributes + } & React.HTMLAttributes >(({ currentPath, path, icon, children, isDraggedOver, ...props }, ref) => { // Force active style when a page is dragged over const active = isDraggedOver || currentPath === path; @@ -196,6 +196,8 @@ export const RootAppSidebar = ({ + {/* fixme: remove the following spacer */} +
{isDesktop && } -
+
diff --git a/apps/electron/src/main/main-window.ts b/apps/electron/src/main/main-window.ts index 93a6adc5ca..8a829cc680 100644 --- a/apps/electron/src/main/main-window.ts +++ b/apps/electron/src/main/main-window.ts @@ -34,7 +34,7 @@ async function createWindow() { : isWindows() ? 'hidden' : 'default', - trafficLightPosition: { x: 24, y: 18 }, + trafficLightPosition: { x: 20, y: 18 }, x: mainWindowState.x, y: mainWindowState.y, width: mainWindowState.width, diff --git a/packages/component/src/components/app-sidebar/category-divider/index.css.ts b/packages/component/src/components/app-sidebar/category-divider/index.css.ts index 5a65b42c0f..27afa7bcdc 100644 --- a/packages/component/src/components/app-sidebar/category-divider/index.css.ts +++ b/packages/component/src/components/app-sidebar/category-divider/index.css.ts @@ -3,13 +3,16 @@ import { style } from '@vanilla-extract/css'; export const root = style({ fontSize: 'var(--affine-font-xs)', minHeight: '16px', + width: 'calc(100% + 6px)', userSelect: 'none', display: 'flex', alignItems: 'center', justifyContent: 'space-between', + marginBottom: '4px', + padding: '0 8px', selectors: { '&:not(:first-of-type)': { - marginTop: '10px', + marginTop: '16px', }, }, }); diff --git a/packages/component/src/components/app-sidebar/index.css.ts b/packages/component/src/components/app-sidebar/index.css.ts index ba5086208e..2443f1a599 100644 --- a/packages/component/src/components/app-sidebar/index.css.ts +++ b/packages/component/src/components/app-sidebar/index.css.ts @@ -52,7 +52,6 @@ export const navStyle = style({ display: 'flex', flexDirection: 'column', zIndex: parseInt(baseTheme.zIndexModal), - borderRight: '1px solid transparent', }); export const navHeaderStyle = style({ @@ -76,6 +75,7 @@ export const navBodyStyle = style({ height: 'calc(100% - 52px)', display: 'flex', flexDirection: 'column', + rowGap: '4px', }); export const sidebarFloatMaskStyle = style({ diff --git a/packages/component/src/components/app-sidebar/menu-item/index.css.ts b/packages/component/src/components/app-sidebar/menu-item/index.css.ts index ef93f4171d..70328c16ac 100644 --- a/packages/component/src/components/app-sidebar/menu-item/index.css.ts +++ b/packages/component/src/components/app-sidebar/menu-item/index.css.ts @@ -1,15 +1,23 @@ import { style } from '@vanilla-extract/css'; + +export const linkItemRoot = style({ + color: 'inherit', + display: 'contents', +}); + export const root = style({ display: 'inline-flex', alignItems: 'center', borderRadius: '4px', + textAlign: 'left', + color: 'inherit', width: '100%', minHeight: '30px', userSelect: 'none', cursor: 'pointer', padding: '0 12px', fontSize: 'var(--affine-font-sm)', - margin: '2px 0', + marginTop: '4px', selectors: { '&:hover': { background: 'var(--affine-hover-color)', @@ -29,10 +37,8 @@ export const root = style({ // 'linear-gradient(0deg, rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0.04)), rgba(0, 0, 0, 0.04)', // }, '&[data-collapsible="true"]': { - width: 'calc(100% + 8px)', - transform: 'translateX(-8px)', paddingLeft: '4px', - paddingRight: '12px', + paddingRight: '4px', }, '&[data-type="collection-list-item"][data-collapsible="false"][data-active="true"],&[data-type="favorite-list-item"][data-collapsible="false"][data-active="true"], &[data-type="favorite-list-item"][data-collapsible="false"]:hover, &[data-type="collection-list-item"][data-collapsible="false"]:hover': { @@ -41,6 +47,9 @@ export const root = style({ paddingLeft: '20px', paddingRight: '12px', }, + [`${linkItemRoot}:first-of-type &`]: { + marginTop: '0px', + }, }, }); @@ -53,6 +62,12 @@ export const content = style({ export const postfix = style({ justifySelf: 'flex-end', + display: 'none', + selectors: { + [`${root}:hover &`]: { + display: 'flex', + }, + }, }); export const icon = style({ @@ -68,10 +83,15 @@ export const collapsedIconContainer = style({ justifyContent: 'center', borderRadius: '2px', transition: 'transform 0.2s', + color: 'inherit', selectors: { '&[data-collapsed="true"]': { transform: 'rotate(-90deg)', }, + '&[data-disabled="true"]': { + opacity: 0.3, + pointerEvents: 'none', + }, '&:hover': { background: 'var(--affine-hover-color)', }, @@ -103,8 +123,3 @@ export const collapsedIcon = style({ export const spacer = style({ flex: 1, }); - -export const linkItemRoot = style({ - color: 'inherit', - display: 'contents', -}); diff --git a/packages/component/src/components/app-sidebar/menu-item/index.tsx b/packages/component/src/components/app-sidebar/menu-item/index.tsx index 0abf0ea4f5..4c67548c35 100644 --- a/packages/component/src/components/app-sidebar/menu-item/index.tsx +++ b/packages/component/src/components/app-sidebar/menu-item/index.tsx @@ -6,11 +6,13 @@ import { Link } from 'react-router-dom'; import * as styles from './index.css'; -export interface MenuItemProps extends React.HTMLAttributes { +export interface MenuItemProps extends React.HTMLAttributes { icon?: React.ReactElement; active?: boolean; disabled?: boolean; - collapsed?: boolean; // true, false, undefined. undefined means no collapse + // true, false, undefined. undefined means no collapse + collapsed?: boolean; + // if onCollapsedChange is given, but collapsed is undefined, then we will render the collapse button as disabled onCollapsedChange?: (collapsed: boolean) => void; postfix?: React.ReactElement; } @@ -23,7 +25,7 @@ const stopPropagation: React.MouseEventHandler = e => { e.stopPropagation(); }; -export const MenuItem = React.forwardRef( +export const MenuItem = React.forwardRef( ( { onClick, @@ -38,14 +40,9 @@ export const MenuItem = React.forwardRef( }, ref ) => { - const collapsible = collapsed !== undefined; - if (collapsible && !onCollapsedChange) { - throw new Error( - 'onCollapsedChange is required when collapsed is defined' - ); - } + const collapsible = onCollapsedChange !== undefined; return ( -
(
{collapsible && (
{ e.stopPropagation(); e.preventDefault(); // for links @@ -68,7 +66,7 @@ export const MenuItem = React.forwardRef( >
)} @@ -84,21 +82,22 @@ export const MenuItem = React.forwardRef( {postfix}
) : null} -
+ ); } ); MenuItem.displayName = 'MenuItem'; -export const MenuLinkItem = React.forwardRef( - ({ to, ...props }, ref) => { - return ( - - {/* The element rendered by Link does not generate display box due to `display: contents` style */} - {/* Thus ref is passed to MenuItem instead of Link */} - - - ); - } -); +export const MenuLinkItem = React.forwardRef< + HTMLButtonElement, + MenuLinkItemProps +>(({ to, ...props }, ref) => { + return ( + + {/* The element rendered by Link does not generate display box due to `display: contents` style */} + {/* Thus ref is passed to MenuItem instead of Link */} + + + ); +}); MenuLinkItem.displayName = 'MenuLinkItem'; diff --git a/packages/component/src/components/app-sidebar/quick-search-input/index.css.ts b/packages/component/src/components/app-sidebar/quick-search-input/index.css.ts index 7033cadd89..d748ab9dbf 100644 --- a/packages/component/src/components/app-sidebar/quick-search-input/index.css.ts +++ b/packages/component/src/components/app-sidebar/quick-search-input/index.css.ts @@ -12,7 +12,7 @@ export const root = style({ userSelect: 'none', cursor: 'pointer', padding: '0 12px', - margin: '12px 0', + margin: '20px 0', position: 'relative', }); diff --git a/packages/component/src/components/app-sidebar/resize-indicator/index.tsx b/packages/component/src/components/app-sidebar/resize-indicator/index.tsx index 2e6f0d9548..666b49ba36 100644 --- a/packages/component/src/components/app-sidebar/resize-indicator/index.tsx +++ b/packages/component/src/components/app-sidebar/resize-indicator/index.tsx @@ -1,6 +1,7 @@ +import { assertExists } from '@blocksuite/global/utils'; import { useAtom, useSetAtom } from 'jotai'; import type { ReactElement } from 'react'; -import { useCallback, useLayoutEffect, useState } from 'react'; +import { useCallback } from 'react'; import { appSidebarOpenAtom, @@ -18,16 +19,10 @@ export const ResizeIndicator = (props: ResizeIndicatorProps): ReactElement => { const [sidebarOpen, setSidebarOpen] = useAtom(appSidebarOpenAtom); const [isResizing, setIsResizing] = useAtom(appSidebarResizingAtom); - const [anchorLeft, setAnchorLeft] = useState(0); - - useLayoutEffect(() => { - if (!props.targetElement) return; - const { left } = props.targetElement.getBoundingClientRect(); - setAnchorLeft(left); - }, [props.targetElement]); - const onResizeStart = useCallback(() => { let resized = false; + assertExists(props.targetElement); + const { left: anchorLeft } = props.targetElement.getBoundingClientRect(); function onMouseMove(e: MouseEvent) { e.preventDefault(); @@ -51,13 +46,7 @@ export const ResizeIndicator = (props: ResizeIndicatorProps): ReactElement => { }, { once: true } ); - }, [ - anchorLeft, - props.targetElement, - setIsResizing, - setSidebarOpen, - setWidth, - ]); + }, [props.targetElement, setIsResizing, setSidebarOpen, setWidth]); return (
{ await first.getByTestId('fav-collapsed-button').click(); const collectionPage = collections.getByTestId('collection-page').nth(0); expect(await collectionPage.textContent()).toBe('test page'); + await collectionPage.hover(); await collectionPage.getByTestId('collection-page-options').click(); const deletePage = page .getByTestId('collection-page-option') .getByText('Delete'); await deletePage.click(); expect(await collections.getByTestId('collection-page').count()).toBe(0); + await first.hover(); await first.getByTestId('collection-options').click(); const deleteCollection = page .getByTestId('collection-option') @@ -76,6 +78,7 @@ test('pin and unpin collection', async ({ page }) => { await page.waitForTimeout(50); expect(await items.count()).toBe(1); const first = items.first(); + await first.hover(); await first.getByTestId('collection-options').click(); const deleteCollection = page .getByTestId('collection-option') @@ -99,6 +102,7 @@ test('edit collection', async ({ page }) => { const items = collections.getByTestId('collection-item'); expect(await items.count()).toBe(1); const first = items.first(); + await first.hover(); await first.getByTestId('collection-options').click(); const editCollection = page .getByTestId('collection-option') @@ -117,6 +121,7 @@ test('edit collection and change filter date', async ({ page }) => { const items = collections.getByTestId('collection-item'); expect(await items.count()).toBe(1); const first = items.first(); + await first.hover(); await first.getByTestId('collection-options').click(); const editCollection = page .getByTestId('collection-option') diff --git a/tests/affine-local/e2e/local-first-favorites-items.spec.ts b/tests/affine-local/e2e/local-first-favorites-items.spec.ts index e2bd320927..d672fb9af1 100644 --- a/tests/affine-local/e2e/local-first-favorites-items.spec.ts +++ b/tests/affine-local/e2e/local-first-favorites-items.spec.ts @@ -122,7 +122,7 @@ test("Deleted page's reference will not be shown in sidebar", async ({ '[data-testid="fav-collapsed-button"]' ); - await expect(collapseButton).not.toBeVisible(); + expect(collapseButton).toHaveAttribute('data-disabled', 'true'); const currentWorkspace = await workspace.current(); expect(currentWorkspace.flavour).toContain('local');