mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-16 17:46:18 +08:00
feat: modify page list
This commit is contained in:
@@ -16,13 +16,16 @@ import {
|
||||
} from '@blocksuite/icons';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import ThemeModeSwitch from '@/components/theme-mode-switch';
|
||||
import { IconButton } from '@/ui/button';
|
||||
import { IconButton, Button } from '@/ui/button';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { getWarningMessage, shouldShowWarning } from './utils';
|
||||
import { Menu, MenuItem } from '@/ui/menu';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useConfirm } from '@/providers/confirm-provider';
|
||||
|
||||
const PopoverContent = () => {
|
||||
const { editor, mode, setMode } = useEditor();
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem
|
||||
@@ -81,9 +84,71 @@ const BrowserWarning = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const Header = ({ children }: PropsWithChildren<{}>) => {
|
||||
const [showWarning, setShowWarning] = useState(shouldShowWarning());
|
||||
const HeaderRight = () => {
|
||||
const { pageList, toggleDeletePage, permanentlyDeletePage } = useEditor();
|
||||
const { confirm } = useConfirm();
|
||||
const router = useRouter();
|
||||
const currentPageMeta = pageList.find(p => p.id === router.query.pageId);
|
||||
const isTrash = !!currentPageMeta?.trash;
|
||||
|
||||
if (isTrash) {
|
||||
const { id } = currentPageMeta;
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
bold={true}
|
||||
shape="round"
|
||||
style={{ marginRight: '24px' }}
|
||||
onClick={() => {
|
||||
toggleDeletePage(id);
|
||||
}}
|
||||
>
|
||||
Restore it
|
||||
</Button>
|
||||
<Button
|
||||
bold={true}
|
||||
shape="round"
|
||||
type="danger"
|
||||
onClick={() => {
|
||||
confirm({
|
||||
title: 'Permanently delete',
|
||||
content:
|
||||
"Once deleted, you can't undo this action. Do you confirm?",
|
||||
confirmText: 'Delete',
|
||||
confirmType: 'danger',
|
||||
}).then(confirm => {
|
||||
if (confirm) {
|
||||
router.push({ pathname: '/page-list/all' });
|
||||
permanentlyDeletePage(id);
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
Delete permanently
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<ThemeModeSwitch />
|
||||
<Menu content={<PopoverContent />} placement="bottom-end">
|
||||
<IconButton>
|
||||
<MoreVertical_24pxIcon />
|
||||
</IconButton>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const Header = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { pageList } = useEditor();
|
||||
|
||||
const [showWarning, setShowWarning] = useState(shouldShowWarning());
|
||||
const router = useRouter();
|
||||
const currentPageMeta = pageList.find(p => p.id === router.query.pageId);
|
||||
const isTrash = !!currentPageMeta?.trash;
|
||||
console.log('isTrash', isTrash);
|
||||
return (
|
||||
<StyledHeaderContainer hasWarning={showWarning}>
|
||||
<BrowserWarning
|
||||
@@ -95,12 +160,7 @@ export const Header = ({ children }: PropsWithChildren<{}>) => {
|
||||
<StyledHeader hasWarning={showWarning}>
|
||||
{children}
|
||||
<StyledHeaderRightSide>
|
||||
<ThemeModeSwitch />
|
||||
<Menu content={<PopoverContent />} placement="bottom-end">
|
||||
<IconButton>
|
||||
<MoreVertical_24pxIcon />
|
||||
</IconButton>
|
||||
</Menu>
|
||||
<HeaderRight />
|
||||
</StyledHeaderRightSide>
|
||||
</StyledHeader>
|
||||
</StyledHeaderContainer>
|
||||
|
||||
@@ -6,7 +6,7 @@ import EditorModeSwitch from '@/components/editor-mode-switch';
|
||||
import Header from './header';
|
||||
|
||||
export const PageHeader = () => {
|
||||
const [title, setTitle] = useState('');
|
||||
const [title, setTitle] = useState('Untitled');
|
||||
const [isHover, setIsHover] = useState(false);
|
||||
|
||||
const { editor } = useEditor();
|
||||
@@ -22,24 +22,22 @@ export const PageHeader = () => {
|
||||
|
||||
return (
|
||||
<Header>
|
||||
{title ? (
|
||||
<StyledTitle
|
||||
onMouseEnter={() => {
|
||||
setIsHover(true);
|
||||
<StyledTitle
|
||||
onMouseEnter={() => {
|
||||
setIsHover(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setIsHover(false);
|
||||
}}
|
||||
>
|
||||
<EditorModeSwitch
|
||||
isHover={isHover}
|
||||
style={{
|
||||
marginRight: '12px',
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setIsHover(false);
|
||||
}}
|
||||
>
|
||||
<EditorModeSwitch
|
||||
isHover={isHover}
|
||||
style={{
|
||||
marginRight: '12px',
|
||||
}}
|
||||
/>
|
||||
<StyledTitleWrapper>{title}</StyledTitleWrapper>
|
||||
</StyledTitle>
|
||||
) : null}
|
||||
/>
|
||||
<StyledTitleWrapper>{title}</StyledTitleWrapper>
|
||||
</StyledTitle>
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
export const Empty = () => {
|
||||
return (
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<p>Tips: Click Add to Favourites/Trash and the page will appear here.</p>
|
||||
<p>(Designer is grappling with designing)</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Empty;
|
||||
@@ -0,0 +1,97 @@
|
||||
import { PageMeta, useEditor } from '@/providers/editor-provider';
|
||||
import {
|
||||
MiddleFavouritedStatus2Icon,
|
||||
MiddleFavouritesIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import {
|
||||
StyledFavoriteButton,
|
||||
StyledTableContainer,
|
||||
StyledTableRow,
|
||||
StyledTitleContent,
|
||||
StyledTitleWrapper,
|
||||
} from './styles';
|
||||
import { Table, TableBody, TableCell, TableHead, TableRow } from '@/ui/table';
|
||||
import { OperationCell, TrashOperationCell } from './operation-cell';
|
||||
import Empty from './empty';
|
||||
import Link from 'next/link';
|
||||
import React from 'react';
|
||||
const FavoriteTag = ({ pageMeta }: { pageMeta: PageMeta }) => {
|
||||
const { toggleFavoritePage } = useEditor();
|
||||
|
||||
return (
|
||||
<StyledFavoriteButton
|
||||
className="favorite-button"
|
||||
favorite={pageMeta.favorite}
|
||||
onClick={() => {
|
||||
toggleFavoritePage(pageMeta.id);
|
||||
}}
|
||||
>
|
||||
{pageMeta.favorite ? (
|
||||
<MiddleFavouritedStatus2Icon />
|
||||
) : (
|
||||
<MiddleFavouritesIcon />
|
||||
)}
|
||||
</StyledFavoriteButton>
|
||||
);
|
||||
};
|
||||
|
||||
export const PageList = ({
|
||||
pageList,
|
||||
showFavoriteTag = false,
|
||||
isTrash = false,
|
||||
}: {
|
||||
pageList: PageMeta[];
|
||||
showFavoriteTag?: boolean;
|
||||
isTrash?: boolean;
|
||||
}) => {
|
||||
if (pageList.length === 0) {
|
||||
return <Empty />;
|
||||
}
|
||||
return (
|
||||
<StyledTableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell proportion={0.5}>Documents</TableCell>
|
||||
<TableCell proportion={0.2}>Created</TableCell>
|
||||
<TableCell proportion={0.2}>
|
||||
{isTrash ? 'Uploaded' : 'Moved to Trash'}
|
||||
</TableCell>
|
||||
<TableCell proportion={0.1}></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{pageList.map((pageMeta, index) => {
|
||||
return (
|
||||
<StyledTableRow key={`${pageMeta.id}-${index}`}>
|
||||
<TableCell>
|
||||
<StyledTitleWrapper>
|
||||
<Link
|
||||
href={{ pathname: '/', query: { pageId: pageMeta.id } }}
|
||||
>
|
||||
<StyledTitleContent>
|
||||
{pageMeta.title || pageMeta.id}
|
||||
</StyledTitleContent>
|
||||
</Link>
|
||||
{showFavoriteTag && <FavoriteTag pageMeta={pageMeta} />}
|
||||
</StyledTitleWrapper>
|
||||
</TableCell>
|
||||
<TableCell ellipsis={true}>{pageMeta.createDate}</TableCell>
|
||||
<TableCell ellipsis={true}>{pageMeta.createDate}</TableCell>
|
||||
<TableCell>
|
||||
{isTrash ? (
|
||||
<TrashOperationCell pageMeta={pageMeta} />
|
||||
) : (
|
||||
<OperationCell pageMeta={pageMeta} />
|
||||
)}
|
||||
</TableCell>
|
||||
</StyledTableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</StyledTableContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageList;
|
||||
@@ -0,0 +1,96 @@
|
||||
import { PageMeta, useEditor } from '@/providers/editor-provider';
|
||||
import { useConfirm } from '@/providers/confirm-provider';
|
||||
import { Menu, MenuItem } from '@/ui/menu';
|
||||
import { Wrapper } from '@/ui/layout';
|
||||
import { IconButton } from '@/ui/button';
|
||||
import {
|
||||
MoreVertical_24pxIcon,
|
||||
RestoreIcon,
|
||||
TrashDeleteforeverIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import React from 'react';
|
||||
|
||||
export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
|
||||
const { id, favorite } = pageMeta;
|
||||
const { openPage, toggleFavoritePage, toggleDeletePage } = useEditor();
|
||||
const { confirm } = useConfirm();
|
||||
|
||||
const OperationMenu = (
|
||||
<>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
toggleFavoritePage(id);
|
||||
}}
|
||||
>
|
||||
{favorite ? 'Remove' : 'Add'} to favourites
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
openPage(id);
|
||||
}}
|
||||
>
|
||||
Open in new tab
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
confirm({
|
||||
title: 'Delete',
|
||||
content:
|
||||
'Deleted items will be moved to Trash Bin. Do you confirm?',
|
||||
confirmText: 'Delete',
|
||||
confirmType: 'danger',
|
||||
}).then(confirm => {
|
||||
confirm && toggleDeletePage(id);
|
||||
});
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<Wrapper alignItems="center" justifyContent="center">
|
||||
<Menu content={OperationMenu} placement="bottom-end" disablePortal={true}>
|
||||
<IconButton hoverBackground="#E0E6FF">
|
||||
<MoreVertical_24pxIcon />
|
||||
</IconButton>
|
||||
</Menu>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export const TrashOperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
|
||||
const { id } = pageMeta;
|
||||
const { permanentlyDeletePage, toggleDeletePage } = useEditor();
|
||||
const { confirm } = useConfirm();
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<IconButton
|
||||
hoverBackground="#E0E6FF"
|
||||
style={{ marginRight: '12px' }}
|
||||
onClick={() => {
|
||||
toggleDeletePage(id);
|
||||
}}
|
||||
>
|
||||
<RestoreIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
hoverBackground="#E0E6FF"
|
||||
onClick={() => {
|
||||
confirm({
|
||||
title: 'Permanently delete',
|
||||
content:
|
||||
"Once deleted, you can't undo this action. Do you confirm?",
|
||||
confirmText: 'Delete',
|
||||
confirmType: 'danger',
|
||||
}).then(confirm => {
|
||||
confirm && permanentlyDeletePage(id);
|
||||
});
|
||||
}}
|
||||
>
|
||||
<TrashDeleteforeverIcon />
|
||||
</IconButton>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
import { displayFlex, styled, textEllipsis } from '@/styles';
|
||||
import { TableRow } from '@/ui/table';
|
||||
|
||||
export const StyledTableContainer = styled.div(() => {
|
||||
return {
|
||||
height: 'calc(100vh - 60px)',
|
||||
padding: '78px 72px',
|
||||
overflowY: 'auto',
|
||||
};
|
||||
});
|
||||
export const StyledTitleWrapper = styled.div(({ theme }) => {
|
||||
return {
|
||||
...displayFlex('flex-start', 'center'),
|
||||
a: {
|
||||
color: 'inherit',
|
||||
},
|
||||
'a:visited': {
|
||||
color: 'unset',
|
||||
},
|
||||
'a:hover': {
|
||||
color: theme.colors.primaryColor,
|
||||
},
|
||||
};
|
||||
});
|
||||
export const StyledTitleContent = styled.div(({ theme }) => {
|
||||
return {
|
||||
maxWidth: '90%',
|
||||
marginRight: '18px',
|
||||
...textEllipsis(1),
|
||||
};
|
||||
});
|
||||
export const StyledFavoriteButton = styled.button<{ favorite: boolean }>(
|
||||
({ theme, favorite }) => {
|
||||
return {
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
display: 'none',
|
||||
color: favorite ? theme.colors.primaryColor : theme.colors.iconColor,
|
||||
'&:hover': {
|
||||
color: theme.colors.primaryColor,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
export const StyledTableRow = styled(TableRow)(({ theme }) => {
|
||||
return {
|
||||
'&:hover': {
|
||||
'.favorite-button': {
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -8,17 +8,52 @@ import {
|
||||
StyledSubListItem,
|
||||
} from './style';
|
||||
import { Arrow } from './icons';
|
||||
import Collapse from '@mui/material/Collapse';
|
||||
import { MiddleIconArrowDownSmallIcon } from '@blocksuite/icons';
|
||||
import Link from 'next/link';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import { IconButton } from '@/ui/button';
|
||||
|
||||
const FavoriteList = ({ showList }: { showList: boolean }) => {
|
||||
const { pageList, openPage } = useEditor();
|
||||
const router = useRouter();
|
||||
|
||||
const favoriteList = pageList.filter(p => p.favorite);
|
||||
return (
|
||||
<Collapse in={showList}>
|
||||
{favoriteList.map((pageMeta, index) => {
|
||||
const active = router.query.pageId === pageMeta.id;
|
||||
return (
|
||||
<StyledSubListItem
|
||||
active={active}
|
||||
key={`${pageMeta}-${index}`}
|
||||
onClick={() => {
|
||||
if (active) {
|
||||
return;
|
||||
}
|
||||
openPage(pageMeta.id);
|
||||
}}
|
||||
>
|
||||
{pageMeta.title || pageMeta.id}
|
||||
</StyledSubListItem>
|
||||
);
|
||||
})}
|
||||
{favoriteList.length === 0 && (
|
||||
<StyledSubListItem disable={true}>No item</StyledSubListItem>
|
||||
)}
|
||||
</Collapse>
|
||||
);
|
||||
};
|
||||
export const WorkSpaceSliderBar = () => {
|
||||
const [show, setShow] = useState(false);
|
||||
const [showSubFavorite, setShowSubFavorite] = useState(false);
|
||||
const { createPage } = useEditor();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledSliderBar show={show}>
|
||||
<StyledListItem>Quick search</StyledListItem>
|
||||
|
||||
<StyledListItem
|
||||
onClick={() => {
|
||||
router.push({
|
||||
@@ -31,18 +66,40 @@ export const WorkSpaceSliderBar = () => {
|
||||
>
|
||||
Back to Doc
|
||||
</StyledListItem>
|
||||
<Link href={{ pathname: '/all-page', query: { name: 'test' } }}>
|
||||
<StyledListItem>All pages</StyledListItem>
|
||||
<Link href={{ pathname: '/page-list/all' }}>
|
||||
<StyledListItem active={router.pathname === '/page-list/all'}>
|
||||
All pages
|
||||
</StyledListItem>
|
||||
</Link>
|
||||
<StyledListItem>Favourites</StyledListItem>
|
||||
<StyledSubListItem>
|
||||
document 1, this is a paper icondocument 1
|
||||
</StyledSubListItem>
|
||||
<StyledSubListItem>document 2</StyledSubListItem>
|
||||
<StyledSubListItem>document 4</StyledSubListItem>
|
||||
<StyledListItem>Import</StyledListItem>
|
||||
<StyledListItem>Bin</StyledListItem>
|
||||
<StyledListItem active={router.pathname === '/page-list/favorite'}>
|
||||
<Link
|
||||
href={{ pathname: '/page-list/favorite' }}
|
||||
style={{ flexGrow: 1, textAlign: 'left', color: 'inherit' }}
|
||||
>
|
||||
Favourites
|
||||
</Link>
|
||||
<IconButton
|
||||
hoverBackground="#E0E6FF"
|
||||
onClick={() => {
|
||||
setShowSubFavorite(!showSubFavorite);
|
||||
}}
|
||||
>
|
||||
<MiddleIconArrowDownSmallIcon
|
||||
style={{
|
||||
transform: `rotate(${showSubFavorite ? '180' : '0'}deg)`,
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
</StyledListItem>
|
||||
<FavoriteList showList={showSubFavorite} />
|
||||
|
||||
<StyledListItem>Import</StyledListItem>
|
||||
|
||||
<Link href={{ pathname: '/page-list/trash' }}>
|
||||
<StyledListItem active={router.pathname === '/page-list/trash'}>
|
||||
Trash
|
||||
</StyledListItem>
|
||||
</Link>
|
||||
<StyledNewPageButton
|
||||
onClick={() => {
|
||||
createPage();
|
||||
|
||||
@@ -5,7 +5,7 @@ export const StyledSliderBar = styled.div<{ show: boolean }>(
|
||||
return {
|
||||
width: show ? '320px' : '0',
|
||||
height: '100vh',
|
||||
background: '#FBFBFC',
|
||||
background: theme.mode === 'dark' ? '#272727' : '#FBFBFC',
|
||||
boxShadow: theme.shadow.modal,
|
||||
transition: 'width .15s',
|
||||
position: 'relative',
|
||||
@@ -42,22 +42,25 @@ export const StyledArrowButton = styled.button<{ isShow: boolean }>(
|
||||
}
|
||||
);
|
||||
|
||||
export const StyledListItem = styled.button(({ theme }) => {
|
||||
return {
|
||||
width: '296px',
|
||||
height: '32px',
|
||||
marginTop: '12px',
|
||||
fontSize: theme.font.sm,
|
||||
color: theme.colors.popoverColor,
|
||||
padding: '0 12px',
|
||||
borderRadius: '5px',
|
||||
...displayFlex('flex-start', 'center'),
|
||||
':hover': {
|
||||
color: theme.colors.primaryColor,
|
||||
backgroundColor: theme.colors.hoverBackground,
|
||||
},
|
||||
};
|
||||
});
|
||||
export const StyledListItem = styled.button<{ active?: boolean }>(
|
||||
({ theme, active }) => {
|
||||
return {
|
||||
width: '296px',
|
||||
height: '32px',
|
||||
marginTop: '12px',
|
||||
fontSize: theme.font.sm,
|
||||
color: active ? theme.colors.primaryColor : theme.colors.popoverColor,
|
||||
backgroundColor: active ? theme.colors.hoverBackground : 'unset',
|
||||
paddingLeft: '12px',
|
||||
borderRadius: '5px',
|
||||
...displayFlex('flex-start', 'center'),
|
||||
':hover': {
|
||||
color: theme.colors.primaryColor,
|
||||
backgroundColor: theme.colors.hoverBackground,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export const StyledNewPageButton = styled(StyledListItem)(({ theme }) => {
|
||||
return {
|
||||
@@ -69,20 +72,32 @@ export const StyledNewPageButton = styled(StyledListItem)(({ theme }) => {
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSubListItem = styled.button(({ theme }) => {
|
||||
export const StyledSubListItem = styled.button<{
|
||||
disable?: boolean;
|
||||
active?: boolean;
|
||||
}>(({ theme, disable, active }) => {
|
||||
return {
|
||||
width: '296px',
|
||||
height: '32px',
|
||||
marginTop: '4px',
|
||||
fontSize: theme.font.sm,
|
||||
color: theme.colors.popoverColor,
|
||||
color: disable
|
||||
? theme.colors.iconColor
|
||||
: active
|
||||
? theme.colors.primaryColor
|
||||
: theme.colors.popoverColor,
|
||||
backgroundColor: active ? theme.colors.hoverBackground : 'unset',
|
||||
|
||||
cursor: disable ? 'not-allowed' : 'pointer',
|
||||
paddingLeft: '45px',
|
||||
lineHeight: '32px',
|
||||
textAlign: 'start',
|
||||
...textEllipsis(1),
|
||||
':hover': {
|
||||
color: theme.colors.primaryColor,
|
||||
backgroundColor: theme.colors.hoverBackground,
|
||||
},
|
||||
':hover': disable
|
||||
? {}
|
||||
: {
|
||||
color: theme.colors.primaryColor,
|
||||
backgroundColor: theme.colors.hoverBackground,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -3,6 +3,11 @@ import { ThemeModeSwitch } from '@/components/theme-mode-switch';
|
||||
import { Loading } from '@/components/loading';
|
||||
import Modal from '@/ui/modal';
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@/ui/button';
|
||||
import {
|
||||
MiddleFavouritedStatus2Icon,
|
||||
MiddleFavouritesIcon,
|
||||
} from '@blocksuite/icons';
|
||||
export const StyledHeader = styled('div')({
|
||||
height: '60px',
|
||||
width: '100vw',
|
||||
@@ -35,6 +40,20 @@ const Affine = () => {
|
||||
<div>hi</div>
|
||||
</Modal>
|
||||
<Loading />
|
||||
|
||||
<Button icon={<MiddleFavouritedStatus2Icon />}>click me!</Button>
|
||||
<Button icon={<MiddleFavouritedStatus2Icon />} type={'primary'}>
|
||||
click me!
|
||||
</Button>
|
||||
<Button icon={<MiddleFavouritedStatus2Icon />} type={'warning'}>
|
||||
click me!
|
||||
</Button>
|
||||
<Button icon={<MiddleFavouritedStatus2Icon />} type={'danger'}>
|
||||
click me!
|
||||
</Button>
|
||||
|
||||
<Button icon={<MiddleFavouritedStatus2Icon />}></Button>
|
||||
<Button icon={<MiddleFavouritedStatus2Icon />} shape="round"></Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,169 +1,18 @@
|
||||
import React from 'react';
|
||||
import { Header } from '@/components/header';
|
||||
import { displayFlex, styled, textEllipsis } from '@/styles';
|
||||
import { Table, TableCell, TableHead, TableRow, TableBody } from '../ui/table';
|
||||
import { useConfirm } from '@/providers/confirm-provider';
|
||||
import { IconButton } from '@/ui/button';
|
||||
import { MoreVertical_24pxIcon } from '@blocksuite/icons';
|
||||
import { Menu, MenuItem } from '@/ui/menu';
|
||||
import { PageMeta, useEditor } from '@/providers/editor-provider';
|
||||
import { Wrapper } from '@/ui/layout';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import { PageList } from '@/components/page-list';
|
||||
|
||||
import {
|
||||
MiddleFavouritesIcon,
|
||||
MiddleFavouritedStatus2Icon,
|
||||
} from '@blocksuite/icons';
|
||||
|
||||
const StyledTableContainer = styled.div(() => {
|
||||
return {
|
||||
height: 'calc(100vh - 60px)',
|
||||
padding: '78px 72px',
|
||||
overflowY: 'auto',
|
||||
};
|
||||
});
|
||||
const StyledTitleWrapper = styled.div(({ theme }) => {
|
||||
return {
|
||||
...displayFlex('flex-start', 'center'),
|
||||
'favorite-heart': {},
|
||||
};
|
||||
});
|
||||
const StyledTitleContent = styled.div(({ theme }) => {
|
||||
return {
|
||||
maxWidth: '90%',
|
||||
marginRight: '18px',
|
||||
...textEllipsis(1),
|
||||
};
|
||||
});
|
||||
const StyledFavoriteButton = styled.button<{ favorite: boolean }>(
|
||||
({ theme, favorite }) => {
|
||||
return {
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
display: 'none',
|
||||
color: favorite ? theme.colors.primaryColor : theme.colors.iconColor,
|
||||
'&:hover': {
|
||||
color: theme.colors.primaryColor,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
const StyledTableRow = styled(TableRow)(({ theme }) => {
|
||||
return {
|
||||
'&:hover': {
|
||||
'.favorite-button': {
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const OperationArea = ({ pageMeta }: { pageMeta: PageMeta }) => {
|
||||
const { id, favorite } = pageMeta;
|
||||
const { openPage, toggleFavoritePage, toggleDeletePage } = useEditor();
|
||||
|
||||
const OperationMenu = (
|
||||
<>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
toggleFavoritePage(id);
|
||||
}}
|
||||
>
|
||||
{favorite ? 'Remove' : 'Add'} to favourites
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
openPage(id);
|
||||
}}
|
||||
>
|
||||
Open in new tab
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
toggleDeletePage(id);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<Wrapper alignItems="center" justifyContent="center">
|
||||
<Menu content={OperationMenu} placement="bottom-end" disablePortal={true}>
|
||||
<IconButton hoverBackground="#E0E6FF">
|
||||
<MoreVertical_24pxIcon />
|
||||
</IconButton>
|
||||
</Menu>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export const AllPage = () => {
|
||||
const { confirm } = useConfirm();
|
||||
const { pageList, toggleFavoritePage } = useEditor();
|
||||
export const All = () => {
|
||||
const { pageList: allPageList } = useEditor();
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<button
|
||||
onClick={() => {
|
||||
confirm({
|
||||
title: 'Permanently delete',
|
||||
content: "Once deleted, you can't undo this action.Do you confirm?",
|
||||
confirmText: 'Delete',
|
||||
confirmType: 'danger',
|
||||
});
|
||||
}}
|
||||
>
|
||||
click to show confirm
|
||||
</button>
|
||||
<StyledTableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell proportion={0.5}>Documents</TableCell>
|
||||
<TableCell proportion={0.2}>Created</TableCell>
|
||||
<TableCell proportion={0.2}>Uploaded</TableCell>
|
||||
<TableCell proportion={0.1}></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{pageList.map((pageMeta, index) => {
|
||||
return (
|
||||
<StyledTableRow key={`${pageMeta.id}-${index}`}>
|
||||
<TableCell>
|
||||
<StyledTitleWrapper>
|
||||
<StyledTitleContent>
|
||||
{pageMeta.title || pageMeta.id}
|
||||
</StyledTitleContent>
|
||||
<StyledFavoriteButton
|
||||
className="favorite-button"
|
||||
favorite={pageMeta.favorite}
|
||||
onClick={() => {
|
||||
toggleFavoritePage(pageMeta.id);
|
||||
}}
|
||||
>
|
||||
{pageMeta.favorite ? (
|
||||
<MiddleFavouritedStatus2Icon />
|
||||
) : (
|
||||
<MiddleFavouritesIcon />
|
||||
)}
|
||||
</StyledFavoriteButton>
|
||||
</StyledTitleWrapper>
|
||||
</TableCell>
|
||||
<TableCell ellipsis={true}>{pageMeta.createDate}</TableCell>
|
||||
<TableCell ellipsis={true}>{pageMeta.createDate}</TableCell>
|
||||
<TableCell>
|
||||
<OperationArea pageMeta={pageMeta} />
|
||||
</TableCell>
|
||||
</StyledTableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</StyledTableContainer>
|
||||
<PageList
|
||||
pageList={allPageList.filter(p => !p.trash)}
|
||||
showFavoriteTag={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AllPage;
|
||||
export default All;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Header } from '@/components/header';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import { PageList } from '@/components/page-list';
|
||||
|
||||
export const Favorite = () => {
|
||||
const { pageList: allPageList } = useEditor();
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<PageList pageList={allPageList.filter(p => p.favorite && !p.trash)} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Favorite;
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Header } from '@/components/header';
|
||||
import { useEditor } from '@/providers/editor-provider';
|
||||
import { PageList } from '@/components/page-list';
|
||||
|
||||
export const Trash = () => {
|
||||
const { pageList: allPageList } = useEditor();
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<PageList pageList={allPageList.filter(p => p.trash)} isTrash={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Trash;
|
||||
@@ -3,12 +3,12 @@ import type { PropsWithChildren } from 'react';
|
||||
import { Confirm, ConfirmProps } from '@/ui/confirm';
|
||||
|
||||
type ConfirmContextValue = {
|
||||
confirm: (props: ConfirmProps) => void;
|
||||
confirm: (props: ConfirmProps) => Promise<boolean>;
|
||||
};
|
||||
type ConfirmContextProps = PropsWithChildren<{}>;
|
||||
|
||||
export const ConfirmContext = createContext<ConfirmContextValue>({
|
||||
confirm: () => {},
|
||||
confirm: () => Promise.resolve(false),
|
||||
});
|
||||
|
||||
export const useConfirm = () => useContext(ConfirmContext);
|
||||
@@ -22,21 +22,33 @@ export const ConfirmProvider = ({
|
||||
return (
|
||||
<ConfirmContext.Provider
|
||||
value={{
|
||||
confirm: (props: ConfirmProps) => {
|
||||
const confirmId = String(Date.now());
|
||||
setConfirmRecord(oldConfirmRecord => {
|
||||
return {
|
||||
...oldConfirmRecord,
|
||||
[confirmId]: (
|
||||
<Confirm
|
||||
{...props}
|
||||
onClose={() => {
|
||||
delete confirmRecord[confirmId];
|
||||
setConfirmRecord({ ...confirmRecord });
|
||||
}}
|
||||
/>
|
||||
),
|
||||
confirm: ({ onClose, onCancel, onConfirm, ...props }: ConfirmProps) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const confirmId = String(Date.now());
|
||||
const closeHandler = () => {
|
||||
delete confirmRecord[confirmId];
|
||||
setConfirmRecord({ ...confirmRecord });
|
||||
};
|
||||
setConfirmRecord(oldConfirmRecord => {
|
||||
return {
|
||||
...oldConfirmRecord,
|
||||
[confirmId]: (
|
||||
<Confirm
|
||||
{...props}
|
||||
onCancel={() => {
|
||||
closeHandler();
|
||||
onCancel?.();
|
||||
resolve(false);
|
||||
}}
|
||||
onConfirm={() => {
|
||||
closeHandler();
|
||||
onConfirm?.();
|
||||
resolve(true);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
});
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -39,6 +39,7 @@ type EditorHandlers = {
|
||||
favoritePage: (pageId: string) => void;
|
||||
unFavoritePage: (pageId: string) => void;
|
||||
toggleFavoritePage: (pageId: string) => void;
|
||||
permanentlyDeletePage: (pageId: string) => void;
|
||||
};
|
||||
|
||||
type EditorContextProps = PropsWithChildren<{}>;
|
||||
@@ -59,6 +60,7 @@ export const EditorContext = createContext<EditorContextValue>({
|
||||
favoritePage: () => {},
|
||||
unFavoritePage: () => {},
|
||||
toggleFavoritePage: () => {},
|
||||
permanentlyDeletePage: () => {},
|
||||
});
|
||||
|
||||
export const useEditor = () => useContext(EditorContext);
|
||||
@@ -108,19 +110,23 @@ export const EditorProvider = ({
|
||||
});
|
||||
},
|
||||
deletePage: pageId => {
|
||||
workspace?.setPage(pageId, { trash: true });
|
||||
workspace?.setPageMeta(pageId, { trash: true });
|
||||
},
|
||||
recyclePage: pageId => {
|
||||
workspace?.setPage(pageId, { trash: false });
|
||||
workspace?.setPageMeta(pageId, { trash: false });
|
||||
},
|
||||
toggleDeletePage: pageId => {
|
||||
const pageMeta = workspace?.meta.pages.find(p => p.id === pageId);
|
||||
if (pageMeta) {
|
||||
workspace?.setPage(pageId, { trash: !pageMeta.trash });
|
||||
workspace?.setPageMeta(pageId, { trash: !pageMeta.trash });
|
||||
}
|
||||
},
|
||||
favoritePage: pageId => {
|
||||
workspace?.setPage(pageId, { favorite: true });
|
||||
workspace?.setPageMeta(pageId, { favorite: true });
|
||||
},
|
||||
permanentlyDeletePage: pageId => {
|
||||
// TODO: workspace.meta.removePage or workspace.removePage?
|
||||
workspace?.meta.removePage(pageId);
|
||||
},
|
||||
unFavoritePage: pageId => {
|
||||
workspace?.setPageMeta(pageId, { favorite: true });
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
import {
|
||||
ThemeProvider as EmotionThemeProvider,
|
||||
Global,
|
||||
css,
|
||||
} from '@emotion/react';
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
import {
|
||||
ThemeProvider as MuiThemeProvider,
|
||||
createTheme as MuiCreateTheme,
|
||||
} from '@mui/material/styles';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import {
|
||||
Theme,
|
||||
@@ -26,6 +30,7 @@ export const ThemeContext = createContext<ThemeProviderValue>({
|
||||
});
|
||||
|
||||
export const useTheme = () => useContext(ThemeContext);
|
||||
const muiTheme = MuiCreateTheme();
|
||||
|
||||
export const ThemeProvider = ({
|
||||
defaultTheme = 'light',
|
||||
@@ -87,16 +92,21 @@ export const ThemeProvider = ({
|
||||
// }, [mode]);
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ mode, changeMode, theme: themeStyle }}>
|
||||
<Global
|
||||
styles={css`
|
||||
:root {
|
||||
${globalThemeVariables(mode, themeStyle) as {}}
|
||||
}
|
||||
`}
|
||||
/>
|
||||
<EmotionThemeProvider theme={themeStyle}>{children}</EmotionThemeProvider>
|
||||
</ThemeContext.Provider>
|
||||
// Use MuiThemeProvider is just because some Transitions in Mui components need it
|
||||
<MuiThemeProvider theme={muiTheme}>
|
||||
<ThemeContext.Provider value={{ mode, changeMode, theme: themeStyle }}>
|
||||
<Global
|
||||
styles={css`
|
||||
:root {
|
||||
${globalThemeVariables(mode, themeStyle) as {}}
|
||||
}
|
||||
`}
|
||||
/>
|
||||
<EmotionThemeProvider theme={themeStyle}>
|
||||
{children}
|
||||
</EmotionThemeProvider>
|
||||
</ThemeContext.Provider>
|
||||
</MuiThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user