From bd7c422c46d1260745c452c53705ce4ca2cdd43b Mon Sep 17 00:00:00 2001 From: CatsJuice Date: Mon, 18 Nov 2024 08:30:07 +0000 Subject: [PATCH] feat(mobile): impl masonry docs with flex and predict card height (#8849) previous `columns` implementation has some limitation: - the card order is not as expected - there may be strange shadow on top --- .../src/mobile/components/doc-card/index.tsx | 6 +-- .../mobile/views/all-docs/doc/masonry.css.ts | 15 ++++--- .../src/mobile/views/all-docs/doc/masonry.tsx | 44 ++++++++++++++----- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/packages/frontend/core/src/mobile/components/doc-card/index.tsx b/packages/frontend/core/src/mobile/components/doc-card/index.tsx index 06804425c7..328b62c0df 100644 --- a/packages/frontend/core/src/mobile/components/doc-card/index.tsx +++ b/packages/frontend/core/src/mobile/components/doc-card/index.tsx @@ -17,11 +17,9 @@ import { forwardRef, type ReactNode, useMemo } from 'react'; import * as styles from './styles.css'; import { DocCardTags } from './tag'; -const calcRowsById = (id: string) => { - const [MIN, MAX] = [2, 8]; - +export const calcRowsById = (id: string, min = 2, max = 8) => { const code = id.charCodeAt(0); - return Math.floor((code % (MAX - MIN)) + MIN); + return Math.floor((code % (max - min)) + min); }; export interface DocCardProps extends Omit { 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 index 4fe2ac27d6..b5b40bd58c 100644 --- 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 @@ -3,11 +3,16 @@ import { style } from '@vanilla-extract/css'; export const paddingX = 16; export const columnGap = 17; -export const masonry = style({ +export const columns = style({ padding: `16px ${paddingX}px`, - columnGap: columnGap, + display: 'flex', + gap: columnGap, }); -export const masonryItem = style({ - breakInside: 'avoid', - marginBottom: 10, + +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 index 57c453cd1a..4e887a9794 100644 --- a/packages/frontend/core/src/mobile/views/all-docs/doc/masonry.tsx +++ b/packages/frontend/core/src/mobile/views/all-docs/doc/masonry.tsx @@ -1,8 +1,8 @@ import { useGlobalEvent } from '@affine/core/mobile/hooks/use-global-events'; import type { DocMeta } from '@blocksuite/affine/store'; -import { useCallback, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; -import { DocCard } from '../../../components'; +import { calcRowsById, DocCard } from '../../../components'; import * as styles from './masonry.css'; const calcColumnCount = () => { @@ -14,6 +14,20 @@ const calcColumnCount = () => { return Math.max(newColumnCount, 2); }; +const calcColumns = (items: DocMeta[], length: number) => { + const columns = Array.from({ length }, () => [] as DocMeta[]); + const heights = Array.from({ length }, () => 0); + + items.forEach(item => { + const itemHeight = calcRowsById(item.id); + const minHeightIndex = heights.indexOf(Math.min(...heights)); + heights[minHeightIndex] += itemHeight; + columns[minHeightIndex].push(item); + }); + + return columns; +}; + export const MasonryDocs = ({ items, showTags, @@ -28,16 +42,24 @@ export const MasonryDocs = ({ }, []); useGlobalEvent('resize', updateColumnCount); + const columns = useMemo( + () => calcColumns(items, columnCount), + [items, columnCount] + ); + return ( -
- {items.map(item => ( - +
+ {columns.map((col, index) => ( +
+ {col.map(item => ( + + ))} +
))}
);