Skip to content

Commit

Permalink
feat(core): impl doc display meta extension
Browse files Browse the repository at this point in the history
  • Loading branch information
fundon committed Dec 16, 2024
1 parent aaaea89 commit 5129461
Show file tree
Hide file tree
Showing 17 changed files with 414 additions and 221 deletions.
2 changes: 1 addition & 1 deletion packages/common/env/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"private": true,
"type": "module",
"devDependencies": {
"@blocksuite/affine": "0.19.0",
"@blocksuite/affine": "0.0.0-canary-20241216011454",
"vitest": "2.1.8"
},
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion packages/common/infra/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@affine/debug": "workspace:*",
"@affine/env": "workspace:*",
"@affine/templates": "workspace:*",
"@blocksuite/affine": "0.19.0",
"@blocksuite/affine": "0.0.0-canary-20241216011454",
"@datastructures-js/binary-search-tree": "^5.3.2",
"eventemitter2": "^6.4.9",
"foxact": "^0.2.43",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/apps/android/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@affine/component": "workspace:*",
"@affine/core": "workspace:*",
"@affine/i18n": "workspace:*",
"@blocksuite/affine": "0.19.0",
"@blocksuite/affine": "0.0.0-canary-20241216011454",
"@blocksuite/icons": "2.1.75",
"@capacitor/android": "^6.2.0",
"@capacitor/core": "^6.2.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/apps/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@affine/i18n": "workspace:*",
"@affine/native": "workspace:*",
"@affine/nbstore": "workspace:*",
"@blocksuite/affine": "0.19.0",
"@blocksuite/affine": "0.0.0-canary-20241216011454",
"@electron-forge/cli": "^7.6.0",
"@electron-forge/core": "^7.6.0",
"@electron-forge/core-utils": "^7.6.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/apps/ios/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@affine/component": "workspace:*",
"@affine/core": "workspace:*",
"@affine/i18n": "workspace:*",
"@blocksuite/affine": "0.19.0",
"@blocksuite/affine": "0.0.0-canary-20241216011454",
"@blocksuite/icons": "2.1.75",
"@capacitor/app": "^6.0.2",
"@capacitor/browser": "^6.0.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@affine/component": "workspace:*",
"@affine/core": "workspace:*",
"@affine/i18n": "workspace:*",
"@blocksuite/affine": "0.19.0",
"@blocksuite/affine": "0.0.0-canary-20241216011454",
"@blocksuite/icons": "2.1.75",
"@sentry/react": "^8.44.0",
"react": "^19.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/component/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"zod": "^3.24.1"
},
"devDependencies": {
"@blocksuite/affine": "0.19.0",
"@blocksuite/affine": "0.0.0-canary-20241216011454",
"@blocksuite/icons": "2.1.75",
"@chromatic-com/storybook": "^3.2.2",
"@storybook/addon-essentials": "^8.4.7",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@affine/i18n": "workspace:*",
"@affine/templates": "workspace:*",
"@affine/track": "workspace:*",
"@blocksuite/affine": "0.19.0",
"@blocksuite/affine": "0.0.0-canary-20241216011454",
"@blocksuite/icons": "2.1.75",
"@capacitor/app": "^6.0.2",
"@capacitor/browser": "^6.0.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { JournalService } from '@affine/core/modules/journal';
import { PeekViewService } from '@affine/core/modules/peek-view/services/peek-view';
import { useInsidePeekView } from '@affine/core/modules/peek-view/view/modal-container';
import { WorkbenchLink } from '@affine/core/modules/workbench';
import { useI18n } from '@affine/i18n';
import { track } from '@affine/track';
import type { DocMode } from '@blocksuite/affine/blocks';
import type { DocCollection } from '@blocksuite/affine/store';
Expand All @@ -30,7 +29,7 @@ import * as styles from './styles.css';
interface AffinePageReferenceProps {
pageId: string;
params?: URLSearchParams;
title?: string | null; // title alias
title?: string; // title alias
className?: string;
Icon?: ComponentType;
onClick?: (e: MouseEvent) => void;
Expand All @@ -44,7 +43,6 @@ function AffinePageReferenceInner({
}: AffinePageReferenceProps) {
const docDisplayMetaService = useService(DocDisplayMetaService);
const docsService = useService(DocsService);
const i18n = useI18n();

let referenceWithMode: DocMode | null = null;
let referenceToNode = false;
Expand Down Expand Up @@ -74,18 +72,10 @@ function AffinePageReferenceInner({

const notFound = !useLiveData(docsService.list.doc$(pageId));

const docTitle = useLiveData(
docDisplayMetaService.title$(pageId, { reference: true })
title = useLiveData(
docDisplayMetaService.title$(pageId, { title, reference: true })
);

if (notFound) {
title = i18n.t('com.affine.notFoundPage.title');
}

if (!title) {
title = i18n.t(docTitle);
}

return (
<span className={notFound ? styles.notFound : ''}>
<Icon className={styles.pageReferenceIcon} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import {
AIEdgelessRootBlockSpec,
AIPageRootBlockSpec,
} from '@affine/core/blocksuite/presets/ai';
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { AppThemeService } from '@affine/core/modules/theme';
import { I18n, i18nTime } from '@affine/i18n';
import { mixpanel } from '@affine/track';
import {
ConfigExtension,
Expand All @@ -12,12 +14,15 @@ import {
StdIdentifier,
} from '@blocksuite/affine/block-std';
import type {
DocDisplayMetaExtension,
DocDisplayMetaParams,
RootBlockConfig,
TelemetryEventMap,
ThemeExtension,
} from '@blocksuite/affine/blocks';
import {
ColorScheme,
DocDisplayMetaProvider,
EdgelessBuiltInManager,
EdgelessRootBlockSpec,
EdgelessToolExtension,
Expand All @@ -27,18 +32,33 @@ import {
TelemetryProvider,
ThemeExtensionIdentifier,
} from '@blocksuite/affine/blocks';
import type { Disposable } from '@blocksuite/affine/global/utils';
import {
createSignalFromObservable,
referenceToNode,
type Signal,
SpecProvider,
} from '@blocksuite/affine-shared/utils';
import type { Container } from '@blocksuite/global/di';
import {
AliasIcon,
BlockLinkIcon,
DeleteIcon,
EdgelessIcon,
LinkedEdgelessIcon,
LinkedPageIcon,
PageIcon,
} from '@blocksuite/icons/lit';
import { computed, signal } from '@preact/signals-core';
import {
type DocRecord,
DocService,
DocsService,
FeatureFlagService,
type FrameworkProvider,
LiveData,
} from '@toeverything/infra';
import type { TemplateResult } from 'lit';
import type { Observable } from 'rxjs';
import { combineLatest, map } from 'rxjs';

Expand Down Expand Up @@ -141,6 +161,192 @@ function getThemeExtension(framework: FrameworkProvider) {
return AffineThemeExtension;
}

export function buildDocDisplayMetaExtension(framework: FrameworkProvider) {
const docDisplayMetaService = framework.get(DocDisplayMetaService);
const docsService = docDisplayMetaService.docsService;
const journalService = docDisplayMetaService.journalService;

const icons = {
deleted: iconBuilder(DeleteIcon),
aliased: iconBuilder(AliasIcon),
page: iconBuilder(PageIcon),
edgeless: iconBuilder(EdgelessIcon),
linkedBlock: iconBuilder(BlockLinkIcon),
linkedPage: iconBuilder(LinkedPageIcon),
linkedEdgeless: iconBuilder(LinkedEdgelessIcon),
} as const;

function iconBuilder(icon: typeof PageIcon, size = '1.25em') {
return icon({
width: size,
height: size,
style:
'user-select:none;flex-shrink:0;vertical-align:middle;font-size:inherit;margin-bottom:0.1em;',
});
}

function getDocIcons(referenced: boolean) {
return referenced
? { edgeless: icons.linkedEdgeless, page: icons.linkedPage }
: { edgeless: icons.edgeless, page: icons.page };
}

class AffineDocDisplayMetaService
extends LifeCycleWatcher
implements DocDisplayMetaExtension
{
static override key = 'doc-display-meta';

readonly disposables: Disposable[] = [];

readonly iconMap = new WeakMap<DocRecord, Signal<TemplateResult>>();

readonly titleMap = new WeakMap<DocRecord, Signal<string>>();

static override setup(di: Container) {
super.setup(di);
di.override(DocDisplayMetaProvider, AffineDocDisplayMetaService, [
StdIdentifier,
]);
}

dispose() {
while (this.disposables.length > 0) {
this.disposables.pop()?.dispose();
}
}

icon(
docId: string,
{ params, title, referenced = false }: DocDisplayMetaParams = {}
): Signal<TemplateResult> {
const doc = docsService.list.doc$(docId).value;

if (!doc) {
return signal(icons.deleted);
}

let icon = this.iconMap.get(doc);
if (!icon) {
const docIcons = getDocIcons(referenced);

icon = signal(
doc.primaryMode$.value === 'edgeless'
? docIcons.edgeless
: docIcons.page
);

const icon$ = LiveData.computed(get => {
const journalDate = docDisplayMetaService.toDayjs(
get(journalService.journalDate$(docId))
);
if (journalDate) {
return iconBuilder(
docDisplayMetaService.getJournalIcon(journalDate, { type: 'lit' })
);
}

return get(doc.primaryMode$) === 'edgeless'
? docIcons.edgeless
: docIcons.page;
});
const subscription = icon$.subscribe({
next: value => {
if (!icon) return;
icon.value = value;
},
});
const disposable = {
dispose: () => subscription.unsubscribe(),
};

this.disposables.push(disposable);
this.disposables.push(
this.std.collection.slots.docRemoved
.filter(docId => docId === doc.id)
.once(() => {
const index = this.disposables.findIndex(d => d === disposable);
if (index !== -1) {
this.disposables.splice(index, 1);
disposable.dispose();
}
this.iconMap.delete(doc);
})
);
this.iconMap.set(doc, icon);
}

return computed(() => {
if (title) {
return icons.aliased;
}

if (referenceToNode({ pageId: docId, params })) {
return icons.linkedBlock;
}

return icon.value;
});
}

title(docId: string): Signal<string> {
const doc = docsService.list.doc$(docId).value;
if (!doc) return signal(I18n['com.affine.notFoundPage.title']());

let title = this.titleMap.get(doc);
if (title) return title;

const journalDateString = journalService.journalDate$(docId).value;
title = signal(
journalDateString && journalDateString.length > 0
? i18nTime(journalDateString, { absolute: { accuracy: 'day' } })
: doc.title$.value
);

const title$ = LiveData.computed(get => {
let title = get(journalService.journalDate$(docId));
if (title) return i18nTime(title, { absolute: { accuracy: 'day' } });

title = get(doc.title$);
if (title) return title;

return I18n.Untitled();
});
const subscription = title$.subscribe({
next: value => {
title.value = value;
},
});
const disposable = {
dispose: () => subscription.unsubscribe(),
};

this.disposables.push(disposable);
this.disposables.push(
this.std.collection.slots.docRemoved
.filter(docId => docId === doc.id)
.once(() => {
const index = this.disposables.findIndex(d => d === disposable);
if (index !== -1) {
this.disposables.splice(index, 1);
disposable.dispose();
}
this.titleMap.delete(doc);
})
);
this.titleMap.set(doc, title);

return title;
}

override unmounted() {
this.dispose();
}
}

return AffineDocDisplayMetaService;
}

function getEditorConfigExtension(
framework: FrameworkProvider
): ExtensionType[] {
Expand Down Expand Up @@ -184,6 +390,7 @@ export function createPageRootBlockSpec(
getFontConfigExtension(),
getTelemetryExtension(),
getEditorConfigExtension(framework),
buildDocDisplayMetaExtension(framework),
].flat();
}

Expand All @@ -201,5 +408,6 @@ export function createEdgelessRootBlockSpec(
getFontConfigExtension(),
getTelemetryExtension(),
getEditorConfigExtension(framework),
buildDocDisplayMetaExtension(framework),
].flat();
}
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ export function patchDocModeService(
return (mode || DEFAULT_MODE) as DocMode;
};
onPrimaryModeChange = (handler: (mode: DocMode) => void, id?: string) => {
// eslint-disable-next-line rxjs/finnish
const mode$ = id
? docsService.list.primaryMode$(id)
: docService.doc.primaryMode$;
Expand Down
Loading

0 comments on commit 5129461

Please sign in to comment.