feat: modify sidebar style (#1703)

This commit is contained in:
Qi
2023-03-28 02:41:04 +08:00
committed by GitHub
parent c2b1a9b118
commit 628ce08d8d
24 changed files with 503 additions and 383 deletions

View File

@@ -18,7 +18,7 @@
"@affine/workspace": "workspace:*",
"@blocksuite/blocks": "0.5.0-20230324040005-14417c2",
"@blocksuite/editor": "0.5.0-20230324040005-14417c2",
"@blocksuite/icons": "2.0.23",
"@blocksuite/icons": "latest",
"@blocksuite/store": "0.5.0-20230324040005-14417c2",
"@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.6",

View File

@@ -79,7 +79,7 @@ export const OperationCell: React.FC<OperationCellProps> = ({
disablePortal={true}
trigger="click"
>
<IconButton darker={true}>
<IconButton>
<MoreVerticalIcon />
</IconButton>
</Menu>
@@ -127,7 +127,6 @@ export const TrashOperationCell: React.FC<TrashOperationCellProps> = ({
<FlexWrapper>
<Tooltip content={t('Restore it')} placement="top-start">
<IconButton
darker={true}
style={{ marginRight: '12px' }}
onClick={() => {
onRestorePage(id);
@@ -139,7 +138,6 @@ export const TrashOperationCell: React.FC<TrashOperationCellProps> = ({
</Tooltip>
<Tooltip content={t('Delete permanently')} placement="top-start">
<IconButton
darker={true}
onClick={() => {
setOpen(true);
}}

View File

@@ -56,7 +56,6 @@ const FavoriteTag: React.FC<FavoriteTagProps> = ({
placement="top-start"
>
<IconButton
darker={true}
iconSize={[20, 20]}
onClick={e => {
e.stopPropagation();
@@ -88,13 +87,12 @@ type PageListProps = {
};
const filter = {
all: (pageMeta: PageMeta, allMetas: PageMeta[]) => !pageMeta.trash,
all: (pageMeta: PageMeta) => !pageMeta.trash,
trash: (pageMeta: PageMeta, allMetas: PageMeta[]) => {
const parentMeta = allMetas.find(m => m.subpageIds?.includes(pageMeta.id));
return !parentMeta?.trash && pageMeta.trash;
},
favorite: (pageMeta: PageMeta, allMetas: PageMeta[]) =>
pageMeta.favorite && !pageMeta.trash,
favorite: (pageMeta: PageMeta) => pageMeta.favorite && !pageMeta.trash,
};
export const PageList: React.FC<PageListProps> = ({

View File

@@ -8,16 +8,16 @@ import {
export const StyledHeaderContainer = styled('div')<{ hasWarning: boolean }>(
({ hasWarning }) => {
return {
height: hasWarning ? '96px' : '60px',
height: hasWarning ? '96px' : '48px',
};
}
);
export const StyledHeader = styled('div')<{ hasWarning: boolean }>(
({ theme }) => {
return {
height: '64px',
height: '48px',
width: '100%',
padding: '0 28px',
padding: '0 20px',
...displayFlex('space-between', 'center'),
background: theme.colors.pageBackground,
transition: 'background-color 0.5s',

View File

@@ -1,9 +1,16 @@
import { CloudWorkspaceIcon, LocalWorkspaceIcon } from '@blocksuite/icons';
import type React from 'react';
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
import { useBlockSuiteWorkspaceName } from '../../../../hooks/use-blocksuite-workspace-name';
import type { RemWorkspace } from '../../../../shared';
import { WorkspaceAvatar } from '../../workspace-avatar';
import { SelectorWrapper, WorkspaceName } from './styles';
import {
StyledSelectorContainer,
StyledSelectorWrapper,
StyledWorkspaceName,
StyledWorkspaceStatus,
} from './styles';
export type WorkspaceSelectorProps = {
currentWorkspace: RemWorkspace | null;
@@ -17,19 +24,32 @@ export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
const [name] = useBlockSuiteWorkspaceName(
currentWorkspace?.blockSuiteWorkspace ?? null
);
const [workspace] = useCurrentWorkspace();
return (
<>
<SelectorWrapper onClick={onClick} data-testid="current-workspace">
<StyledSelectorContainer onClick={onClick} data-testid="current-workspace">
<WorkspaceAvatar
data-testid="workspace-avatar"
style={{
flexShrink: 0,
}}
size={32}
size={40}
workspace={currentWorkspace}
/>
<WorkspaceName data-testid="workspace-name">{name}</WorkspaceName>
</SelectorWrapper>
</>
<StyledSelectorWrapper>
<StyledWorkspaceName data-testid="workspace-name">
{name}
</StyledWorkspaceName>
{workspace && (
<StyledWorkspaceStatus>
{workspace.flavour === 'local' ? (
<LocalWorkspaceIcon />
) : (
<CloudWorkspaceIcon />
)}
{workspace.flavour === 'local' ? 'Local' : 'AFFiNE Cloud'}
</StyledWorkspaceStatus>
)}
</StyledSelectorWrapper>
</StyledSelectorContainer>
);
};

View File

@@ -1,13 +1,14 @@
import { MuiAvatar, textEllipsis } from '@affine/component';
import { displayFlex, textEllipsis } from '@affine/component';
import { styled } from '@affine/component';
export const SelectorWrapper = styled('div')(({ theme }) => {
export const StyledSelectorContainer = styled('div')(({ theme }) => {
return {
marginTop: '4px',
height: '56px',
height: '58px',
display: 'flex',
alignItems: 'center',
padding: '0 44px 0 12px',
borderRadius: '5px',
padding: '0 6px',
marginBottom: '16px',
borderRadius: '8px',
color: theme.colors.textColor,
position: 'relative',
':hover': {
@@ -17,17 +18,31 @@ export const SelectorWrapper = styled('div')(({ theme }) => {
};
});
export const Avatar = styled(MuiAvatar)({
height: '28px',
width: '28px',
});
export const WorkspaceName = styled('span')(({ theme }) => {
export const StyledSelectorWrapper = styled('div')(() => {
return {
marginLeft: '12px',
fontSize: theme.font.h6,
fontWeight: 500,
marginLeft: '8px',
flexGrow: 1,
overflow: 'hidden',
};
});
export const StyledWorkspaceName = styled('div')(() => {
return {
lineHeight: '24px',
fontWeight: 600,
...textEllipsis(1),
};
});
export const StyledWorkspaceStatus = styled('div')(({ theme }) => {
return {
height: '22px',
...displayFlex('flex-start', 'center'),
fontSize: theme.font.sm,
color: theme.colors.secondaryTextColor,
svg: {
color: theme.colors.iconColor,
fontSize: theme.font.base,
marginRight: '4px',
},
};
});

View File

@@ -0,0 +1,70 @@
import { MuiCollapse } from '@affine/component';
import { useTranslation } from '@affine/i18n';
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
import { useAtomValue } from 'jotai';
import { useRouter } from 'next/router';
import { useMemo } from 'react';
import { workspacePreferredModeAtom } from '../../../../atoms';
import type { FavoriteListProps } from '../index';
import { StyledCollapseItem } from '../shared-styles';
export const FavoriteList = ({
pageMeta,
openPage,
showList,
}: FavoriteListProps) => {
const router = useRouter();
const { t } = useTranslation();
const record = useAtomValue(workspacePreferredModeAtom);
const favoriteList = useMemo(
() => pageMeta.filter(p => p.favorite && !p.trash),
[pageMeta]
);
return (
<MuiCollapse
in={showList}
style={{
maxHeight: 300,
overflowY: 'auto',
marginLeft: '16px',
}}
>
{favoriteList.map((pageMeta, index) => {
const active = router.query.pageId === pageMeta.id;
return (
<div key={`${pageMeta}-${index}`}>
<StyledCollapseItem
data-testid={`favorite-list-item-${pageMeta.id}`}
active={active}
ref={ref => {
if (ref && active) {
ref.scrollIntoView({ behavior: 'smooth' });
}
}}
onClick={() => {
if (active) {
return;
}
openPage(pageMeta.id);
}}
>
{record[pageMeta.id] === 'edgeless' ? (
<EdgelessIcon />
) : (
<PageIcon />
)}
{pageMeta.title || 'Untitled'}
</StyledCollapseItem>
</div>
);
})}
{favoriteList.length === 0 && (
<StyledCollapseItem disable={true}>{t('No item')}</StyledCollapseItem>
)}
</MuiCollapse>
);
};
export default FavoriteList;

View File

@@ -0,0 +1,62 @@
import { useTranslation } from '@affine/i18n';
import { ArrowDownSmallIcon, FavoriteIcon } from '@blocksuite/icons';
import { useCallback, useState } from 'react';
import { usePageMeta } from '../../../../hooks/use-page-meta';
import type { WorkSpaceSliderBarProps } from '../index';
import { StyledCollapseButton, StyledListItem } from '../shared-styles';
import { StyledLink } from '../style';
import FavoriteList from './favorite-list';
export const Favorite = ({
currentPath,
paths,
currentPageId,
openPage,
currentWorkspace,
}: Pick<
WorkSpaceSliderBarProps,
'currentPath' | 'paths' | 'currentPageId' | 'openPage' | 'currentWorkspace'
>) => {
const currentWorkspaceId = currentWorkspace?.id || null;
const pageMeta = usePageMeta(currentWorkspace?.blockSuiteWorkspace ?? null);
const [showSubFavorite, setOpenSubFavorite] = useState(true);
const { t } = useTranslation();
return (
<>
<StyledListItem
active={
currentPath ===
(currentWorkspaceId && paths.favorite(currentWorkspaceId))
}
>
<StyledCollapseButton
onClick={useCallback(() => {
setOpenSubFavorite(!showSubFavorite);
}, [showSubFavorite])}
collapse={showSubFavorite}
>
<ArrowDownSmallIcon />
</StyledCollapseButton>
<StyledLink
href={{
pathname: currentWorkspaceId && paths.favorite(currentWorkspaceId),
}}
>
<FavoriteIcon />
{t('Favorites')}
</StyledLink>
</StyledListItem>
<FavoriteList
currentPageId={currentPageId}
showList={showSubFavorite}
openPage={openPage}
pageMeta={pageMeta}
/>
</>
);
};
export default Favorite;

View File

@@ -1,35 +1,29 @@
import { MuiCollapse } from '@affine/component';
import { IconButton } from '@affine/component';
import { config } from '@affine/env';
import { useTranslation } from '@affine/i18n';
import {
ArrowDownSmallIcon,
DeleteTemporarilyIcon,
FavoriteIcon,
FolderIcon,
PlusIcon,
SearchIcon,
SettingsIcon,
} from '@blocksuite/icons';
import type { Page, PageMeta } from '@blocksuite/store';
import Link from 'next/link';
import { useRouter } from 'next/router';
import type React from 'react';
import { useCallback, useMemo, useState } from 'react';
import { useCallback } from 'react';
import { useSidebarStatus } from '../../../hooks/affine/use-sidebar-status';
import { usePageMeta } from '../../../hooks/use-page-meta';
import type { RemWorkspace } from '../../../shared';
import { SidebarSwitch } from '../../affine/sidebar-switch';
import Favorite from './favorite';
import { Pivot } from './pivot';
import { StyledListItem } from './shared-styles';
import {
StyledLink,
StyledListItem,
StyledNewPageButton,
StyledSidebarWrapper,
StyledSidebarSwitchWrapper,
StyledSlidebarWrapper,
StyledSliderBar,
StyledSliderBarWrapper,
StyledSubListItem,
} from './style';
import { WorkspaceSelector } from './WorkspaceSelector';
@@ -40,57 +34,6 @@ export type FavoriteListProps = {
pageMeta: PageMeta[];
};
const FavoriteList: React.FC<FavoriteListProps> = ({
pageMeta,
openPage,
showList,
}) => {
const router = useRouter();
const { t } = useTranslation();
const favoriteList = useMemo(
() => pageMeta.filter(p => p.favorite && !p.trash),
[pageMeta]
);
return (
<MuiCollapse
in={showList}
style={{
maxHeight: 300,
overflowY: 'auto',
}}
>
{favoriteList.map((pageMeta, index) => {
const active = router.query.pageId === pageMeta.id;
return (
<div key={`${pageMeta}-${index}`}>
<StyledSubListItem
data-testid={`favorite-list-item-${pageMeta.id}`}
active={active}
ref={ref => {
if (ref && active) {
ref.scrollIntoView({ behavior: 'smooth' });
}
}}
onClick={() => {
if (active) {
return;
}
openPage(pageMeta.id);
}}
>
{pageMeta.title || 'Untitled'}
</StyledSubListItem>
</div>
);
})}
{favoriteList.length === 0 && (
<StyledSubListItem disable={true}>{t('No item')}</StyledSubListItem>
)}
</MuiCollapse>
);
};
export type WorkSpaceSliderBarProps = {
isPublicWorkspace: boolean;
onOpenQuickSearchModal: () => void;
@@ -120,7 +63,6 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
onOpenWorkspaceListModal,
}) => {
const currentWorkspaceId = currentWorkspace?.id || null;
const [showSubFavorite, setOpenSubFavorite] = useState(true);
const { t } = useTranslation();
const [sidebarOpen] = useSidebarStatus();
const pageMeta = usePageMeta(currentWorkspace?.blockSuiteWorkspace ?? null);
@@ -131,15 +73,15 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
return (
<>
<StyledSliderBar show={isPublicWorkspace ? false : sidebarOpen}>
<StyledSidebarWrapper>
<StyledSidebarSwitchWrapper>
<SidebarSwitch
visible={sidebarOpen}
tooltipContent={t('Collapse sidebar')}
testid="sliderBar-arrowButton-collapse"
/>
</StyledSidebarWrapper>
</StyledSidebarSwitchWrapper>
<StyledSliderBarWrapper data-testid="sliderBar">
<StyledSlidebarWrapper data-testid="sliderBar">
<WorkspaceSelector
currentWorkspace={currentWorkspace}
onClick={onOpenWorkspaceListModal}
@@ -147,7 +89,6 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
<StyledListItem
data-testid="slider-bar-quick-search-button"
style={{ cursor: 'pointer' }}
onClick={useCallback(() => {
onOpenQuickSearchModal();
}, [onOpenQuickSearchModal])}
@@ -155,70 +96,16 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
<SearchIcon />
{t('Quick search')}
</StyledListItem>
<Link
href={{
pathname: currentWorkspaceId && paths.all(currentWorkspaceId),
}}
>
<StyledListItem
active={
currentPath ===
(currentWorkspaceId && paths.all(currentWorkspaceId))
}
>
<FolderIcon />
<span data-testid="all-pages">{t('All pages')}</span>
</StyledListItem>
</Link>
{config.enableSubpage && !!currentWorkspace && (
<Pivot
currentWorkspace={currentWorkspace}
openPage={openPage}
allMetas={pageMeta}
/>
)}
<StyledListItem
active={
currentPath ===
(currentWorkspaceId && paths.favorite(currentWorkspaceId))
}
>
<StyledLink
href={{
pathname:
currentWorkspaceId && paths.favorite(currentWorkspaceId),
}}
>
<FavoriteIcon />
{t('Favorites')}
</StyledLink>
<IconButton
darker={true}
onClick={useCallback(() => {
setOpenSubFavorite(!showSubFavorite);
}, [showSubFavorite])}
>
<ArrowDownSmallIcon
style={{
transform: `rotate(${showSubFavorite ? '180' : '0'}deg)`,
}}
/>
</IconButton>
</StyledListItem>
<FavoriteList
currentPageId={currentPageId}
showList={showSubFavorite}
openPage={openPage}
pageMeta={pageMeta}
/>
<StyledListItem
active={
currentPath ===
(currentWorkspaceId && paths.setting(currentWorkspaceId))
}
data-testid="slider-bar-workspace-setting-button"
style={{
marginBottom: '16px',
}}
>
<StyledLink
href={{
@@ -231,42 +118,62 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
</StyledLink>
</StyledListItem>
{/* <WorkspaceSetting
isShow={showWorkspaceSetting}
onClose={() => {
setOpenWorkspaceSetting(false);
}}
/> */}
{/* TODO: will finish the feature next version */}
{/* <StyledListItem
onClick={() => {
triggerImportModal();
}}
<StyledListItem
active={
currentPath ===
(currentWorkspaceId && paths.all(currentWorkspaceId))
}
>
<ImportIcon /> {t('Import')}
</StyledListItem> */}
<Link
<StyledLink
href={{
pathname: currentWorkspaceId && paths.trash(currentWorkspaceId),
pathname: currentWorkspaceId && paths.all(currentWorkspaceId),
}}
>
<FolderIcon />
<span data-testid="all-pages">{t('All pages')}</span>
</StyledLink>
</StyledListItem>
<Favorite
currentPath={currentPath}
paths={paths}
currentPageId={currentPageId}
openPage={openPage}
currentWorkspace={currentWorkspace}
/>
{config.enableSubpage && !!currentWorkspace && (
<Pivot
currentWorkspace={currentWorkspace}
openPage={openPage}
allMetas={pageMeta}
/>
)}
<StyledListItem
active={
currentPath ===
(currentWorkspaceId && paths.trash(currentWorkspaceId))
}
style={{
marginTop: '16px',
}}
>
<StyledLink
href={{
pathname: currentWorkspaceId && paths.trash(currentWorkspaceId),
}}
>
<DeleteTemporarilyIcon /> {t('Trash')}
</StyledLink>
</StyledListItem>
</Link>
</StyledSlidebarWrapper>
<StyledNewPageButton
data-testid="new-page-button"
onClick={onClickNewPage}
>
<PlusIcon /> {t('New Page')}
</StyledNewPageButton>
</StyledSliderBarWrapper>
</StyledSliderBar>
</>
);

View File

@@ -1,5 +1,6 @@
import { IconButton, MuiCollapse, TreeView } from '@affine/component';
import { MuiCollapse, TreeView } from '@affine/component';
import { DebugLogger } from '@affine/debug';
import { useTranslation } from '@affine/i18n';
import { ArrowDownSmallIcon, FolderIcon } from '@blocksuite/icons';
import type { PageMeta } from '@blocksuite/store';
import { nanoid } from '@blocksuite/store';
@@ -8,7 +9,7 @@ import { useCallback, useMemo, useState } from 'react';
import { useBlockSuiteWorkspaceHelper } from '../../../../hooks/use-blocksuite-workspace-helper';
import { usePageMetaHelper } from '../../../../hooks/use-page-meta';
import type { RemWorkspace } from '../../../../shared';
import { StyledListItem } from '../style';
import { StyledCollapseButton, StyledListItem } from '../shared-styles';
import type { TreeNode } from './types';
import { flattenToTree } from './utils';
const logger = new DebugLogger('pivot');
@@ -178,6 +179,7 @@ export const PivotInternal = ({
onAdd={handleAdd}
onDelete={handleDelete}
onDrop={handleDrop}
indent={16}
/>
);
};
@@ -191,32 +193,30 @@ export const Pivot = ({
openPage: (pageId: string) => void;
allMetas: PageMeta[];
}) => {
const { t } = useTranslation();
const [showPivot, setShowPivot] = useState(true);
return (
<>
<StyledListItem>
<FolderIcon />
Pivot
<IconButton
darker={true}
<StyledCollapseButton
onClick={useCallback(() => {
setShowPivot(!showPivot);
}, [showPivot])}
collapse={showPivot}
>
<ArrowDownSmallIcon
style={{
transform: `rotate(${showPivot ? '180' : '0'}deg)`,
}}
/>
</IconButton>
<ArrowDownSmallIcon />
</StyledCollapseButton>
<FolderIcon />
{t('Pivots')}
</StyledListItem>
<MuiCollapse
in={showPivot}
style={{
maxHeight: 300,
paddingLeft: '12px',
paddingLeft: '16px',
overflowY: 'auto',
}}
>

View File

@@ -1,12 +1,18 @@
import { IconButton } from '@affine/component';
import {
ArrowDownSmallIcon,
DeleteTemporarilyIcon,
PlusIcon,
EdgelessIcon,
// DeleteTemporarilyIcon,
// PlusIcon,
MoreVerticalIcon,
PageIcon,
} from '@blocksuite/icons';
import type { PageMeta } from '@blocksuite/store';
import { useAtomValue } from 'jotai';
import { useRouter } from 'next/router';
import { StyledCollapsedButton, StyledPivotItem } from './styles';
import { workspacePreferredModeAtom } from '../../../../atoms';
import { StyledCollapseButton, StyledCollapseItem } from '../shared-styles';
import type { TreeNode } from './types';
export const TreeNodeRender: TreeNode['render'] = (
@@ -14,12 +20,17 @@ export const TreeNodeRender: TreeNode['render'] = (
{ onAdd, onDelete, collapsed, setCollapsed },
extendProps
) => {
const { openPage } = extendProps as { openPage: (pageId: string) => void };
const { openPage, pageMeta } = extendProps as {
openPage: (pageId: string) => void;
pageMeta: PageMeta;
};
const record = useAtomValue(workspacePreferredModeAtom);
const router = useRouter();
const active = router.query.pageId === node.id;
return (
<StyledPivotItem
<StyledCollapseItem
onClick={() => {
if (active) {
return;
@@ -28,42 +39,49 @@ export const TreeNodeRender: TreeNode['render'] = (
}}
active={active}
>
<StyledCollapsedButton
<StyledCollapseButton
collapse={collapsed}
show={!!node.children?.length}
onClick={e => {
e.stopPropagation();
setCollapsed(!collapsed);
}}
size="small"
>
<ArrowDownSmallIcon
style={{
transform: `rotate(${collapsed ? '0' : '180'}deg)`,
}}
/>
</StyledCollapsedButton>
<ArrowDownSmallIcon />
</StyledCollapseButton>
{record[pageMeta.id] === 'edgeless' ? <EdgelessIcon /> : <PageIcon />}
<span>{node.title || 'Untitled'}</span>
<IconButton
onClick={e => {
e.stopPropagation();
onAdd();
}}
size="small"
className="pivot-item-button"
>
<PlusIcon />
</IconButton>
<IconButton
className="operation-button"
onClick={e => {
e.stopPropagation();
}}
>
<MoreVerticalIcon />
</IconButton>
onDelete();
}}
size="small"
className="pivot-item-button"
>
<DeleteTemporarilyIcon />
</IconButton>
</StyledPivotItem>
{/*<IconButton*/}
{/* onClick={e => {*/}
{/* e.stopPropagation();*/}
{/* onAdd();*/}
{/* }}*/}
{/* size="small"*/}
{/* className="operation-button"*/}
{/*>*/}
{/* <PlusIcon />*/}
{/*</IconButton>*/}
{/*<IconButton*/}
{/* onClick={e => {*/}
{/* e.stopPropagation();*/}
{/* onDelete();*/}
{/* }}*/}
{/* size="small"*/}
{/* className="operation-button"*/}
{/*>*/}
{/* <DeleteTemporarilyIcon />*/}
{/*</IconButton>*/}
</StyledCollapseItem>
);
};

View File

@@ -1,35 +1,17 @@
import {
displayFlex,
IconButton,
styled,
textEllipsis,
} from '@affine/component';
import { IconButton, styled } from '@affine/component';
export const StyledPivotItem = styled('div')<{ active: boolean }>(
({ active, theme }) => {
export const StyledOperationButton = styled('button')(({ theme }) => {
return {
width: '100%',
height: '32px',
...displayFlex('flex-start', 'center'),
paddingLeft: '24px',
position: 'relative',
color: active ? theme.colors.primaryColor : theme.colors.textColor,
cursor: 'pointer',
span: {
flexGrow: '1',
...textEllipsis(1),
},
'.pivot-item-button': {
height: '20px',
width: '20px',
fontSize: '20px',
color: theme.colors.iconColor,
display: 'none',
},
':hover': {
'.pivot-item-button': {
display: 'flex',
},
background: theme.colors.hoverBackground,
},
};
}
);
});
export const StyledCollapsedButton = styled(IconButton, {
shouldForwardProp: prop => {

View File

@@ -32,7 +32,11 @@ export const flattenToTree = (
const returnedMeta: TreeNode = {
...internalMeta,
children: helper(childrenMetas),
render: (node, props) => TreeNodeRender!(node, props, renderProps),
render: (node, props) =>
TreeNodeRender!(node, props, {
pageMeta: internalMeta,
...renderProps,
}),
};
// @ts-ignore
returnedMetas.push(returnedMeta);

View File

@@ -0,0 +1,98 @@
import { displayFlex, styled, textEllipsis } from '@affine/component';
export const StyledListItem = styled('div')<{
active?: boolean;
disabled?: boolean;
}>(({ theme, active, disabled }) => {
return {
height: '32px',
color: active ? theme.colors.primaryColor : theme.colors.textColor,
padding: '0 16px',
borderRadius: '8px',
cursor: 'pointer',
marginBottom: '4px',
position: 'relative',
...displayFlex('flex-start', 'center'),
...(disabled
? {
cursor: 'not-allowed',
color: theme.colors.borderColor,
}
: {}),
'> svg, a > svg': {
fontSize: '20px',
marginRight: '12px',
color: active ? theme.colors.primaryColor : theme.colors.iconColor,
},
':hover:not([disabled])': {
backgroundColor: theme.colors.hoverBackground,
},
};
});
export const StyledCollapseButton = styled('button')<{
collapse: boolean;
show?: boolean;
}>(({ collapse, show = true, theme }) => {
return {
width: '16px',
height: '16px',
fontSize: '16px',
position: 'absolute',
left: '0',
top: '0',
bottom: '0',
margin: 'auto',
color: theme.colors.iconColor,
opacity: '.6',
display: show ? 'block' : 'none',
svg: {
transform: `rotate(${collapse ? '0' : '-90'}deg)`,
},
};
});
export const StyledCollapseItem = styled('button')<{
disable?: boolean;
active?: boolean;
}>(({ disable = false, active = false, theme }) => {
return {
width: '100%',
height: '32px',
borderRadius: '8px',
...displayFlex('flex-start', 'center'),
padding: '0 2px 0 16px',
position: 'relative',
color: disable
? theme.colors.disableColor
: active
? theme.colors.primaryColor
: theme.colors.textColor,
cursor: disable ? 'not-allowed' : 'pointer',
span: {
flexGrow: '1',
textAlign: 'left',
...textEllipsis(1),
},
'> svg': {
fontSize: '20px',
marginRight: '8px',
flexShrink: '0',
color: active ? theme.colors.primaryColor : theme.colors.iconColor,
},
'.operation-button': {
display: 'none',
},
':hover': disable
? {}
: {
backgroundColor: theme.colors.hoverBackground,
'.operation-button': {
display: 'flex',
},
},
};
});

View File

@@ -1,6 +1,5 @@
import { displayFlex, styled, textEllipsis } from '@affine/component';
import { displayFlex, styled } from '@affine/component';
import Link from 'next/link';
export const StyledSliderBar = styled('div')<{ show: boolean }>(
({ theme, show }) => {
return {
@@ -13,60 +12,30 @@ export const StyledSliderBar = styled('div')<{ show: boolean }>(
transition: 'width .15s, padding .15s',
position: 'relative',
zIndex: theme.zIndex.modal,
padding: show ? '0 12px' : '0',
padding: show ? '0 4px' : '0',
flexShrink: 0,
display: 'flex',
flexDirection: 'column',
};
}
);
export const StyledSidebarWrapper = styled('div')(() => {
export const StyledSidebarSwitchWrapper = styled('div')(() => {
return {
position: 'absolute',
right: '12px',
top: '16px',
zIndex: 1,
height: '48px',
padding: '0 16px',
...displayFlex('flex-start', 'center'),
};
});
export const StyledSliderBarWrapper = styled('div')(() => {
export const StyledSlidebarWrapper = styled('div')(() => {
return {
height: '100%',
flexGrow: 1,
overflowX: 'hidden',
overflowY: 'auto',
position: 'relative',
};
});
export const StyledListItem = styled('div')<{
active?: boolean;
disabled?: boolean;
}>(({ theme, active, disabled }) => {
return {
height: '32px',
marginTop: '12px',
color: active ? theme.colors.primaryColor : theme.colors.textColor,
paddingLeft: '12px',
borderRadius: '5px',
cursor: 'pointer',
...displayFlex('flex-start', 'center'),
...(disabled
? {
cursor: 'not-allowed',
color: theme.colors.borderColor,
}
: {}),
'> svg': {
fontSize: '20px',
marginRight: '12px',
color: active ? theme.colors.primaryColor : theme.colors.iconColor,
},
':hover:not([disabled])': {
color: theme.colors.primaryColor,
backgroundColor: theme.colors.hoverBackground,
},
};
});
export const StyledLink = styled(Link)(({ theme }) => {
export const StyledLink = styled(Link)(() => {
return {
flexGrow: 1,
textAlign: 'left',
@@ -75,51 +44,25 @@ export const StyledLink = styled(Link)(({ theme }) => {
':visited': {
color: 'inherit',
},
'>svg': {
};
});
export const StyledNewPageButton = styled('button')(({ theme }) => {
return {
height: '48px',
...displayFlex('flex-start', 'center'),
borderTop: '1px solid',
borderColor: theme.colors.borderColor,
padding: '0 8px',
svg: {
fontSize: '20px',
marginRight: '12px',
color: theme.colors.iconColor,
marginRight: '8px',
},
};
});
export const StyledNewPageButton = styled(StyledListItem)(() => {
return {
position: 'absolute',
bottom: '24px',
left: '0',
right: '0',
margin: 'auto',
':hover': {
cursor: 'pointer',
},
};
});
export const StyledSubListItem = styled('button')<{
disable?: boolean;
active?: boolean;
}>(({ theme, disable, active }) => {
return {
width: '100%',
height: '32px',
marginTop: '4px',
color: disable
? theme.colors.disableColor
: active
? theme.colors.primaryColor
: theme.colors.textColor,
backgroundColor: active ? theme.colors.hoverBackground : 'unset',
cursor: disable ? 'not-allowed' : 'pointer',
paddingLeft: '45px',
lineHeight: '32px',
textAlign: 'start',
...textEllipsis(1),
':hover': disable
? {}
: {
color: theme.colors.primaryColor,
backgroundColor: theme.colors.hoverBackground,
svg: {
color: theme.colors.primaryColor,
},
},
};
});

View File

@@ -18,7 +18,7 @@ export const getLightTheme = (
colors: {
primaryColor: '#5438FF',
pageBackground: '#fff',
hoverBackground: '#F1F1F4',
hoverBackground: 'rgba(0,0,0,.04)',
innerHoverBackground: '#E9E9EC',
popoverBackground: '#fff',
tooltipBackground: '#261499',
@@ -97,7 +97,7 @@ export const getDarkTheme = (
colors: {
primaryColor: '#5438FF',
pageBackground: '#2c2c2c',
hoverBackground: '#3C3C42',
hoverBackground: 'rgba(0,0,0,.04)',
innerHoverBackground: '#5A5A5A',
popoverBackground: '#1F2021',
tooltipBackground: '#0C0A15',

View File

@@ -1,5 +1,5 @@
import type { CSSProperties, HTMLAttributes, ReactElement } from 'react';
import { Children, cloneElement, forwardRef } from 'react';
import { forwardRef } from 'react';
import { StyledIconButton } from './styles';
const SIZE_SMALL = 'small' as const;
@@ -9,7 +9,7 @@ const SIZE_NORMAL = 'normal' as const;
const SIZE_CONFIG = {
[SIZE_SMALL]: {
iconSize: 16,
areaSize: 24,
areaSize: 20,
},
[SIZE_MIDDLE]: {
iconSize: 20,
@@ -42,19 +42,14 @@ export type IconButtonProps = {
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
(
{
size = 'normal',
iconSize = 'normal',
disabled = false,
children,
...props
},
{ size = 'normal', iconSize, disabled = false, children, ...props },
ref
) => {
iconSize = size;
const [width, height] = Array.isArray(size)
? size
: [SIZE_CONFIG[size]['areaSize'], SIZE_CONFIG[size]['areaSize']];
const [iconWidth, iconHeight] = Array.isArray(iconSize)
const [iconWidth] = Array.isArray(iconSize)
? iconSize
: [SIZE_CONFIG[iconSize]['iconSize'], SIZE_CONFIG[iconSize]['iconSize']];
@@ -65,12 +60,10 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
width={width}
height={height}
borderRadius={iconWidth / 4}
fontSize={iconWidth}
{...props}
>
{cloneElement(Children.only(children), {
width: iconWidth,
height: iconHeight,
})}
{children}
</StyledIconButton>
);
}

View File

@@ -15,7 +15,7 @@ export const StyledIconButton = styled('button', {
'hoverBackground',
'hoverColor',
'hoverStyle',
'darker',
'fontSize',
].includes(prop as string);
},
})<{
@@ -27,7 +27,7 @@ export const StyledIconButton = styled('button', {
hoverColor?: string;
hoverStyle?: CSSProperties;
// In some cases, button is in a normal hover status, it should be darkened
darker?: boolean;
fontSize?: CSSProperties['fontSize'];
}>(
({
theme,
@@ -38,11 +38,12 @@ export const StyledIconButton = styled('button', {
hoverBackground,
hoverColor,
hoverStyle,
darker = false,
fontSize,
}) => {
return {
width,
height,
fontSize,
color: theme.colors.iconColor,
...displayInlineFlex('center', 'center'),
position: 'relative',
@@ -67,11 +68,7 @@ export const StyledIconButton = styled('button', {
':hover': {
color: hoverColor ?? theme.colors.primaryColor,
'::after': {
background:
hoverBackground ||
(darker
? theme.colors.innerHoverBackground
: theme.colors.hoverBackground),
background: hoverBackground || theme.colors.hoverBackground,
},
...(hoverStyle ?? {}),
},

View File

@@ -46,7 +46,7 @@ export const TreeNode = <N,>({
allDrop = true,
...otherProps
}: TreeNodeProps<N>) => {
const { onAdd, onDelete, onDrop } = otherProps;
const { onAdd, onDelete, onDrop, indent } = otherProps;
const [collapsed, setCollapsed] = useState(false);
const [{ isDragging }, drag] = useDrag(() => ({
@@ -109,7 +109,7 @@ export const TreeNode = <N,>({
)}
</StyledTreeNodeItem>
<StyledCollapse in={!collapsed}>
<StyledCollapse in={!collapsed} indent={indent}>
{node.children &&
node.children.map((childNode, index) => (
<TreeNode

View File

@@ -1,10 +1,13 @@
import MuiCollapse from '@mui/material/Collapse';
import type { CSSProperties } from 'react';
import { styled } from '../../styles';
export const StyledCollapse = styled(MuiCollapse)(() => {
export const StyledCollapse = styled(MuiCollapse)<{
indent?: CSSProperties['paddingLeft'];
}>(({ indent = 12 }) => {
return {
paddingLeft: '12px',
paddingLeft: indent,
};
});
export const StyledTreeNodeItem = styled('div')<{

View File

@@ -1,4 +1,4 @@
import type { ReactNode } from 'react';
import type { CSSProperties, ReactNode } from 'react';
export type Node<N> = {
id: string;
@@ -16,6 +16,7 @@ export type Node<N> = {
} & N;
type CommonProps<N> = {
indent?: CSSProperties['paddingLeft'];
onAdd?: (node: Node<N>) => void;
onDelete?: (node: Node<N>) => void;
onDrop?: (

View File

@@ -193,5 +193,6 @@
"Help and Feedback": "Help and Feedback",
"Please make sure you are online": "Please make sure you are online",
"Workspace Owner": "Workspace Owner",
"Members": "Members"
"Members": "Members",
"Pivots": "Pivots"
}

View File

@@ -3,7 +3,7 @@ import type { Page } from '@playwright/test';
export async function newPage(page: Page) {
await page.waitForSelector('v-line');
// fixme(himself65): if too fast, the page will crash
await page.getByTestId('sliderBar').getByText('New Page').click({
await page.getByTestId('new-page-button').click({
delay: 100,
});
await page.waitForSelector('v-line');

View File

@@ -227,7 +227,7 @@ __metadata:
"@affine/workspace": "workspace:*"
"@blocksuite/blocks": 0.5.0-20230324040005-14417c2
"@blocksuite/editor": 0.5.0-20230324040005-14417c2
"@blocksuite/icons": 2.0.23
"@blocksuite/icons": latest
"@blocksuite/store": 0.5.0-20230324040005-14417c2
"@emotion/cache": ^11.10.5
"@emotion/react": ^11.10.6
@@ -1855,6 +1855,16 @@ __metadata:
languageName: node
linkType: hard
"@blocksuite/icons@npm:latest":
version: 2.0.26
resolution: "@blocksuite/icons@npm:2.0.26"
peerDependencies:
"@types/react": ^18.0.25
react: ^18.2.0
checksum: bb0142cd503098ca1bd768401d7e4cc761027d7f60ac974f21bb368d3415e7ae2f13a128c83d4389d00aa18c523cd14bee53101e078c2a941186b98d6be7ba07
languageName: node
linkType: hard
"@blocksuite/phasor@npm:0.5.0-20230324040005-14417c2":
version: 0.5.0-20230324040005-14417c2
resolution: "@blocksuite/phasor@npm:0.5.0-20230324040005-14417c2"