fix: a series of bugs

This commit is contained in:
QiShaoXuan
2022-12-19 17:06:14 +08:00
parent 0c7aa70645
commit 0c68c00bd6
11 changed files with 163 additions and 88 deletions
+44 -3
View File
@@ -13,6 +13,9 @@ import {
ExportToHtmlIcon, ExportToHtmlIcon,
ExportToMarkdownIcon, ExportToMarkdownIcon,
MoreVerticalIcon, MoreVerticalIcon,
FavouritesIcon,
FavouritedIcon,
TrashIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import { useEditor } from '@/providers/editor-provider'; import { useEditor } from '@/providers/editor-provider';
import ThemeModeSwitch from '@/components/theme-mode-switch'; import ThemeModeSwitch from '@/components/theme-mode-switch';
@@ -22,15 +25,37 @@ import { getWarningMessage, shouldShowWarning } from './utils';
import { Menu, MenuItem } from '@/ui/menu'; import { Menu, MenuItem } from '@/ui/menu';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useConfirm } from '@/providers/confirm-provider'; import { useConfirm } from '@/providers/confirm-provider';
import { useModal } from '@/providers/global-modal-provider';
import { useAppState } from '@/providers/app-state-provider';
import { SyncIcon } from './sync-icon'; import { SyncIcon } from './sync-icon';
import { toast } from '@/components/toast';
const PopoverContent = () => { const PopoverContent = () => {
const { editor, mode, setMode } = useEditor(); const {
editor,
mode,
setMode,
getPageMeta,
page,
toggleFavoritePage,
toggleDeletePage,
} = useEditor();
const { confirm } = useConfirm();
const { id, favorite, title } = getPageMeta(page?.id) ?? {
id: '',
favorite: false,
title: '',
};
return ( return (
<> <>
<MenuItem
onClick={() => {
toggleFavoritePage(id);
}}
icon={favorite ? <FavouritedIcon /> : <FavouritesIcon />}
>
{favorite ? 'Remove' : 'Add'} to favourites
</MenuItem>
<MenuItem <MenuItem
icon={mode === 'page' ? <EdgelessIcon /> : <PaperIcon />} icon={mode === 'page' ? <EdgelessIcon /> : <PaperIcon />}
onClick={() => { onClick={() => {
@@ -66,6 +91,22 @@ const PopoverContent = () => {
Export Export
</MenuItem> </MenuItem>
</Menu> </Menu>
<MenuItem
onClick={() => {
confirm({
title: 'Delete page?',
content: `${title || 'Untitled'} will be moved to Trash`,
confirmText: 'Delete',
confirmType: 'danger',
}).then(confirm => {
confirm && toggleDeletePage(id);
toast('Moved to Trash');
});
}}
icon={<TrashIcon />}
>
Delete
</MenuItem>
</> </>
); );
}; };
+39 -17
View File
@@ -6,7 +6,6 @@ import {
EdgelessIcon, EdgelessIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import { import {
StyledFavoriteButton,
StyledTableContainer, StyledTableContainer,
StyledTableRow, StyledTableRow,
StyledTitleLink, StyledTitleLink,
@@ -18,19 +17,31 @@ import Empty from './empty';
import { Content } from '@/ui/layout'; import { Content } from '@/ui/layout';
import React from 'react'; import React from 'react';
import DateCell from '@/components/page-list/date-cell'; import DateCell from '@/components/page-list/date-cell';
const FavoriteTag = ({ pageMeta }: { pageMeta: PageMeta }) => { import { IconButton } from '@/ui/button';
import { Tooltip } from '@/ui/tooltip';
import { router } from 'next/client';
const FavoriteTag = ({
pageMeta: { favorite, id },
}: {
pageMeta: PageMeta;
}) => {
const { toggleFavoritePage } = useEditor(); const { toggleFavoritePage } = useEditor();
return ( return (
<StyledFavoriteButton <Tooltip
className="favorite-button" content={favorite ? 'Favourited' : 'Favourite'}
favorite={pageMeta.favorite} placement="top-start"
onClick={() => {
toggleFavoritePage(pageMeta.id);
}}
> >
{pageMeta.favorite ? <FavouritedIcon /> : <FavouritesIcon />} <IconButton
</StyledFavoriteButton> darker={true}
iconSize={[20, 20]}
onClick={e => {
e.stopPropagation();
toggleFavoritePage(id);
}}
>
{favorite ? <FavouritedIcon /> : <FavouritesIcon />}
</IconButton>
</Tooltip>
); );
}; };
@@ -52,7 +63,7 @@ export const PageList = ({
<Table> <Table>
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell proportion={0.5}>Documents</TableCell> <TableCell proportion={0.5}>Title</TableCell>
<TableCell proportion={0.2}>Created</TableCell> <TableCell proportion={0.2}>Created</TableCell>
<TableCell proportion={0.2}> <TableCell proportion={0.2}>
{isTrash ? 'Moved to Trash' : 'Updated'} {isTrash ? 'Moved to Trash' : 'Updated'}
@@ -63,12 +74,18 @@ export const PageList = ({
<TableBody> <TableBody>
{pageList.map((pageMeta, index) => { {pageList.map((pageMeta, index) => {
return ( return (
<StyledTableRow key={`${pageMeta.id}-${index}`}> <StyledTableRow
key={`${pageMeta.id}-${index}`}
onClick={() => {
router.push({
pathname: '/',
query: { pageId: pageMeta.id },
});
}}
>
<TableCell> <TableCell>
<StyledTitleWrapper> <StyledTitleWrapper>
<StyledTitleLink <StyledTitleLink>
href={{ pathname: '/', query: { pageId: pageMeta.id } }}
>
{pageMeta.mode === 'edgeless' ? ( {pageMeta.mode === 'edgeless' ? (
<EdgelessIcon /> <EdgelessIcon />
) : ( ) : (
@@ -87,7 +104,12 @@ export const PageList = ({
dateKey={isTrash ? 'trashDate' : 'updatedDate'} dateKey={isTrash ? 'trashDate' : 'updatedDate'}
backupKey={isTrash ? 'trashDate' : 'createDate'} backupKey={isTrash ? 'trashDate' : 'createDate'}
/> />
<TableCell style={{ padding: 0 }}> <TableCell
style={{ padding: 0 }}
onClick={e => {
e.stopPropagation();
}}
>
{isTrash ? ( {isTrash ? (
<TrashOperationCell pageMeta={pageMeta} /> <TrashOperationCell pageMeta={pageMeta} />
) : ( ) : (
@@ -12,7 +12,7 @@ import {
OpenInNewIcon, OpenInNewIcon,
TrashIcon, TrashIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import React from 'react'; import { toast } from '@/components/toast';
export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => { export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
const { id, favorite } = pageMeta; const { id, favorite } = pageMeta;
@@ -41,11 +41,12 @@ export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
onClick={() => { onClick={() => {
confirm({ confirm({
title: 'Delete page?', title: 'Delete page?',
content: `${pageMeta.title} will be moved to Trash`, content: `${pageMeta.title || 'Untitled'} will be moved to Trash`,
confirmText: 'Delete', confirmText: 'Delete',
confirmType: 'danger', confirmType: 'danger',
}).then(confirm => { }).then(confirm => {
confirm && toggleDeletePage(id); confirm && toggleDeletePage(id);
toast('Moved to Trash');
}); });
}} }}
icon={<TrashIcon />} icon={<TrashIcon />}
@@ -57,7 +58,7 @@ export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
return ( return (
<Wrapper alignItems="center" justifyContent="center"> <Wrapper alignItems="center" justifyContent="center">
<Menu content={OperationMenu} placement="bottom-end" disablePortal={true}> <Menu content={OperationMenu} placement="bottom-end" disablePortal={true}>
<IconButton hoverBackground="#E0E6FF"> <IconButton darker={true}>
<MoreVerticalIcon /> <MoreVerticalIcon />
</IconButton> </IconButton>
</Menu> </Menu>
@@ -67,31 +68,34 @@ export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
export const TrashOperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => { export const TrashOperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
const { id } = pageMeta; const { id } = pageMeta;
const { permanentlyDeletePage, toggleDeletePage } = useEditor(); const { permanentlyDeletePage, toggleDeletePage, openPage, getPageMeta } =
useEditor();
const { confirm } = useConfirm(); const { confirm } = useConfirm();
return ( return (
<Wrapper> <Wrapper>
<IconButton <IconButton
hoverBackground="#E0E6FF" darker={true}
style={{ marginRight: '12px' }} style={{ marginRight: '12px' }}
onClick={() => { onClick={() => {
toggleDeletePage(id); toggleDeletePage(id);
toast(`${getPageMeta(id)?.title || 'Untitled'} restored`);
openPage(id);
}} }}
> >
<RestoreIcon /> <RestoreIcon />
</IconButton> </IconButton>
<IconButton <IconButton
hoverBackground="#E0E6FF" darker={true}
onClick={() => { onClick={() => {
confirm({ confirm({
title: 'Permanently delete', title: 'Delete permanently?',
content: content: "Once deleted, you can't undo this action.",
"Once deleted, you can't undo this action. Do you confirm?",
confirmText: 'Delete', confirmText: 'Delete',
confirmType: 'danger', confirmType: 'danger',
}).then(confirm => { }).then(confirm => {
confirm && permanentlyDeletePage(id); confirm && permanentlyDeletePage(id);
toast('Permanently deleted');
}); });
}} }}
> >
@@ -23,7 +23,7 @@ export const StyledTitleWrapper = styled.div(({ theme }) => {
}, },
}; };
}); });
export const StyledTitleLink = styled(Link)(({ theme }) => { export const StyledTitleLink = styled.div(({ theme }) => {
return { return {
maxWidth: '80%', maxWidth: '80%',
marginRight: '18px', marginRight: '18px',
@@ -34,31 +34,12 @@ export const StyledTitleLink = styled(Link)(({ theme }) => {
marginRight: '12px', marginRight: '12px',
color: theme.colors.iconColor, color: theme.colors.iconColor,
}, },
':hover': {
color: theme.colors.textColor,
'>svg': {
color: theme.colors.primaryColor,
},
},
}; };
}); });
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 }) => { export const StyledTableRow = styled(TableRow)(({ theme }) => {
return { return {
cursor: 'pointer',
'&:hover': { '&:hover': {
'.favorite-button': { '.favorite-button': {
display: 'flex', display: 'flex',
@@ -19,6 +19,7 @@ import {
ImportIcon, ImportIcon,
TrashIcon, TrashIcon,
AddIcon, AddIcon,
FavouritedIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import Link from 'next/link'; import Link from 'next/link';
import { Tooltip } from '@/ui/tooltip'; import { Tooltip } from '@/ui/tooltip';
@@ -93,7 +94,7 @@ export const WorkSpaceSliderBar = () => {
Favourites Favourites
</StyledLink> </StyledLink>
<IconButton <IconButton
hoverBackground="#E0E6FF" darker={true}
onClick={() => { onClick={() => {
setShowSubFavorite(!showSubFavorite); setShowSubFavorite(!showSubFavorite);
}} }}
@@ -107,13 +108,16 @@ export const WorkSpaceSliderBar = () => {
</StyledListItem> </StyledListItem>
<FavoriteList showList={showSubFavorite} /> <FavoriteList showList={showSubFavorite} />
<StyledListItem <Tooltip content="Coming soon" placement="right-start" zIndex={9999}>
onClick={() => { <StyledListItem
triggerImportModal(); disabled={true}
}} onClick={() => {
> // triggerImportModal();
<ImportIcon /> Import }}
</StyledListItem> >
<ImportIcon /> Import
</StyledListItem>
</Tooltip>
<Link href={{ pathname: '/page-list/trash' }}> <Link href={{ pathname: '/page-list/trash' }}>
<StyledListItem active={router.pathname === '/page-list/trash'}> <StyledListItem active={router.pathname === '/page-list/trash'}>
@@ -43,29 +43,33 @@ export const StyledArrowButton = styled.button<{ isShow: boolean }>(
} }
); );
export const StyledListItem = styled.button<{ active?: boolean }>( export const StyledListItem = styled.button<{
({ theme, active }) => { active?: boolean;
return { disabled?: boolean;
width: '296px', }>(({ theme, active, disabled }) => {
height: '32px', return {
marginTop: '12px', width: '296px',
fontSize: theme.font.sm, height: '32px',
color: active ? theme.colors.primaryColor : theme.colors.popoverColor, marginTop: '12px',
backgroundColor: active ? theme.colors.hoverBackground : 'unset', fontSize: theme.font.sm,
paddingLeft: '12px', color: active ? theme.colors.primaryColor : theme.colors.popoverColor,
borderRadius: '5px', paddingLeft: '12px',
...displayFlex('flex-start', 'center'), borderRadius: '5px',
'>svg': { ...displayFlex('flex-start', 'center'),
fontSize: '20px', ...(disabled
marginRight: '12px', ? { cursor: 'not-allowed', color: theme.colors.borderColor }
}, : {}),
':hover': {
color: theme.colors.primaryColor, '>svg': {
backgroundColor: theme.colors.hoverBackground, fontSize: '20px',
}, marginRight: '12px',
}; },
} ':hover:not([disabled])': {
); color: theme.colors.primaryColor,
backgroundColor: theme.colors.hoverBackground,
},
};
});
export const StyledListItemForWorkspace = styled(StyledListItem)({ export const StyledListItemForWorkspace = styled(StyledListItem)({
height: '52px', height: '52px',
@@ -7,7 +7,7 @@ export const Favorite = () => {
const { pageList: allPageList } = useEditor(); const { pageList: allPageList } = useEditor();
return ( return (
<> <>
<PageListHeader icon={<FavouritesIcon />}>Favorites</PageListHeader> <PageListHeader icon={<FavouritesIcon />}>Favourites</PageListHeader>
<PageList pageList={allPageList.filter(p => p.favorite && !p.trash)} /> <PageList pageList={allPageList.filter(p => p.favorite && !p.trash)} />
</> </>
); );
@@ -31,7 +31,7 @@ export type EditorHandlers = {
pageId: string, pageId: string,
query?: { [key: string]: string } query?: { [key: string]: string }
) => Promise<boolean>; ) => Promise<boolean>;
getPageMeta: (pageId?: string) => PageMeta | void; getPageMeta: (pageId?: string) => PageMeta;
toggleDeletePage: (pageId: string) => void; toggleDeletePage: (pageId: string) => void;
toggleFavoritePage: (pageId: string) => void; toggleFavoritePage: (pageId: string) => void;
permanentlyDeletePage: (pageId: string) => void; permanentlyDeletePage: (pageId: string) => void;
@@ -43,6 +43,7 @@ export type IconButtonProps = {
hoverColor?: string; hoverColor?: string;
hoverStyle?: CSSProperties; hoverStyle?: CSSProperties;
children: ReactElement<HTMLAttributes<SVGElement>, 'svg'>; children: ReactElement<HTMLAttributes<SVGElement>, 'svg'>;
darker?: boolean;
} & HTMLAttributes<HTMLButtonElement>; } & HTMLAttributes<HTMLButtonElement>;
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>( export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
+15 -4
View File
@@ -14,6 +14,7 @@ export const StyledIconButton = styled('button', {
'hoverBackground', 'hoverBackground',
'hoverColor', 'hoverColor',
'hoverStyle', 'hoverStyle',
'darker',
].includes(prop); ].includes(prop);
}, },
})<{ })<{
@@ -24,6 +25,8 @@ export const StyledIconButton = styled('button', {
hoverBackground?: CSSProperties['background']; hoverBackground?: CSSProperties['background'];
hoverColor?: string; hoverColor?: string;
hoverStyle?: CSSProperties; hoverStyle?: CSSProperties;
// In some cases, button is in a normal hover status, it should be darkened
darker?: boolean;
}>( }>(
({ ({
theme, theme,
@@ -33,6 +36,7 @@ export const StyledIconButton = styled('button', {
hoverBackground, hoverBackground,
hoverColor, hoverColor,
hoverStyle, hoverStyle,
darker = false,
}) => { }) => {
return { return {
width, width,
@@ -40,7 +44,7 @@ export const StyledIconButton = styled('button', {
color: theme.colors.iconColor, color: theme.colors.iconColor,
...displayInlineFlex('center', 'center'), ...displayInlineFlex('center', 'center'),
position: 'relative', position: 'relative',
...(disabled ? { cursor: 'not-allowed', pointerEvents: 'none' } : {}), ...(disabled ? { cursor: 'not-allowed' } : {}),
transition: 'background .15s', transition: 'background .15s',
// TODO: we need to add @emotion/babel-plugin // TODO: we need to add @emotion/babel-plugin
@@ -61,7 +65,10 @@ export const StyledIconButton = styled('button', {
':hover': { ':hover': {
color: hoverColor ?? theme.colors.primaryColor, color: hoverColor ?? theme.colors.primaryColor,
'::after': { '::after': {
background: hoverBackground ?? theme.colors.hoverBackground, background:
hoverBackground ?? darker
? theme.colors.innerHoverBackground
: theme.colors.hoverBackground,
}, },
...(hoverStyle ?? {}), ...(hoverStyle ?? {}),
}, },
@@ -116,7 +123,7 @@ export const StyledTextButton = styled('button', {
paddingRight: padding, paddingRight: padding,
...displayInlineFlex('flex-start', 'center'), ...displayInlineFlex('flex-start', 'center'),
position: 'relative', position: 'relative',
...(disabled ? { cursor: 'not-allowed', pointerEvents: 'none' } : {}), ...(disabled ? { cursor: 'not-allowed' } : {}),
transition: 'background .15s', transition: 'background .15s',
// TODO: Implement circle shape // TODO: Implement circle shape
borderRadius: shape === 'default' ? borderRadius : height / 2, borderRadius: shape === 'default' ? borderRadius : height / 2,
@@ -171,7 +178,10 @@ export const StyledButton = styled('button', {
border: '1px solid', border: '1px solid',
...displayInlineFlex('flex-start', 'center'), ...displayInlineFlex('flex-start', 'center'),
position: 'relative', position: 'relative',
...(disabled ? { cursor: 'not-allowed', pointerEvents: 'none' } : {}), // TODO: disabled color is not decided
...(disabled
? { cursor: 'not-allowed', color: theme.colors.borderColor }
: {}),
transition: 'background .15s', transition: 'background .15s',
// TODO: Implement circle shape // TODO: Implement circle shape
borderRadius: shape === 'default' ? borderRadius : height / 2, borderRadius: shape === 'default' ? borderRadius : height / 2,
@@ -190,6 +200,7 @@ export const StyledButton = styled('button', {
hoverStyle, hoverStyle,
}), }),
// TODO: disabled hover should be implemented
// //
// ':hover': { // ':hover': {
// color: hoverColor ?? theme.colors.primaryColor, // color: hoverColor ?? theme.colors.primaryColor,
+7
View File
@@ -40,6 +40,13 @@ export const StyledTableCell = styled.td<
export const StyledTableHead = styled.thead(({ theme }) => { export const StyledTableHead = styled.thead(({ theme }) => {
return { return {
fontWeight: 500, fontWeight: 500,
tr: {
':hover': {
td: {
background: 'unset',
},
},
},
}; };
}); });