feat: fav page references (#2422)

Co-authored-by: Himself65 <himself65@outlook.com>
This commit is contained in:
Peng Xiao
2023-05-18 13:18:40 +08:00
committed by GitHub
parent b7cee3185e
commit 2f7b51d7ff
9 changed files with 270 additions and 38 deletions

View File

@@ -6,7 +6,7 @@ import {
} from '@blocksuite/icons';
import type { Meta, StoryFn } from '@storybook/react';
import { useAtom } from 'jotai';
import type { PropsWithChildren } from 'react';
import { type PropsWithChildren, useState } from 'react';
import { AppSidebar, AppSidebarFallback, appSidebarOpenAtom } from '.';
import { AddPageButton } from './add-page-button';
@@ -79,6 +79,7 @@ export const Fallback = () => {
};
export const WithItems: StoryFn = () => {
const [collapsed, setCollapsed] = useState(false);
return (
<Container>
<AppSidebar>
@@ -111,11 +112,22 @@ export const WithItems: StoryFn = () => {
<SidebarScrollableContainer>
<CategoryDivider label="Favorites" />
<MenuLinkItem
collapsed={collapsed}
onCollapsedChange={setCollapsed}
icon={<SettingsIcon />}
href="/test"
onClick={() => alert('opened')}
>
Settings
Collapsible Item
</MenuLinkItem>
<MenuLinkItem
collapsed={!collapsed}
onCollapsedChange={setCollapsed}
icon={<SettingsIcon />}
href="/test"
onClick={() => alert('opened')}
>
Collapsible Item
</MenuLinkItem>
<MenuLinkItem
icon={<SettingsIcon />}

View File

@@ -8,7 +8,7 @@ export const root = style({
minHeight: '30px',
userSelect: 'none',
cursor: 'pointer',
padding: '0 12px',
padding: '0 8px 0 12px',
fontSize: 'var(--affine-font-sm)',
selectors: {
'&:hover': {
@@ -27,6 +27,11 @@ export const root = style({
// make this a variable?
'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: '8px',
},
},
});
@@ -37,11 +42,49 @@ export const content = style({
});
export const icon = style({
marginRight: '14px',
color: 'var(--affine-icon-color)',
fontSize: '20px',
});
export const collapsedIconContainer = style({
width: '12px',
height: '12px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '2px',
transition: 'transform 0.2s',
selectors: {
'&[data-collapsed="true"]': {
transform: 'rotate(-90deg)',
},
'&:hover': {
background: 'var(--affine-hover-color)',
},
},
});
export const iconsContainer = style({
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
width: '28px',
selectors: {
'&[data-collapsible="true"]': {
width: '40px',
},
},
});
export const collapsedIcon = style({
transition: 'transform 0.2s ease-in-out',
selectors: {
'&[data-collapsed="true"]': {
transform: 'rotate(-90deg)',
},
},
});
export const spacer = style({
flex: 1,
});

View File

@@ -1,5 +1,6 @@
import { SettingsIcon } from '@blocksuite/icons';
import type { Meta, StoryFn } from '@storybook/react';
import { useState } from 'react';
import { MenuItem, MenuLinkItem } from '.';
@@ -9,6 +10,7 @@ export default {
} satisfies Meta;
export const Default: StoryFn = () => {
const [collapsed, setCollapsed] = useState(false);
return (
<main style={{ width: '240px' }}>
<MenuItem icon={<SettingsIcon />} onClick={() => alert('opened')}>
@@ -29,6 +31,14 @@ export const Default: StoryFn = () => {
>
Primary Item
</MenuLinkItem>
<MenuItem
collapsed={collapsed}
onCollapsedChange={setCollapsed}
icon={<SettingsIcon />}
onClick={() => alert('opened')}
>
Collapsible Item
</MenuItem>
</main>
);
};

View File

@@ -1,3 +1,4 @@
import { ArrowDownSmallIcon } from '@blocksuite/icons';
import clsx from 'clsx';
import type { LinkProps } from 'next/link';
import Link from 'next/link';
@@ -9,6 +10,8 @@ interface MenuItemProps extends React.HTMLAttributes<HTMLDivElement> {
icon?: React.ReactElement;
active?: boolean;
disabled?: boolean;
collapsed?: boolean; // true, false, undefined. undefined means no collapse
onCollapsedChange?: (collapsed: boolean) => void;
}
interface MenuLinkItemProps extends MenuItemProps, Pick<LinkProps, 'href'> {}
@@ -19,8 +22,14 @@ export function MenuItem({
active,
children,
disabled,
collapsed,
onCollapsedChange,
...props
}: MenuItemProps) {
const collapsible = collapsed !== undefined;
if (collapsible && !onCollapsedChange) {
throw new Error('onCollapsedChange is required when collapsed is defined');
}
return (
<div
{...props}
@@ -28,11 +37,31 @@ export function MenuItem({
onClick={onClick}
data-active={active}
data-disabled={disabled}
data-collapsible={collapsible}
>
{icon &&
React.cloneElement(icon, {
className: clsx([styles.icon, icon.props.className]),
})}
<div className={styles.iconsContainer} data-collapsible={collapsible}>
{collapsible && (
<div
onClick={e => {
e.stopPropagation();
e.preventDefault(); // for links
onCollapsedChange?.(!collapsed);
}}
data-testid="fav-collapsed-button"
className={styles.collapsedIconContainer}
>
<ArrowDownSmallIcon
className={styles.collapsedIcon}
data-collapsed={collapsed}
/>
</div>
)}
{icon &&
React.cloneElement(icon, {
className: clsx([styles.icon, icon.props.className]),
})}
</div>
<div className={styles.content}>{children}</div>
</div>
);

View File

@@ -17,7 +17,7 @@ export const root = style({
});
export const icon = style({
marginRight: '14px',
marginRight: '8px',
color: 'var(--affine-icon-color)',
fontSize: '20px',
});