From a96cd3eb0a7f077cbb87d0d90b1e5e32f9c237ea Mon Sep 17 00:00:00 2001 From: CatsJuice Date: Fri, 23 May 2025 07:07:09 +0000 Subject: [PATCH] feat(mobile): new docs list for mobile (#12329) close AF-2514 ## Summary by CodeRabbit - **New Features** - Enhanced document explorer on mobile with live updates, responsive masonry layout, and improved empty state handling for all documents, collections, and tags. - Added customization for card height and masonry item width in document explorer views. - Extended layout components to support additional flexbox styling options for improved layout flexibility. - **Bug Fixes** - Improved flexibility in layout components by supporting additional flexbox styling options. - **Refactor** - Replaced older static document list and menu components with a unified, context-driven explorer for a more dynamic and interactive experience. - Removed obsolete CSS and component files related to the previous document list and menu implementations. --- .../component/src/ui/layout/wrapper.tsx | 6 + .../explorer/docs-view/docs-list.tsx | 18 ++- .../core/src/mobile/pages/workspace/all.tsx | 80 ++++++++++++- .../views/all-docs/collection/detail.tsx | 64 ++++++++++- .../src/mobile/views/all-docs/doc/index.ts | 3 - .../src/mobile/views/all-docs/doc/list.css.ts | 36 ------ .../src/mobile/views/all-docs/doc/list.tsx | 107 ------------------ .../mobile/views/all-docs/doc/masonry.css.ts | 18 --- .../src/mobile/views/all-docs/doc/masonry.tsx | 44 ------- .../src/mobile/views/all-docs/doc/menu.css.ts | 65 ----------- .../src/mobile/views/all-docs/doc/menu.tsx | 73 ------------ .../core/src/mobile/views/all-docs/index.ts | 1 - .../src/mobile/views/all-docs/tag/detail.tsx | 84 +++++++++++++- tests/affine-mobile/e2e/detail.spec.ts | 6 +- tests/affine-mobile/e2e/home.spec.ts | 2 +- 15 files changed, 241 insertions(+), 366 deletions(-) delete mode 100644 packages/frontend/core/src/mobile/views/all-docs/doc/index.ts delete mode 100644 packages/frontend/core/src/mobile/views/all-docs/doc/list.css.ts delete mode 100644 packages/frontend/core/src/mobile/views/all-docs/doc/list.tsx delete mode 100644 packages/frontend/core/src/mobile/views/all-docs/doc/masonry.css.ts delete mode 100644 packages/frontend/core/src/mobile/views/all-docs/doc/masonry.tsx delete mode 100644 packages/frontend/core/src/mobile/views/all-docs/doc/menu.css.ts delete mode 100644 packages/frontend/core/src/mobile/views/all-docs/doc/menu.tsx diff --git a/packages/frontend/component/src/ui/layout/wrapper.tsx b/packages/frontend/component/src/ui/layout/wrapper.tsx index 7a9ce850af..5199063b65 100644 --- a/packages/frontend/component/src/ui/layout/wrapper.tsx +++ b/packages/frontend/component/src/ui/layout/wrapper.tsx @@ -16,6 +16,8 @@ export type WrapperProps = { marginLeft?: CSSProperties['marginLeft']; marginRight?: CSSProperties['marginRight']; marginBottom?: CSSProperties['marginBottom']; + flexGrow?: CSSProperties['flexGrow']; + flexShrink?: CSSProperties['flexShrink']; }; export type FlexWrapperProps = { @@ -64,6 +66,8 @@ export const Wrapper = styled('div', { marginLeft, marginRight, marginBottom, + flexGrow, + flexShrink, }) => { return { display, @@ -79,6 +83,8 @@ export const Wrapper = styled('div', { marginLeft, marginRight, marginBottom, + flexGrow, + flexShrink, }; }); diff --git a/packages/frontend/core/src/components/explorer/docs-view/docs-list.tsx b/packages/frontend/core/src/components/explorer/docs-view/docs-list.tsx index 184b0dfbfc..fe914da14b 100644 --- a/packages/frontend/core/src/components/explorer/docs-view/docs-list.tsx +++ b/packages/frontend/core/src/components/explorer/docs-view/docs-list.tsx @@ -69,15 +69,15 @@ const GroupHeader = memo(function GroupHeader({ return header; }); -const calcCardHeightById = (id: string) => { +const calcCardHeightById = (id: string, base = 250, scale = 10) => { if (!id) { - return 250; + return base; } const max = 5; const min = 1; const code = id.charCodeAt(0); const value = Math.floor((code % (max - min)) + min); - return 250 + value * 10; + return base + value * scale; }; export const DocListItemComponent = memo(function DocListItemComponent({ @@ -93,9 +93,15 @@ export const DocListItemComponent = memo(function DocListItemComponent({ export const DocsExplorer = ({ className, disableMultiDelete, + masonryItemWidthMin, + heightBase, + heightScale, }: { className?: string; disableMultiDelete?: boolean; + masonryItemWidthMin?: number; + heightBase?: number; + heightScale?: number; }) => { const t = useI18n(); const contextValue = useContext(DocExplorerContext); @@ -126,7 +132,7 @@ export const DocsExplorer = ({ ? 42 : view === 'grid' ? 280 - : calcCardHeightById(docId), + : calcCardHeightById(docId, heightBase, heightScale), 'data-view': view, className: styles.docItem, }; @@ -134,7 +140,7 @@ export const DocsExplorer = ({ } satisfies MasonryGroup; }); return items; - }, [groupBy, groups, view]); + }, [groupBy, groups, heightBase, heightScale, view]); const handleCloseFloatingToolbar = useCallback(() => { contextValue.selectMode$?.next(false); @@ -206,7 +212,7 @@ export const DocsExplorer = ({ groupsGap={12} groupHeaderGapWithItems={12} columns={view === 'list' ? 1 : undefined} - itemWidthMin={220} + itemWidthMin={masonryItemWidthMin ?? 220} preloadHeight={100} itemWidth={'stretch'} virtualScroll diff --git a/packages/frontend/core/src/mobile/pages/workspace/all.tsx b/packages/frontend/core/src/mobile/pages/workspace/all.tsx index d7ae521e3e..312c01349e 100644 --- a/packages/frontend/core/src/mobile/pages/workspace/all.tsx +++ b/packages/frontend/core/src/mobile/pages/workspace/all.tsx @@ -1,14 +1,88 @@ -import { useThemeColorV2 } from '@affine/component'; +import { useThemeColorV2, Wrapper } from '@affine/component'; +import { EmptyDocs } from '@affine/core/components/affine/empty'; +import { + createDocExplorerContext, + DocExplorerContext, +} from '@affine/core/components/explorer/context'; +import { DocsExplorer } from '@affine/core/components/explorer/docs-view/docs-list'; +import { CollectionRulesService } from '@affine/core/modules/collection-rules'; +import { useLiveData, useService } from '@toeverything/infra'; +import { useEffect, useState } from 'react'; import { Page } from '../../components/page'; -import { AllDocList, AllDocsHeader } from '../../views'; +import { AllDocsHeader } from '../../views'; + +const AllDocs = () => { + const [explorerContextValue] = useState(() => + createDocExplorerContext({ + quickFavorite: true, + displayProperties: ['createdAt', 'updatedAt', 'tags'], + view: 'masonry', + showDragHandle: false, + }) + ); + const collectionRulesService = useService(CollectionRulesService); + const groups = useLiveData(explorerContextValue.groups$); + const isEmpty = + groups.length === 0 || + (groups.length && groups.every(group => !group.items.length)); + + useEffect(() => { + const subscription = collectionRulesService + .watch({ + filters: [ + { type: 'system', key: 'trash', method: 'is', value: 'false' }, + ], + extraFilters: [ + { type: 'system', key: 'trash', method: 'is', value: 'false' }, + { + type: 'system', + key: 'empty-journal', + method: 'is', + value: 'false', + }, + ], + orderBy: { + type: 'property', + key: 'createdAt', + desc: true, + }, + }) + .subscribe({ + next: result => { + explorerContextValue.groups$.next(result.groups); + }, + error: console.error, + }); + return () => subscription.unsubscribe(); + }, [collectionRulesService, explorerContextValue.groups$]); + + if (isEmpty) { + return ( + <> + + + + ); + } + + return ( + + + + ); +}; export const Component = () => { useThemeColorV2('layer/background/mobile/primary'); return ( } tab> - + ); }; diff --git a/packages/frontend/core/src/mobile/views/all-docs/collection/detail.tsx b/packages/frontend/core/src/mobile/views/all-docs/collection/detail.tsx index eb4182380c..1fb6c8ed7a 100644 --- a/packages/frontend/core/src/mobile/views/all-docs/collection/detail.tsx +++ b/packages/frontend/core/src/mobile/views/all-docs/collection/detail.tsx @@ -1,11 +1,20 @@ -import { EmptyCollectionDetail } from '@affine/core/components/affine/empty'; +import { Wrapper } from '@affine/component'; +import { + EmptyCollectionDetail, + EmptyDocs, +} from '@affine/core/components/affine/empty'; +import { + createDocExplorerContext, + DocExplorerContext, +} from '@affine/core/components/explorer/context'; +import { DocsExplorer } from '@affine/core/components/explorer/docs-view/docs-list'; import { PageHeader } from '@affine/core/mobile/components'; import { Page } from '@affine/core/mobile/components/page'; import type { Collection } from '@affine/core/modules/collection'; import { ViewLayersIcon } from '@blocksuite/icons/rc'; import { useLiveData } from '@toeverything/infra'; +import { useEffect, useState } from 'react'; -import { AllDocList } from '../doc/list'; import * as styles from './detail.css'; export const DetailHeader = ({ collection }: { collection: Collection }) => { @@ -20,6 +29,55 @@ export const DetailHeader = ({ collection }: { collection: Collection }) => { ); }; +const CollectionDocs = ({ collection }: { collection: Collection }) => { + const [explorerContextValue] = useState(() => + createDocExplorerContext({ + quickFavorite: true, + displayProperties: ['createdAt', 'updatedAt', 'tags'], + view: 'masonry', + showDragHandle: false, + }) + ); + const groups = useLiveData(explorerContextValue.groups$); + const isEmpty = + groups.length === 0 || + (groups.length && groups.every(group => !group.items.length)); + + useEffect(() => { + const subscription = collection.watch().subscribe({ + next: result => { + explorerContextValue.groups$.next([ + { + key: 'collection', + items: result, + }, + ]); + }, + error: console.error, + }); + return () => subscription.unsubscribe(); + }, [collection, explorerContextValue.groups$]); + + if (isEmpty) { + return ( + <> + + + + ); + } + + return ( + + + + ); +}; + export const CollectionDetail = ({ collection, }: { @@ -38,7 +96,7 @@ export const CollectionDetail = ({ return ( }> - + ); }; diff --git a/packages/frontend/core/src/mobile/views/all-docs/doc/index.ts b/packages/frontend/core/src/mobile/views/all-docs/doc/index.ts deleted file mode 100644 index 9c183702d6..0000000000 --- a/packages/frontend/core/src/mobile/views/all-docs/doc/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './list'; -export * from './masonry'; -export * from './menu'; diff --git a/packages/frontend/core/src/mobile/views/all-docs/doc/list.css.ts b/packages/frontend/core/src/mobile/views/all-docs/doc/list.css.ts deleted file mode 100644 index 0334cebf45..0000000000 --- a/packages/frontend/core/src/mobile/views/all-docs/doc/list.css.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { cssVarV2 } from '@toeverything/theme/v2'; -import { globalStyle, style } from '@vanilla-extract/css'; - -export const groupTitle = style({ - display: 'flex', - alignItems: 'center', - padding: '0px 16px', - width: '100%', -}); -// to override style defined in `core` -globalStyle(`${groupTitle} > div`, { - marginRight: -4, -}); -globalStyle(`${groupTitle} div[data-testid^='group-label']`, { - fontSize: `20px !important`, - color: `${cssVarV2('text/primary')} !important`, - lineHeight: '25px !important', -}); -export const groupTitleIcon = style({ - color: cssVarV2('icon/tertiary'), - transition: 'transform 0.2s', - selectors: { - '[data-state="closed"] &': { - transform: `rotate(-90deg)`, - }, - }, -}); -export const groups = style({ - display: 'flex', - flexDirection: 'column', - gap: 32, -}); -export const emptySpaceY = style({ - height: 0, - flexGrow: 1, -}); diff --git a/packages/frontend/core/src/mobile/views/all-docs/doc/list.tsx b/packages/frontend/core/src/mobile/views/all-docs/doc/list.tsx deleted file mode 100644 index 784998fd64..0000000000 --- a/packages/frontend/core/src/mobile/views/all-docs/doc/list.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { EmptyDocs } from '@affine/core/components/affine/empty'; -import { useBlockSuiteDocMeta } from '@affine/core/components/hooks/use-block-suite-page-meta'; -import { - type ItemGroupProps, - useAllDocDisplayProperties, -} from '@affine/core/components/page-list'; -import type { Collection } from '@affine/core/modules/collection'; -import { DocsService } from '@affine/core/modules/doc'; -import type { Tag } from '@affine/core/modules/tag'; -import { WorkspaceService } from '@affine/core/modules/workspace'; -import type { DocMeta } from '@blocksuite/affine/store'; -import { ToggleDownIcon } from '@blocksuite/icons/rc'; -import * as Collapsible from '@radix-ui/react-collapsible'; -import { LiveData, useLiveData, useService } from '@toeverything/infra'; -import { useEffect, useMemo, useState } from 'react'; - -import * as styles from './list.css'; -import { MasonryDocs } from './masonry'; - -export const DocGroup = ({ group }: { group: ItemGroupProps }) => { - const [properties] = useAllDocDisplayProperties(); - const showTags = properties.displayProperties.tags; - - if (group.id === 'all') { - return ; - } - - return ( - - - {group.label} - - - - - - - ); -}; - -export interface AllDocListProps { - collection?: Collection; - tag?: Tag; - trash?: boolean; -} - -export const AllDocList = ({ trash, collection, tag }: AllDocListProps) => { - const [properties] = useAllDocDisplayProperties(); - const workspace = useService(WorkspaceService).workspace; - const allPageMetas = useBlockSuiteDocMeta(workspace.docCollection); - const docsService = useService(DocsService); - - const allTrashPageIds = useLiveData( - LiveData.from(docsService.allTrashDocIds$(), []) - ); - - const tagPageIds = useLiveData(tag?.pageIds$); - - const [filteredPageIds, setFilteredPageIds] = useState([]); - - useEffect(() => { - const subscription = collection?.watch().subscribe(docIds => { - setFilteredPageIds(docIds); - }); - return () => subscription?.unsubscribe(); - }, [collection]); - - const finalPageMetas = useMemo(() => { - const collectionFilteredPageMetas = collection - ? allPageMetas.filter(page => filteredPageIds.includes(page.id)) - : allPageMetas; - - const filteredPageMetas = collectionFilteredPageMetas.filter( - page => allTrashPageIds.includes(page.id) === !!trash - ); - - if (tag) { - const pageIdsSet = new Set(tagPageIds); - return filteredPageMetas.filter(page => pageIdsSet.has(page.id)); - } - return filteredPageMetas; - }, [ - allPageMetas, - allTrashPageIds, - collection, - filteredPageIds, - tag, - tagPageIds, - trash, - ]); - - if (!finalPageMetas.length) { - return ( - <> - -
- - ); - } - - return ( - - ); -}; diff --git a/packages/frontend/core/src/mobile/views/all-docs/doc/masonry.css.ts b/packages/frontend/core/src/mobile/views/all-docs/doc/masonry.css.ts deleted file mode 100644 index b5b40bd58c..0000000000 --- a/packages/frontend/core/src/mobile/views/all-docs/doc/masonry.css.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { style } from '@vanilla-extract/css'; - -export const paddingX = 16; -export const columnGap = 17; - -export const columns = style({ - padding: `16px ${paddingX}px`, - display: 'flex', - gap: columnGap, -}); - -export const column = style({ - display: 'flex', - flexDirection: 'column', - gap: 10, - width: 0, - flex: 1, -}); diff --git a/packages/frontend/core/src/mobile/views/all-docs/doc/masonry.tsx b/packages/frontend/core/src/mobile/views/all-docs/doc/masonry.tsx deleted file mode 100644 index b7fd815a89..0000000000 --- a/packages/frontend/core/src/mobile/views/all-docs/doc/masonry.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Masonry } from '@affine/component'; -import type { DocMeta } from '@blocksuite/affine/store'; -import { useMemo } from 'react'; - -import { calcRowsById, DocCard } from '../../../components'; - -const fullStyle = { - width: '100%', - height: '100%', -}; - -export const MasonryDocs = ({ - items, - showTags, -}: { - items: DocMeta[]; - showTags?: boolean; -}) => { - const masonryItems = useMemo( - () => - items.map(item => { - return { - id: item.id, - height: calcRowsById(item.id) * 18 + 95, - children: ( - - ), - }; - }), - [items, showTags] - ); - return ( - - ); -}; diff --git a/packages/frontend/core/src/mobile/views/all-docs/doc/menu.css.ts b/packages/frontend/core/src/mobile/views/all-docs/doc/menu.css.ts deleted file mode 100644 index 9a0dafe726..0000000000 --- a/packages/frontend/core/src/mobile/views/all-docs/doc/menu.css.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { bodyEmphasized, bodyRegular } from '@toeverything/theme/typography'; -import { cssVarV2 } from '@toeverything/theme/v2'; -import { style } from '@vanilla-extract/css'; - -export const root = style({ - display: 'flex', - flexDirection: 'column', - gap: 10, -}); -export const head = style([ - bodyEmphasized, - { - padding: '10px 20px', - color: cssVarV2('text/primary'), - }, -]); - -export const item = style([ - bodyRegular, - { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - gap: 4, - height: 34, - padding: '0 20px', - }, -]); -export const itemSuffix = style({ - display: 'flex', - gap: 8, - alignItems: 'center', -}); -export const itemSuffixText = style({ - color: cssVarV2('text/secondary'), -}); -export const itemSuffixIcon = style({ - color: cssVarV2('icon/primary'), - fontSize: 20, -}); -export const divider = style({ - width: '100%', - height: 16, - display: 'flex', - alignItems: 'center', - ':before': { - content: "''", - height: 0.5, - width: '100%', - backgroundColor: cssVarV2('layer/insideBorder/border'), - }, -}); -export const propertiesList = style({ - padding: '4px 20px', - display: 'flex', - gap: 8, -}); -export const propertyButton = style({ - opacity: 0.4, - selectors: { - '&[data-selected="true"]': { - opacity: 1, - }, - }, -}); diff --git a/packages/frontend/core/src/mobile/views/all-docs/doc/menu.tsx b/packages/frontend/core/src/mobile/views/all-docs/doc/menu.tsx deleted file mode 100644 index 6fa1b55258..0000000000 --- a/packages/frontend/core/src/mobile/views/all-docs/doc/menu.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Button, MobileMenu, MobileMenuItem } from '@affine/component'; -import { - getGroupOptions, - useAllDocDisplayProperties, -} from '@affine/core/components/page-list'; -import { useI18n } from '@affine/i18n'; -import { ArrowRightSmallIcon } from '@blocksuite/icons/rc'; -import { useMemo } from 'react'; - -import * as styles from './menu.css'; - -export const AllDocsMenu = () => { - const t = useI18n(); - - const [properties, setProperties] = useAllDocDisplayProperties(); - const groupOptions = useMemo(() => getGroupOptions(t), [t]); - - const activeGroup = useMemo( - () => groupOptions.find(g => g.value === properties.groupBy), - [groupOptions, properties.groupBy] - ); - - return ( -
-
Display Settings
- -
- {groupOptions.map(group => ( - setProperties('groupBy', group.value)} - selected={properties.groupBy === group.value} - key={group.value} - > - {group.label} - - ))} - - } - > -
- {t['com.affine.page.display.grouping']()} -
- {activeGroup?.label} - -
-
- - -
- -
- {t['com.affine.page.display.display-properties']()} -
-
- -
-
- ); -}; diff --git a/packages/frontend/core/src/mobile/views/all-docs/index.ts b/packages/frontend/core/src/mobile/views/all-docs/index.ts index 7cc2e75cfc..200e45b17e 100644 --- a/packages/frontend/core/src/mobile/views/all-docs/index.ts +++ b/packages/frontend/core/src/mobile/views/all-docs/index.ts @@ -1,4 +1,3 @@ export * from './collection'; -export * from './doc/'; export * from './header'; export * from './tag'; diff --git a/packages/frontend/core/src/mobile/views/all-docs/tag/detail.tsx b/packages/frontend/core/src/mobile/views/all-docs/tag/detail.tsx index f11b68292a..7110a17511 100644 --- a/packages/frontend/core/src/mobile/views/all-docs/tag/detail.tsx +++ b/packages/frontend/core/src/mobile/views/all-docs/tag/detail.tsx @@ -1,13 +1,93 @@ +import { Wrapper } from '@affine/component'; +import { EmptyDocs } from '@affine/core/components/affine/empty'; +import { + createDocExplorerContext, + DocExplorerContext, +} from '@affine/core/components/explorer/context'; +import { DocsExplorer } from '@affine/core/components/explorer/docs-view/docs-list'; import { Page } from '@affine/core/mobile/components/page'; +import { CollectionRulesService } from '@affine/core/modules/collection-rules'; import type { Tag } from '@affine/core/modules/tag'; +import { useLiveData, useService } from '@toeverything/infra'; +import { useEffect, useState } from 'react'; -import { AllDocList } from '../doc'; import { TagDetailHeader } from './detail-header'; +const TagDocs = ({ tag }: { tag: Tag }) => { + const [explorerContextValue] = useState(() => + createDocExplorerContext({ + quickFavorite: true, + displayProperties: ['createdAt', 'updatedAt', 'tags'], + view: 'masonry', + showDragHandle: false, + }) + ); + const collectionRulesService = useService(CollectionRulesService); + const groups = useLiveData(explorerContextValue.groups$); + const isEmpty = + groups.length === 0 || + (groups.length && groups.every(group => !group.items.length)); + + useEffect(() => { + const subscription = collectionRulesService + .watch({ + filters: [ + { type: 'system', key: 'trash', method: 'is', value: 'false' }, + { + type: 'system', + key: 'tags', + method: 'include-all', + value: tag.id, + }, + ], + extraFilters: [ + { type: 'system', key: 'trash', method: 'is', value: 'false' }, + { + type: 'system', + key: 'empty-journal', + method: 'is', + value: 'false', + }, + ], + orderBy: { + type: 'property', + key: 'createdAt', + desc: true, + }, + }) + .subscribe({ + next: result => { + explorerContextValue.groups$.next(result.groups); + }, + error: console.error, + }); + return () => subscription.unsubscribe(); + }, [collectionRulesService, explorerContextValue.groups$, tag.id]); + + if (isEmpty) { + return ( + <> + + + + ); + } + + return ( + + + + ); +}; + export const TagDetail = ({ tag }: { tag: Tag }) => { return ( } tab> - + ); }; diff --git a/tests/affine-mobile/e2e/detail.spec.ts b/tests/affine-mobile/e2e/detail.spec.ts index 2311be7259..71fcdb7ce1 100644 --- a/tests/affine-mobile/e2e/detail.spec.ts +++ b/tests/affine-mobile/e2e/detail.spec.ts @@ -13,7 +13,7 @@ test.beforeEach(async ({ page }) => { const docsTab = page.locator('#app-tabs').getByRole('tab', { name: 'all' }); await expect(docsTab).toBeVisible(); await docsTab.click(); - await page.getByTestId('doc-card').first().click(); + await page.getByTestId('doc-list-item').first().click(); await expect(page.locator('.affine-page-viewport')).toBeVisible(); }); @@ -53,7 +53,5 @@ test('can add text property', async ({ page }) => { ).toBeVisible(); await page.getByTestId('mobile-menu-back-button').last().click(); - await expect(page.getByTestId('mobile-menu-back-button')).toContainText( - 'Getting Started' - ); + await expect(page.getByTestId('mobile-menu-back-button')).toBeVisible(); }); diff --git a/tests/affine-mobile/e2e/home.spec.ts b/tests/affine-mobile/e2e/home.spec.ts index 1f4b4cfe2c..1b419fb4ec 100644 --- a/tests/affine-mobile/e2e/home.spec.ts +++ b/tests/affine-mobile/e2e/home.spec.ts @@ -47,6 +47,6 @@ test('all tab', async ({ page }) => { await docsTab.click(); - const todayDocs = page.getByTestId('doc-card'); + const todayDocs = page.getByTestId('doc-list-item'); expect(await todayDocs.count()).toBeGreaterThan(0); });