feat(core): new all docs list ui (#12102)

### New all docs list ui
close AF-2531, AF-2585, AF-2586, AF-2580

### What changed

- a new `display-menu` component
  - properties visibility
  - quick actions visibility
- extend DocPropertyType definition
  - `showInDocList`: configure whether to show in doc and how to show (stack | inline)
  - `docListProperty`: define how to render property in doc
  - `groupHeader`: define how to render group header when grouped
- implement all properties's `docListProperty` renderer and `groupHeader` renderer
- new `docs-view` component
  - render doc in `card` | `list` view
  - split doc card into minimal components for reuse in list and card views, as well as visibility control
- implement docs-list with `<Masonry />` and multi-view support
  - for list view, make masonry column count always `1`

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Redesigned document explorer with multiple view modes (list, grid, masonry), grouping, selection, and multi-delete.
  - Added customizable display properties and quick actions (favorite, trash, split view, new tab, select) for documents.
  - Introduced new group header and document item components with improved styling and interaction.
  - Enabled dynamic rendering of document properties including tags, dates, users, templates, and themes.
  - Added filtering support for trash status and enhanced localization for UI elements.
  - Introduced drag handle size customization and expanded masonry layout configurability.
  - Added contextual "More" menu with document operations like favorite, info, duplicate, and trash.
  - Implemented shared context for explorer state management and multi-selection logic.

- **Enhancements**
  - Improved virtual scrolling with active item tracking and configurable preload and debounce settings.
  - Responsive, theme-aware styling applied across explorer and property components.
  - Configurable UI elements and quick actions via user preferences.
  - Enhanced error messages for unsupported property types in filters.
  - Refined padding and layout calculations in masonry component for better visual consistency.
  - Avatar and date components refactored for explicit prop-driven rendering and customization.

- **Bug Fixes**
  - Improved error messages for unsupported property types in filters.

- **Documentation**
  - Added new localization keys and updated language completeness for new features.

- **Chores**
  - Modularized workspace property types with list and group header display components.
  - Consolidated imports and enhanced code maintainability.
  - Added new CSS styling modules for explorer components and workspace property types.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
CatsJuice
2025-05-09 05:31:10 +00:00
parent 93e01b4442
commit 2e3b721603
48 changed files with 3060 additions and 124 deletions
@@ -1,13 +1,22 @@
import type { MasonryGroup, MasonryItem, MasonryItemXYWH } from './type';
import type {
MasonryGroup,
MasonryItem,
MasonryItemXYWH,
MasonryPX,
} from './type';
export const calcPX = (px: MasonryPX, totalWidth: number) =>
typeof px === 'number' ? px : px(totalWidth);
export const calcColumns = (
totalWidth: number,
itemWidth: number | 'stretch',
itemWidthMin: number,
gapX: number,
paddingX: number,
_paddingX: MasonryPX,
columns?: number
) => {
const paddingX = calcPX(_paddingX, totalWidth);
const availableWidth = totalWidth - paddingX * 2;
if (columns) {
@@ -47,7 +56,7 @@ export const calcLayout = (
width: number;
gapX: number;
gapY: number;
paddingX: number;
paddingX: MasonryPX;
paddingY: number;
groupsGap: number;
groupHeaderGapWithItems: number;
@@ -60,12 +69,13 @@ export const calcLayout = (
width,
gapX,
gapY,
paddingX,
paddingX: _paddingX,
paddingY,
groupsGap,
groupHeaderGapWithItems,
collapsedGroups,
} = options;
const paddingX = calcPX(_paddingX, totalWidth);
const layout = new Map<string, MasonryItemXYWH>();
let finalHeight = paddingY;
@@ -79,9 +89,9 @@ export const calcLayout = (
// calculate group header
const groupHeaderLayout: MasonryItemXYWH = {
type: 'group',
x: paddingX,
x: 0,
y: finalHeight,
w: totalWidth - paddingX * 2,
w: totalWidth,
h: group.height,
};
layout.set(group.id, groupHeaderLayout);
@@ -97,10 +107,11 @@ export const calcLayout = (
const itemId = group.id ? `${group.id}:${item.id}` : item.id;
const minHeight = Math.min(...heightStack);
const minHeightIndex = heightStack.indexOf(minHeight);
const hasGap = heightStack[minHeightIndex] ? gapY : 0;
const x = minHeightIndex * (width + gapX) + paddingX;
const y = minHeight + finalHeight;
const y = finalHeight + minHeight + hasGap;
heightStack[minHeightIndex] += item.height + gapY;
heightStack[minHeightIndex] += item.height + hasGap;
layout.set(itemId, {
type: 'item',
x,
@@ -117,7 +128,7 @@ export const calcLayout = (
return { layout, height: finalHeight };
};
export const calcSleep = (options: {
export const calcActive = (options: {
viewportHeight: number;
scrollY: number;
layoutMap: Map<MasonryItem['id'], MasonryItemXYWH>;
@@ -125,7 +136,7 @@ export const calcSleep = (options: {
}) => {
const { viewportHeight, scrollY, layoutMap, preloadHeight } = options;
const sleepMap = new Map<MasonryItem['id'], boolean>();
const activeMap = new Map<MasonryItem['id'], boolean>();
layoutMap.forEach((layout, id) => {
const { y, h } = layout;
@@ -134,10 +145,12 @@ export const calcSleep = (options: {
y + h + preloadHeight > scrollY &&
y - preloadHeight < scrollY + viewportHeight;
sleepMap.set(id, !isInView);
if (isInView) {
activeMap.set(id, true);
}
});
return sleepMap;
return activeMap;
};
export const calcSticky = (options: {