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

View File

@@ -38,8 +38,6 @@ export type { ServerConfig } from './types';
// eslint-disable-next-line simple-import-sort/imports
import { type Framework } from '@toeverything/infra';
import { DocScope } from '../doc/scopes/doc';
import { DocService } from '../doc/services/doc';
import { GlobalCache, GlobalState } from '../storage/providers/global';
import { GlobalStateService } from '../storage/services/global';
import { UrlService } from '../url';
@@ -101,7 +99,7 @@ import { DocCreatedByService } from './services/doc-created-by';
import { DocUpdatedByService } from './services/doc-updated-by';
import { DocCreatedByUpdatedBySyncService } from './services/doc-created-by-updated-by-sync';
import { WorkspacePermissionService } from '../permissions';
import { DocsService } from '../doc';
import { DocScope, DocService, DocsService } from '../doc';
import { DocCreatedByUpdatedBySyncStore } from './stores/doc-created-by-updated-by-sync';
export function configureCloudModule(framework: Framework) {

View File

@@ -7,7 +7,15 @@ import { useLayoutEffect, useMemo } from 'react';
import { PublicUserService } from '../services/public-user';
import * as styles from './public-user.css';
export const PublicUserLabel = ({ id }: { id: string }) => {
export const PublicUserLabel = ({
id,
size = 20,
showName = true,
}: {
id: string;
size?: number;
showName?: boolean;
}) => {
const serverService = useCurrentServerService();
const publicUser = useMemo(() => {
return serverService?.scope.get(PublicUserService);
@@ -28,10 +36,16 @@ export const PublicUserLabel = ({ id }: { id: string }) => {
}
if (user?.removed) {
return (
return showName ? (
<span className={styles.publicUserLabelRemoved}>
{t['Unknown User']()}
</span>
) : (
<Avatar
size={size}
name={t['Unknown User']()}
className={styles.publicUserLabelAvatar}
/>
);
}
@@ -40,10 +54,10 @@ export const PublicUserLabel = ({ id }: { id: string }) => {
<Avatar
url={user?.avatar}
name={user?.name ?? ''}
size={20}
size={size}
className={styles.publicUserLabelAvatar}
/>
{user?.name}
{showName && user?.name}
</span>
);
};

View File

@@ -25,7 +25,7 @@ export class PropertyFilterProvider extends Service implements FilterProvider {
FilterProvider('property:' + type)
);
if (!provider) {
throw new Error('Unsupported property type');
throw new Error(`Unsupported property type: ${type}`);
}
return provider.filter$(params);
})

View File

@@ -0,0 +1,21 @@
import type { DocsService } from '@affine/core/modules/doc';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { FilterProvider } from '../../provider';
import type { FilterParams } from '../../types';
export class TrashFilterProvider extends Service implements FilterProvider {
constructor(private readonly docsService: DocsService) {
super();
}
filter$(params: FilterParams): Observable<Set<string>> {
if (params.value === 'true') {
return this.docsService.allTrashDocIds$().pipe(map(ids => new Set(ids)));
} else {
return this.docsService
.allNonTrashDocIds$()
.pipe(map(ids => new Set(ids)));
}
}
}

View File

@@ -14,6 +14,7 @@ import { PropertyFilterProvider } from './impls/filters/property';
import { SystemFilterProvider } from './impls/filters/system';
import { TagsFilterProvider } from './impls/filters/tags';
import { TextPropertyFilterProvider } from './impls/filters/text';
import { TrashFilterProvider } from './impls/filters/trash';
import { UpdatedAtFilterProvider } from './impls/filters/updated-at';
import { UpdatedByFilterProvider } from './impls/filters/updated-by';
import { CheckboxPropertyGroupByProvider } from './impls/group-by/checkbox';
@@ -79,6 +80,7 @@ export function configureCollectionRulesModule(framework: Framework) {
DocPrimaryModeFilterProvider,
[DocsService]
)
.impl(FilterProvider('system:trash'), TrashFilterProvider, [DocsService])
.impl(FilterProvider('property:date'), DatePropertyFilterProvider, [
DocsService,
])

View File

@@ -69,6 +69,14 @@ export class DocsService extends Service {
return this.store.watchAllDocTagIds();
}
allNonTrashDocIds$() {
return this.store.watchNonTrashDocIds();
}
allTrashDocIds$() {
return this.store.watchTrashDocIds();
}
constructor(
private readonly store: DocsStore,
private readonly docPropertiesStore: DocPropertiesStore,