diff --git a/packages/frontend/core/src/components/affine/page-properties/info-modal/info-modal.tsx b/packages/frontend/core/src/components/affine/page-properties/info-modal/info-modal.tsx
index ddc5e438bd..b613a2e5db 100644
--- a/packages/frontend/core/src/components/affine/page-properties/info-modal/info-modal.tsx
+++ b/packages/frontend/core/src/components/affine/page-properties/info-modal/info-modal.tsx
@@ -4,9 +4,15 @@ import {
Modal,
Scrollable,
} from '@affine/component';
+import { DocInfoService } from '@affine/core/modules/doc-info';
import { DocsSearchService } from '@affine/core/modules/docs-search';
import { useI18n } from '@affine/i18n';
-import { LiveData, useLiveData, useServices } from '@toeverything/infra';
+import {
+ LiveData,
+ useLiveData,
+ useService,
+ useServices,
+} from '@toeverything/infra';
import { Suspense, useCallback, useContext, useMemo, useRef } from 'react';
import { BlocksuiteHeaderTitle } from '../../../blocksuite/block-suite-header/title';
@@ -22,20 +28,23 @@ import { LinksRow } from './links-row';
import { TagsRow } from './tags-row';
import { TimeRow } from './time-row';
-export const InfoModal = ({
- open,
- onOpenChange,
- docId,
-}: {
- open: boolean;
- onOpenChange: (open: boolean) => void;
- docId: string;
-}) => {
+export const InfoModal = () => {
+ const modal = useService(DocInfoService).modal;
+ const docId = useLiveData(modal.docId$);
+
+ if (!docId) return null;
+
+ return ;
+};
+
+const InfoModalOpened = ({ docId }: { docId: string }) => {
+ const modal = useService(DocInfoService).modal;
+
const titleInputHandleRef = useRef(null);
- const manager = usePagePropertiesManager(docId);
+ const manager = usePagePropertiesManager(docId ?? '');
const handleClose = useCallback(() => {
- onOpenChange(false);
- }, [onOpenChange]);
+ modal.close();
+ }, [modal]);
if (!manager.page || manager.readonly) {
return null;
@@ -46,8 +55,8 @@ export const InfoModal = ({
contentOptions={{
className: styles.container,
}}
- open={open}
- onOpenChange={onOpenChange}
+ open
+ onOpenChange={v => modal.onOpenChange(v)}
withoutCloseButton
>
diff --git a/packages/frontend/core/src/components/atoms/index.ts b/packages/frontend/core/src/components/atoms/index.ts
index c519e959ff..7ffbf3f36c 100644
--- a/packages/frontend/core/src/components/atoms/index.ts
+++ b/packages/frontend/core/src/components/atoms/index.ts
@@ -12,7 +12,6 @@ export const openQuotaModalAtom = atom(false);
export const openStarAFFiNEModalAtom = atom(false);
export const openIssueFeedbackModalAtom = atom(false);
export const openHistoryTipsModalAtom = atom(false);
-export const openInfoModalAtom = atom(false);
export const rightSidebarWidthAtom = atom(320);
diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-header/info/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-header/info/index.tsx
index 1474241c51..55936d8afc 100644
--- a/packages/frontend/core/src/components/blocksuite/block-suite-header/info/index.tsx
+++ b/packages/frontend/core/src/components/blocksuite/block-suite-header/info/index.tsx
@@ -1,19 +1,19 @@
import { IconButton } from '@affine/component';
-import { openInfoModalAtom } from '@affine/core/components/atoms';
+import { DocInfoService } from '@affine/core/modules/doc-info';
import { useI18n } from '@affine/i18n';
import { track } from '@affine/track';
import { InformationIcon } from '@blocksuite/icons/rc';
-import { useSetAtom } from 'jotai';
+import { useService } from '@toeverything/infra';
import { useCallback } from 'react';
-export const InfoButton = () => {
- const setOpenInfoModal = useSetAtom(openInfoModalAtom);
+export const InfoButton = ({ docId }: { docId: string }) => {
+ const modal = useService(DocInfoService).modal;
const t = useI18n();
const onOpenInfoModal = useCallback(() => {
track.$.header.actions.openDocInfo();
- setOpenInfoModal(true);
- }, [setOpenInfoModal]);
+ modal.open(docId);
+ }, [docId, modal]);
return (
{
track.$.header.pageInfo.open();
- setOpenInfoModal(true);
- }, [setOpenInfoModal]);
+ docInfoModal.open(pageId);
+ }, [docInfoModal, pageId]);
const handleOpenInNewTab = useCallback(() => {
workbench.openDoc(pageId, {
diff --git a/packages/frontend/core/src/components/hooks/affine/use-register-blocksuite-editor-commands.tsx b/packages/frontend/core/src/components/hooks/affine/use-register-blocksuite-editor-commands.tsx
index 116e3fd125..917221082c 100644
--- a/packages/frontend/core/src/components/hooks/affine/use-register-blocksuite-editor-commands.tsx
+++ b/packages/frontend/core/src/components/hooks/affine/use-register-blocksuite-editor-commands.tsx
@@ -3,7 +3,7 @@ import {
PreconditionStrategy,
registerAffineCommand,
} from '@affine/core/commands';
-import { openInfoModalAtom } from '@affine/core/components/atoms';
+import { DocInfoService } from '@affine/core/modules/doc-info';
import type { Editor } from '@affine/core/modules/editor';
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
import { WorkspaceFlavour } from '@affine/env/workspace';
@@ -36,7 +36,7 @@ export function useRegisterBlocksuiteEditorCommands(editor: Editor) {
const trash = useLiveData(doc.trash$);
const setPageHistoryModalState = useSetAtom(pageHistoryModalAtom);
- const setInfoModalState = useSetAtom(openInfoModalAtom);
+ const docInfoModal = useService(DocInfoService).modal;
const openHistoryModal = useCallback(() => {
setPageHistoryModalState(() => ({
@@ -46,8 +46,8 @@ export function useRegisterBlocksuiteEditorCommands(editor: Editor) {
}, [docId, setPageHistoryModalState]);
const openInfoModal = useCallback(() => {
- setInfoModalState(true);
- }, [setInfoModalState]);
+ docInfoModal.open(docId);
+ }, [docId, docInfoModal]);
const { duplicate } = useBlockSuiteMetaHelper();
const exportHandler = useExportPage();
diff --git a/packages/frontend/core/src/components/page-list/operation-cell.tsx b/packages/frontend/core/src/components/page-list/operation-cell.tsx
index 9ca95c3d80..36d02a986a 100644
--- a/packages/frontend/core/src/components/page-list/operation-cell.tsx
+++ b/packages/frontend/core/src/components/page-list/operation-cell.tsx
@@ -8,6 +8,7 @@ import {
import { useBlockSuiteMetaHelper } from '@affine/core/components/hooks/affine/use-block-suite-meta-helper';
import { useTrashModalHelper } from '@affine/core/components/hooks/affine/use-trash-modal-helper';
import { useCatchEventCallback } from '@affine/core/components/hooks/use-catch-event-hook';
+import { DocInfoService } from '@affine/core/modules/doc-info';
import { FavoriteService } from '@affine/core/modules/favorite';
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
import { WorkbenchService } from '@affine/core/modules/workbench';
@@ -32,6 +33,7 @@ import {
import {
FeatureFlagService,
useLiveData,
+ useService,
useServices,
WorkspaceService,
} from '@toeverything/infra';
@@ -39,7 +41,6 @@ import type { MouseEvent } from 'react';
import { useCallback, useState } from 'react';
import type { CollectionService } from '../../modules/collection';
-import { InfoModal } from '../affine/page-properties';
import { usePageHelper } from '../blocksuite/block-suite-page-list/utils';
import { IsFavoriteIcon } from '../pure/icons';
import { FavoriteTag } from './components/favorite-tag';
@@ -86,11 +87,11 @@ export const PageOperationCell = ({
const { duplicate } = useBlockSuiteMetaHelper();
const blocksuiteDoc = currentWorkspace.docCollection.getDoc(page.id);
- const [openInfoModal, setOpenInfoModal] = useState(false);
+ const docInfoModal = useService(DocInfoService).modal;
const onOpenInfoModal = useCallback(() => {
track.$.docInfoPanel.$.open();
- setOpenInfoModal(true);
- }, []);
+ docInfoModal.open(blocksuiteDoc?.id);
+ }, [blocksuiteDoc?.id, docInfoModal]);
const onDisablePublicSharing = useCallback(() => {
// TODO(@EYHN): implement disable public sharing
@@ -214,13 +215,6 @@ export const PageOperationCell = ({
- {blocksuiteDoc ? (
-
- ) : null}
>
);
};
diff --git a/packages/frontend/core/src/components/providers/modal-provider.tsx b/packages/frontend/core/src/components/providers/modal-provider.tsx
index 83a2695152..afdecc41ed 100644
--- a/packages/frontend/core/src/components/providers/modal-provider.tsx
+++ b/packages/frontend/core/src/components/providers/modal-provider.tsx
@@ -21,6 +21,7 @@ import { AuthModal } from '../affine/auth';
import { AiLoginRequiredModal } from '../affine/auth/ai-login-required';
import { HistoryTipsModal } from '../affine/history-tips-modal';
import { IssueFeedbackModal } from '../affine/issue-feedback-modal';
+import { InfoModal } from '../affine/page-properties/info-modal/info-modal';
import {
CloudQuotaModal,
LocalQuotaModal,
@@ -126,6 +127,7 @@ export function CurrentWorkspaceModals() {
onOpenChange={onTrashConfirmOpenChange}
titles={deletePageTitles}
/>
+
>
);
}
diff --git a/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page-header.tsx b/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page-header.tsx
index dbefe6a8c8..a8df2f9f81 100644
--- a/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page-header.tsx
+++ b/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page-header.tsx
@@ -3,8 +3,6 @@ import {
type InlineEditHandle,
observeResize,
} from '@affine/component';
-import { InfoModal } from '@affine/core/components/affine/page-properties';
-import { openInfoModalAtom } from '@affine/core/components/atoms';
import { FavoriteButton } from '@affine/core/components/blocksuite/block-suite-header/favorite';
import { InfoButton } from '@affine/core/components/blocksuite/block-suite-header/info';
import { JournalWeekDatePicker } from '@affine/core/components/blocksuite/block-suite-header/journal/date-picker';
@@ -19,7 +17,7 @@ import { EditorService } from '@affine/core/modules/editor';
import { ViewIcon, ViewTitle } from '@affine/core/modules/workbench';
import type { Doc } from '@blocksuite/affine/store';
import { useLiveData, useService, type Workspace } from '@toeverything/infra';
-import { useAtom, useAtomValue } from 'jotai';
+import { useAtomValue } from 'jotai';
import { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
import { SharePageButton } from '../../../../components/affine/share-page-modal';
@@ -139,7 +137,7 @@ export function NormalPageHeader({ page, workspace }: PageHeaderProps) {
{hideCollect ? null : (
<>
-
+
>
)}
- {isJournal && !isInTrash ? (
-
- ) : (
-
- )}
-
- >
+ return isJournal && !isInTrash ? (
+
+ ) : (
+
);
}
diff --git a/packages/frontend/core/src/mobile/provider/model-provider.tsx b/packages/frontend/core/src/mobile/provider/model-provider.tsx
index 606ddc00f5..07d4bc8c0a 100644
--- a/packages/frontend/core/src/mobile/provider/model-provider.tsx
+++ b/packages/frontend/core/src/mobile/provider/model-provider.tsx
@@ -2,6 +2,7 @@ import { NotificationCenter } from '@affine/component';
import { AiLoginRequiredModal } from '@affine/core/components/affine/auth/ai-login-required';
import { HistoryTipsModal } from '@affine/core/components/affine/history-tips-modal';
import { IssueFeedbackModal } from '@affine/core/components/affine/issue-feedback-modal';
+import { InfoModal } from '@affine/core/components/affine/page-properties/info-modal/info-modal';
import {
CloudQuotaModal,
LocalQuotaModal,
@@ -57,6 +58,7 @@ export function MobileCurrentWorkspaceModals() {
onOpenChange={onTrashConfirmOpenChange}
titles={deletePageTitles}
/>
+
>
);
}
diff --git a/packages/frontend/core/src/modules/doc-info/entities/modal.ts b/packages/frontend/core/src/modules/doc-info/entities/modal.ts
new file mode 100644
index 0000000000..c596847724
--- /dev/null
+++ b/packages/frontend/core/src/modules/doc-info/entities/modal.ts
@@ -0,0 +1,22 @@
+import { Entity, LiveData } from '@toeverything/infra';
+
+export class DocInfoModal extends Entity {
+ public readonly docId$ = new LiveData(null);
+ public readonly open$ = LiveData.computed(get => !!get(this.docId$));
+
+ public open(docId?: string) {
+ if (docId) {
+ this.docId$.next(docId);
+ } else {
+ this.docId$.next(null);
+ }
+ }
+
+ public close() {
+ this.docId$.next(null);
+ }
+
+ public onOpenChange(open: boolean) {
+ if (!open) this.docId$.next(null);
+ }
+}
diff --git a/packages/frontend/core/src/modules/doc-info/index.ts b/packages/frontend/core/src/modules/doc-info/index.ts
new file mode 100644
index 0000000000..14d8afa3df
--- /dev/null
+++ b/packages/frontend/core/src/modules/doc-info/index.ts
@@ -0,0 +1,10 @@
+import { type Framework, WorkspaceScope } from '@toeverything/infra';
+
+import { DocInfoModal } from './entities/modal';
+import { DocInfoService } from './services/doc-info';
+
+export { DocInfoService };
+
+export function configureDocInfoModule(framework: Framework) {
+ framework.scope(WorkspaceScope).service(DocInfoService).entity(DocInfoModal);
+}
diff --git a/packages/frontend/core/src/modules/doc-info/services/doc-info.ts b/packages/frontend/core/src/modules/doc-info/services/doc-info.ts
new file mode 100644
index 0000000000..1ff35f9b2a
--- /dev/null
+++ b/packages/frontend/core/src/modules/doc-info/services/doc-info.ts
@@ -0,0 +1,7 @@
+import { Service } from '@toeverything/infra';
+
+import { DocInfoModal } from '../entities/modal';
+
+export class DocInfoService extends Service {
+ public readonly modal = this.framework.createEntity(DocInfoModal);
+}
diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx
index 2774f009da..6e15bf32cc 100644
--- a/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx
+++ b/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx
@@ -5,9 +5,9 @@ import {
toast,
Tooltip,
} from '@affine/component';
-import { InfoModal } from '@affine/core/components/affine/page-properties';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
+import { DocInfoService } from '@affine/core/modules/doc-info';
import { DocsSearchService } from '@affine/core/modules/docs-search';
import type { AffineDNDData } from '@affine/core/types/dnd';
import { useI18n } from '@affine/i18n';
@@ -17,6 +17,7 @@ import {
GlobalContextService,
LiveData,
useLiveData,
+ useService,
useServices,
} from '@toeverything/infra';
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
@@ -175,15 +176,15 @@ export const ExplorerDocNode = ({
[canDrop]
);
- const [enableInfoModal, setEnableInfoModal] = useState(false);
+ const docInfoModal = useService(DocInfoService).modal;
const operations = useExplorerDocNodeOperations(
docId,
useMemo(
() => ({
- openInfoModal: () => setEnableInfoModal(true),
+ openInfoModal: () => docInfoModal.open(docId),
openNodeCollapsed: () => setCollapsed(false),
}),
- []
+ [docId, docInfoModal]
)
);
@@ -199,57 +200,48 @@ export const ExplorerDocNode = ({
}
return (
- <>
-
-
-
-
-
- )
- }
- reorderable={reorderable}
- onRename={handleRename}
- childrenPlaceholder={}
- operations={finalOperations}
- dropEffect={handleDropEffectOnDoc}
- data-testid={`explorer-doc-${docId}`}
- >
- {children?.map(child => (
-
- ))}
-
- {enableInfoModal && (
-
+
+
+
+
+ )
+ }
+ reorderable={reorderable}
+ onRename={handleRename}
+ childrenPlaceholder={}
+ operations={finalOperations}
+ dropEffect={handleDropEffectOnDoc}
+ data-testid={`explorer-doc-${docId}`}
+ >
+ {children?.map(child => (
+
- )}
- >
+ ))}
+
);
};
diff --git a/packages/frontend/core/src/modules/index.ts b/packages/frontend/core/src/modules/index.ts
index 24dc1d489d..3d4ebc151a 100644
--- a/packages/frontend/core/src/modules/index.ts
+++ b/packages/frontend/core/src/modules/index.ts
@@ -5,6 +5,7 @@ import { configureCloudModule } from './cloud';
import { configureCollectionModule } from './collection';
import { configureCreateWorkspaceModule } from './create-workspace';
import { configureDocDisplayMetaModule } from './doc-display-meta';
+import { configureDocInfoModule } from './doc-info';
import { configureDocLinksModule } from './doc-link';
import { configureDocsSearchModule } from './docs-search';
import { configureEditorModule } from './editor';
@@ -55,4 +56,5 @@ export function configureCommonModules(framework: Framework) {
configureImportTemplateModule(framework);
configureCreateWorkspaceModule(framework);
configureUserspaceModule(framework);
+ configureDocInfoModule(framework);
}