mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
refactor: use date obj in all pages (#2523)
This commit is contained in:
@@ -16,15 +16,9 @@ import { TitleCell } from './components/title-cell';
|
||||
import { AllPageListMobileView, TrashListMobileView } from './mobile';
|
||||
import { TrashOperationCell } from './operation-cell';
|
||||
import { StyledTableContainer, StyledTableRow } from './styles';
|
||||
import type { ListData } from './type';
|
||||
import type { ListData, PageListProps, TrashListData } from './type';
|
||||
import { useSorter } from './use-sorter';
|
||||
|
||||
export type PageListProps = {
|
||||
isPublicWorkspace?: boolean;
|
||||
list: ListData[];
|
||||
onCreateNewPage: () => void;
|
||||
onCreateNewEdgeless: () => void;
|
||||
};
|
||||
import { formatDate } from './utils';
|
||||
|
||||
const AllPagesHead = ({
|
||||
isPublicWorkspace,
|
||||
@@ -166,19 +160,6 @@ const TrashListHead = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export type TrashListData = {
|
||||
pageId: string;
|
||||
icon: JSX.Element;
|
||||
title: string;
|
||||
createDate: string;
|
||||
updatedDate?: string;
|
||||
trashDate?: string;
|
||||
// isPublic: boolean;
|
||||
onClickPage: () => void;
|
||||
onRestorePage: () => void;
|
||||
onPermanentlyDeletePage: () => void;
|
||||
};
|
||||
|
||||
export const PageListTrashView: React.FC<{
|
||||
list: TrashListData[];
|
||||
}> = ({ list }) => {
|
||||
@@ -220,10 +201,10 @@ export const PageListTrashView: React.FC<{
|
||||
onClick={onClickPage}
|
||||
/>
|
||||
<TableCell ellipsis={true} onClick={onClickPage}>
|
||||
{createDate}
|
||||
{formatDate(createDate)}
|
||||
</TableCell>
|
||||
<TableCell ellipsis={true} onClick={onClickPage}>
|
||||
{trashDate}
|
||||
{trashDate ? formatDate(trashDate) : '--'}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
style={{ padding: 0 }}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { TitleCell } from './components/title-cell';
|
||||
import { OperationCell } from './operation-cell';
|
||||
import { StyledTableRow } from './styles';
|
||||
import type { ListData } from './type';
|
||||
import { formatDate } from './utils';
|
||||
|
||||
export const AllPagesBody = ({
|
||||
isPublicWorkspace,
|
||||
@@ -55,7 +56,7 @@ export const AllPagesBody = ({
|
||||
hidden={isSmallDevices}
|
||||
onClick={onClickPage}
|
||||
>
|
||||
{createDate}
|
||||
{formatDate(createDate)}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
data-testid="updated-date"
|
||||
@@ -63,7 +64,7 @@ export const AllPagesBody = ({
|
||||
hidden={isSmallDevices}
|
||||
onClick={onClickPage}
|
||||
>
|
||||
{updatedDate ?? createDate}
|
||||
{formatDate(updatedDate ?? createDate)}
|
||||
</TableCell>
|
||||
{!isPublicWorkspace && (
|
||||
<TableCell
|
||||
|
||||
@@ -3,9 +3,8 @@ export type ListData = {
|
||||
icon: JSX.Element;
|
||||
title: string;
|
||||
favorite: boolean;
|
||||
createDate: string;
|
||||
updatedDate?: string;
|
||||
trashDate?: string;
|
||||
createDate: Date;
|
||||
updatedDate: Date;
|
||||
isPublicPage: boolean;
|
||||
onClickPage: () => void;
|
||||
onOpenPageInNewTab: () => void;
|
||||
@@ -13,3 +12,22 @@ export type ListData = {
|
||||
removeToTrash: () => void;
|
||||
onDisablePublicSharing: () => void;
|
||||
};
|
||||
|
||||
export type TrashListData = {
|
||||
pageId: string;
|
||||
icon: JSX.Element;
|
||||
title: string;
|
||||
createDate: Date;
|
||||
// TODO remove optional after assert that trashDate is always set
|
||||
trashDate?: Date;
|
||||
onClickPage: () => void;
|
||||
onRestorePage: () => void;
|
||||
onPermanentlyDeletePage: () => void;
|
||||
};
|
||||
|
||||
export type PageListProps = {
|
||||
isPublicWorkspace?: boolean;
|
||||
list: ListData[];
|
||||
onCreateNewPage: () => void;
|
||||
onCreateNewEdgeless: () => void;
|
||||
};
|
||||
|
||||
@@ -17,15 +17,27 @@ const defaultSortingFn = <T extends Record<keyof any, unknown>>(
|
||||
const valA = a[ctx.key];
|
||||
const valB = b[ctx.key];
|
||||
const revert = ctx.order === 'desc';
|
||||
if (typeof valA !== typeof valB) {
|
||||
return 0;
|
||||
const revertSymbol = revert ? -1 : 1;
|
||||
if (typeof valA === 'string' && typeof valB === 'string') {
|
||||
return valA.localeCompare(valB) * revertSymbol;
|
||||
}
|
||||
if (typeof valA === 'string') {
|
||||
return valA.localeCompare(valB as string) * (revert ? -1 : 1);
|
||||
if (typeof valA === 'number' && typeof valB === 'number') {
|
||||
return valA - valB * revertSymbol;
|
||||
}
|
||||
if (typeof valA === 'number') {
|
||||
return valA - (valB as number) * (revert ? -1 : 1);
|
||||
if (valA instanceof Date && valB instanceof Date) {
|
||||
return (valA.getTime() - valB.getTime()) * revertSymbol;
|
||||
}
|
||||
if (!valA) {
|
||||
return -1 * revertSymbol;
|
||||
}
|
||||
if (!valB) {
|
||||
return 1 * revertSymbol;
|
||||
}
|
||||
console.warn(
|
||||
'Unsupported sorting type! Please use custom sorting function.',
|
||||
valA,
|
||||
valB
|
||||
);
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -48,6 +60,7 @@ export const useSorter = <T extends Record<keyof any, unknown>>({
|
||||
key: sorter.key,
|
||||
order: sorter.order,
|
||||
};
|
||||
// TODO supports custom sorting function
|
||||
const sortingFn = (a: T, b: T) => defaultSortingFn(sortCtx, a, b);
|
||||
const sortedData = data.sort(sortingFn);
|
||||
|
||||
@@ -72,7 +85,7 @@ export const useSorter = <T extends Record<keyof any, unknown>>({
|
||||
order: sorter.order,
|
||||
key: sorter.order !== 'none' ? sorter.key : null,
|
||||
/**
|
||||
* @deprecated In most cases, we no necessary use `setSorter` directly.
|
||||
* @deprecated In most cases, we no necessary use `updateSorter` directly.
|
||||
*/
|
||||
updateSorter: (newVal: Partial<SorterConfig<T>>) =>
|
||||
setSorter({ ...sorter, ...newVal }),
|
||||
|
||||
23
packages/component/src/components/page-list/utils.tsx
Normal file
23
packages/component/src/components/page-list/utils.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
const isToday = (date: Date) => {
|
||||
const today = new Date();
|
||||
return (
|
||||
date.getDate() == today.getDate() &&
|
||||
date.getMonth() == today.getMonth() &&
|
||||
date.getFullYear() == today.getFullYear()
|
||||
);
|
||||
};
|
||||
|
||||
export const formatDate = (date: Date): string => {
|
||||
// yyyy-mm-dd MM-DD HH:mm
|
||||
// const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
if (isToday(date)) {
|
||||
// HH:mm
|
||||
return `${hours}:${minutes}`;
|
||||
}
|
||||
// MM-DD HH:mm
|
||||
return `${month}-${day} ${hours}:${minutes}`;
|
||||
};
|
||||
@@ -4,10 +4,6 @@ import type { StoryFn } from '@storybook/react';
|
||||
import { userEvent } from '@storybook/testing-library';
|
||||
|
||||
import { AffineLoading } from '../components/affine-loading';
|
||||
import type {
|
||||
PageListProps,
|
||||
TrashListData,
|
||||
} from '../components/page-list/all-page';
|
||||
import { PageListTrashView } from '../components/page-list/all-page';
|
||||
import { PageList } from '../components/page-list/all-page';
|
||||
import { NewPageButton } from '../components/page-list/components/new-page-buttton';
|
||||
@@ -59,7 +55,7 @@ AffineNewPageButton.play = async ({ canvasElement }) => {
|
||||
userEvent.click(dropdown);
|
||||
};
|
||||
|
||||
export const AffineAllPageList: StoryFn<PageListProps> = ({ ...props }) => (
|
||||
export const AffineAllPageList: StoryFn<typeof PageList> = ({ ...props }) => (
|
||||
<PageList {...props} />
|
||||
);
|
||||
|
||||
@@ -68,14 +64,28 @@ AffineAllPageList.args = {
|
||||
onCreateNewPage: () => toast('Create new page'),
|
||||
onCreateNewEdgeless: () => toast('Create new edgeless'),
|
||||
list: [
|
||||
{
|
||||
pageId: '1',
|
||||
favorite: false,
|
||||
icon: <PageIcon />,
|
||||
isPublicPage: true,
|
||||
title: 'Today Page',
|
||||
createDate: new Date(),
|
||||
updatedDate: new Date(),
|
||||
bookmarkPage: () => toast('Bookmark page'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
onOpenPageInNewTab: () => toast('Open page in new tab'),
|
||||
removeToTrash: () => toast('Remove to trash'),
|
||||
},
|
||||
{
|
||||
pageId: '1',
|
||||
favorite: false,
|
||||
icon: <PageIcon />,
|
||||
isPublicPage: true,
|
||||
title: '1 Example Public Page with long title that will be truncated',
|
||||
createDate: '2021-01-01',
|
||||
updatedDate: '2021-01-02',
|
||||
createDate: new Date('2021-01-01'),
|
||||
updatedDate: new Date('2021-01-02'),
|
||||
bookmarkPage: () => toast('Bookmark page'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
@@ -88,8 +98,8 @@ AffineAllPageList.args = {
|
||||
isPublicPage: false,
|
||||
icon: <PageIcon />,
|
||||
title: '2 Favorited Page',
|
||||
createDate: '2021-01-02',
|
||||
updatedDate: '2021-01-01',
|
||||
createDate: new Date('2021-01-02'),
|
||||
updatedDate: new Date('2021-01-01'),
|
||||
bookmarkPage: () => toast('Bookmark page'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
@@ -99,15 +109,15 @@ AffineAllPageList.args = {
|
||||
],
|
||||
};
|
||||
|
||||
export const AffinePublicPageList: StoryFn<PageListProps> = ({ ...props }) => (
|
||||
<PageList {...props} />
|
||||
);
|
||||
export const AffinePublicPageList: StoryFn<typeof PageList> = ({
|
||||
...props
|
||||
}) => <PageList {...props} />;
|
||||
AffinePublicPageList.args = {
|
||||
...AffineAllPageList.args,
|
||||
isPublicWorkspace: true,
|
||||
};
|
||||
|
||||
export const AffineAllPageMobileList: StoryFn<PageListProps> = ({
|
||||
export const AffineAllPageMobileList: StoryFn<typeof PageList> = ({
|
||||
...props
|
||||
}) => <PageList {...props} />;
|
||||
|
||||
@@ -118,9 +128,9 @@ AffineAllPageMobileList.parameters = {
|
||||
},
|
||||
};
|
||||
|
||||
export const AffineTrashPageList: StoryFn<{
|
||||
list: TrashListData[];
|
||||
}> = ({ ...props }) => <PageListTrashView {...props} />;
|
||||
export const AffineTrashPageList: StoryFn<typeof PageListTrashView> = ({
|
||||
...props
|
||||
}) => <PageListTrashView {...props} />;
|
||||
|
||||
AffineTrashPageList.args = {
|
||||
list: [
|
||||
@@ -128,9 +138,8 @@ AffineTrashPageList.args = {
|
||||
pageId: '1',
|
||||
icon: <PageIcon />,
|
||||
title: 'Example Page',
|
||||
updatedDate: '2021-02-01',
|
||||
createDate: '2021-01-01',
|
||||
trashDate: '2021-01-01',
|
||||
createDate: new Date('2021-01-01'),
|
||||
trashDate: new Date('2021-01-01'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onPermanentlyDeletePage: () => toast('Permanently delete page'),
|
||||
onRestorePage: () => toast('Restore page'),
|
||||
@@ -139,9 +148,7 @@ AffineTrashPageList.args = {
|
||||
pageId: '2',
|
||||
icon: <PageIcon />,
|
||||
title: 'Example Page with long title that will be truncated',
|
||||
updatedDate: '2021-01-01',
|
||||
createDate: '2021-01-01',
|
||||
trashDate: '2021-01-01',
|
||||
createDate: new Date('2021-01-01'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onPermanentlyDeletePage: () => toast('Permanently delete page'),
|
||||
onRestorePage: () => toast('Restore page'),
|
||||
|
||||
Reference in New Issue
Block a user