mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-08 20:57:08 +08:00
feat: modify sidebar style (#1703)
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
"@affine/workspace": "workspace:*",
|
"@affine/workspace": "workspace:*",
|
||||||
"@blocksuite/blocks": "0.5.0-20230324040005-14417c2",
|
"@blocksuite/blocks": "0.5.0-20230324040005-14417c2",
|
||||||
"@blocksuite/editor": "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",
|
"@blocksuite/store": "0.5.0-20230324040005-14417c2",
|
||||||
"@emotion/cache": "^11.10.5",
|
"@emotion/cache": "^11.10.5",
|
||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
|
|||||||
+1
-3
@@ -79,7 +79,7 @@ export const OperationCell: React.FC<OperationCellProps> = ({
|
|||||||
disablePortal={true}
|
disablePortal={true}
|
||||||
trigger="click"
|
trigger="click"
|
||||||
>
|
>
|
||||||
<IconButton darker={true}>
|
<IconButton>
|
||||||
<MoreVerticalIcon />
|
<MoreVerticalIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Menu>
|
</Menu>
|
||||||
@@ -127,7 +127,6 @@ export const TrashOperationCell: React.FC<TrashOperationCellProps> = ({
|
|||||||
<FlexWrapper>
|
<FlexWrapper>
|
||||||
<Tooltip content={t('Restore it')} placement="top-start">
|
<Tooltip content={t('Restore it')} placement="top-start">
|
||||||
<IconButton
|
<IconButton
|
||||||
darker={true}
|
|
||||||
style={{ marginRight: '12px' }}
|
style={{ marginRight: '12px' }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onRestorePage(id);
|
onRestorePage(id);
|
||||||
@@ -139,7 +138,6 @@ export const TrashOperationCell: React.FC<TrashOperationCellProps> = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip content={t('Delete permanently')} placement="top-start">
|
<Tooltip content={t('Delete permanently')} placement="top-start">
|
||||||
<IconButton
|
<IconButton
|
||||||
darker={true}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ const FavoriteTag: React.FC<FavoriteTagProps> = ({
|
|||||||
placement="top-start"
|
placement="top-start"
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
darker={true}
|
|
||||||
iconSize={[20, 20]}
|
iconSize={[20, 20]}
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -88,13 +87,12 @@ type PageListProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
all: (pageMeta: PageMeta, allMetas: PageMeta[]) => !pageMeta.trash,
|
all: (pageMeta: PageMeta) => !pageMeta.trash,
|
||||||
trash: (pageMeta: PageMeta, allMetas: PageMeta[]) => {
|
trash: (pageMeta: PageMeta, allMetas: PageMeta[]) => {
|
||||||
const parentMeta = allMetas.find(m => m.subpageIds?.includes(pageMeta.id));
|
const parentMeta = allMetas.find(m => m.subpageIds?.includes(pageMeta.id));
|
||||||
return !parentMeta?.trash && pageMeta.trash;
|
return !parentMeta?.trash && pageMeta.trash;
|
||||||
},
|
},
|
||||||
favorite: (pageMeta: PageMeta, allMetas: PageMeta[]) =>
|
favorite: (pageMeta: PageMeta) => pageMeta.favorite && !pageMeta.trash,
|
||||||
pageMeta.favorite && !pageMeta.trash,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PageList: React.FC<PageListProps> = ({
|
export const PageList: React.FC<PageListProps> = ({
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ import {
|
|||||||
export const StyledHeaderContainer = styled('div')<{ hasWarning: boolean }>(
|
export const StyledHeaderContainer = styled('div')<{ hasWarning: boolean }>(
|
||||||
({ hasWarning }) => {
|
({ hasWarning }) => {
|
||||||
return {
|
return {
|
||||||
height: hasWarning ? '96px' : '60px',
|
height: hasWarning ? '96px' : '48px',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
export const StyledHeader = styled('div')<{ hasWarning: boolean }>(
|
export const StyledHeader = styled('div')<{ hasWarning: boolean }>(
|
||||||
({ theme }) => {
|
({ theme }) => {
|
||||||
return {
|
return {
|
||||||
height: '64px',
|
height: '48px',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
padding: '0 28px',
|
padding: '0 20px',
|
||||||
...displayFlex('space-between', 'center'),
|
...displayFlex('space-between', 'center'),
|
||||||
background: theme.colors.pageBackground,
|
background: theme.colors.pageBackground,
|
||||||
transition: 'background-color 0.5s',
|
transition: 'background-color 0.5s',
|
||||||
|
|||||||
+34
-14
@@ -1,9 +1,16 @@
|
|||||||
|
import { CloudWorkspaceIcon, LocalWorkspaceIcon } from '@blocksuite/icons';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
|
|
||||||
|
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
|
||||||
import { useBlockSuiteWorkspaceName } from '../../../../hooks/use-blocksuite-workspace-name';
|
import { useBlockSuiteWorkspaceName } from '../../../../hooks/use-blocksuite-workspace-name';
|
||||||
import type { RemWorkspace } from '../../../../shared';
|
import type { RemWorkspace } from '../../../../shared';
|
||||||
import { WorkspaceAvatar } from '../../workspace-avatar';
|
import { WorkspaceAvatar } from '../../workspace-avatar';
|
||||||
import { SelectorWrapper, WorkspaceName } from './styles';
|
import {
|
||||||
|
StyledSelectorContainer,
|
||||||
|
StyledSelectorWrapper,
|
||||||
|
StyledWorkspaceName,
|
||||||
|
StyledWorkspaceStatus,
|
||||||
|
} from './styles';
|
||||||
|
|
||||||
export type WorkspaceSelectorProps = {
|
export type WorkspaceSelectorProps = {
|
||||||
currentWorkspace: RemWorkspace | null;
|
currentWorkspace: RemWorkspace | null;
|
||||||
@@ -17,19 +24,32 @@ export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
|
|||||||
const [name] = useBlockSuiteWorkspaceName(
|
const [name] = useBlockSuiteWorkspaceName(
|
||||||
currentWorkspace?.blockSuiteWorkspace ?? null
|
currentWorkspace?.blockSuiteWorkspace ?? null
|
||||||
);
|
);
|
||||||
|
const [workspace] = useCurrentWorkspace();
|
||||||
return (
|
return (
|
||||||
<>
|
<StyledSelectorContainer onClick={onClick} data-testid="current-workspace">
|
||||||
<SelectorWrapper onClick={onClick} data-testid="current-workspace">
|
<WorkspaceAvatar
|
||||||
<WorkspaceAvatar
|
data-testid="workspace-avatar"
|
||||||
data-testid="workspace-avatar"
|
style={{
|
||||||
style={{
|
flexShrink: 0,
|
||||||
flexShrink: 0,
|
}}
|
||||||
}}
|
size={40}
|
||||||
size={32}
|
workspace={currentWorkspace}
|
||||||
workspace={currentWorkspace}
|
/>
|
||||||
/>
|
<StyledSelectorWrapper>
|
||||||
<WorkspaceName data-testid="workspace-name">{name}</WorkspaceName>
|
<StyledWorkspaceName data-testid="workspace-name">
|
||||||
</SelectorWrapper>
|
{name}
|
||||||
</>
|
</StyledWorkspaceName>
|
||||||
|
{workspace && (
|
||||||
|
<StyledWorkspaceStatus>
|
||||||
|
{workspace.flavour === 'local' ? (
|
||||||
|
<LocalWorkspaceIcon />
|
||||||
|
) : (
|
||||||
|
<CloudWorkspaceIcon />
|
||||||
|
)}
|
||||||
|
{workspace.flavour === 'local' ? 'Local' : 'AFFiNE Cloud'}
|
||||||
|
</StyledWorkspaceStatus>
|
||||||
|
)}
|
||||||
|
</StyledSelectorWrapper>
|
||||||
|
</StyledSelectorContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { MuiAvatar, textEllipsis } from '@affine/component';
|
import { displayFlex, textEllipsis } from '@affine/component';
|
||||||
import { styled } from '@affine/component';
|
import { styled } from '@affine/component';
|
||||||
export const SelectorWrapper = styled('div')(({ theme }) => {
|
export const StyledSelectorContainer = styled('div')(({ theme }) => {
|
||||||
return {
|
return {
|
||||||
marginTop: '4px',
|
marginTop: '4px',
|
||||||
height: '56px',
|
height: '58px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '0 44px 0 12px',
|
padding: '0 6px',
|
||||||
borderRadius: '5px',
|
marginBottom: '16px',
|
||||||
|
borderRadius: '8px',
|
||||||
color: theme.colors.textColor,
|
color: theme.colors.textColor,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
':hover': {
|
':hover': {
|
||||||
@@ -17,17 +18,31 @@ export const SelectorWrapper = styled('div')(({ theme }) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Avatar = styled(MuiAvatar)({
|
export const StyledSelectorWrapper = styled('div')(() => {
|
||||||
height: '28px',
|
|
||||||
width: '28px',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const WorkspaceName = styled('span')(({ theme }) => {
|
|
||||||
return {
|
return {
|
||||||
marginLeft: '12px',
|
marginLeft: '8px',
|
||||||
fontSize: theme.font.h6,
|
|
||||||
fontWeight: 500,
|
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
|
overflow: 'hidden',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
export const StyledWorkspaceName = styled('div')(() => {
|
||||||
|
return {
|
||||||
|
lineHeight: '24px',
|
||||||
|
fontWeight: 600,
|
||||||
...textEllipsis(1),
|
...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',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -1,35 +1,29 @@
|
|||||||
import { MuiCollapse } from '@affine/component';
|
|
||||||
import { IconButton } from '@affine/component';
|
|
||||||
import { config } from '@affine/env';
|
import { config } from '@affine/env';
|
||||||
import { useTranslation } from '@affine/i18n';
|
import { useTranslation } from '@affine/i18n';
|
||||||
import {
|
import {
|
||||||
ArrowDownSmallIcon,
|
|
||||||
DeleteTemporarilyIcon,
|
DeleteTemporarilyIcon,
|
||||||
FavoriteIcon,
|
|
||||||
FolderIcon,
|
FolderIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
} from '@blocksuite/icons';
|
} from '@blocksuite/icons';
|
||||||
import type { Page, PageMeta } from '@blocksuite/store';
|
import type { Page, PageMeta } from '@blocksuite/store';
|
||||||
import Link from 'next/link';
|
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { useSidebarStatus } from '../../../hooks/affine/use-sidebar-status';
|
import { useSidebarStatus } from '../../../hooks/affine/use-sidebar-status';
|
||||||
import { usePageMeta } from '../../../hooks/use-page-meta';
|
import { usePageMeta } from '../../../hooks/use-page-meta';
|
||||||
import type { RemWorkspace } from '../../../shared';
|
import type { RemWorkspace } from '../../../shared';
|
||||||
import { SidebarSwitch } from '../../affine/sidebar-switch';
|
import { SidebarSwitch } from '../../affine/sidebar-switch';
|
||||||
|
import Favorite from './favorite';
|
||||||
import { Pivot } from './pivot';
|
import { Pivot } from './pivot';
|
||||||
|
import { StyledListItem } from './shared-styles';
|
||||||
import {
|
import {
|
||||||
StyledLink,
|
StyledLink,
|
||||||
StyledListItem,
|
|
||||||
StyledNewPageButton,
|
StyledNewPageButton,
|
||||||
StyledSidebarWrapper,
|
StyledSidebarSwitchWrapper,
|
||||||
|
StyledSlidebarWrapper,
|
||||||
StyledSliderBar,
|
StyledSliderBar,
|
||||||
StyledSliderBarWrapper,
|
|
||||||
StyledSubListItem,
|
|
||||||
} from './style';
|
} from './style';
|
||||||
import { WorkspaceSelector } from './WorkspaceSelector';
|
import { WorkspaceSelector } from './WorkspaceSelector';
|
||||||
|
|
||||||
@@ -40,57 +34,6 @@ export type FavoriteListProps = {
|
|||||||
pageMeta: PageMeta[];
|
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 = {
|
export type WorkSpaceSliderBarProps = {
|
||||||
isPublicWorkspace: boolean;
|
isPublicWorkspace: boolean;
|
||||||
onOpenQuickSearchModal: () => void;
|
onOpenQuickSearchModal: () => void;
|
||||||
@@ -120,7 +63,6 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
onOpenWorkspaceListModal,
|
onOpenWorkspaceListModal,
|
||||||
}) => {
|
}) => {
|
||||||
const currentWorkspaceId = currentWorkspace?.id || null;
|
const currentWorkspaceId = currentWorkspace?.id || null;
|
||||||
const [showSubFavorite, setOpenSubFavorite] = useState(true);
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [sidebarOpen] = useSidebarStatus();
|
const [sidebarOpen] = useSidebarStatus();
|
||||||
const pageMeta = usePageMeta(currentWorkspace?.blockSuiteWorkspace ?? null);
|
const pageMeta = usePageMeta(currentWorkspace?.blockSuiteWorkspace ?? null);
|
||||||
@@ -131,15 +73,15 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledSliderBar show={isPublicWorkspace ? false : sidebarOpen}>
|
<StyledSliderBar show={isPublicWorkspace ? false : sidebarOpen}>
|
||||||
<StyledSidebarWrapper>
|
<StyledSidebarSwitchWrapper>
|
||||||
<SidebarSwitch
|
<SidebarSwitch
|
||||||
visible={sidebarOpen}
|
visible={sidebarOpen}
|
||||||
tooltipContent={t('Collapse sidebar')}
|
tooltipContent={t('Collapse sidebar')}
|
||||||
testid="sliderBar-arrowButton-collapse"
|
testid="sliderBar-arrowButton-collapse"
|
||||||
/>
|
/>
|
||||||
</StyledSidebarWrapper>
|
</StyledSidebarSwitchWrapper>
|
||||||
|
|
||||||
<StyledSliderBarWrapper data-testid="sliderBar">
|
<StyledSlidebarWrapper data-testid="sliderBar">
|
||||||
<WorkspaceSelector
|
<WorkspaceSelector
|
||||||
currentWorkspace={currentWorkspace}
|
currentWorkspace={currentWorkspace}
|
||||||
onClick={onOpenWorkspaceListModal}
|
onClick={onOpenWorkspaceListModal}
|
||||||
@@ -147,7 +89,6 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
|
|
||||||
<StyledListItem
|
<StyledListItem
|
||||||
data-testid="slider-bar-quick-search-button"
|
data-testid="slider-bar-quick-search-button"
|
||||||
style={{ cursor: 'pointer' }}
|
|
||||||
onClick={useCallback(() => {
|
onClick={useCallback(() => {
|
||||||
onOpenQuickSearchModal();
|
onOpenQuickSearchModal();
|
||||||
}, [onOpenQuickSearchModal])}
|
}, [onOpenQuickSearchModal])}
|
||||||
@@ -155,70 +96,16 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
{t('Quick search')}
|
{t('Quick search')}
|
||||||
</StyledListItem>
|
</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
|
<StyledListItem
|
||||||
active={
|
active={
|
||||||
currentPath ===
|
currentPath ===
|
||||||
(currentWorkspaceId && paths.setting(currentWorkspaceId))
|
(currentWorkspaceId && paths.setting(currentWorkspaceId))
|
||||||
}
|
}
|
||||||
data-testid="slider-bar-workspace-setting-button"
|
data-testid="slider-bar-workspace-setting-button"
|
||||||
|
style={{
|
||||||
|
marginBottom: '16px',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<StyledLink
|
<StyledLink
|
||||||
href={{
|
href={{
|
||||||
@@ -231,42 +118,62 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
|
|||||||
</StyledLink>
|
</StyledLink>
|
||||||
</StyledListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
{/* <WorkspaceSetting
|
<StyledListItem
|
||||||
isShow={showWorkspaceSetting}
|
active={
|
||||||
onClose={() => {
|
currentPath ===
|
||||||
setOpenWorkspaceSetting(false);
|
(currentWorkspaceId && paths.all(currentWorkspaceId))
|
||||||
}}
|
}
|
||||||
/> */}
|
|
||||||
{/* TODO: will finish the feature next version */}
|
|
||||||
{/* <StyledListItem
|
|
||||||
onClick={() => {
|
|
||||||
triggerImportModal();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<ImportIcon /> {t('Import')}
|
<StyledLink
|
||||||
</StyledListItem> */}
|
href={{
|
||||||
|
pathname: currentWorkspaceId && paths.all(currentWorkspaceId),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FolderIcon />
|
||||||
|
<span data-testid="all-pages">{t('All pages')}</span>
|
||||||
|
</StyledLink>
|
||||||
|
</StyledListItem>
|
||||||
|
|
||||||
<Link
|
<Favorite
|
||||||
href={{
|
currentPath={currentPath}
|
||||||
pathname: currentWorkspaceId && paths.trash(currentWorkspaceId),
|
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',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StyledListItem
|
<StyledLink
|
||||||
active={
|
href={{
|
||||||
currentPath ===
|
pathname: currentWorkspaceId && paths.trash(currentWorkspaceId),
|
||||||
(currentWorkspaceId && paths.trash(currentWorkspaceId))
|
}}
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<DeleteTemporarilyIcon /> {t('Trash')}
|
<DeleteTemporarilyIcon /> {t('Trash')}
|
||||||
</StyledListItem>
|
</StyledLink>
|
||||||
</Link>
|
</StyledListItem>
|
||||||
<StyledNewPageButton
|
</StyledSlidebarWrapper>
|
||||||
data-testid="new-page-button"
|
|
||||||
onClick={onClickNewPage}
|
<StyledNewPageButton
|
||||||
>
|
data-testid="new-page-button"
|
||||||
<PlusIcon /> {t('New Page')}
|
onClick={onClickNewPage}
|
||||||
</StyledNewPageButton>
|
>
|
||||||
</StyledSliderBarWrapper>
|
<PlusIcon /> {t('New Page')}
|
||||||
|
</StyledNewPageButton>
|
||||||
</StyledSliderBar>
|
</StyledSliderBar>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { IconButton, MuiCollapse, TreeView } from '@affine/component';
|
import { MuiCollapse, TreeView } from '@affine/component';
|
||||||
import { DebugLogger } from '@affine/debug';
|
import { DebugLogger } from '@affine/debug';
|
||||||
|
import { useTranslation } from '@affine/i18n';
|
||||||
import { ArrowDownSmallIcon, FolderIcon } from '@blocksuite/icons';
|
import { ArrowDownSmallIcon, FolderIcon } from '@blocksuite/icons';
|
||||||
import type { PageMeta } from '@blocksuite/store';
|
import type { PageMeta } from '@blocksuite/store';
|
||||||
import { nanoid } 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 { useBlockSuiteWorkspaceHelper } from '../../../../hooks/use-blocksuite-workspace-helper';
|
||||||
import { usePageMetaHelper } from '../../../../hooks/use-page-meta';
|
import { usePageMetaHelper } from '../../../../hooks/use-page-meta';
|
||||||
import type { RemWorkspace } from '../../../../shared';
|
import type { RemWorkspace } from '../../../../shared';
|
||||||
import { StyledListItem } from '../style';
|
import { StyledCollapseButton, StyledListItem } from '../shared-styles';
|
||||||
import type { TreeNode } from './types';
|
import type { TreeNode } from './types';
|
||||||
import { flattenToTree } from './utils';
|
import { flattenToTree } from './utils';
|
||||||
const logger = new DebugLogger('pivot');
|
const logger = new DebugLogger('pivot');
|
||||||
@@ -178,6 +179,7 @@ export const PivotInternal = ({
|
|||||||
onAdd={handleAdd}
|
onAdd={handleAdd}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
|
indent={16}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -191,32 +193,30 @@ export const Pivot = ({
|
|||||||
openPage: (pageId: string) => void;
|
openPage: (pageId: string) => void;
|
||||||
allMetas: PageMeta[];
|
allMetas: PageMeta[];
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [showPivot, setShowPivot] = useState(true);
|
const [showPivot, setShowPivot] = useState(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledListItem>
|
<StyledListItem>
|
||||||
<FolderIcon />
|
<StyledCollapseButton
|
||||||
Pivot
|
|
||||||
<IconButton
|
|
||||||
darker={true}
|
|
||||||
onClick={useCallback(() => {
|
onClick={useCallback(() => {
|
||||||
setShowPivot(!showPivot);
|
setShowPivot(!showPivot);
|
||||||
}, [showPivot])}
|
}, [showPivot])}
|
||||||
|
collapse={showPivot}
|
||||||
>
|
>
|
||||||
<ArrowDownSmallIcon
|
<ArrowDownSmallIcon />
|
||||||
style={{
|
</StyledCollapseButton>
|
||||||
transform: `rotate(${showPivot ? '180' : '0'}deg)`,
|
<FolderIcon />
|
||||||
}}
|
{t('Pivots')}
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
</StyledListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
<MuiCollapse
|
<MuiCollapse
|
||||||
in={showPivot}
|
in={showPivot}
|
||||||
style={{
|
style={{
|
||||||
maxHeight: 300,
|
maxHeight: 300,
|
||||||
paddingLeft: '12px',
|
paddingLeft: '16px',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import { IconButton } from '@affine/component';
|
import { IconButton } from '@affine/component';
|
||||||
import {
|
import {
|
||||||
ArrowDownSmallIcon,
|
ArrowDownSmallIcon,
|
||||||
DeleteTemporarilyIcon,
|
EdgelessIcon,
|
||||||
PlusIcon,
|
// DeleteTemporarilyIcon,
|
||||||
|
// PlusIcon,
|
||||||
|
MoreVerticalIcon,
|
||||||
|
PageIcon,
|
||||||
} from '@blocksuite/icons';
|
} from '@blocksuite/icons';
|
||||||
|
import type { PageMeta } from '@blocksuite/store';
|
||||||
|
import { useAtomValue } from 'jotai';
|
||||||
import { useRouter } from 'next/router';
|
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';
|
import type { TreeNode } from './types';
|
||||||
|
|
||||||
export const TreeNodeRender: TreeNode['render'] = (
|
export const TreeNodeRender: TreeNode['render'] = (
|
||||||
@@ -14,12 +20,17 @@ export const TreeNodeRender: TreeNode['render'] = (
|
|||||||
{ onAdd, onDelete, collapsed, setCollapsed },
|
{ onAdd, onDelete, collapsed, setCollapsed },
|
||||||
extendProps
|
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 router = useRouter();
|
||||||
const active = router.query.pageId === node.id;
|
const active = router.query.pageId === node.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledPivotItem
|
<StyledCollapseItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (active) {
|
if (active) {
|
||||||
return;
|
return;
|
||||||
@@ -28,42 +39,49 @@ export const TreeNodeRender: TreeNode['render'] = (
|
|||||||
}}
|
}}
|
||||||
active={active}
|
active={active}
|
||||||
>
|
>
|
||||||
<StyledCollapsedButton
|
<StyledCollapseButton
|
||||||
|
collapse={collapsed}
|
||||||
show={!!node.children?.length}
|
show={!!node.children?.length}
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setCollapsed(!collapsed);
|
setCollapsed(!collapsed);
|
||||||
}}
|
}}
|
||||||
size="small"
|
|
||||||
>
|
>
|
||||||
<ArrowDownSmallIcon
|
<ArrowDownSmallIcon />
|
||||||
style={{
|
</StyledCollapseButton>
|
||||||
transform: `rotate(${collapsed ? '0' : '180'}deg)`,
|
{record[pageMeta.id] === 'edgeless' ? <EdgelessIcon /> : <PageIcon />}
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</StyledCollapsedButton>
|
|
||||||
<span>{node.title || 'Untitled'}</span>
|
<span>{node.title || 'Untitled'}</span>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={e => {
|
|
||||||
e.stopPropagation();
|
|
||||||
onAdd();
|
|
||||||
}}
|
|
||||||
size="small"
|
size="small"
|
||||||
className="pivot-item-button"
|
className="operation-button"
|
||||||
>
|
|
||||||
<PlusIcon />
|
|
||||||
</IconButton>
|
|
||||||
<IconButton
|
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreVerticalIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
onDelete();
|
{/*<IconButton*/}
|
||||||
}}
|
{/* onClick={e => {*/}
|
||||||
size="small"
|
{/* e.stopPropagation();*/}
|
||||||
className="pivot-item-button"
|
{/* onAdd();*/}
|
||||||
>
|
{/* }}*/}
|
||||||
<DeleteTemporarilyIcon />
|
{/* size="small"*/}
|
||||||
</IconButton>
|
{/* className="operation-button"*/}
|
||||||
</StyledPivotItem>
|
{/*>*/}
|
||||||
|
{/* <PlusIcon />*/}
|
||||||
|
{/*</IconButton>*/}
|
||||||
|
{/*<IconButton*/}
|
||||||
|
{/* onClick={e => {*/}
|
||||||
|
{/* e.stopPropagation();*/}
|
||||||
|
|
||||||
|
{/* onDelete();*/}
|
||||||
|
{/* }}*/}
|
||||||
|
{/* size="small"*/}
|
||||||
|
{/* className="operation-button"*/}
|
||||||
|
{/*>*/}
|
||||||
|
{/* <DeleteTemporarilyIcon />*/}
|
||||||
|
{/*</IconButton>*/}
|
||||||
|
</StyledCollapseItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,35 +1,17 @@
|
|||||||
import {
|
import { IconButton, styled } from '@affine/component';
|
||||||
displayFlex,
|
|
||||||
IconButton,
|
|
||||||
styled,
|
|
||||||
textEllipsis,
|
|
||||||
} from '@affine/component';
|
|
||||||
|
|
||||||
export const StyledPivotItem = styled('div')<{ active: boolean }>(
|
export const StyledOperationButton = styled('button')(({ theme }) => {
|
||||||
({ active, theme }) => {
|
return {
|
||||||
return {
|
height: '20px',
|
||||||
width: '100%',
|
width: '20px',
|
||||||
height: '32px',
|
fontSize: '20px',
|
||||||
...displayFlex('flex-start', 'center'),
|
color: theme.colors.iconColor,
|
||||||
paddingLeft: '24px',
|
display: 'none',
|
||||||
position: 'relative',
|
':hover': {
|
||||||
color: active ? theme.colors.primaryColor : theme.colors.textColor,
|
background: theme.colors.hoverBackground,
|
||||||
cursor: 'pointer',
|
},
|
||||||
span: {
|
};
|
||||||
flexGrow: '1',
|
});
|
||||||
...textEllipsis(1),
|
|
||||||
},
|
|
||||||
'.pivot-item-button': {
|
|
||||||
display: 'none',
|
|
||||||
},
|
|
||||||
':hover': {
|
|
||||||
'.pivot-item-button': {
|
|
||||||
display: 'flex',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const StyledCollapsedButton = styled(IconButton, {
|
export const StyledCollapsedButton = styled(IconButton, {
|
||||||
shouldForwardProp: prop => {
|
shouldForwardProp: prop => {
|
||||||
|
|||||||
@@ -32,7 +32,11 @@ export const flattenToTree = (
|
|||||||
const returnedMeta: TreeNode = {
|
const returnedMeta: TreeNode = {
|
||||||
...internalMeta,
|
...internalMeta,
|
||||||
children: helper(childrenMetas),
|
children: helper(childrenMetas),
|
||||||
render: (node, props) => TreeNodeRender!(node, props, renderProps),
|
render: (node, props) =>
|
||||||
|
TreeNodeRender!(node, props, {
|
||||||
|
pageMeta: internalMeta,
|
||||||
|
...renderProps,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
returnedMetas.push(returnedMeta);
|
returnedMetas.push(returnedMeta);
|
||||||
|
|||||||
@@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { displayFlex, styled, textEllipsis } from '@affine/component';
|
import { displayFlex, styled } from '@affine/component';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
export const StyledSliderBar = styled('div')<{ show: boolean }>(
|
export const StyledSliderBar = styled('div')<{ show: boolean }>(
|
||||||
({ theme, show }) => {
|
({ theme, show }) => {
|
||||||
return {
|
return {
|
||||||
@@ -13,60 +12,30 @@ export const StyledSliderBar = styled('div')<{ show: boolean }>(
|
|||||||
transition: 'width .15s, padding .15s',
|
transition: 'width .15s, padding .15s',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
zIndex: theme.zIndex.modal,
|
zIndex: theme.zIndex.modal,
|
||||||
padding: show ? '0 12px' : '0',
|
padding: show ? '0 4px' : '0',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
export const StyledSidebarWrapper = styled('div')(() => {
|
export const StyledSidebarSwitchWrapper = styled('div')(() => {
|
||||||
return {
|
return {
|
||||||
position: 'absolute',
|
height: '48px',
|
||||||
right: '12px',
|
padding: '0 16px',
|
||||||
top: '16px',
|
...displayFlex('flex-start', 'center'),
|
||||||
zIndex: 1,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
export const StyledSliderBarWrapper = styled('div')(() => {
|
export const StyledSlidebarWrapper = styled('div')(() => {
|
||||||
return {
|
return {
|
||||||
height: '100%',
|
flexGrow: 1,
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const StyledListItem = styled('div')<{
|
export const StyledLink = styled(Link)(() => {
|
||||||
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 }) => {
|
|
||||||
return {
|
return {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
@@ -75,51 +44,25 @@ export const StyledLink = styled(Link)(({ theme }) => {
|
|||||||
':visited': {
|
':visited': {
|
||||||
color: 'inherit',
|
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',
|
fontSize: '20px',
|
||||||
marginRight: '12px',
|
|
||||||
color: theme.colors.iconColor,
|
color: theme.colors.iconColor,
|
||||||
|
marginRight: '8px',
|
||||||
},
|
},
|
||||||
};
|
|
||||||
});
|
|
||||||
export const StyledNewPageButton = styled(StyledListItem)(() => {
|
|
||||||
return {
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: '24px',
|
|
||||||
left: '0',
|
|
||||||
right: '0',
|
|
||||||
margin: 'auto',
|
|
||||||
':hover': {
|
':hover': {
|
||||||
cursor: 'pointer',
|
color: theme.colors.primaryColor,
|
||||||
|
svg: {
|
||||||
|
color: theme.colors.primaryColor,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const getLightTheme = (
|
|||||||
colors: {
|
colors: {
|
||||||
primaryColor: '#5438FF',
|
primaryColor: '#5438FF',
|
||||||
pageBackground: '#fff',
|
pageBackground: '#fff',
|
||||||
hoverBackground: '#F1F1F4',
|
hoverBackground: 'rgba(0,0,0,.04)',
|
||||||
innerHoverBackground: '#E9E9EC',
|
innerHoverBackground: '#E9E9EC',
|
||||||
popoverBackground: '#fff',
|
popoverBackground: '#fff',
|
||||||
tooltipBackground: '#261499',
|
tooltipBackground: '#261499',
|
||||||
@@ -97,7 +97,7 @@ export const getDarkTheme = (
|
|||||||
colors: {
|
colors: {
|
||||||
primaryColor: '#5438FF',
|
primaryColor: '#5438FF',
|
||||||
pageBackground: '#2c2c2c',
|
pageBackground: '#2c2c2c',
|
||||||
hoverBackground: '#3C3C42',
|
hoverBackground: 'rgba(0,0,0,.04)',
|
||||||
innerHoverBackground: '#5A5A5A',
|
innerHoverBackground: '#5A5A5A',
|
||||||
popoverBackground: '#1F2021',
|
popoverBackground: '#1F2021',
|
||||||
tooltipBackground: '#0C0A15',
|
tooltipBackground: '#0C0A15',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { CSSProperties, HTMLAttributes, ReactElement } from 'react';
|
import type { CSSProperties, HTMLAttributes, ReactElement } from 'react';
|
||||||
import { Children, cloneElement, forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
|
|
||||||
import { StyledIconButton } from './styles';
|
import { StyledIconButton } from './styles';
|
||||||
const SIZE_SMALL = 'small' as const;
|
const SIZE_SMALL = 'small' as const;
|
||||||
@@ -9,7 +9,7 @@ const SIZE_NORMAL = 'normal' as const;
|
|||||||
const SIZE_CONFIG = {
|
const SIZE_CONFIG = {
|
||||||
[SIZE_SMALL]: {
|
[SIZE_SMALL]: {
|
||||||
iconSize: 16,
|
iconSize: 16,
|
||||||
areaSize: 24,
|
areaSize: 20,
|
||||||
},
|
},
|
||||||
[SIZE_MIDDLE]: {
|
[SIZE_MIDDLE]: {
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
@@ -42,19 +42,14 @@ export type IconButtonProps = {
|
|||||||
|
|
||||||
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
||||||
(
|
(
|
||||||
{
|
{ size = 'normal', iconSize, disabled = false, children, ...props },
|
||||||
size = 'normal',
|
|
||||||
iconSize = 'normal',
|
|
||||||
disabled = false,
|
|
||||||
children,
|
|
||||||
...props
|
|
||||||
},
|
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
|
iconSize = size;
|
||||||
const [width, height] = Array.isArray(size)
|
const [width, height] = Array.isArray(size)
|
||||||
? size
|
? size
|
||||||
: [SIZE_CONFIG[size]['areaSize'], SIZE_CONFIG[size]['areaSize']];
|
: [SIZE_CONFIG[size]['areaSize'], SIZE_CONFIG[size]['areaSize']];
|
||||||
const [iconWidth, iconHeight] = Array.isArray(iconSize)
|
const [iconWidth] = Array.isArray(iconSize)
|
||||||
? iconSize
|
? iconSize
|
||||||
: [SIZE_CONFIG[iconSize]['iconSize'], SIZE_CONFIG[iconSize]['iconSize']];
|
: [SIZE_CONFIG[iconSize]['iconSize'], SIZE_CONFIG[iconSize]['iconSize']];
|
||||||
|
|
||||||
@@ -65,12 +60,10 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
borderRadius={iconWidth / 4}
|
borderRadius={iconWidth / 4}
|
||||||
|
fontSize={iconWidth}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{cloneElement(Children.only(children), {
|
{children}
|
||||||
width: iconWidth,
|
|
||||||
height: iconHeight,
|
|
||||||
})}
|
|
||||||
</StyledIconButton>
|
</StyledIconButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const StyledIconButton = styled('button', {
|
|||||||
'hoverBackground',
|
'hoverBackground',
|
||||||
'hoverColor',
|
'hoverColor',
|
||||||
'hoverStyle',
|
'hoverStyle',
|
||||||
'darker',
|
'fontSize',
|
||||||
].includes(prop as string);
|
].includes(prop as string);
|
||||||
},
|
},
|
||||||
})<{
|
})<{
|
||||||
@@ -27,7 +27,7 @@ export const StyledIconButton = styled('button', {
|
|||||||
hoverColor?: string;
|
hoverColor?: string;
|
||||||
hoverStyle?: CSSProperties;
|
hoverStyle?: CSSProperties;
|
||||||
// In some cases, button is in a normal hover status, it should be darkened
|
// In some cases, button is in a normal hover status, it should be darkened
|
||||||
darker?: boolean;
|
fontSize?: CSSProperties['fontSize'];
|
||||||
}>(
|
}>(
|
||||||
({
|
({
|
||||||
theme,
|
theme,
|
||||||
@@ -38,11 +38,12 @@ export const StyledIconButton = styled('button', {
|
|||||||
hoverBackground,
|
hoverBackground,
|
||||||
hoverColor,
|
hoverColor,
|
||||||
hoverStyle,
|
hoverStyle,
|
||||||
darker = false,
|
fontSize,
|
||||||
}) => {
|
}) => {
|
||||||
return {
|
return {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
fontSize,
|
||||||
color: theme.colors.iconColor,
|
color: theme.colors.iconColor,
|
||||||
...displayInlineFlex('center', 'center'),
|
...displayInlineFlex('center', 'center'),
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@@ -67,11 +68,7 @@ export const StyledIconButton = styled('button', {
|
|||||||
':hover': {
|
':hover': {
|
||||||
color: hoverColor ?? theme.colors.primaryColor,
|
color: hoverColor ?? theme.colors.primaryColor,
|
||||||
'::after': {
|
'::after': {
|
||||||
background:
|
background: hoverBackground || theme.colors.hoverBackground,
|
||||||
hoverBackground ||
|
|
||||||
(darker
|
|
||||||
? theme.colors.innerHoverBackground
|
|
||||||
: theme.colors.hoverBackground),
|
|
||||||
},
|
},
|
||||||
...(hoverStyle ?? {}),
|
...(hoverStyle ?? {}),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export const TreeNode = <N,>({
|
|||||||
allDrop = true,
|
allDrop = true,
|
||||||
...otherProps
|
...otherProps
|
||||||
}: TreeNodeProps<N>) => {
|
}: TreeNodeProps<N>) => {
|
||||||
const { onAdd, onDelete, onDrop } = otherProps;
|
const { onAdd, onDelete, onDrop, indent } = otherProps;
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|
||||||
const [{ isDragging }, drag] = useDrag(() => ({
|
const [{ isDragging }, drag] = useDrag(() => ({
|
||||||
@@ -109,7 +109,7 @@ export const TreeNode = <N,>({
|
|||||||
)}
|
)}
|
||||||
</StyledTreeNodeItem>
|
</StyledTreeNodeItem>
|
||||||
|
|
||||||
<StyledCollapse in={!collapsed}>
|
<StyledCollapse in={!collapsed} indent={indent}>
|
||||||
{node.children &&
|
{node.children &&
|
||||||
node.children.map((childNode, index) => (
|
node.children.map((childNode, index) => (
|
||||||
<TreeNode
|
<TreeNode
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import MuiCollapse from '@mui/material/Collapse';
|
import MuiCollapse from '@mui/material/Collapse';
|
||||||
|
import type { CSSProperties } from 'react';
|
||||||
|
|
||||||
import { styled } from '../../styles';
|
import { styled } from '../../styles';
|
||||||
|
|
||||||
export const StyledCollapse = styled(MuiCollapse)(() => {
|
export const StyledCollapse = styled(MuiCollapse)<{
|
||||||
|
indent?: CSSProperties['paddingLeft'];
|
||||||
|
}>(({ indent = 12 }) => {
|
||||||
return {
|
return {
|
||||||
paddingLeft: '12px',
|
paddingLeft: indent,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
export const StyledTreeNodeItem = styled('div')<{
|
export const StyledTreeNodeItem = styled('div')<{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ReactNode } from 'react';
|
import type { CSSProperties, ReactNode } from 'react';
|
||||||
|
|
||||||
export type Node<N> = {
|
export type Node<N> = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -16,6 +16,7 @@ export type Node<N> = {
|
|||||||
} & N;
|
} & N;
|
||||||
|
|
||||||
type CommonProps<N> = {
|
type CommonProps<N> = {
|
||||||
|
indent?: CSSProperties['paddingLeft'];
|
||||||
onAdd?: (node: Node<N>) => void;
|
onAdd?: (node: Node<N>) => void;
|
||||||
onDelete?: (node: Node<N>) => void;
|
onDelete?: (node: Node<N>) => void;
|
||||||
onDrop?: (
|
onDrop?: (
|
||||||
|
|||||||
@@ -193,5 +193,6 @@
|
|||||||
"Help and Feedback": "Help and Feedback",
|
"Help and Feedback": "Help and Feedback",
|
||||||
"Please make sure you are online": "Please make sure you are online",
|
"Please make sure you are online": "Please make sure you are online",
|
||||||
"Workspace Owner": "Workspace Owner",
|
"Workspace Owner": "Workspace Owner",
|
||||||
"Members": "Members"
|
"Members": "Members",
|
||||||
|
"Pivots": "Pivots"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { Page } from '@playwright/test';
|
|||||||
export async function newPage(page: Page) {
|
export async function newPage(page: Page) {
|
||||||
await page.waitForSelector('v-line');
|
await page.waitForSelector('v-line');
|
||||||
// fixme(himself65): if too fast, the page will crash
|
// 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,
|
delay: 100,
|
||||||
});
|
});
|
||||||
await page.waitForSelector('v-line');
|
await page.waitForSelector('v-line');
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ __metadata:
|
|||||||
"@affine/workspace": "workspace:*"
|
"@affine/workspace": "workspace:*"
|
||||||
"@blocksuite/blocks": 0.5.0-20230324040005-14417c2
|
"@blocksuite/blocks": 0.5.0-20230324040005-14417c2
|
||||||
"@blocksuite/editor": 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
|
"@blocksuite/store": 0.5.0-20230324040005-14417c2
|
||||||
"@emotion/cache": ^11.10.5
|
"@emotion/cache": ^11.10.5
|
||||||
"@emotion/react": ^11.10.6
|
"@emotion/react": ^11.10.6
|
||||||
@@ -1855,6 +1855,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@blocksuite/phasor@npm:0.5.0-20230324040005-14417c2":
|
||||||
version: 0.5.0-20230324040005-14417c2
|
version: 0.5.0-20230324040005-14417c2
|
||||||
resolution: "@blocksuite/phasor@npm:0.5.0-20230324040005-14417c2"
|
resolution: "@blocksuite/phasor@npm:0.5.0-20230324040005-14417c2"
|
||||||
|
|||||||
Reference in New Issue
Block a user