mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-20 19:46:32 +08:00
refactor(core): separate editor & doc mode (#7873)
doc.mode -> primaryMode
(*new) editor.mode
New Service:
editor service
Change Mode:
```
const editor = useService(EditorService).editor;
editor.setMode('page')
```
Change primary mode
```
const editor = useService(EditorService).editor;
editor.doc.setPrimaryMode('page')
```
This commit is contained in:
@@ -2,14 +2,10 @@ import { Button, FlexWrapper, notify } from '@affine/component';
|
||||
import { openSettingModalAtom } from '@affine/core/atoms';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { EditorService } from '@affine/core/modules/editor';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { AiIcon } from '@blocksuite/icons/rc';
|
||||
import {
|
||||
DocService,
|
||||
useLiveData,
|
||||
useServices,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import { useLiveData, useServices } from '@toeverything/infra';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import Lottie from 'lottie-react';
|
||||
@@ -46,10 +42,9 @@ const EdgelessOnboardingAnimation = () => {
|
||||
};
|
||||
|
||||
export const AIOnboardingEdgeless = () => {
|
||||
const { docService, subscriptionService } = useServices({
|
||||
WorkspaceService,
|
||||
DocService,
|
||||
const { subscriptionService, editorService } = useServices({
|
||||
SubscriptionService,
|
||||
EditorService,
|
||||
});
|
||||
|
||||
const t = useI18n();
|
||||
@@ -61,8 +56,7 @@ export const AIOnboardingEdgeless = () => {
|
||||
|
||||
const setSettingModal = useSetAtom(openSettingModalAtom);
|
||||
|
||||
const doc = docService.doc;
|
||||
const mode = useLiveData(doc.mode$);
|
||||
const mode = useLiveData(editorService.editor.mode$);
|
||||
|
||||
const goToPricingPlans = useCallback(() => {
|
||||
track.$.aiOnboarding.dialog.viewPlans();
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Modal, useConfirmModal } from '@affine/component/ui/modal';
|
||||
import { openSettingModalAtom } from '@affine/core/atoms';
|
||||
import { useDocCollectionPageTitle } from '@affine/core/hooks/use-block-suite-workspace-page-title';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { EditorService } from '@affine/core/modules/editor';
|
||||
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
||||
import { i18nTime, Trans, useI18n } from '@affine/i18n';
|
||||
@@ -14,7 +15,6 @@ import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import type { DialogContentProps } from '@radix-ui/react-dialog';
|
||||
import {
|
||||
type DocMode,
|
||||
DocService,
|
||||
useLiveData,
|
||||
useService,
|
||||
WorkspaceService,
|
||||
@@ -433,8 +433,8 @@ const PageHistoryManager = ({
|
||||
[activeVersion, onClose, onRestore, snapshotPage]
|
||||
);
|
||||
|
||||
const doc = useService(DocService).doc;
|
||||
const [mode, setMode] = useState<DocMode>(doc.mode$.value);
|
||||
const editor = useService(EditorService).editor;
|
||||
const [mode, setMode] = useState<DocMode>(editor.mode$.value);
|
||||
|
||||
const title = useDocCollectionPageTitle(docCollection, pageId);
|
||||
|
||||
|
||||
+3
-10
@@ -5,12 +5,7 @@ import {
|
||||
Scrollable,
|
||||
} from '@affine/component';
|
||||
import { DocsSearchService } from '@affine/core/modules/docs-search';
|
||||
import {
|
||||
LiveData,
|
||||
useLiveData,
|
||||
useServices,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import { LiveData, useLiveData, useServices } from '@toeverything/infra';
|
||||
import { Suspense, useCallback, useContext, useMemo, useRef } from 'react';
|
||||
|
||||
import { BlocksuiteHeaderTitle } from '../../../blocksuite/block-suite-header/title';
|
||||
@@ -35,9 +30,8 @@ export const InfoModal = ({
|
||||
onOpenChange: (open: boolean) => void;
|
||||
docId: string;
|
||||
}) => {
|
||||
const { docsSearchService, workspaceService } = useServices({
|
||||
const { docsSearchService } = useServices({
|
||||
DocsSearchService,
|
||||
WorkspaceService,
|
||||
});
|
||||
const titleInputHandleRef = useRef<InlineEditHandle>(null);
|
||||
const manager = usePagePropertiesManager(docId);
|
||||
@@ -72,10 +66,9 @@ export const InfoModal = ({
|
||||
>
|
||||
<div className={styles.titleContainer} data-testid="info-modal-title">
|
||||
<BlocksuiteHeaderTitle
|
||||
docId={docId}
|
||||
className={styles.titleStyle}
|
||||
inputHandleRef={titleInputHandleRef}
|
||||
pageId={docId}
|
||||
docCollection={workspaceService.workspace.docCollection}
|
||||
/>
|
||||
</div>
|
||||
<managerContext.Provider value={manager}>
|
||||
|
||||
@@ -84,10 +84,17 @@ export function AffinePageReference({
|
||||
const t = useI18n();
|
||||
|
||||
const docsService = useService(DocsService);
|
||||
const mode$ = LiveData.from(docsService.list.observeMode(pageId), undefined);
|
||||
const docMode = useLiveData(mode$) ?? null;
|
||||
const docPrimaryMode = useLiveData(
|
||||
LiveData.computed(get => {
|
||||
const primaryMode$ = get(docsService.list.doc$(pageId))?.primaryMode$;
|
||||
if (!primaryMode$) {
|
||||
return null;
|
||||
}
|
||||
return get(primaryMode$);
|
||||
})
|
||||
);
|
||||
const el = pageReferenceRenderer({
|
||||
docMode,
|
||||
docMode: docPrimaryMode,
|
||||
pageId,
|
||||
pageMetaHelper,
|
||||
journalHelper,
|
||||
|
||||
+4
-3
@@ -3,10 +3,11 @@ import { Divider } from '@affine/component/ui/divider';
|
||||
import { ExportMenuItems } from '@affine/core/components/page-list';
|
||||
import { useExportPage } from '@affine/core/hooks/affine/use-export-page';
|
||||
import { useSharingUrl } from '@affine/core/hooks/affine/use-share-url';
|
||||
import { EditorService } from '@affine/core/modules/editor';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { CopyIcon } from '@blocksuite/icons/rc';
|
||||
import { DocService, useLiveData, useService } from '@toeverything/infra';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
|
||||
import * as styles from './index.css';
|
||||
import type { ShareMenuProps } from './share-menu';
|
||||
@@ -16,7 +17,7 @@ export const ShareExport = ({
|
||||
currentPage,
|
||||
}: ShareMenuProps) => {
|
||||
const t = useI18n();
|
||||
const doc = useService(DocService).doc;
|
||||
const editor = useService(EditorService).editor;
|
||||
const workspaceId = workspace.id;
|
||||
const pageId = currentPage.id;
|
||||
const { sharingUrl, onClickCopyLink } = useSharingUrl({
|
||||
@@ -25,7 +26,7 @@ export const ShareExport = ({
|
||||
urlType: 'workspace',
|
||||
});
|
||||
const exportHandler = useExportPage(currentPage);
|
||||
const currentMode = useLiveData(doc.mode$);
|
||||
const currentMode = useLiveData(editor.mode$);
|
||||
const isMac = environment.isBrowser && environment.isMacOs;
|
||||
|
||||
return (
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ export const AffineSharePage = (props: ShareMenuProps) => {
|
||||
isSharedPage === null || sharedMode === null || baseUrl === null;
|
||||
const [showDisable, setShowDisable] = useState(false);
|
||||
|
||||
const currentDocMode = useLiveData(doc.mode$);
|
||||
const currentDocMode = useLiveData(doc.primaryMode$);
|
||||
|
||||
const mode = useMemo(() => {
|
||||
if (isSharedPage && sharedMode) {
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ export function createLinkedWidgetConfig(framework: FrameworkProvider) {
|
||||
const MAX_DOCS = 6;
|
||||
const docsService = framework.get(DocsService);
|
||||
const isEdgeless = (d: DocMeta) =>
|
||||
docsService.list.getMode(d.id) === 'edgeless';
|
||||
docsService.list.getPrimaryMode(d.id) === 'edgeless';
|
||||
return Promise.resolve([
|
||||
{
|
||||
name: 'Link to Doc',
|
||||
|
||||
+9
-9
@@ -279,28 +279,28 @@ export function patchDocModeService(
|
||||
pageService.docModeService = {
|
||||
setMode: (mode: DocMode, id?: string) => {
|
||||
if (id) {
|
||||
docsService.list.setMode(id, mode);
|
||||
docsService.list.setPrimaryMode(id, mode);
|
||||
} else {
|
||||
docService.doc.setMode(mode);
|
||||
docService.doc.setPrimaryMode(mode);
|
||||
}
|
||||
},
|
||||
getMode: (id?: string) => {
|
||||
const mode = id
|
||||
? docsService.list.getMode(id)
|
||||
: docService.doc.getMode();
|
||||
? docsService.list.getPrimaryMode(id)
|
||||
: docService.doc.getPrimaryMode();
|
||||
return mode || DEFAULT_MODE;
|
||||
},
|
||||
toggleMode: (id?: string) => {
|
||||
const mode = id
|
||||
? docsService.list.toggleMode(id)
|
||||
: docService.doc.toggleMode();
|
||||
? docsService.list.togglePrimaryMode(id)
|
||||
: docService.doc.togglePrimaryMode();
|
||||
return mode || DEFAULT_MODE;
|
||||
},
|
||||
onModeChange: (handler: (mode: DocMode) => void, id?: string) => {
|
||||
// eslint-disable-next-line rxjs/finnish
|
||||
const mode$ = id
|
||||
? docsService.list.observeMode(id)
|
||||
: docService.doc.observeMode();
|
||||
? docsService.list.primaryMode$(id)
|
||||
: docService.doc.primaryMode$;
|
||||
const sub = mode$.subscribe(m => handler(m || DEFAULT_MODE));
|
||||
return {
|
||||
dispose: sub.unsubscribe,
|
||||
@@ -412,7 +412,7 @@ export function patchQuickSearchService(
|
||||
? 'edgeless'
|
||||
: 'page';
|
||||
const newDoc = docsService.createDoc({
|
||||
mode,
|
||||
primaryMode: mode,
|
||||
title: result.payload.title,
|
||||
});
|
||||
resolve({
|
||||
|
||||
+12
-14
@@ -19,6 +19,7 @@ import { useExportPage } from '@affine/core/hooks/affine/use-export-page';
|
||||
import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { EditorService } from '@affine/core/modules/editor';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { ViewService } from '@affine/core/modules/workbench/services/view';
|
||||
import { useDetailPageHeaderResponsive } from '@affine/core/pages/workspace/detail-page/use-header-responsive';
|
||||
@@ -41,12 +42,7 @@ import {
|
||||
TocIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import type { Doc } from '@blocksuite/store';
|
||||
import {
|
||||
DocService,
|
||||
useLiveData,
|
||||
useService,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
@@ -75,9 +71,11 @@ export const PageHeaderMenuButton = ({
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const docCollection = workspace.docCollection;
|
||||
|
||||
const doc = useService(DocService).doc;
|
||||
const isInTrash = useLiveData(doc.meta$.map(m => m.trash));
|
||||
const currentMode = useLiveData(doc.mode$);
|
||||
const editorService = useService(EditorService);
|
||||
const isInTrash = useLiveData(
|
||||
editorService.editor.doc.meta$.map(meta => meta.trash)
|
||||
);
|
||||
const currentMode = useLiveData(editorService.editor.mode$);
|
||||
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
|
||||
@@ -139,9 +137,9 @@ export const PageHeaderMenuButton = ({
|
||||
setTrashModal({
|
||||
open: true,
|
||||
pageIds: [pageId],
|
||||
pageTitles: [doc.meta$.value.title ?? ''],
|
||||
pageTitles: [editorService.editor.doc.meta$.value.title ?? ''],
|
||||
});
|
||||
}, [doc.meta$.value.title, pageId, setTrashModal]);
|
||||
}, [editorService, pageId, setTrashModal]);
|
||||
|
||||
const handleRename = useCallback(() => {
|
||||
rename?.();
|
||||
@@ -149,7 +147,7 @@ export const PageHeaderMenuButton = ({
|
||||
}, [rename]);
|
||||
|
||||
const handleSwitchMode = useCallback(() => {
|
||||
doc.toggleMode();
|
||||
editorService.editor.toggleMode();
|
||||
track.$.header.docOptions.switchPageMode({
|
||||
mode: currentMode === 'page' ? 'edgeless' : 'page',
|
||||
});
|
||||
@@ -158,7 +156,7 @@ export const PageHeaderMenuButton = ({
|
||||
? t['com.affine.toastMessage.edgelessMode']()
|
||||
: t['com.affine.toastMessage.pageMode']()
|
||||
);
|
||||
}, [currentMode, doc, t]);
|
||||
}, [currentMode, editorService, t]);
|
||||
const menuItemStyle = {
|
||||
padding: '4px 12px',
|
||||
transition: 'all 0.3s',
|
||||
@@ -170,7 +168,7 @@ export const PageHeaderMenuButton = ({
|
||||
}
|
||||
}, []);
|
||||
|
||||
const exportHandler = useExportPage(doc.blockSuiteDoc);
|
||||
const exportHandler = useExportPage(editorService.editor.doc.blockSuiteDoc);
|
||||
|
||||
const handleDuplicate = useCallback(() => {
|
||||
duplicate(pageId);
|
||||
|
||||
+22
-23
@@ -1,53 +1,52 @@
|
||||
import type { InlineEditProps } from '@affine/component';
|
||||
import { InlineEdit } from '@affine/component';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import {
|
||||
useBlockSuiteDocMeta,
|
||||
useDocMetaHelper,
|
||||
} from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import type { DocCollection } from '@affine/core/shared';
|
||||
DocsService,
|
||||
useLiveData,
|
||||
useService,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import * as styles from './style.css';
|
||||
|
||||
export interface BlockSuiteHeaderTitleProps {
|
||||
docCollection: DocCollection;
|
||||
pageId: string;
|
||||
docId: string;
|
||||
/** if set, title cannot be edited */
|
||||
isPublic?: boolean;
|
||||
inputHandleRef?: InlineEditProps['handleRef'];
|
||||
className?: string;
|
||||
onEditSave?: () => void;
|
||||
}
|
||||
|
||||
const inputAttrs = {
|
||||
'data-testid': 'title-content',
|
||||
} as HTMLAttributes<HTMLInputElement>;
|
||||
export const BlocksuiteHeaderTitle = (props: BlockSuiteHeaderTitleProps) => {
|
||||
const { docCollection, pageId, isPublic, inputHandleRef, onEditSave } = props;
|
||||
const currentPage = docCollection.getDoc(pageId);
|
||||
const pageMeta = useBlockSuiteDocMeta(docCollection).find(
|
||||
meta => meta.id === currentPage?.id
|
||||
);
|
||||
const title = pageMeta?.title;
|
||||
const { setDocTitle } = useDocMetaHelper(docCollection);
|
||||
const { inputHandleRef, docId } = props;
|
||||
const workspaceService = useService(WorkspaceService);
|
||||
const isSharedMode = workspaceService.workspace.openOptions.isSharedMode;
|
||||
const docsService = useService(DocsService);
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: string) => {
|
||||
onEditSave?.();
|
||||
setDocTitle(currentPage?.id || '', v);
|
||||
const docRecord = useLiveData(docsService.list.doc$(docId));
|
||||
const docTitle = useLiveData(docRecord?.title$);
|
||||
|
||||
const onChange = useAsyncCallback(
|
||||
async (v: string) => {
|
||||
await docsService.changeDocTitle(docId, v);
|
||||
track.$.header.actions.renameDoc();
|
||||
},
|
||||
[currentPage?.id, onEditSave, setDocTitle]
|
||||
[docId, docsService]
|
||||
);
|
||||
|
||||
return (
|
||||
<InlineEdit
|
||||
className={clsx(styles.title, props.className)}
|
||||
autoSelect
|
||||
value={title}
|
||||
value={docTitle}
|
||||
onChange={onChange}
|
||||
editable={!isPublic}
|
||||
editable={!isSharedMode}
|
||||
exitible={true}
|
||||
placeholder="Untitled"
|
||||
data-testid="title-edit-button"
|
||||
|
||||
+21
-28
@@ -1,14 +1,10 @@
|
||||
import { RadioGroup, type RadioItem, toast, Tooltip } from '@affine/component';
|
||||
import { registerAffineCommand } from '@affine/core/commands';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { EditorService } from '@affine/core/modules/editor';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { EdgelessIcon, PageIcon } from '@blocksuite/icons/rc';
|
||||
import {
|
||||
type DocMode,
|
||||
DocsService,
|
||||
useLiveData,
|
||||
useService,
|
||||
} from '@toeverything/infra';
|
||||
import { type DocMode, useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
|
||||
import { switchItem } from './style.css';
|
||||
@@ -33,30 +29,28 @@ const PageRadioItem: RadioItem = {
|
||||
className: switchItem,
|
||||
};
|
||||
|
||||
export const EditorModeSwitch = ({
|
||||
pageId,
|
||||
isPublic,
|
||||
publicMode,
|
||||
}: EditorModeSwitchProps) => {
|
||||
export const EditorModeSwitch = () => {
|
||||
const t = useI18n();
|
||||
const docsService = useService(DocsService);
|
||||
const doc = useLiveData(docsService.list.doc$(pageId));
|
||||
const trash = useLiveData(doc?.trash$);
|
||||
const currentMode = useLiveData(doc?.mode$);
|
||||
const editor = useService(EditorService).editor;
|
||||
const trash = useLiveData(editor.doc.trash$);
|
||||
const isSharedMode = editor.isSharedMode;
|
||||
const currentMode = useLiveData(editor.mode$);
|
||||
|
||||
const togglePage = useCallback(() => {
|
||||
if (currentMode === 'page' || isPublic || trash) return;
|
||||
doc?.setMode('page');
|
||||
if (currentMode === 'page' || isSharedMode || trash) return;
|
||||
editor.setMode('page');
|
||||
editor.doc.setPrimaryMode('page');
|
||||
toast(t['com.affine.toastMessage.pageMode']());
|
||||
track.$.header.actions.switchPageMode({ mode: 'page' });
|
||||
}, [currentMode, doc, isPublic, t, trash]);
|
||||
}, [currentMode, editor, isSharedMode, t, trash]);
|
||||
|
||||
const toggleEdgeless = useCallback(() => {
|
||||
if (currentMode === 'edgeless' || isPublic || trash) return;
|
||||
doc?.setMode('edgeless');
|
||||
if (currentMode === 'edgeless' || isSharedMode || trash) return;
|
||||
editor.setMode('edgeless');
|
||||
editor.doc.setPrimaryMode('edgeless');
|
||||
toast(t['com.affine.toastMessage.edgelessMode']());
|
||||
track.$.header.actions.switchPageMode({ mode: 'edgeless' });
|
||||
}, [currentMode, doc, isPublic, t, trash]);
|
||||
}, [currentMode, editor, isSharedMode, t, trash]);
|
||||
|
||||
const onModeChange = useCallback(
|
||||
(mode: DocMode) => {
|
||||
@@ -66,13 +60,12 @@ export const EditorModeSwitch = ({
|
||||
);
|
||||
|
||||
const shouldHide = useCallback(
|
||||
(mode: DocMode) =>
|
||||
(trash && currentMode !== mode) || (isPublic && publicMode !== mode),
|
||||
[currentMode, isPublic, publicMode, trash]
|
||||
(mode: DocMode) => (trash || isSharedMode) && currentMode !== mode,
|
||||
[currentMode, isSharedMode, trash]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (trash || isPublic || currentMode === undefined) return;
|
||||
if (trash || isSharedMode || currentMode === undefined) return;
|
||||
return registerAffineCommand({
|
||||
id: 'affine:doc-mode-switch',
|
||||
category: 'editor:page',
|
||||
@@ -87,14 +80,14 @@ export const EditorModeSwitch = ({
|
||||
},
|
||||
run: () => onModeChange(currentMode === 'edgeless' ? 'page' : 'edgeless'),
|
||||
});
|
||||
}, [currentMode, isPublic, onModeChange, t, trash]);
|
||||
}, [currentMode, isSharedMode, onModeChange, t, trash]);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={t['Switch']()}
|
||||
shortcut={['$alt', 'S']}
|
||||
side="bottom"
|
||||
options={{ hidden: isPublic || trash }}
|
||||
options={{ hidden: trash || isSharedMode }}
|
||||
>
|
||||
<div>
|
||||
<PureEditorModeSwitch
|
||||
@@ -110,7 +103,7 @@ export const EditorModeSwitch = ({
|
||||
|
||||
export interface PureEditorModeSwitchProps {
|
||||
mode?: DocMode;
|
||||
setMode: (mode: DocMode) => void;
|
||||
setMode?: (mode: DocMode) => void;
|
||||
hidePage?: boolean;
|
||||
hideEdgeless?: boolean;
|
||||
}
|
||||
|
||||
@@ -9,19 +9,14 @@ import type { DocCollection } from '../../../shared';
|
||||
export const usePageHelper = (docCollection: DocCollection) => {
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
const { createDoc } = useDocCollectionHelper(docCollection);
|
||||
const docRecordList = useService(DocsService).list;
|
||||
|
||||
const isPreferredEdgeless = useCallback(
|
||||
(pageId: string) =>
|
||||
docRecordList.doc$(pageId).value?.mode$.value === 'edgeless',
|
||||
[docRecordList]
|
||||
);
|
||||
const docsService = useService(DocsService);
|
||||
const docRecordList = docsService.list;
|
||||
|
||||
const createPageAndOpen = useCallback(
|
||||
(mode?: 'page' | 'edgeless', open?: boolean | 'new-tab') => {
|
||||
const page = createDoc();
|
||||
initEmptyPage(page);
|
||||
docRecordList.doc$(page.id).value?.setMode(mode || 'page');
|
||||
docRecordList.doc$(page.id).value?.setPrimaryMode(mode || 'page');
|
||||
if (open !== false)
|
||||
workbench.openDoc(page.id, {
|
||||
at: open === 'new-tab' ? 'new-tab' : 'active',
|
||||
@@ -82,16 +77,10 @@ export const usePageHelper = (docCollection: DocCollection) => {
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
isPreferredEdgeless,
|
||||
createPage: (open?: boolean | 'new-tab') =>
|
||||
createPageAndOpen('page', open),
|
||||
createEdgeless: createEdgelessAndOpen,
|
||||
importFile: importFileAndOpen,
|
||||
};
|
||||
}, [
|
||||
isPreferredEdgeless,
|
||||
createEdgelessAndOpen,
|
||||
createPageAndOpen,
|
||||
importFileAndOpen,
|
||||
]);
|
||||
}, [createEdgelessAndOpen, createPageAndOpen, importFileAndOpen]);
|
||||
};
|
||||
|
||||
@@ -6,7 +6,6 @@ import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||
import type { Doc as BlockSuiteDoc, DocCollection } from '@blocksuite/store';
|
||||
import {
|
||||
type DocMode,
|
||||
DocService,
|
||||
fontStyleOptions,
|
||||
useLiveData,
|
||||
useService,
|
||||
@@ -17,6 +16,7 @@ import { memo, Suspense, useCallback, useMemo } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { useAppSettingHelper } from '../hooks/affine/use-app-setting-helper';
|
||||
import { EditorService } from '../modules/editor';
|
||||
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
|
||||
import * as styles from './page-detail-editor.css';
|
||||
|
||||
@@ -45,19 +45,10 @@ function useRouterHash() {
|
||||
const PageDetailEditorMain = memo(function PageDetailEditorMain({
|
||||
page,
|
||||
onLoad,
|
||||
isPublic,
|
||||
publishMode,
|
||||
}: PageDetailEditorProps & { page: BlockSuiteDoc }) {
|
||||
const currentMode = useLiveData(useService(DocService).doc.mode$);
|
||||
const mode = useMemo(() => {
|
||||
const shareMode = publishMode || currentMode;
|
||||
|
||||
if (isPublic) {
|
||||
return shareMode;
|
||||
}
|
||||
return currentMode;
|
||||
}, [isPublic, publishMode, currentMode]);
|
||||
|
||||
const editor = useService(EditorService).editor;
|
||||
const mode = useLiveData(editor.mode$);
|
||||
const isSharedMode = editor.isSharedMode;
|
||||
const { appSettings } = useAppSettingHelper();
|
||||
|
||||
const value = useMemo(() => {
|
||||
@@ -97,8 +88,8 @@ const PageDetailEditorMain = memo(function PageDetailEditorMain({
|
||||
return (
|
||||
<Editor
|
||||
className={clsx(styles.editor, {
|
||||
'full-screen': !isPublic && appSettings.fullWidthLayout,
|
||||
'is-public': isPublic,
|
||||
'full-screen': !isSharedMode && appSettings.fullWidthLayout,
|
||||
'is-public': isSharedMode,
|
||||
})}
|
||||
style={
|
||||
{
|
||||
@@ -107,7 +98,7 @@ const PageDetailEditorMain = memo(function PageDetailEditorMain({
|
||||
}
|
||||
mode={mode}
|
||||
page={page}
|
||||
shared={isPublic}
|
||||
shared={isSharedMode}
|
||||
defaultSelectedBlockId={blockId}
|
||||
onLoadEditor={onLoadEditor}
|
||||
/>
|
||||
|
||||
@@ -9,7 +9,6 @@ import type { DocMeta } from '@blocksuite/store';
|
||||
import { useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { usePageHelper } from '../../blocksuite/block-suite-page-list/utils';
|
||||
import { ListFloatingToolbar } from '../components/list-floating-toolbar';
|
||||
import { usePageItemGroupDefinitions } from '../group-definitions';
|
||||
import { usePageHeaderColsDef } from '../header-col-def';
|
||||
@@ -69,7 +68,6 @@ export const VirtualizedPageList = ({
|
||||
const currentWorkspace = useService(WorkspaceService).workspace;
|
||||
const pageMetas = useBlockSuiteDocMeta(currentWorkspace.docCollection);
|
||||
const pageOperations = usePageOperationsRenderer();
|
||||
const { isPreferredEdgeless } = usePageHelper(currentWorkspace.docCollection);
|
||||
const pageHeaderColsDef = usePageHeaderColsDef();
|
||||
|
||||
const filteredPageMetas = useFilteredPageMetas(pageMetas, {
|
||||
@@ -162,7 +160,6 @@ export const VirtualizedPageList = ({
|
||||
onSelectedIdsChange={setSelectedPageIds}
|
||||
items={pageMetasToRender}
|
||||
rowAsLink
|
||||
isPreferredEdgeless={isPreferredEdgeless}
|
||||
docCollection={currentWorkspace.docCollection}
|
||||
operationsRenderer={pageOperationRenderer}
|
||||
itemRenderer={pageItemRenderer}
|
||||
|
||||
@@ -201,7 +201,6 @@ export const ItemGroup = <T extends ListItem>({
|
||||
const requiredPropNames = [
|
||||
'docCollection',
|
||||
'rowAsLink',
|
||||
'isPreferredEdgeless',
|
||||
'operationsRenderer',
|
||||
'selectedIds',
|
||||
'onSelectedIdsChange',
|
||||
@@ -294,13 +293,12 @@ const PageTitle = ({ id }: { id: string }) => {
|
||||
const UnifiedPageIcon = ({
|
||||
id,
|
||||
docCollection,
|
||||
isPreferredEdgeless,
|
||||
}: {
|
||||
id: string;
|
||||
docCollection: DocCollection;
|
||||
isPreferredEdgeless?: (id: string) => boolean;
|
||||
}) => {
|
||||
const isEdgeless = isPreferredEdgeless ? isPreferredEdgeless(id) : false;
|
||||
const list = useService(DocsService).list;
|
||||
const isEdgeless = useLiveData(list.primaryMode$(id)) === 'edgeless';
|
||||
const { isJournal } = useJournalInfoHelper(docCollection, id);
|
||||
if (isJournal) {
|
||||
return <TodayIcon />;
|
||||
@@ -340,13 +338,7 @@ function pageMetaToListItemProp(
|
||||
updatedDate: item.updatedDate ? new Date(item.updatedDate) : undefined,
|
||||
to: props.rowAsLink && !props.selectable ? `/${item.id}` : undefined,
|
||||
onClick: toggleSelection,
|
||||
icon: (
|
||||
<UnifiedPageIcon
|
||||
id={item.id}
|
||||
docCollection={props.docCollection}
|
||||
isPreferredEdgeless={props.isPreferredEdgeless}
|
||||
/>
|
||||
),
|
||||
icon: <UnifiedPageIcon id={item.id} docCollection={props.docCollection} />,
|
||||
tags:
|
||||
item.tags
|
||||
?.map(id => tagIdToTagOption(id, props.docCollection))
|
||||
|
||||
@@ -95,7 +95,6 @@ export interface ListProps<T> {
|
||||
className?: string;
|
||||
hideHeader?: boolean; // whether or not to hide the header. default is false (showing header)
|
||||
groupBy?: ItemGroupDefinition<T>[];
|
||||
isPreferredEdgeless?: (pageId: string) => boolean; // determines the icon used for each row
|
||||
rowAsLink?: boolean;
|
||||
selectable?: 'toggle' | boolean; // show selection checkbox. toggle means showing a toggle selection in header on click; boolean == true means showing a selection checkbox for each item
|
||||
selectedIds?: string[]; // selected page ids
|
||||
|
||||
-1
@@ -192,7 +192,6 @@ export const EditCollection = ({
|
||||
export type AllPageListConfig = {
|
||||
allPages: DocMeta[];
|
||||
docCollection: DocCollection;
|
||||
isEdgeless: (id: string) => boolean;
|
||||
/**
|
||||
* Return `undefined` if the page is not public
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
ToggleCollapseIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { DocsService, useLiveData, useService } from '@toeverything/infra';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import clsx from 'clsx';
|
||||
import type { ReactNode } from 'react';
|
||||
@@ -42,6 +42,7 @@ export const RulesMode = ({
|
||||
const [showPreview, setShowPreview] = useState(true);
|
||||
const allowListPages: DocMeta[] = [];
|
||||
const rulesPages: DocMeta[] = [];
|
||||
const docsService = useService(DocsService);
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
const favorites = useLiveData(favAdapter.favorites$);
|
||||
allPageListConfig.allPages.forEach(meta => {
|
||||
@@ -158,7 +159,8 @@ export const RulesMode = ({
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{allPageListConfig.isEdgeless(id) ? (
|
||||
{docsService.list.getPrimaryMode(id) ===
|
||||
'edgeless' ? (
|
||||
<EdgelessIcon style={{ width: 16, height: 16 }} />
|
||||
) : (
|
||||
<PageIcon style={{ width: 16, height: 16 }} />
|
||||
@@ -211,7 +213,6 @@ export const RulesMode = ({
|
||||
className={styles.resultPages}
|
||||
items={rulesPages}
|
||||
docCollection={allPageListConfig.docCollection}
|
||||
isPreferredEdgeless={allPageListConfig.isEdgeless}
|
||||
operationsRenderer={operationsRenderer}
|
||||
></List>
|
||||
) : (
|
||||
@@ -230,7 +231,6 @@ export const RulesMode = ({
|
||||
className={styles.resultPages}
|
||||
items={allowListPages}
|
||||
docCollection={allPageListConfig.docCollection}
|
||||
isPreferredEdgeless={allPageListConfig.isEdgeless}
|
||||
operationsRenderer={operationsRenderer}
|
||||
></List>
|
||||
</div>
|
||||
|
||||
+6
-20
@@ -7,7 +7,6 @@ import { Trans, useI18n } from '@affine/i18n';
|
||||
import { FilterIcon } from '@blocksuite/icons/rc';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import {
|
||||
DocsService,
|
||||
useLiveData,
|
||||
useServices,
|
||||
WorkspaceService,
|
||||
@@ -57,17 +56,12 @@ export const SelectPage = ({
|
||||
const clearSelected = useCallback(() => {
|
||||
onChange([]);
|
||||
}, [onChange]);
|
||||
const {
|
||||
workspaceService,
|
||||
compatibleFavoriteItemsAdapter,
|
||||
shareDocsService,
|
||||
docsService,
|
||||
} = useServices({
|
||||
DocsService,
|
||||
ShareDocsService,
|
||||
WorkspaceService,
|
||||
CompatibleFavoriteItemsAdapter,
|
||||
});
|
||||
const { workspaceService, compatibleFavoriteItemsAdapter, shareDocsService } =
|
||||
useServices({
|
||||
ShareDocsService,
|
||||
WorkspaceService,
|
||||
CompatibleFavoriteItemsAdapter,
|
||||
});
|
||||
const shareDocs = useLiveData(shareDocsService.shareDocs?.list$);
|
||||
const workspace = workspaceService.workspace;
|
||||
const docCollection = workspace.docCollection;
|
||||
@@ -97,13 +91,6 @@ export const SelectPage = ({
|
||||
[favourites]
|
||||
);
|
||||
|
||||
const isEdgeless = useCallback(
|
||||
(id: string) => {
|
||||
return docsService.list.doc$(id).value?.mode$.value === 'edgeless';
|
||||
},
|
||||
[docsService.list]
|
||||
);
|
||||
|
||||
const onToggleFavoritePage = useCallback(
|
||||
(page: DocMeta) => {
|
||||
const status = isFavorite(page);
|
||||
@@ -207,7 +194,6 @@ export const SelectPage = ({
|
||||
selectable
|
||||
onSelectedIdsChange={onChange}
|
||||
selectedIds={value}
|
||||
isPreferredEdgeless={isEdgeless}
|
||||
operationsRenderer={operationsRenderer}
|
||||
itemRenderer={pageItemRenderer}
|
||||
headerRenderer={pageHeaderRenderer}
|
||||
|
||||
@@ -6,7 +6,6 @@ import type { DocMeta } from '@blocksuite/store';
|
||||
import { useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { usePageHelper } from '../blocksuite/block-suite-page-list/utils';
|
||||
import { ListFloatingToolbar } from './components/list-floating-toolbar';
|
||||
import { usePageHeaderColsDef } from './header-col-def';
|
||||
import { TrashOperationCell } from './operation-cell';
|
||||
@@ -26,8 +25,6 @@ export const VirtualizedTrashList = () => {
|
||||
trash: true,
|
||||
});
|
||||
|
||||
const { isPreferredEdgeless } = usePageHelper(docCollection);
|
||||
|
||||
const listRef = useRef<ItemListHandle>(null);
|
||||
const [showFloatingToolbar, setShowFloatingToolbar] = useState(false);
|
||||
const [selectedPageIds, setSelectedPageIds] = useState<string[]>([]);
|
||||
@@ -121,7 +118,6 @@ export const VirtualizedTrashList = () => {
|
||||
selectable="toggle"
|
||||
items={filteredPageMetas}
|
||||
rowAsLink
|
||||
isPreferredEdgeless={isPreferredEdgeless}
|
||||
onSelectionActiveChange={setShowFloatingToolbar}
|
||||
docCollection={currentWorkspace.docCollection}
|
||||
operationsRenderer={pageOperationsRenderer}
|
||||
|
||||
@@ -3,10 +3,9 @@ import { popupWindow } from '@affine/core/utils';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { CloseIcon, NewIcon } from '@blocksuite/icons/rc';
|
||||
import {
|
||||
DocsService,
|
||||
GlobalContextService,
|
||||
useLiveData,
|
||||
useService,
|
||||
useServices,
|
||||
} from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai/react';
|
||||
import { useCallback, useState } from 'react';
|
||||
@@ -33,12 +32,11 @@ type IslandItemNames = 'whatNew' | 'contact' | 'shortcuts';
|
||||
const showList = environment.isDesktop ? DESKTOP_SHOW_LIST : DEFAULT_SHOW_LIST;
|
||||
|
||||
export const HelpIsland = () => {
|
||||
const docId = useLiveData(
|
||||
useService(GlobalContextService).globalContext.docId.$
|
||||
);
|
||||
const docRecordList = useService(DocsService).list;
|
||||
const doc = useLiveData(docId ? docRecordList.doc$(docId) : undefined);
|
||||
const mode = useLiveData(doc?.mode$);
|
||||
const { globalContextService } = useServices({
|
||||
GlobalContextService,
|
||||
});
|
||||
const docId = useLiveData(globalContextService.globalContext.docId.$);
|
||||
const docMode = useLiveData(globalContextService.globalContext.docMode.$);
|
||||
const setOpenSettingModalAtom = useSetAtom(openSettingModalAtom);
|
||||
const [spread, setShowSpread] = useState(false);
|
||||
const t = useI18n();
|
||||
@@ -69,7 +67,7 @@ export const HelpIsland = () => {
|
||||
onClick={() => {
|
||||
setShowSpread(!spread);
|
||||
}}
|
||||
inEdgelessPage={!!docId && mode === 'edgeless'}
|
||||
inEdgelessPage={!!docId && docMode === 'edgeless'}
|
||||
>
|
||||
<StyledAnimateWrapper
|
||||
style={{ height: spread ? `${showList.length * 40 + 4}px` : 0 }}
|
||||
|
||||
Reference in New Issue
Block a user