mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
feat(core): extract DocDisplayMetaService to resolve doc icon/title (#8226)
AF-1315
This commit is contained in:
@@ -32,5 +32,6 @@ globalStyle(`${wrapper} span`, {
|
|||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
borderBottom: 'none',
|
// don't modify border width to avoid layout shift
|
||||||
|
borderBottomColor: 'transparent',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import type { Backlink, Link } from '@affine/core/modules/doc-link';
|
import type { Backlink, Link } from '@affine/core/modules/doc-link';
|
||||||
import { useContext } from 'react';
|
|
||||||
|
|
||||||
import { AffinePageReference } from '../../reference-link';
|
import { AffinePageReference } from '../../reference-link';
|
||||||
import { managerContext } from '../common';
|
|
||||||
import * as styles from './links-row.css';
|
import * as styles from './links-row.css';
|
||||||
|
|
||||||
export const LinksRow = ({
|
export const LinksRow = ({
|
||||||
@@ -16,20 +14,18 @@ export const LinksRow = ({
|
|||||||
className?: string;
|
className?: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const manager = useContext(managerContext);
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<div className={styles.title}>
|
<div className={styles.title}>
|
||||||
{label} · {references.length}
|
{label} · {references.length}
|
||||||
</div>
|
</div>
|
||||||
{references.map(link => (
|
{references.map((link, index) => (
|
||||||
<AffinePageReference
|
<AffinePageReference
|
||||||
key={link.docId}
|
key={index}
|
||||||
pageId={link.docId}
|
pageId={link.docId}
|
||||||
wrapper={props => (
|
wrapper={props => (
|
||||||
<div className={styles.wrapper} onClick={onClick} {...props} />
|
<div className={styles.wrapper} onClick={onClick} {...props} />
|
||||||
)}
|
)}
|
||||||
docCollection={manager.workspace.docCollection}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -379,8 +379,6 @@ export const PageBacklinksPopup = ({
|
|||||||
backlinks,
|
backlinks,
|
||||||
children,
|
children,
|
||||||
}: PageBacklinksPopupProps) => {
|
}: PageBacklinksPopupProps) => {
|
||||||
const manager = useContext(managerContext);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu
|
<Menu
|
||||||
contentOptions={{
|
contentOptions={{
|
||||||
@@ -395,7 +393,6 @@ export const PageBacklinksPopup = ({
|
|||||||
key={link.docId + ':' + link.blockId}
|
key={link.docId + ':' + link.blockId}
|
||||||
wrapper={MenuItem}
|
wrapper={MenuItem}
|
||||||
pageId={link.docId}
|
pageId={link.docId}
|
||||||
docCollection={manager.workspace.docCollection}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useDocMetaHelper } from '@affine/core/components/hooks/use-block-suite-page-meta';
|
import { useJournalInfoHelper } from '@affine/core/components/hooks/use-journal';
|
||||||
import { useJournalHelper } from '@affine/core/components/hooks/use-journal';
|
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||||
import {
|
import {
|
||||||
PeekViewService,
|
PeekViewService,
|
||||||
useInsidePeekView,
|
useInsidePeekView,
|
||||||
@@ -8,15 +8,8 @@ import { WorkbenchLink } from '@affine/core/modules/workbench';
|
|||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
import type { DocMode } from '@blocksuite/blocks';
|
import type { DocMode } from '@blocksuite/blocks';
|
||||||
import {
|
|
||||||
BlockLinkIcon,
|
|
||||||
DeleteIcon,
|
|
||||||
LinkedEdgelessIcon,
|
|
||||||
LinkedPageIcon,
|
|
||||||
TodayIcon,
|
|
||||||
} from '@blocksuite/icons/rc';
|
|
||||||
import type { DocCollection } from '@blocksuite/store';
|
import type { DocCollection } from '@blocksuite/store';
|
||||||
import { DocsService, useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import {
|
import {
|
||||||
type PropsWithChildren,
|
type PropsWithChildren,
|
||||||
@@ -29,77 +22,18 @@ import { Link } from 'react-router-dom';
|
|||||||
|
|
||||||
import * as styles from './styles.css';
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
export interface PageReferenceRendererOptions {
|
|
||||||
pageId: string;
|
|
||||||
docCollection: DocCollection;
|
|
||||||
pageMetaHelper: ReturnType<typeof useDocMetaHelper>;
|
|
||||||
journalHelper: ReturnType<typeof useJournalHelper>;
|
|
||||||
t: ReturnType<typeof useI18n>;
|
|
||||||
docMode?: DocMode;
|
|
||||||
// Link to block or element
|
|
||||||
linkToNode?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use a function to be rendered in the lit renderer
|
|
||||||
export function pageReferenceRenderer({
|
|
||||||
pageId,
|
|
||||||
pageMetaHelper,
|
|
||||||
journalHelper,
|
|
||||||
t,
|
|
||||||
docMode,
|
|
||||||
linkToNode = false,
|
|
||||||
}: PageReferenceRendererOptions) {
|
|
||||||
const { isPageJournal, getLocalizedJournalDateString } = journalHelper;
|
|
||||||
const referencedPage = pageMetaHelper.getDocMeta(pageId);
|
|
||||||
let title =
|
|
||||||
referencedPage?.title ?? t['com.affine.editor.reference-not-found']();
|
|
||||||
|
|
||||||
let Icon = DeleteIcon;
|
|
||||||
|
|
||||||
if (referencedPage) {
|
|
||||||
if (docMode === 'edgeless') {
|
|
||||||
Icon = LinkedEdgelessIcon;
|
|
||||||
} else {
|
|
||||||
Icon = LinkedPageIcon;
|
|
||||||
}
|
|
||||||
if (linkToNode) {
|
|
||||||
Icon = BlockLinkIcon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const isJournal = isPageJournal(pageId);
|
|
||||||
const localizedJournalDate = getLocalizedJournalDateString(pageId);
|
|
||||||
if (isJournal && localizedJournalDate) {
|
|
||||||
title = localizedJournalDate;
|
|
||||||
Icon = TodayIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Icon className={styles.pageReferenceIcon} />
|
|
||||||
<span className="affine-reference-title">
|
|
||||||
{title ? title : t['Untitled']()}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AffinePageReference({
|
export function AffinePageReference({
|
||||||
pageId,
|
pageId,
|
||||||
docCollection,
|
|
||||||
wrapper: Wrapper,
|
wrapper: Wrapper,
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
pageId: string;
|
pageId: string;
|
||||||
docCollection: DocCollection;
|
|
||||||
wrapper?: React.ComponentType<PropsWithChildren>;
|
wrapper?: React.ComponentType<PropsWithChildren>;
|
||||||
params?: URLSearchParams;
|
params?: URLSearchParams;
|
||||||
}) {
|
}) {
|
||||||
|
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||||
|
const journalHelper = useJournalInfoHelper();
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const pageMetaHelper = useDocMetaHelper();
|
|
||||||
const journalHelper = useJournalHelper(docCollection);
|
|
||||||
const docsService = useService(DocsService);
|
|
||||||
const mode = useLiveData(docsService.list.primaryMode$(pageId));
|
|
||||||
|
|
||||||
let linkWithMode: DocMode | null = null;
|
let linkWithMode: DocMode | null = null;
|
||||||
let linkToNode = false;
|
let linkToNode = false;
|
||||||
@@ -111,15 +45,23 @@ export function AffinePageReference({
|
|||||||
linkToNode = params.has('blockIds') || params.has('elementIds');
|
linkToNode = params.has('blockIds') || params.has('elementIds');
|
||||||
}
|
}
|
||||||
|
|
||||||
const el = pageReferenceRenderer({
|
const Icon = useLiveData(
|
||||||
docMode: linkWithMode ?? mode ?? 'page',
|
docDisplayMetaService.icon$(pageId, {
|
||||||
pageId,
|
mode: linkWithMode ?? undefined,
|
||||||
pageMetaHelper,
|
reference: true,
|
||||||
journalHelper,
|
referenceToNode: linkToNode,
|
||||||
docCollection,
|
})
|
||||||
t,
|
);
|
||||||
linkToNode,
|
const title = useLiveData(docDisplayMetaService.title$(pageId));
|
||||||
});
|
|
||||||
|
const el = (
|
||||||
|
<>
|
||||||
|
<Icon className={styles.pageReferenceIcon} />
|
||||||
|
<span className="affine-reference-title">
|
||||||
|
{typeof title === 'string' ? title : t[title.key]()}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
const ref = useRef<HTMLAnchorElement>(null);
|
const ref = useRef<HTMLAnchorElement>(null);
|
||||||
|
|
||||||
@@ -186,11 +128,9 @@ export function AffineSharedPageReference({
|
|||||||
wrapper?: React.ComponentType<PropsWithChildren>;
|
wrapper?: React.ComponentType<PropsWithChildren>;
|
||||||
params?: URLSearchParams;
|
params?: URLSearchParams;
|
||||||
}) {
|
}) {
|
||||||
|
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||||
|
const journalHelper = useJournalInfoHelper();
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const pageMetaHelper = useDocMetaHelper();
|
|
||||||
const journalHelper = useJournalHelper(docCollection);
|
|
||||||
const docsService = useService(DocsService);
|
|
||||||
const mode = useLiveData(docsService.list.primaryMode$(pageId));
|
|
||||||
|
|
||||||
let linkWithMode: DocMode | null = null;
|
let linkWithMode: DocMode | null = null;
|
||||||
let linkToNode = false;
|
let linkToNode = false;
|
||||||
@@ -202,15 +142,22 @@ export function AffineSharedPageReference({
|
|||||||
linkToNode = params.has('blockIds') || params.has('elementIds');
|
linkToNode = params.has('blockIds') || params.has('elementIds');
|
||||||
}
|
}
|
||||||
|
|
||||||
const el = pageReferenceRenderer({
|
const Icon = useLiveData(
|
||||||
docMode: linkWithMode ?? mode ?? 'page',
|
docDisplayMetaService.icon$(pageId, {
|
||||||
pageId,
|
mode: linkWithMode ?? undefined,
|
||||||
pageMetaHelper,
|
reference: true,
|
||||||
journalHelper,
|
referenceToNode: linkToNode,
|
||||||
docCollection,
|
})
|
||||||
t,
|
);
|
||||||
linkToNode,
|
const title = useLiveData(docDisplayMetaService.title$(pageId));
|
||||||
});
|
const el = (
|
||||||
|
<>
|
||||||
|
<Icon className={styles.pageReferenceIcon} />
|
||||||
|
<span className="affine-reference-title">
|
||||||
|
{typeof title === 'string' ? title : t[title.key]()}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
const ref = useRef<HTMLAnchorElement>(null);
|
const ref = useRef<HTMLAnchorElement>(null);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import { DocLinksService } from '@affine/core/modules/doc-link';
|
import { DocLinksService } from '@affine/core/modules/doc-link';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import {
|
import { useLiveData, useServices } from '@toeverything/infra';
|
||||||
useLiveData,
|
|
||||||
useServices,
|
|
||||||
WorkspaceService,
|
|
||||||
} from '@toeverything/infra';
|
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { AffinePageReference } from '../../affine/reference-link';
|
import { AffinePageReference } from '../../affine/reference-link';
|
||||||
@@ -12,9 +8,8 @@ import * as styles from './bi-directional-link-panel.css';
|
|||||||
|
|
||||||
export const BiDirectionalLinkPanel = () => {
|
export const BiDirectionalLinkPanel = () => {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
const { docLinksService, workspaceService } = useServices({
|
const { docLinksService } = useServices({
|
||||||
DocLinksService,
|
DocLinksService,
|
||||||
WorkspaceService,
|
|
||||||
});
|
});
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
@@ -50,11 +45,7 @@ export const BiDirectionalLinkPanel = () => {
|
|||||||
</div>
|
</div>
|
||||||
{backlinks.map(link => (
|
{backlinks.map(link => (
|
||||||
<div key={link.docId} className={styles.link}>
|
<div key={link.docId} className={styles.link}>
|
||||||
<AffinePageReference
|
<AffinePageReference key={link.docId} pageId={link.docId} />
|
||||||
key={link.docId}
|
|
||||||
pageId={link.docId}
|
|
||||||
docCollection={workspaceService.workspace.docCollection}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -68,11 +59,7 @@ export const BiDirectionalLinkPanel = () => {
|
|||||||
key={`${link.docId}-${link.params?.toString()}-${i}`}
|
key={`${link.docId}-${link.params?.toString()}-${i}`}
|
||||||
className={styles.link}
|
className={styles.link}
|
||||||
>
|
>
|
||||||
<AffinePageReference
|
<AffinePageReference pageId={link.docId} params={link.params} />
|
||||||
pageId={link.docId}
|
|
||||||
params={link.params}
|
|
||||||
docCollection={workspaceService.workspace.docCollection}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as styles from './styles.css';
|
|||||||
|
|
||||||
export const BlocksuiteEditorJournalDocTitle = ({ page }: { page: Doc }) => {
|
export const BlocksuiteEditorJournalDocTitle = ({ page }: { page: Doc }) => {
|
||||||
const { localizedJournalDate, isTodayJournal, journalDate } =
|
const { localizedJournalDate, isTodayJournal, journalDate } =
|
||||||
useJournalInfoHelper(page.collection, page.id);
|
useJournalInfoHelper(page.id);
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
// TODO(catsjuice): i18n
|
// TODO(catsjuice): i18n
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ interface BlocksuiteEditorProps {
|
|||||||
shared?: boolean;
|
shared?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const usePatchSpecs = (page: Doc, shared: boolean, mode: DocMode) => {
|
const usePatchSpecs = (shared: boolean, mode: DocMode) => {
|
||||||
const [reactToLit, portals] = useLitPortalFactory();
|
const [reactToLit, portals] = useLitPortalFactory();
|
||||||
const {
|
const {
|
||||||
peekViewService,
|
peekViewService,
|
||||||
@@ -110,15 +110,9 @@ const usePatchSpecs = (page: Doc, shared: boolean, mode: DocMode) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <AffinePageReference pageId={pageId} params={params} />;
|
||||||
<AffinePageReference
|
|
||||||
docCollection={page.collection}
|
|
||||||
pageId={pageId}
|
|
||||||
params={params}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}, [page.collection, workspaceService]);
|
}, [workspaceService]);
|
||||||
|
|
||||||
const specs = useMemo(() => {
|
const specs = useMemo(() => {
|
||||||
const enableAI = featureFlagService.flags.enable_ai.value;
|
const enableAI = featureFlagService.flags.enable_ai.value;
|
||||||
@@ -184,7 +178,7 @@ export const BlocksuiteDocEditor = forwardRef<
|
|||||||
) {
|
) {
|
||||||
const titleRef = useRef<DocTitle | null>(null);
|
const titleRef = useRef<DocTitle | null>(null);
|
||||||
const docRef = useRef<PageEditor | null>(null);
|
const docRef = useRef<PageEditor | null>(null);
|
||||||
const { isJournal } = useJournalInfoHelper(page.collection, page.id);
|
const { isJournal } = useJournalInfoHelper(page.id);
|
||||||
|
|
||||||
const editorSettingService = useService(EditorSettingService);
|
const editorSettingService = useService(EditorSettingService);
|
||||||
|
|
||||||
@@ -216,7 +210,7 @@ export const BlocksuiteDocEditor = forwardRef<
|
|||||||
[externalTitleRef]
|
[externalTitleRef]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [specs, portals] = usePatchSpecs(page, !!shared, 'page');
|
const [specs, portals] = usePatchSpecs(!!shared, 'page');
|
||||||
|
|
||||||
const displayBiDirectionalLink = useLiveData(
|
const displayBiDirectionalLink = useLiveData(
|
||||||
editorSettingService.editorSetting.settings$.selector(
|
editorSettingService.editorSetting.settings$.selector(
|
||||||
@@ -257,7 +251,7 @@ export const BlocksuiteEdgelessEditor = forwardRef<
|
|||||||
EdgelessEditor,
|
EdgelessEditor,
|
||||||
BlocksuiteEditorProps
|
BlocksuiteEditorProps
|
||||||
>(function BlocksuiteEdgelessEditor({ page, shared }, ref) {
|
>(function BlocksuiteEdgelessEditor({ page, shared }, ref) {
|
||||||
const [specs, portals] = usePatchSpecs(page, !!shared, 'edgeless');
|
const [specs, portals] = usePatchSpecs(!!shared, 'edgeless');
|
||||||
const editorRef = useRef<EdgelessEditor | null>(null);
|
const editorRef = useRef<EdgelessEditor | null>(null);
|
||||||
|
|
||||||
const onDocRef = useCallback(
|
const onDocRef = useCallback(
|
||||||
|
|||||||
@@ -1,20 +1,12 @@
|
|||||||
|
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||||
import { WorkspacePropertiesAdapter } from '@affine/core/modules/properties';
|
import { WorkspacePropertiesAdapter } from '@affine/core/modules/properties';
|
||||||
import { I18n, i18nTime } from '@affine/i18n';
|
import { I18n } from '@affine/i18n';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
import type { EditorHost } from '@blocksuite/block-std';
|
import type { EditorHost } from '@blocksuite/block-std';
|
||||||
import type { AffineInlineEditor } from '@blocksuite/blocks';
|
import type { AffineInlineEditor } from '@blocksuite/blocks';
|
||||||
import { LinkedWidgetUtils } from '@blocksuite/blocks';
|
import { LinkedWidgetUtils } from '@blocksuite/blocks';
|
||||||
import {
|
|
||||||
LinkedEdgelessIcon,
|
|
||||||
LinkedPageIcon,
|
|
||||||
TodayIcon,
|
|
||||||
} from '@blocksuite/icons/lit';
|
|
||||||
import type { DocMeta } from '@blocksuite/store';
|
import type { DocMeta } from '@blocksuite/store';
|
||||||
import {
|
import { type FrameworkProvider, WorkspaceService } from '@toeverything/infra';
|
||||||
DocsService,
|
|
||||||
type FrameworkProvider,
|
|
||||||
WorkspaceService,
|
|
||||||
} from '@toeverything/infra';
|
|
||||||
|
|
||||||
// TODO: fix the type
|
// TODO: fix the type
|
||||||
export function createLinkedWidgetConfig(
|
export function createLinkedWidgetConfig(
|
||||||
@@ -33,6 +25,7 @@ export function createLinkedWidgetConfig(
|
|||||||
const isJournal = (d: DocMeta) =>
|
const isJournal = (d: DocMeta) =>
|
||||||
!!adapter.getJournalPageDateString(d.id);
|
!!adapter.getJournalPageDateString(d.id);
|
||||||
|
|
||||||
|
const docDisplayMetaService = framework.get(DocDisplayMetaService);
|
||||||
const docMetas = rawMetas
|
const docMetas = rawMetas
|
||||||
.filter(meta => {
|
.filter(meta => {
|
||||||
if (isJournal(meta) && !meta.updatedDate) {
|
if (isJournal(meta) && !meta.updatedDate) {
|
||||||
@@ -41,37 +34,28 @@ export function createLinkedWidgetConfig(
|
|||||||
return !meta.trash;
|
return !meta.trash;
|
||||||
})
|
})
|
||||||
.map(meta => {
|
.map(meta => {
|
||||||
if (isJournal(meta)) {
|
const title = docDisplayMetaService.title$(meta.id).value;
|
||||||
const date = adapter.getJournalPageDateString(meta.id);
|
return {
|
||||||
if (date) {
|
...meta,
|
||||||
const title = i18nTime(date, { absolute: { accuracy: 'day' } });
|
title: typeof title === 'string' ? title : I18n[title.key](),
|
||||||
return { ...meta, title };
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!meta.title) {
|
|
||||||
const title = I18n['Untitled']();
|
|
||||||
return { ...meta, title };
|
|
||||||
}
|
|
||||||
return meta;
|
|
||||||
})
|
})
|
||||||
.filter(({ title }) => isFuzzyMatch(title, query));
|
.filter(({ title }) => isFuzzyMatch(title, query));
|
||||||
|
|
||||||
// TODO need i18n if BlockSuite supported
|
// TODO need i18n if BlockSuite supported
|
||||||
const MAX_DOCS = 6;
|
const MAX_DOCS = 6;
|
||||||
const docsService = framework.get(DocsService);
|
|
||||||
const isEdgeless = (d: DocMeta) =>
|
|
||||||
docsService.list.getPrimaryMode(d.id) === 'edgeless';
|
|
||||||
return Promise.resolve([
|
return Promise.resolve([
|
||||||
{
|
{
|
||||||
name: 'Link to Doc',
|
name: 'Link to Doc',
|
||||||
items: docMetas.map(doc => ({
|
items: docMetas.map(doc => ({
|
||||||
key: doc.id,
|
key: doc.id,
|
||||||
name: doc.title,
|
name: doc.title,
|
||||||
icon: isJournal(doc)
|
icon: docDisplayMetaService
|
||||||
? TodayIcon()
|
.icon$(doc.id, {
|
||||||
: isEdgeless(doc)
|
type: 'lit',
|
||||||
? LinkedEdgelessIcon()
|
reference: true,
|
||||||
: LinkedPageIcon(),
|
})
|
||||||
|
.value(),
|
||||||
action: () => {
|
action: () => {
|
||||||
abort();
|
abort();
|
||||||
LinkedWidgetUtils.insertLinkedNode({
|
LinkedWidgetUtils.insertLinkedNode({
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const JournalWeekDatePicker = ({
|
|||||||
page,
|
page,
|
||||||
}: JournalWeekDatePickerProps) => {
|
}: JournalWeekDatePickerProps) => {
|
||||||
const handleRef = useRef<WeekDatePickerHandle>(null);
|
const handleRef = useRef<WeekDatePickerHandle>(null);
|
||||||
const { journalDate } = useJournalInfoHelper(docCollection, page.id);
|
const { journalDate } = useJournalInfoHelper(page.id);
|
||||||
const { openJournal } = useJournalRouteHelper(docCollection);
|
const { openJournal } = useJournalRouteHelper(docCollection);
|
||||||
const [date, setDate] = useState(
|
const [date, setDate] = useState(
|
||||||
(journalDate ?? dayjs()).format('YYYY-MM-DD')
|
(journalDate ?? dayjs()).format('YYYY-MM-DD')
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useCallback, useMemo } from 'react';
|
|||||||
|
|
||||||
import { useAsyncCallback } from './affine-async-hooks';
|
import { useAsyncCallback } from './affine-async-hooks';
|
||||||
import { useAllBlockSuiteDocMeta } from './use-all-block-suite-page-meta';
|
import { useAllBlockSuiteDocMeta } from './use-all-block-suite-page-meta';
|
||||||
import { useJournalHelper } from './use-journal';
|
import { useJournalInfoHelper } from './use-journal';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get pageMetas excluding journal pages without updatedDate
|
* Get pageMetas excluding journal pages without updatedDate
|
||||||
@@ -13,7 +13,7 @@ import { useJournalHelper } from './use-journal';
|
|||||||
*/
|
*/
|
||||||
export function useBlockSuiteDocMeta(docCollection: DocCollection) {
|
export function useBlockSuiteDocMeta(docCollection: DocCollection) {
|
||||||
const pageMetas = useAllBlockSuiteDocMeta(docCollection);
|
const pageMetas = useAllBlockSuiteDocMeta(docCollection);
|
||||||
const { isPageJournal } = useJournalHelper(docCollection);
|
const { isPageJournal } = useJournalInfoHelper();
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() =>
|
() =>
|
||||||
pageMetas.filter(
|
pageMetas.filter(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { Atom } from 'jotai';
|
|||||||
import { atom, useAtomValue } from 'jotai';
|
import { atom, useAtomValue } from 'jotai';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { useJournalHelper, useJournalInfoHelper } from './use-journal';
|
import { useJournalInfoHelper } from './use-journal';
|
||||||
|
|
||||||
const weakMap = new WeakMap<DocCollection, Map<string, Atom<string>>>();
|
const weakMap = new WeakMap<DocCollection, Map<string, Atom<string>>>();
|
||||||
|
|
||||||
@@ -32,6 +32,9 @@ function getAtom(w: DocCollection, pageId: string): Atom<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `useDocTitle(docId: string)` instead
|
||||||
|
*/
|
||||||
export function useDocCollectionPageTitle(
|
export function useDocCollectionPageTitle(
|
||||||
docCollection: DocCollection,
|
docCollection: DocCollection,
|
||||||
pageId: string
|
pageId: string
|
||||||
@@ -39,13 +42,13 @@ export function useDocCollectionPageTitle(
|
|||||||
const titleAtom = getAtom(docCollection, pageId);
|
const titleAtom = getAtom(docCollection, pageId);
|
||||||
assertExists(titleAtom);
|
assertExists(titleAtom);
|
||||||
const title = useAtomValue(titleAtom);
|
const title = useAtomValue(titleAtom);
|
||||||
const { localizedJournalDate } = useJournalInfoHelper(docCollection, pageId);
|
const { localizedJournalDate } = useJournalInfoHelper(pageId);
|
||||||
return localizedJournalDate || title;
|
return localizedJournalDate || title;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This hook is NOT reactive to the page title change
|
// This hook is NOT reactive to the page title change
|
||||||
export function useGetDocCollectionPageTitle(docCollection: DocCollection) {
|
export function useGetDocCollectionPageTitle(docCollection: DocCollection) {
|
||||||
const { getLocalizedJournalDateString } = useJournalHelper(docCollection);
|
const { getLocalizedJournalDateString } = useJournalInfoHelper();
|
||||||
return useCallback(
|
return useCallback(
|
||||||
(pageId: string) => {
|
(pageId: string) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export const useJournalHelper = (docCollection: DocCollection) => {
|
|||||||
EditorSettingService,
|
EditorSettingService,
|
||||||
});
|
});
|
||||||
const adapter = useCurrentWorkspacePropertiesAdapter();
|
const adapter = useCurrentWorkspacePropertiesAdapter();
|
||||||
|
const { isPageJournal } = useJournalInfoHelper();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@@ -67,13 +68,6 @@ export const useJournalHelper = (docCollection: DocCollection) => {
|
|||||||
[adapter, bsWorkspaceHelper, docsService.list, editorSettingService]
|
[adapter, bsWorkspaceHelper, docsService.list, editorSettingService]
|
||||||
);
|
);
|
||||||
|
|
||||||
const isPageJournal = useCallback(
|
|
||||||
(pageId: string) => {
|
|
||||||
return !!adapter.getJournalPageDateString(pageId);
|
|
||||||
},
|
|
||||||
[adapter]
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* query all journals by date
|
* query all journals by date
|
||||||
*/
|
*/
|
||||||
@@ -104,31 +98,6 @@ export const useJournalHelper = (docCollection: DocCollection) => {
|
|||||||
[_createJournal, getJournalsByDate]
|
[_createJournal, getJournalsByDate]
|
||||||
);
|
);
|
||||||
|
|
||||||
const isPageTodayJournal = useCallback(
|
|
||||||
(pageId: string) => {
|
|
||||||
const date = dayjs().format(JOURNAL_DATE_FORMAT);
|
|
||||||
const d = adapter.getJournalPageDateString(pageId);
|
|
||||||
return isPageJournal(pageId) && d === date;
|
|
||||||
},
|
|
||||||
[adapter, isPageJournal]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getJournalDateString = useCallback(
|
|
||||||
(pageId: string) => {
|
|
||||||
return adapter.getJournalPageDateString(pageId);
|
|
||||||
},
|
|
||||||
[adapter]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getLocalizedJournalDateString = useCallback(
|
|
||||||
(pageId: string) => {
|
|
||||||
const journalDateString = getJournalDateString(pageId);
|
|
||||||
if (!journalDateString) return null;
|
|
||||||
return i18nTime(journalDateString, { absolute: { accuracy: 'day' } });
|
|
||||||
},
|
|
||||||
[getJournalDateString]
|
|
||||||
);
|
|
||||||
|
|
||||||
const appendContentToToday = useCallback(
|
const appendContentToToday = useCallback(
|
||||||
async (content: string) => {
|
async (content: string) => {
|
||||||
if (!content) return;
|
if (!content) return;
|
||||||
@@ -148,21 +117,9 @@ export const useJournalHelper = (docCollection: DocCollection) => {
|
|||||||
() => ({
|
() => ({
|
||||||
getJournalsByDate,
|
getJournalsByDate,
|
||||||
getJournalByDate,
|
getJournalByDate,
|
||||||
getJournalDateString,
|
|
||||||
getLocalizedJournalDateString,
|
|
||||||
isPageJournal,
|
|
||||||
isPageTodayJournal,
|
|
||||||
appendContentToToday,
|
appendContentToToday,
|
||||||
}),
|
}),
|
||||||
[
|
[getJournalsByDate, getJournalByDate, appendContentToToday]
|
||||||
getJournalsByDate,
|
|
||||||
getJournalByDate,
|
|
||||||
getJournalDateString,
|
|
||||||
getLocalizedJournalDateString,
|
|
||||||
isPageJournal,
|
|
||||||
isPageTodayJournal,
|
|
||||||
appendContentToToday,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -207,16 +164,41 @@ export const useJournalRouteHelper = (docCollection: DocCollection) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useJournalInfoHelper = (
|
// get journal info that don't rely on `docCollection`
|
||||||
docCollection: DocCollection,
|
export const useJournalInfoHelper = (pageId?: string | null) => {
|
||||||
pageId?: string | null
|
const adapter = useCurrentWorkspacePropertiesAdapter();
|
||||||
) => {
|
|
||||||
const {
|
const isPageJournal = useCallback(
|
||||||
isPageJournal,
|
(pageId: string) => {
|
||||||
getJournalDateString,
|
return !!adapter.getJournalPageDateString(pageId);
|
||||||
getLocalizedJournalDateString,
|
},
|
||||||
isPageTodayJournal,
|
[adapter]
|
||||||
} = useJournalHelper(docCollection);
|
);
|
||||||
|
|
||||||
|
const isPageTodayJournal = useCallback(
|
||||||
|
(pageId: string) => {
|
||||||
|
const date = dayjs().format(JOURNAL_DATE_FORMAT);
|
||||||
|
const d = adapter.getJournalPageDateString(pageId);
|
||||||
|
return isPageJournal(pageId) && d === date;
|
||||||
|
},
|
||||||
|
[adapter, isPageJournal]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getJournalDateString = useCallback(
|
||||||
|
(pageId: string) => {
|
||||||
|
return adapter.getJournalPageDateString(pageId);
|
||||||
|
},
|
||||||
|
[adapter]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getLocalizedJournalDateString = useCallback(
|
||||||
|
(pageId: string) => {
|
||||||
|
const journalDateString = getJournalDateString(pageId);
|
||||||
|
if (!journalDateString) return null;
|
||||||
|
return i18nTime(journalDateString, { absolute: { accuracy: 'day' } });
|
||||||
|
},
|
||||||
|
[getJournalDateString]
|
||||||
|
);
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -226,6 +208,10 @@ export const useJournalInfoHelper = (
|
|||||||
? getLocalizedJournalDateString(pageId)
|
? getLocalizedJournalDateString(pageId)
|
||||||
: null,
|
: null,
|
||||||
isTodayJournal: pageId ? isPageTodayJournal(pageId) : false,
|
isTodayJournal: pageId ? isPageTodayJournal(pageId) : false,
|
||||||
|
isPageJournal,
|
||||||
|
isPageTodayJournal,
|
||||||
|
getJournalDateString,
|
||||||
|
getLocalizedJournalDateString,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
getJournalDateString,
|
getJournalDateString,
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
import { useJournalInfoHelper } from '@affine/core/components/hooks/use-journal';
|
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||||
import type { Tag } from '@affine/env/filter';
|
import type { Tag } from '@affine/env/filter';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { assertExists } from '@blocksuite/global/utils';
|
import { assertExists } from '@blocksuite/global/utils';
|
||||||
import {
|
import { ToggleCollapseIcon, ViewLayersIcon } from '@blocksuite/icons/rc';
|
||||||
EdgelessIcon,
|
|
||||||
PageIcon,
|
|
||||||
TodayIcon,
|
|
||||||
ToggleCollapseIcon,
|
|
||||||
ViewLayersIcon,
|
|
||||||
} from '@blocksuite/icons/rc';
|
|
||||||
import type { DocCollection, DocMeta } from '@blocksuite/store';
|
import type { DocCollection, DocMeta } from '@blocksuite/store';
|
||||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||||
import { DocsService, useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { selectAtom } from 'jotai/utils';
|
import { selectAtom } from 'jotai/utils';
|
||||||
import type { MouseEventHandler } from 'react';
|
import type { MouseEventHandler } from 'react';
|
||||||
@@ -284,26 +278,16 @@ function tagIdToTagOption(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PageTitle = ({ id }: { id: string }) => {
|
const PageTitle = ({ id }: { id: string }) => {
|
||||||
const doc = useLiveData(useService(DocsService).list.doc$(id));
|
|
||||||
const title = useLiveData(doc?.title$);
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
return title || t['Untitled']();
|
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||||
|
const title = useLiveData(docDisplayMetaService.title$(id));
|
||||||
|
return typeof title === 'string' ? title : t[title.key]();
|
||||||
};
|
};
|
||||||
|
|
||||||
const UnifiedPageIcon = ({
|
const UnifiedPageIcon = ({ id }: { id: string }) => {
|
||||||
id,
|
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||||
docCollection,
|
const Icon = useLiveData(docDisplayMetaService.icon$(id));
|
||||||
}: {
|
return <Icon />;
|
||||||
id: string;
|
|
||||||
docCollection: DocCollection;
|
|
||||||
}) => {
|
|
||||||
const list = useService(DocsService).list;
|
|
||||||
const isEdgeless = useLiveData(list.primaryMode$(id)) === 'edgeless';
|
|
||||||
const { isJournal } = useJournalInfoHelper(docCollection, id);
|
|
||||||
if (isJournal) {
|
|
||||||
return <TodayIcon />;
|
|
||||||
}
|
|
||||||
return isEdgeless ? <EdgelessIcon /> : <PageIcon />;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function pageMetaToListItemProp(
|
function pageMetaToListItemProp(
|
||||||
@@ -338,7 +322,7 @@ function pageMetaToListItemProp(
|
|||||||
updatedDate: item.updatedDate ? new Date(item.updatedDate) : undefined,
|
updatedDate: item.updatedDate ? new Date(item.updatedDate) : undefined,
|
||||||
to: props.rowAsLink && !props.selectable ? `/${item.id}` : undefined,
|
to: props.rowAsLink && !props.selectable ? `/${item.id}` : undefined,
|
||||||
onClick: toggleSelection,
|
onClick: toggleSelection,
|
||||||
icon: <UnifiedPageIcon id={item.id} docCollection={props.docCollection} />,
|
icon: <UnifiedPageIcon id={item.id} />,
|
||||||
tags:
|
tags:
|
||||||
item.tags
|
item.tags
|
||||||
?.map(id => tagIdToTagOption(id, props.docCollection))
|
?.map(id => tagIdToTagOption(id, props.docCollection))
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ import {
|
|||||||
useJournalInfoHelper,
|
useJournalInfoHelper,
|
||||||
useJournalRouteHelper,
|
useJournalRouteHelper,
|
||||||
} from '@affine/core/components/hooks/use-journal';
|
} from '@affine/core/components/hooks/use-journal';
|
||||||
|
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||||
import { isNewTabTrigger } from '@affine/core/utils';
|
import { isNewTabTrigger } from '@affine/core/utils';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { TodayIcon, TomorrowIcon, YesterdayIcon } from '@blocksuite/icons/rc';
|
import { TodayIcon } from '@blocksuite/icons/rc';
|
||||||
import type { DocCollection } from '@blocksuite/store';
|
import type { DocCollection } from '@blocksuite/store';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { type MouseEvent } from 'react';
|
import { type MouseEvent } from 'react';
|
||||||
@@ -21,13 +22,11 @@ export const AppSidebarJournalButton = ({
|
|||||||
docCollection,
|
docCollection,
|
||||||
}: AppSidebarJournalButtonProps) => {
|
}: AppSidebarJournalButtonProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||||
const workbench = useService(WorkbenchService).workbench;
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
const location = useLiveData(workbench.location$);
|
const location = useLiveData(workbench.location$);
|
||||||
const { openToday } = useJournalRouteHelper(docCollection);
|
const { openToday } = useJournalRouteHelper(docCollection);
|
||||||
const { journalDate, isJournal } = useJournalInfoHelper(
|
const { isJournal } = useJournalInfoHelper(location.pathname.split('/')[1]);
|
||||||
docCollection,
|
|
||||||
location.pathname.split('/')[1]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleOpenToday = useCatchEventCallback(
|
const handleOpenToday = useCatchEventCallback(
|
||||||
(e: MouseEvent) => {
|
(e: MouseEvent) => {
|
||||||
@@ -36,14 +35,12 @@ export const AppSidebarJournalButton = ({
|
|||||||
[openToday]
|
[openToday]
|
||||||
);
|
);
|
||||||
|
|
||||||
const Icon =
|
const JournalIcon = useLiveData(
|
||||||
isJournal && journalDate
|
docDisplayMetaService.icon$(docCollection.id, {
|
||||||
? journalDate.isBefore(new Date(), 'day')
|
compareDate: new Date(),
|
||||||
? YesterdayIcon
|
})
|
||||||
: journalDate.isAfter(new Date(), 'day')
|
);
|
||||||
? TomorrowIcon
|
const Icon = isJournal ? JournalIcon : TodayIcon;
|
||||||
: TodayIcon
|
|
||||||
: TodayIcon;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ export function NormalPageHeader({ page, workspace }: PageHeaderProps) {
|
|||||||
|
|
||||||
export function DetailPageHeader(props: PageHeaderProps) {
|
export function DetailPageHeader(props: PageHeaderProps) {
|
||||||
const { page, workspace } = props;
|
const { page, workspace } = props;
|
||||||
const { isJournal } = useJournalInfoHelper(page.collection, page.id);
|
const { isJournal } = useJournalInfoHelper(page.id);
|
||||||
const isInTrash = page.meta?.trash;
|
const isInTrash = page.meta?.trash;
|
||||||
const [openInfoModal, setOpenInfoModal] = useAtom(openInfoModalAtom);
|
const [openInfoModal, setOpenInfoModal] = useAtom(openInfoModalAtom);
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
import type { DateCell } from '@affine/component';
|
import type { DateCell } from '@affine/component';
|
||||||
import { DatePicker, IconButton, Menu, Scrollable } from '@affine/component';
|
import { DatePicker, IconButton, Menu, Scrollable } from '@affine/component';
|
||||||
import { useTrashModalHelper } from '@affine/core/components/hooks/affine/use-trash-modal-helper';
|
import { useTrashModalHelper } from '@affine/core/components/hooks/affine/use-trash-modal-helper';
|
||||||
import { useDocCollectionPageTitle } from '@affine/core/components/hooks/use-block-suite-workspace-page-title';
|
|
||||||
import {
|
import {
|
||||||
useJournalHelper,
|
useJournalHelper,
|
||||||
useJournalInfoHelper,
|
useJournalInfoHelper,
|
||||||
useJournalRouteHelper,
|
useJournalRouteHelper,
|
||||||
} from '@affine/core/components/hooks/use-journal';
|
} from '@affine/core/components/hooks/use-journal';
|
||||||
import { MoveToTrash } from '@affine/core/components/page-list';
|
import { MoveToTrash } from '@affine/core/components/page-list';
|
||||||
|
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||||
import { WorkbenchLink } from '@affine/core/modules/workbench';
|
import { WorkbenchLink } from '@affine/core/modules/workbench';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import {
|
import { MoreHorizontalIcon } from '@blocksuite/icons/rc';
|
||||||
EdgelessIcon,
|
|
||||||
MoreHorizontalIcon,
|
|
||||||
PageIcon,
|
|
||||||
TodayIcon,
|
|
||||||
} from '@blocksuite/icons/rc';
|
|
||||||
import type { DocRecord } from '@toeverything/infra';
|
import type { DocRecord } from '@toeverything/infra';
|
||||||
import {
|
import {
|
||||||
DocService,
|
DocService,
|
||||||
@@ -28,7 +23,7 @@ import { assignInlineVars } from '@vanilla-extract/dynamic';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import type { HTMLAttributes, PropsWithChildren, ReactNode } from 'react';
|
import type { HTMLAttributes, PropsWithChildren, ReactNode } from 'react';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import * as styles from './journal.css';
|
import * as styles from './journal.css';
|
||||||
|
|
||||||
@@ -44,30 +39,22 @@ const CountDisplay = ({
|
|||||||
};
|
};
|
||||||
interface PageItemProps
|
interface PageItemProps
|
||||||
extends Omit<HTMLAttributes<HTMLAnchorElement>, 'onClick'> {
|
extends Omit<HTMLAttributes<HTMLAnchorElement>, 'onClick'> {
|
||||||
docRecord: DocRecord;
|
docId: string;
|
||||||
right?: ReactNode;
|
right?: ReactNode;
|
||||||
}
|
}
|
||||||
const PageItem = ({ docRecord, right, className, ...attrs }: PageItemProps) => {
|
const PageItem = ({ docId, right, className, ...attrs }: PageItemProps) => {
|
||||||
const mode = useLiveData(docRecord.primaryMode$);
|
const t = useI18n();
|
||||||
const workspace = useService(WorkspaceService).workspace;
|
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||||
const title = useDocCollectionPageTitle(
|
const Icon = useLiveData(
|
||||||
workspace.docCollection,
|
docDisplayMetaService.icon$(docId, { compareDate: new Date() })
|
||||||
docRecord.id
|
|
||||||
);
|
|
||||||
const { isJournal } = useJournalInfoHelper(
|
|
||||||
workspace.docCollection,
|
|
||||||
docRecord.id
|
|
||||||
);
|
);
|
||||||
|
const titleMeta = useLiveData(docDisplayMetaService.title$(docId));
|
||||||
|
const title = typeof titleMeta === 'string' ? titleMeta : t[titleMeta.key]();
|
||||||
|
|
||||||
const Icon = isJournal
|
|
||||||
? TodayIcon
|
|
||||||
: mode === 'edgeless'
|
|
||||||
? EdgelessIcon
|
|
||||||
: PageIcon;
|
|
||||||
return (
|
return (
|
||||||
<WorkbenchLink
|
<WorkbenchLink
|
||||||
aria-label={title}
|
aria-label={title}
|
||||||
to={`/${docRecord.id}`}
|
to={`/${docId}`}
|
||||||
className={clsx(className, styles.pageItem)}
|
className={clsx(className, styles.pageItem)}
|
||||||
{...attrs}
|
{...attrs}
|
||||||
>
|
>
|
||||||
@@ -95,16 +82,8 @@ export const EditorJournalPanel = () => {
|
|||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const doc = useService(DocService).doc;
|
const doc = useService(DocService).doc;
|
||||||
const workspace = useService(WorkspaceService).workspace;
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
const { journalDate, isJournal } = useJournalInfoHelper(
|
const { journalDate, isJournal } = useJournalInfoHelper(doc.id);
|
||||||
workspace.docCollection,
|
|
||||||
doc.id
|
|
||||||
);
|
|
||||||
const { openJournal } = useJournalRouteHelper(workspace.docCollection);
|
const { openJournal } = useJournalRouteHelper(workspace.docCollection);
|
||||||
const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'));
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
journalDate && setDate(journalDate.format('YYYY-MM-DD'));
|
|
||||||
}, [journalDate]);
|
|
||||||
|
|
||||||
const onDateSelect = useCallback(
|
const onDateSelect = useCallback(
|
||||||
(date: string) => {
|
(date: string) => {
|
||||||
@@ -150,14 +129,18 @@ export const EditorJournalPanel = () => {
|
|||||||
monthNames={t['com.affine.calendar-date-picker.month-names']()}
|
monthNames={t['com.affine.calendar-date-picker.month-names']()}
|
||||||
todayLabel={t['com.affine.calendar-date-picker.today']()}
|
todayLabel={t['com.affine.calendar-date-picker.today']()}
|
||||||
customDayRenderer={customDayRenderer}
|
customDayRenderer={customDayRenderer}
|
||||||
value={date}
|
value={journalDate?.format('YYYY-MM-DD')}
|
||||||
onChange={onDateSelect}
|
onChange={onDateSelect}
|
||||||
monthHeaderCellClassName={styles.journalDateCellWrapper}
|
monthHeaderCellClassName={styles.journalDateCellWrapper}
|
||||||
monthBodyCellClassName={styles.journalDateCellWrapper}
|
monthBodyCellClassName={styles.journalDateCellWrapper}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<JournalConflictBlock date={dayjs(date)} />
|
{journalDate ? (
|
||||||
<JournalDailyCountBlock date={dayjs(date)} />
|
<>
|
||||||
|
<JournalConflictBlock date={journalDate} />
|
||||||
|
<JournalDailyCountBlock date={journalDate} />
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -276,7 +259,7 @@ const JournalDailyCountBlock = ({ date }: JournalBlockProps) => {
|
|||||||
<PageItem
|
<PageItem
|
||||||
tabIndex={name === activeItem ? 0 : -1}
|
tabIndex={name === activeItem ? 0 : -1}
|
||||||
key={index}
|
key={index}
|
||||||
docRecord={pageRecord}
|
docId={pageRecord.id}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -322,7 +305,7 @@ const ConflictList = ({
|
|||||||
return (
|
return (
|
||||||
<PageItem
|
<PageItem
|
||||||
aria-selected={isCurrent}
|
aria-selected={isCurrent}
|
||||||
docRecord={docRecord}
|
docId={docRecord.id}
|
||||||
key={docRecord.id}
|
key={docRecord.id}
|
||||||
right={
|
right={
|
||||||
<Menu
|
<Menu
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { IconButton, MobileMenu } from '@affine/component';
|
import { IconButton, MobileMenu } from '@affine/component';
|
||||||
import { useJournalInfoHelper } from '@affine/core/components/hooks/use-journal';
|
import { useJournalInfoHelper } from '@affine/core/components/hooks/use-journal';
|
||||||
import { EditorJournalPanel } from '@affine/core/desktop/pages/workspace/detail-page/tabs/journal';
|
import { EditorJournalPanel } from '@affine/core/desktop/pages/workspace/detail-page/tabs/journal';
|
||||||
import { TodayIcon, TomorrowIcon, YesterdayIcon } from '@blocksuite/icons/rc';
|
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||||
import { useService, WorkspaceService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
|
|
||||||
export const JournalIconButton = ({
|
export const JournalIconButton = ({
|
||||||
docId,
|
docId,
|
||||||
@@ -11,18 +11,14 @@ export const JournalIconButton = ({
|
|||||||
docId: string;
|
docId: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const workspace = useService(WorkspaceService).workspace;
|
const { isJournal } = useJournalInfoHelper(docId);
|
||||||
const { journalDate, isJournal } = useJournalInfoHelper(
|
|
||||||
workspace.docCollection,
|
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||||
docId
|
const Icon = useLiveData(
|
||||||
|
docDisplayMetaService.icon$(docId, {
|
||||||
|
compareDate: new Date(),
|
||||||
|
})
|
||||||
);
|
);
|
||||||
const Icon = journalDate
|
|
||||||
? journalDate.isBefore(new Date(), 'day')
|
|
||||||
? YesterdayIcon
|
|
||||||
: journalDate.isAfter(new Date(), 'day')
|
|
||||||
? TomorrowIcon
|
|
||||||
: TodayIcon
|
|
||||||
: TodayIcon;
|
|
||||||
|
|
||||||
if (!isJournal) {
|
if (!isJournal) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
16
packages/frontend/core/src/modules/doc-display-meta/index.ts
Normal file
16
packages/frontend/core/src/modules/doc-display-meta/index.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import {
|
||||||
|
DocsService,
|
||||||
|
type Framework,
|
||||||
|
WorkspaceScope,
|
||||||
|
} from '@toeverything/infra';
|
||||||
|
|
||||||
|
import { WorkspacePropertiesAdapter } from '../properties';
|
||||||
|
import { DocDisplayMetaService } from './services/doc-display-meta';
|
||||||
|
|
||||||
|
export { DocDisplayMetaService };
|
||||||
|
|
||||||
|
export function configureDocDisplayMetaModule(framework: Framework) {
|
||||||
|
framework
|
||||||
|
.scope(WorkspaceScope)
|
||||||
|
.service(DocDisplayMetaService, [WorkspacePropertiesAdapter, DocsService]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
import { i18nTime } from '@affine/i18n';
|
||||||
|
import {
|
||||||
|
BlockLinkIcon as LitBlockLinkIcon,
|
||||||
|
EdgelessIcon as LitEdgelessIcon,
|
||||||
|
LinkedEdgelessIcon as LitLinkedEdgelessIcon,
|
||||||
|
LinkedPageIcon as LitLinkedPageIcon,
|
||||||
|
PageIcon as LitPageIcon,
|
||||||
|
TodayIcon as LitTodayIcon,
|
||||||
|
TomorrowIcon as LitTomorrowIcon,
|
||||||
|
YesterdayIcon as LitYesterdayIcon,
|
||||||
|
} from '@blocksuite/icons/lit';
|
||||||
|
import {
|
||||||
|
BlockLinkIcon,
|
||||||
|
EdgelessIcon,
|
||||||
|
LinkedEdgelessIcon,
|
||||||
|
LinkedPageIcon,
|
||||||
|
PageIcon,
|
||||||
|
TodayIcon,
|
||||||
|
TomorrowIcon,
|
||||||
|
YesterdayIcon,
|
||||||
|
} from '@blocksuite/icons/rc';
|
||||||
|
import type { DocRecord, DocsService } from '@toeverything/infra';
|
||||||
|
import { LiveData, Service } from '@toeverything/infra';
|
||||||
|
import type { Dayjs } from 'dayjs';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
import type { WorkspacePropertiesAdapter } from '../../properties';
|
||||||
|
|
||||||
|
type IconType = 'rc' | 'lit';
|
||||||
|
interface DocDisplayIconOptions<T extends IconType> {
|
||||||
|
type?: T;
|
||||||
|
compareDate?: Date | Dayjs;
|
||||||
|
/**
|
||||||
|
* Override the mode detected inside the hook:
|
||||||
|
* by default, it will use the `primaryMode$` of the doc.
|
||||||
|
*/
|
||||||
|
mode?: 'edgeless' | 'page';
|
||||||
|
reference?: boolean;
|
||||||
|
referenceToNode?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rcIcons = {
|
||||||
|
BlockLinkIcon,
|
||||||
|
EdgelessIcon,
|
||||||
|
LinkedEdgelessIcon,
|
||||||
|
LinkedPageIcon,
|
||||||
|
PageIcon,
|
||||||
|
TodayIcon,
|
||||||
|
TomorrowIcon,
|
||||||
|
YesterdayIcon,
|
||||||
|
};
|
||||||
|
const litIcons = {
|
||||||
|
BlockLinkIcon: LitBlockLinkIcon,
|
||||||
|
EdgelessIcon: LitEdgelessIcon,
|
||||||
|
LinkedEdgelessIcon: LitLinkedEdgelessIcon,
|
||||||
|
LinkedPageIcon: LitLinkedPageIcon,
|
||||||
|
PageIcon: LitPageIcon,
|
||||||
|
TodayIcon: LitTodayIcon,
|
||||||
|
TomorrowIcon: LitTomorrowIcon,
|
||||||
|
YesterdayIcon: LitYesterdayIcon,
|
||||||
|
};
|
||||||
|
const icons = { rc: rcIcons, lit: litIcons } as {
|
||||||
|
rc: Record<keyof typeof rcIcons, any>;
|
||||||
|
lit: Record<keyof typeof litIcons, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class DocDisplayMetaService extends Service {
|
||||||
|
constructor(
|
||||||
|
private readonly propertiesAdapter: WorkspacePropertiesAdapter,
|
||||||
|
private readonly docsService: DocsService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
icon$<T extends IconType = 'rc'>(
|
||||||
|
docId: string,
|
||||||
|
options?: DocDisplayIconOptions<T>
|
||||||
|
): LiveData<T extends 'lit' ? typeof LitTodayIcon : typeof TodayIcon> {
|
||||||
|
const iconSet = icons[options?.type ?? 'rc'];
|
||||||
|
|
||||||
|
return LiveData.computed(get => {
|
||||||
|
const doc = get(this.docsService.list.doc$(docId));
|
||||||
|
const mode = doc ? get(doc.primaryMode$) : undefined;
|
||||||
|
const finalMode = options?.mode ?? mode ?? 'page';
|
||||||
|
|
||||||
|
const journalDate = this._toDayjs(
|
||||||
|
this.propertiesAdapter.getJournalPageDateString(docId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (journalDate) {
|
||||||
|
if (!options?.compareDate) return iconSet.TodayIcon;
|
||||||
|
const compareDate = dayjs(options?.compareDate);
|
||||||
|
return journalDate.isBefore(compareDate, 'day')
|
||||||
|
? iconSet.YesterdayIcon
|
||||||
|
: journalDate.isAfter(compareDate, 'day')
|
||||||
|
? iconSet.TomorrowIcon
|
||||||
|
: iconSet.TodayIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
return options?.reference
|
||||||
|
? options?.referenceToNode
|
||||||
|
? iconSet.BlockLinkIcon
|
||||||
|
: finalMode === 'edgeless'
|
||||||
|
? iconSet.LinkedEdgelessIcon
|
||||||
|
: iconSet.LinkedPageIcon
|
||||||
|
: finalMode === 'edgeless'
|
||||||
|
? iconSet.EdgelessIcon
|
||||||
|
: iconSet.PageIcon;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
title$(docId: string, originalTitle?: string) {
|
||||||
|
return LiveData.computed(get => {
|
||||||
|
const doc = get(this.docsService.list.doc$(docId));
|
||||||
|
const docTitle = doc ? get(doc.title$) : undefined;
|
||||||
|
|
||||||
|
const journalDateString =
|
||||||
|
this.propertiesAdapter.getJournalPageDateString(docId);
|
||||||
|
return journalDateString
|
||||||
|
? i18nTime(journalDateString, { absolute: { accuracy: 'day' } })
|
||||||
|
: originalTitle ||
|
||||||
|
docTitle ||
|
||||||
|
({
|
||||||
|
key: 'Untitled',
|
||||||
|
} as const);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getDocDisplayMeta(docRecord: DocRecord, originalTitle?: string) {
|
||||||
|
return {
|
||||||
|
title: this.title$(docRecord.id, originalTitle).value,
|
||||||
|
icon: this.icon$(docRecord.id).value,
|
||||||
|
updatedDate: docRecord.meta$.value.updatedDate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private _isJournalString(j?: string | false) {
|
||||||
|
return j ? !!j?.match(/^\d{4}-\d{2}-\d{2}$/) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toDayjs(j?: string | false) {
|
||||||
|
if (!j || !this._isJournalString(j)) return null;
|
||||||
|
const day = dayjs(j);
|
||||||
|
if (!day.isValid()) return null;
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,16 +7,11 @@ import {
|
|||||||
} from '@affine/component';
|
} from '@affine/component';
|
||||||
import { InfoModal } from '@affine/core/components/affine/page-properties';
|
import { InfoModal } from '@affine/core/components/affine/page-properties';
|
||||||
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
||||||
|
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||||
import { DocsSearchService } from '@affine/core/modules/docs-search';
|
import { DocsSearchService } from '@affine/core/modules/docs-search';
|
||||||
import type { AffineDNDData } from '@affine/core/types/dnd';
|
import type { AffineDNDData } from '@affine/core/types/dnd';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
import {
|
|
||||||
EdgelessIcon,
|
|
||||||
LinkedEdgelessIcon,
|
|
||||||
LinkedPageIcon,
|
|
||||||
PageIcon,
|
|
||||||
} from '@blocksuite/icons/rc';
|
|
||||||
import {
|
import {
|
||||||
DocsService,
|
DocsService,
|
||||||
GlobalContextService,
|
GlobalContextService,
|
||||||
@@ -46,35 +41,37 @@ export const ExplorerDocNode = ({
|
|||||||
isLinked?: boolean;
|
isLinked?: boolean;
|
||||||
} & GenericExplorerNode) => {
|
} & GenericExplorerNode) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { docsSearchService, docsService, globalContextService } = useServices({
|
const {
|
||||||
|
docsSearchService,
|
||||||
|
docsService,
|
||||||
|
globalContextService,
|
||||||
|
docDisplayMetaService,
|
||||||
|
} = useServices({
|
||||||
DocsSearchService,
|
DocsSearchService,
|
||||||
DocsService,
|
DocsService,
|
||||||
GlobalContextService,
|
GlobalContextService,
|
||||||
|
DocDisplayMetaService,
|
||||||
});
|
});
|
||||||
|
// const pageInfoAdapter = useCurrentWorkspacePropertiesAdapter();
|
||||||
|
|
||||||
const active =
|
const active =
|
||||||
useLiveData(globalContextService.globalContext.docId.$) === docId;
|
useLiveData(globalContextService.globalContext.docId.$) === docId;
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
const [collapsed, setCollapsed] = useState(true);
|
||||||
|
|
||||||
const docRecord = useLiveData(docsService.list.doc$(docId));
|
const docRecord = useLiveData(docsService.list.doc$(docId));
|
||||||
const docPrimaryMode = useLiveData(docRecord?.primaryMode$);
|
const DocIcon = useLiveData(
|
||||||
const docTitle = useLiveData(docRecord?.title$);
|
docDisplayMetaService.icon$(docId, {
|
||||||
|
reference: isLinked,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const docTitle = useLiveData(docDisplayMetaService.title$(docId));
|
||||||
const isInTrash = useLiveData(docRecord?.trash$);
|
const isInTrash = useLiveData(docRecord?.trash$);
|
||||||
|
|
||||||
const Icon = useCallback(
|
const Icon = useCallback(
|
||||||
({ className }: { className?: string }) => {
|
({ className }: { className?: string }) => {
|
||||||
return isLinked ? (
|
return <DocIcon className={className} />;
|
||||||
docPrimaryMode === 'edgeless' ? (
|
|
||||||
<LinkedEdgelessIcon className={className} />
|
|
||||||
) : (
|
|
||||||
<LinkedPageIcon className={className} />
|
|
||||||
)
|
|
||||||
) : docPrimaryMode === 'edgeless' ? (
|
|
||||||
<EdgelessIcon className={className} />
|
|
||||||
) : (
|
|
||||||
<PageIcon className={className} />
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
[docPrimaryMode, isLinked]
|
[DocIcon]
|
||||||
);
|
);
|
||||||
|
|
||||||
const children = useLiveData(
|
const children = useLiveData(
|
||||||
@@ -205,7 +202,7 @@ export const ExplorerDocNode = ({
|
|||||||
<>
|
<>
|
||||||
<ExplorerTreeNode
|
<ExplorerTreeNode
|
||||||
icon={Icon}
|
icon={Icon}
|
||||||
name={docTitle || t['Untitled']()}
|
name={typeof docTitle === 'string' ? docTitle : t[docTitle.key]()}
|
||||||
dndData={dndData}
|
dndData={dndData}
|
||||||
onDrop={handleDropOnDoc}
|
onDrop={handleDropOnDoc}
|
||||||
renameable
|
renameable
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { configureInfraModules, type Framework } from '@toeverything/infra';
|
|||||||
import { configureCloudModule } from './cloud';
|
import { configureCloudModule } from './cloud';
|
||||||
import { configureCollectionModule } from './collection';
|
import { configureCollectionModule } from './collection';
|
||||||
import { configureCreateWorkspaceModule } from './create-workspace';
|
import { configureCreateWorkspaceModule } from './create-workspace';
|
||||||
|
import { configureDocDisplayMetaModule } from './doc-display-meta';
|
||||||
import { configureDocLinksModule } from './doc-link';
|
import { configureDocLinksModule } from './doc-link';
|
||||||
import { configureDocsSearchModule } from './docs-search';
|
import { configureDocsSearchModule } from './docs-search';
|
||||||
import { configureEditorModule } from './editor';
|
import { configureEditorModule } from './editor';
|
||||||
@@ -40,6 +41,7 @@ export function configureCommonModules(framework: Framework) {
|
|||||||
configureTelemetryModule(framework);
|
configureTelemetryModule(framework);
|
||||||
configureFindInPageModule(framework);
|
configureFindInPageModule(framework);
|
||||||
configurePeekViewModule(framework);
|
configurePeekViewModule(framework);
|
||||||
|
configureDocDisplayMetaModule(framework);
|
||||||
configureQuickSearchModule(framework);
|
configureQuickSearchModule(framework);
|
||||||
configureDocsSearchModule(framework);
|
configureDocsSearchModule(framework);
|
||||||
configureDocLinksModule(framework);
|
configureDocLinksModule(framework);
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import {
|
|||||||
import { truncate } from 'lodash-es';
|
import { truncate } from 'lodash-es';
|
||||||
import { EMPTY, map, mergeMap, of, switchMap } from 'rxjs';
|
import { EMPTY, map, mergeMap, of, switchMap } from 'rxjs';
|
||||||
|
|
||||||
|
import type { DocDisplayMetaService } from '../../doc-display-meta';
|
||||||
import type { DocsSearchService } from '../../docs-search';
|
import type { DocsSearchService } from '../../docs-search';
|
||||||
import type { QuickSearchSession } from '../providers/quick-search-provider';
|
import type { QuickSearchSession } from '../providers/quick-search-provider';
|
||||||
import type { DocDisplayMetaService } from '../services/doc-display-meta';
|
|
||||||
import type { QuickSearchItem } from '../types/item';
|
import type { QuickSearchItem } from '../types/item';
|
||||||
|
|
||||||
interface DocsPayload {
|
interface DocsPayload {
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import type { DocsService, WorkspaceService } from '@toeverything/infra';
|
|||||||
import { Entity, LiveData } from '@toeverything/infra';
|
import { Entity, LiveData } from '@toeverything/infra';
|
||||||
import { omit, truncate } from 'lodash-es';
|
import { omit, truncate } from 'lodash-es';
|
||||||
|
|
||||||
|
import type { DocDisplayMetaService } from '../../doc-display-meta';
|
||||||
import { resolveLinkToDoc } from '../../navigation';
|
import { resolveLinkToDoc } from '../../navigation';
|
||||||
import { isLink } from '../../navigation/utils';
|
import { isLink } from '../../navigation/utils';
|
||||||
import type { QuickSearchSession } from '../providers/quick-search-provider';
|
import type { QuickSearchSession } from '../providers/quick-search-provider';
|
||||||
import type { DocDisplayMetaService } from '../services/doc-display-meta';
|
|
||||||
import type { QuickSearchItem } from '../types/item';
|
import type { QuickSearchItem } from '../types/item';
|
||||||
|
|
||||||
type LinkPayload = { docId: string } & ReferenceParams;
|
type LinkPayload = { docId: string } & ReferenceParams;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Entity, LiveData } from '@toeverything/infra';
|
import { Entity, LiveData } from '@toeverything/infra';
|
||||||
|
|
||||||
|
import type { DocDisplayMetaService } from '../../doc-display-meta';
|
||||||
import type { QuickSearchSession } from '../providers/quick-search-provider';
|
import type { QuickSearchSession } from '../providers/quick-search-provider';
|
||||||
import type { DocDisplayMetaService } from '../services/doc-display-meta';
|
|
||||||
import type { RecentDocsService } from '../services/recent-pages';
|
import type { RecentDocsService } from '../services/recent-pages';
|
||||||
import type { QuickSearchGroup } from '../types/group';
|
import type { QuickSearchGroup } from '../types/group';
|
||||||
import type { QuickSearchItem } from '../types/item';
|
import type { QuickSearchItem } from '../types/item';
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
|
|
||||||
import { CollectionService } from '../collection';
|
import { CollectionService } from '../collection';
|
||||||
|
import { DocDisplayMetaService } from '../doc-display-meta/services/doc-display-meta';
|
||||||
import { DocsSearchService } from '../docs-search';
|
import { DocsSearchService } from '../docs-search';
|
||||||
import { WorkspacePropertiesAdapter } from '../properties';
|
|
||||||
import { TagService } from '../tag';
|
import { TagService } from '../tag';
|
||||||
import { WorkbenchService } from '../workbench';
|
import { WorkbenchService } from '../workbench';
|
||||||
import { QuickSearch } from './entities/quick-search';
|
import { QuickSearch } from './entities/quick-search';
|
||||||
@@ -22,7 +22,6 @@ import { LinksQuickSearchSession } from './impls/links';
|
|||||||
import { RecentDocsQuickSearchSession } from './impls/recent-docs';
|
import { RecentDocsQuickSearchSession } from './impls/recent-docs';
|
||||||
import { TagsQuickSearchSession } from './impls/tags';
|
import { TagsQuickSearchSession } from './impls/tags';
|
||||||
import { CMDKQuickSearchService } from './services/cmdk';
|
import { CMDKQuickSearchService } from './services/cmdk';
|
||||||
import { DocDisplayMetaService } from './services/doc-display-meta';
|
|
||||||
import { QuickSearchService } from './services/quick-search';
|
import { QuickSearchService } from './services/quick-search';
|
||||||
import { RecentDocsService } from './services/recent-pages';
|
import { RecentDocsService } from './services/recent-pages';
|
||||||
|
|
||||||
@@ -50,7 +49,6 @@ export function configureQuickSearchModule(framework: Framework) {
|
|||||||
DocsService,
|
DocsService,
|
||||||
])
|
])
|
||||||
.service(RecentDocsService, [WorkspaceLocalState, DocsService])
|
.service(RecentDocsService, [WorkspaceLocalState, DocsService])
|
||||||
.service(DocDisplayMetaService, [WorkspacePropertiesAdapter])
|
|
||||||
.entity(QuickSearch)
|
.entity(QuickSearch)
|
||||||
.entity(CommandsQuickSearchSession, [GlobalContextService])
|
.entity(CommandsQuickSearchSession, [GlobalContextService])
|
||||||
.entity(DocsQuickSearchSession, [
|
.entity(DocsQuickSearchSession, [
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
import { i18nTime } from '@affine/i18n';
|
|
||||||
import { EdgelessIcon, PageIcon, TodayIcon } from '@blocksuite/icons/rc';
|
|
||||||
import type { DocRecord } from '@toeverything/infra';
|
|
||||||
import { Service } from '@toeverything/infra';
|
|
||||||
|
|
||||||
import type { WorkspacePropertiesAdapter } from '../../properties';
|
|
||||||
|
|
||||||
export class DocDisplayMetaService extends Service {
|
|
||||||
constructor(private readonly propertiesAdapter: WorkspacePropertiesAdapter) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
getDocDisplayMeta(docRecord: DocRecord, originalTitle?: string) {
|
|
||||||
const journalDateString = this.propertiesAdapter.getJournalPageDateString(
|
|
||||||
docRecord.id
|
|
||||||
);
|
|
||||||
const icon = journalDateString
|
|
||||||
? TodayIcon
|
|
||||||
: docRecord.primaryMode$.value === 'edgeless'
|
|
||||||
? EdgelessIcon
|
|
||||||
: PageIcon;
|
|
||||||
|
|
||||||
const title = journalDateString
|
|
||||||
? i18nTime(journalDateString, { absolute: { accuracy: 'day' } })
|
|
||||||
: originalTitle ||
|
|
||||||
docRecord.meta$.value.title ||
|
|
||||||
({
|
|
||||||
key: 'Untitled',
|
|
||||||
} as const);
|
|
||||||
|
|
||||||
return {
|
|
||||||
title: title,
|
|
||||||
icon: icon,
|
|
||||||
updatedDate: docRecord.meta$.value.updatedDate,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user