feat: add responvise page view (#2453)

This commit is contained in:
Whitewater
2023-05-21 16:25:25 -07:00
committed by GitHub
parent 1f510799e2
commit d68b421a4b
15 changed files with 381 additions and 287 deletions

View File

@@ -1,72 +1,23 @@
import type { IconButtonProps, TableCellProps } from '@affine/component';
import {
Content,
IconButton,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Tooltip,
} from '@affine/component';
import { OperationCell, TrashOperationCell } from '@affine/component/page-list';
import { TrashOperationCell } from '@affine/component/page-list';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import {
ArrowDownBigIcon,
ArrowUpBigIcon,
FavoritedIcon,
FavoriteIcon,
} from '@blocksuite/icons';
import { ArrowDownBigIcon, ArrowUpBigIcon } from '@blocksuite/icons';
import { useMediaQuery, useTheme } from '@mui/material';
import type { CSSProperties } from 'react';
import { forwardRef } from 'react';
import { NewPageButton } from './new-page-buttton';
import {
StyledTableContainer,
StyledTableRow,
StyledTitleLink,
StyledTitleWrapper,
} from './styles';
import { AllPagesBody } from './all-pages-body';
import { NewPageButton } from './components/new-page-buttton';
import { TitleCell } from './components/title-cell';
import { AllPageListMobileView, TrashListMobileView } from './mobile';
import { StyledTableContainer, StyledTableRow } from './styles';
import { useSorter } from './use-sorter';
// eslint-disable-next-line react/display-name
const FavoriteTag = forwardRef<
HTMLButtonElement,
{
active: boolean;
} & Omit<IconButtonProps, 'children'>
>(({ active, onClick, ...props }, ref) => {
const t = useAFFiNEI18N();
return (
<Tooltip
content={active ? t['Favorited']() : t['Favorite']()}
placement="top-start"
>
<IconButton
ref={ref}
iconSize={[20, 20]}
style={{
color: active
? 'var(--affine-primary-color)'
: 'var(--affine-icon-color)',
}}
onClick={e => {
e.stopPropagation();
onClick?.(e);
}}
{...props}
>
{active ? (
<FavoritedIcon data-testid="favorited-icon" />
) : (
<FavoriteIcon />
)}
</IconButton>
</Tooltip>
);
});
export type PageListProps = {
isPublicWorkspace?: boolean;
list: ListData[];
@@ -74,36 +25,13 @@ export type PageListProps = {
onCreateNewEdgeless: () => void;
};
const TitleCell = ({
icon,
text,
suffix,
...props
}: {
icon: JSX.Element;
text: string;
suffix?: JSX.Element;
} & TableCellProps) => {
return (
<TableCell {...props}>
<StyledTitleWrapper>
<StyledTitleLink>
{icon}
<Content ellipsis={true} color="inherit">
{text}
</Content>
</StyledTitleLink>
{suffix}
</StyledTitleWrapper>
</TableCell>
);
};
const AllPagesHead = ({
isPublicWorkspace,
sorter,
createNewPage,
createNewEdgeless,
}: {
isPublicWorkspace: boolean;
sorter: ReturnType<typeof useSorter<ListData>>;
createNewPage: () => void;
createNewEdgeless: () => void;
@@ -125,6 +53,7 @@ const AllPagesHead = ({
content: t['Updated'](),
proportion: 0.2,
},
{
key: 'unsortable_action',
content: (
@@ -133,11 +62,10 @@ const AllPagesHead = ({
createNewEdgeless={createNewEdgeless}
/>
),
showWhen: () => !isPublicWorkspace,
sortable: false,
styles: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
justifyContent: 'flex-end',
} satisfies CSSProperties,
},
];
@@ -145,8 +73,9 @@ const AllPagesHead = ({
return (
<TableHead>
<TableRow>
{titleList.map(
({ key, content, proportion, sortable = true, styles }) => (
{titleList
.filter(({ showWhen = () => true }) => showWhen())
.map(({ key, content, proportion, sortable = true, styles }) => (
<TableCell
key={key}
proportion={proportion}
@@ -156,18 +85,24 @@ const AllPagesHead = ({
? () => sorter.shiftOrder(key as keyof ListData)
: undefined
}
style={styles}
>
{content}
{sorter.key === key &&
(sorter.order === 'asc' ? (
<ArrowUpBigIcon width={24} height={24} />
) : (
<ArrowDownBigIcon width={24} height={24} />
))}
<div
style={{
display: 'flex',
alignItems: 'center',
...styles,
}}
>
{content}
{sorter.key === key &&
(sorter.order === 'asc' ? (
<ArrowUpBigIcon width={24} height={24} />
) : (
<ArrowDownBigIcon width={24} height={24} />
))}
</div>
</TableCell>
)
)}
))}
</TableRow>
</TableHead>
);
@@ -189,13 +124,12 @@ export type ListData = {
onDisablePublicSharing: () => void;
};
export const PageList: React.FC<PageListProps> = ({
export const PageList = ({
isPublicWorkspace = false,
list,
onCreateNewPage,
onCreateNewEdgeless,
}) => {
const t = useAFFiNEI18N();
}: PageListProps) => {
const sorter = useSorter<ListData>({
data: list,
key: 'createDate',
@@ -205,93 +139,29 @@ export const PageList: React.FC<PageListProps> = ({
const theme = useTheme();
const isSmallDevices = useMediaQuery(theme.breakpoints.down('sm'));
if (isSmallDevices) {
return <PageListMobileView list={sorter.data} />;
return (
<AllPageListMobileView
isPublicWorkspace={isPublicWorkspace}
createNewPage={onCreateNewPage}
createNewEdgeless={onCreateNewEdgeless}
list={sorter.data}
/>
);
}
const ListItems = sorter.data.map(
(
{
pageId,
title,
icon,
isPublicPage,
favorite,
createDate,
updatedDate,
onClickPage,
bookmarkPage,
onOpenPageInNewTab,
removeToTrash,
onDisablePublicSharing,
},
index
) => {
return (
<StyledTableRow
data-testid={`page-list-item-${pageId}`}
key={`${pageId}-${index}`}
>
<TitleCell
icon={icon}
text={title || t['Untitled']()}
data-testid="title"
onClick={onClickPage}
/>
<TableCell
data-testid="created-date"
ellipsis={true}
onClick={onClickPage}
>
{createDate}
</TableCell>
<TableCell
data-testid="updated-date"
ellipsis={true}
onClick={onClickPage}
>
{updatedDate ?? createDate}
</TableCell>
{!isPublicWorkspace && (
<TableCell
style={{
padding: 0,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
gap: '10px',
}}
data-testid={`more-actions-${pageId}`}
>
<FavoriteTag
className={favorite ? '' : 'favorite-button'}
onClick={bookmarkPage}
active={!!favorite}
/>
<OperationCell
title={title}
favorite={favorite}
isPublic={isPublicPage}
onOpenPageInNewTab={onOpenPageInNewTab}
onToggleFavoritePage={bookmarkPage}
onRemoveToTrash={removeToTrash}
onDisablePublicSharing={onDisablePublicSharing}
/>
</TableCell>
)}
</StyledTableRow>
);
}
);
return (
<StyledTableContainer>
<Table>
<AllPagesHead
isPublicWorkspace={isPublicWorkspace}
sorter={sorter}
createNewPage={onCreateNewPage}
createNewEdgeless={onCreateNewEdgeless}
/>
<TableBody>{ListItems}</TableBody>
<AllPagesBody
isPublicWorkspace={isPublicWorkspace}
data={sorter.data}
/>
</Table>
</StyledTableContainer>
);
@@ -338,7 +208,7 @@ export const PageListTrashView: React.FC<{
pageId,
onClickPage,
}));
return <PageListMobileView list={mobileList} />;
return <TrashListMobileView list={mobileList} />;
}
const ListItems = list.map(
(
@@ -395,43 +265,4 @@ export const PageListTrashView: React.FC<{
);
};
const PageListMobileView: React.FC<{
list: {
pageId: string;
title: string;
icon: JSX.Element;
onClickPage: () => void;
}[];
}> = ({ list }) => {
const t = useAFFiNEI18N();
const ListItems = list.map(({ pageId, title, icon, onClickPage }, index) => {
return (
<StyledTableRow
data-testid={`page-list-item-${pageId}`}
key={`${pageId}-${index}`}
>
<TableCell onClick={onClickPage}>
<StyledTitleWrapper>
<StyledTitleLink>
{icon}
<Content ellipsis={true} color="inherit">
{title || t['Untitled']()}
</Content>
</StyledTitleLink>
</StyledTitleWrapper>
</TableCell>
</StyledTableRow>
);
});
return (
<StyledTableContainer>
<Table>
<TableBody>{ListItems}</TableBody>
</Table>
</StyledTableContainer>
);
};
export default PageList;