diff --git a/apps/web/package.json b/apps/web/package.json index b1f3a63d78..a8422f6986 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -36,7 +36,6 @@ "@toeverything/hooks": "workspace:*", "cmdk": "^0.2.0", "css-spring": "^4.1.0", - "dayjs": "^1.11.7", "graphql": "^16.6.0", "jotai": "^2.1.0", "jotai-devtools": "^0.5.3", diff --git a/apps/web/src/components/blocksuite/block-suite-page-list/index.tsx b/apps/web/src/components/blocksuite/block-suite-page-list/index.tsx index 34cd2cff07..f6a910048f 100644 --- a/apps/web/src/components/blocksuite/block-suite-page-list/index.tsx +++ b/apps/web/src/components/blocksuite/block-suite-page-list/index.tsx @@ -12,7 +12,7 @@ import { useBlockSuiteMetaHelper } from '../../../hooks/affine/use-block-suite-m import type { BlockSuiteWorkspace } from '../../../shared'; import { toast } from '../../../utils'; import { pageListEmptyStyle } from './index.css'; -import { formatDate, usePageHelper } from './utils'; +import { usePageHelper } from './utils'; export type BlockSuitePageListProps = { blockSuiteWorkspace: BlockSuiteWorkspace; @@ -91,8 +91,10 @@ export const BlockSuitePageList: React.FC = ({ ), pageId: pageMeta.id, title: pageMeta.title, - createDate: formatDate(pageMeta.createDate), - updatedDate: formatDate(pageMeta.updatedDate ?? pageMeta.createDate), + createDate: new Date(pageMeta.createDate), + trashDate: pageMeta.trashDate + ? new Date(pageMeta.trashDate) + : undefined, onClickPage: () => onOpenPage(pageMeta.id), onClickRestore: () => { restoreFromTrash(pageMeta.id); @@ -117,8 +119,8 @@ export const BlockSuitePageList: React.FC = ({ title: pageMeta.title, favorite: !!pageMeta.favorite, isPublicPage: !!pageMeta.isPublic, - createDate: formatDate(pageMeta.createDate), - updatedDate: formatDate(pageMeta.updatedDate ?? pageMeta.createDate), + createDate: new Date(pageMeta.createDate), + updatedDate: new Date(pageMeta.updatedDate ?? pageMeta.createDate), onClickPage: () => onOpenPage(pageMeta.id), onOpenPageInNewTab: () => onOpenPage(pageMeta.id, true), onClickRestore: () => { diff --git a/apps/web/src/components/blocksuite/block-suite-page-list/utils.tsx b/apps/web/src/components/blocksuite/block-suite-page-list/utils.tsx index e6d807edb3..d21c9ab497 100644 --- a/apps/web/src/components/blocksuite/block-suite-page-list/utils.tsx +++ b/apps/web/src/components/blocksuite/block-suite-page-list/utils.tsx @@ -1,19 +1,10 @@ import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper'; -import dayjs from 'dayjs'; -import localizedFormat from 'dayjs/plugin/localizedFormat'; import { useRouter } from 'next/router'; import { useWorkspacePreferredMode } from '../../../hooks/use-recent-views'; import { useRouterHelper } from '../../../hooks/use-router-helper'; import type { BlockSuiteWorkspace } from '../../../shared'; -dayjs.extend(localizedFormat); -export const formatDate = (date?: number | unknown) => { - const dateStr = - typeof date === 'number' ? dayjs(date).format('MM-DD HH:mm') : '--'; - return dateStr; -}; - export const usePageHelper = (blockSuiteWorkspace: BlockSuiteWorkspace) => { const router = useRouter(); const { openPage } = useRouterHelper(router); diff --git a/packages/component/src/components/page-list/all-page.tsx b/packages/component/src/components/page-list/all-page.tsx index dbc1812411..1594b8d460 100644 --- a/packages/component/src/components/page-list/all-page.tsx +++ b/packages/component/src/components/page-list/all-page.tsx @@ -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} /> - {createDate} + {formatDate(createDate)} - {trashDate} + {trashDate ? formatDate(trashDate) : '--'} {!isPublicWorkspace && ( 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; +}; diff --git a/packages/component/src/components/page-list/use-sorter.ts b/packages/component/src/components/page-list/use-sorter.ts index ab08e0397d..1ddc19ea40 100644 --- a/packages/component/src/components/page-list/use-sorter.ts +++ b/packages/component/src/components/page-list/use-sorter.ts @@ -17,15 +17,27 @@ const defaultSortingFn = >( 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 = >({ 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 = >({ 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>) => setSorter({ ...sorter, ...newVal }), diff --git a/packages/component/src/components/page-list/utils.tsx b/packages/component/src/components/page-list/utils.tsx new file mode 100644 index 0000000000..fa0c593e29 --- /dev/null +++ b/packages/component/src/components/page-list/utils.tsx @@ -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}`; +}; diff --git a/packages/component/src/stories/page-list.stories.tsx b/packages/component/src/stories/page-list.stories.tsx index 791b156d30..83adf78d05 100644 --- a/packages/component/src/stories/page-list.stories.tsx +++ b/packages/component/src/stories/page-list.stories.tsx @@ -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 = ({ ...props }) => ( +export const AffineAllPageList: StoryFn = ({ ...props }) => ( ); @@ -68,14 +64,28 @@ AffineAllPageList.args = { onCreateNewPage: () => toast('Create new page'), onCreateNewEdgeless: () => toast('Create new edgeless'), list: [ + { + pageId: '1', + favorite: false, + icon: , + 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: , 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: , 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 = ({ ...props }) => ( - -); +export const AffinePublicPageList: StoryFn = ({ + ...props +}) => ; AffinePublicPageList.args = { ...AffineAllPageList.args, isPublicWorkspace: true, }; -export const AffineAllPageMobileList: StoryFn = ({ +export const AffineAllPageMobileList: StoryFn = ({ ...props }) => ; @@ -118,9 +128,9 @@ AffineAllPageMobileList.parameters = { }, }; -export const AffineTrashPageList: StoryFn<{ - list: TrashListData[]; -}> = ({ ...props }) => ; +export const AffineTrashPageList: StoryFn = ({ + ...props +}) => ; AffineTrashPageList.args = { list: [ @@ -128,9 +138,8 @@ AffineTrashPageList.args = { pageId: '1', icon: , 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: , 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'), diff --git a/yarn.lock b/yarn.lock index 876b3291c6..ec4e7c2880 100644 --- a/yarn.lock +++ b/yarn.lock @@ -338,7 +338,6 @@ __metadata: "@vanilla-extract/next-plugin": ^2.1.2 cmdk: ^0.2.0 css-spring: ^4.1.0 - dayjs: ^1.11.7 dotenv: ^16.0.3 eslint: ^8.40.0 eslint-config-next: ^13.4.2 @@ -12785,13 +12784,6 @@ __metadata: languageName: node linkType: hard -"dayjs@npm:^1.11.7": - version: 1.11.7 - resolution: "dayjs@npm:1.11.7" - checksum: 5003a7c1dd9ed51385beb658231c3548700b82d3548c0cfbe549d85f2d08e90e972510282b7506941452c58d32136d6362f009c77ca55381a09c704e9f177ebb - languageName: node - linkType: hard - "debounce@npm:^1.2.0": version: 1.2.1 resolution: "debounce@npm:1.2.1"