mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
refactor(core): desktop project struct (#8334)
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
import { MenuItem, notify } from '@affine/component';
|
||||
import {
|
||||
filterPage,
|
||||
useEditCollection,
|
||||
} from '@affine/core/components/page-list';
|
||||
import { filterPage } from '@affine/core/components/page-list';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||
import type { NodeOperation } from '@affine/core/modules/explorer';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite';
|
||||
import { ShareDocsListService } from '@affine/core/modules/share-doc';
|
||||
@@ -40,11 +38,12 @@ export const ExplorerCollectionNode = ({
|
||||
operations?: NodeOperation[];
|
||||
}) => {
|
||||
const t = useI18n();
|
||||
const { globalContextService, collectionService } = useServices({
|
||||
GlobalContextService,
|
||||
CollectionService,
|
||||
});
|
||||
const { open: openEditCollectionModal } = useEditCollection();
|
||||
const { globalContextService, collectionService, workspaceDialogService } =
|
||||
useServices({
|
||||
GlobalContextService,
|
||||
CollectionService,
|
||||
WorkspaceDialogService,
|
||||
});
|
||||
const active =
|
||||
useLiveData(globalContextService.globalContext.collectionId.$) ===
|
||||
collectionId;
|
||||
@@ -60,17 +59,10 @@ export const ExplorerCollectionNode = ({
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
openEditCollectionModal(collection)
|
||||
.then(collection => {
|
||||
return collectionService.updateCollection(
|
||||
collection.id,
|
||||
() => collection
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}, [collection, collectionService, openEditCollectionModal]);
|
||||
workspaceDialogService.open('collection-editor', {
|
||||
collectionId: collection.id,
|
||||
});
|
||||
}, [collection, workspaceDialogService]);
|
||||
|
||||
const collectionOperations = useExplorerCollectionNodeOperationsMenu(
|
||||
collectionId,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Loading } from '@affine/component';
|
||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||
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 { NodeOperation } from '@affine/core/modules/explorer';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -90,13 +90,13 @@ export const ExplorerDocNode = ({
|
||||
);
|
||||
}, [indexerLoading]);
|
||||
|
||||
const docInfoModal = useService(DocInfoService).modal;
|
||||
const workspaceDialogService = useService(WorkspaceDialogService);
|
||||
const option = useMemo(
|
||||
() => ({
|
||||
openInfoModal: () => docInfoModal.open(docId),
|
||||
openInfoModal: () => workspaceDialogService.open('doc-info', { docId }),
|
||||
openNodeCollapsed: () => setCollapsed(false),
|
||||
}),
|
||||
[docId, docInfoModal]
|
||||
[docId, workspaceDialogService]
|
||||
);
|
||||
const operations = useExplorerDocNodeOperationsMenu(docId, option);
|
||||
const { handleAddLinkedPage } = useExplorerDocNodeOperations(docId, option);
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
notify,
|
||||
} from '@affine/component';
|
||||
import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils';
|
||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||
import type {
|
||||
ExplorerTreeNodeIcon,
|
||||
NodeOperation,
|
||||
@@ -37,11 +38,6 @@ import {
|
||||
import { difference } from 'lodash-es';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import {
|
||||
useSelectCollection,
|
||||
useSelectDoc,
|
||||
useSelectTag,
|
||||
} from '../../../selector';
|
||||
import { AddItemPlaceholder } from '../../layouts/add-item-placeholder';
|
||||
import { ExplorerTreeNode } from '../../tree/node';
|
||||
import { ExplorerCollectionNode } from '../collection';
|
||||
@@ -124,14 +120,13 @@ const ExplorerFolderNodeFolder = ({
|
||||
operations?: NodeOperation[];
|
||||
}) => {
|
||||
const t = useI18n();
|
||||
const { workspaceService, featureFlagService } = useServices({
|
||||
WorkspaceService,
|
||||
CompatibleFavoriteItemsAdapter,
|
||||
FeatureFlagService,
|
||||
});
|
||||
const openDocsSelector = useSelectDoc();
|
||||
const openTagsSelector = useSelectTag();
|
||||
const openCollectionsSelector = useSelectCollection();
|
||||
const { workspaceService, featureFlagService, workspaceDialogService } =
|
||||
useServices({
|
||||
WorkspaceService,
|
||||
CompatibleFavoriteItemsAdapter,
|
||||
FeatureFlagService,
|
||||
WorkspaceDialogService,
|
||||
});
|
||||
const name = useLiveData(node.name$);
|
||||
const enableEmojiIcon = useLiveData(
|
||||
featureFlagService.flags.enable_emoji_folder_icon.$
|
||||
@@ -191,12 +186,19 @@ const ExplorerFolderNodeFolder = ({
|
||||
.filter(Boolean) as string[];
|
||||
const selector =
|
||||
type === 'doc'
|
||||
? openDocsSelector
|
||||
? 'doc-selector'
|
||||
: type === 'collection'
|
||||
? openCollectionsSelector
|
||||
: openTagsSelector;
|
||||
selector(initialIds, { type, where: 'folder' })
|
||||
.then(selectedIds => {
|
||||
? 'collection-selector'
|
||||
: 'tag-selector';
|
||||
workspaceDialogService.open(
|
||||
selector,
|
||||
{
|
||||
init: initialIds,
|
||||
},
|
||||
selectedIds => {
|
||||
if (selectedIds === undefined) {
|
||||
return;
|
||||
}
|
||||
const newItemIds = difference(selectedIds, initialIds);
|
||||
const removedItemIds = difference(initialIds, selectedIds);
|
||||
const removedItems = children.filter(
|
||||
@@ -210,22 +212,14 @@ const ExplorerFolderNodeFolder = ({
|
||||
removedItems.forEach(node => node.delete());
|
||||
const updated = newItemIds.length + removedItems.length;
|
||||
updated && setCollapsed(false);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(`Unexpected error while selecting ${type}`, err);
|
||||
});
|
||||
}
|
||||
);
|
||||
track.$.navigationPanel.organize.createOrganizeItem({
|
||||
type: 'link',
|
||||
target: type,
|
||||
});
|
||||
},
|
||||
[
|
||||
children,
|
||||
node,
|
||||
openCollectionsSelector,
|
||||
openDocsSelector,
|
||||
openTagsSelector,
|
||||
]
|
||||
[children, node, workspaceDialogService]
|
||||
);
|
||||
|
||||
const createSubTipRenderer = useCallback(
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { IconButton, MenuItem, MenuSeparator, toast } from '@affine/component';
|
||||
import {
|
||||
IconButton,
|
||||
MenuItem,
|
||||
MenuSeparator,
|
||||
toast,
|
||||
useConfirmModal,
|
||||
} from '@affine/component';
|
||||
import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils';
|
||||
import { IsFavoriteIcon } from '@affine/core/components/pure/icons';
|
||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||
import type { NodeOperation } from '@affine/core/modules/explorer';
|
||||
import { FavoriteService } from '@affine/core/modules/favorite';
|
||||
import { TagService } from '@affine/core/modules/tag';
|
||||
@@ -16,6 +23,7 @@ import {
|
||||
import {
|
||||
DocsService,
|
||||
FeatureFlagService,
|
||||
GlobalCacheService,
|
||||
useLiveData,
|
||||
useService,
|
||||
useServices,
|
||||
@@ -23,7 +31,6 @@ import {
|
||||
} from '@toeverything/infra';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { useSelectDoc } from '../../../selector';
|
||||
import { TagRenameSubMenu } from './dialog';
|
||||
|
||||
export const useExplorerTagNodeOperations = (
|
||||
@@ -35,15 +42,23 @@ export const useExplorerTagNodeOperations = (
|
||||
}
|
||||
) => {
|
||||
const t = useI18n();
|
||||
const openDocSelector = useSelectDoc();
|
||||
const { workbenchService, workspaceService, tagService, favoriteService } =
|
||||
useServices({
|
||||
WorkbenchService,
|
||||
WorkspaceService,
|
||||
TagService,
|
||||
DocsService,
|
||||
FavoriteService,
|
||||
});
|
||||
const {
|
||||
workbenchService,
|
||||
workspaceService,
|
||||
tagService,
|
||||
favoriteService,
|
||||
workspaceDialogService,
|
||||
globalCacheService,
|
||||
} = useServices({
|
||||
WorkbenchService,
|
||||
WorkspaceService,
|
||||
TagService,
|
||||
DocsService,
|
||||
FavoriteService,
|
||||
WorkspaceDialogService,
|
||||
GlobalCacheService,
|
||||
});
|
||||
const { openConfirmModal } = useConfirmModal();
|
||||
|
||||
const favorite = useLiveData(
|
||||
favoriteService.favoriteList.favorite$('tag', tagId)
|
||||
@@ -122,15 +137,57 @@ export const useExplorerTagNodeOperations = (
|
||||
);
|
||||
const handleOpenDocSelector = useCallback(() => {
|
||||
const initialIds = tagRecord?.pageIds$.value;
|
||||
openDocSelector(initialIds, { where: 'tag', type: 'doc' })
|
||||
.then(selectedIds => {
|
||||
workspaceDialogService.open(
|
||||
'doc-selector',
|
||||
{
|
||||
init: initialIds ?? [],
|
||||
onBeforeConfirm(ids, cb) {
|
||||
const hasRemoved = initialIds?.some(id => !ids?.includes(id));
|
||||
if (
|
||||
hasRemoved &&
|
||||
globalCacheService.globalCache.get(
|
||||
'mobile:tags:will-be-removed-warning-read'
|
||||
) !== true
|
||||
) {
|
||||
openConfirmModal({
|
||||
title: t['com.affine.m.selector.remove-warning.title'](),
|
||||
description: t['com.affine.m.selector.remove-warning.message']({
|
||||
type: t['com.affine.m.selector.type-doc'](),
|
||||
where: t['com.affine.m.selector.where-tag'](),
|
||||
}),
|
||||
cancelText: t['com.affine.m.selector.remove-warning.cancel'](),
|
||||
confirmText: t['com.affine.m.selector.remove-warning.confirm'](),
|
||||
reverseFooter: true,
|
||||
onConfirm: () => {
|
||||
globalCacheService.globalCache.set(
|
||||
'mobile:tags:will-be-removed-warning-read',
|
||||
true
|
||||
);
|
||||
cb();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
},
|
||||
},
|
||||
selectedIds => {
|
||||
if (selectedIds === undefined) {
|
||||
return;
|
||||
}
|
||||
const newIds = selectedIds.filter(id => !initialIds?.includes(id));
|
||||
const removedIds = initialIds?.filter(id => !selectedIds.includes(id));
|
||||
newIds.forEach(id => tagRecord?.tag(id));
|
||||
removedIds?.forEach(id => tagRecord?.untag(id));
|
||||
})
|
||||
.catch(console.error);
|
||||
}, [openDocSelector, tagRecord]);
|
||||
}
|
||||
);
|
||||
}, [
|
||||
tagRecord,
|
||||
workspaceDialogService,
|
||||
globalCacheService.globalCache,
|
||||
openConfirmModal,
|
||||
t,
|
||||
]);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const createTips = style({
|
||||
color: cssVar('textSecondaryColor'),
|
||||
fontSize: 12,
|
||||
lineHeight: '20px',
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
import { usePromptModal } from '@affine/component';
|
||||
import { createEmptyCollection } from '@affine/core/components/page-list/use-collection-manager';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import { ExplorerService } from '@affine/core/modules/explorer';
|
||||
@@ -7,12 +8,12 @@ import { useI18n } from '@affine/i18n';
|
||||
import { track } from '@affine/track';
|
||||
import { useLiveData, useServices } from '@toeverything/infra';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { AddItemPlaceholder } from '../../layouts/add-item-placeholder';
|
||||
import { CollapsibleSection } from '../../layouts/collapsible-section';
|
||||
import { ExplorerCollectionNode } from '../../nodes/collection';
|
||||
import { CollectionRenameDialog } from '../../nodes/collection/dialog';
|
||||
import * as styles from './index.css';
|
||||
|
||||
export const ExplorerCollections = () => {
|
||||
const t = useI18n();
|
||||
@@ -23,22 +24,42 @@ export const ExplorerCollections = () => {
|
||||
});
|
||||
const explorerSection = explorerService.sections.collections;
|
||||
const collections = useLiveData(collectionService.collections$);
|
||||
const [showCreateCollectionModal, setShowCreateCollectionModal] =
|
||||
useState(false);
|
||||
const { openPromptModal } = usePromptModal();
|
||||
|
||||
const handleCreateCollection = useCallback(
|
||||
(name: string) => {
|
||||
setShowCreateCollectionModal(false);
|
||||
const id = nanoid();
|
||||
collectionService.addCollection(createEmptyCollection(id, { name }));
|
||||
track.$.navigationPanel.organize.createOrganizeItem({
|
||||
type: 'collection',
|
||||
});
|
||||
workbenchService.workbench.openCollection(id);
|
||||
explorerSection.setCollapsed(false);
|
||||
},
|
||||
[collectionService, explorerSection, workbenchService.workbench]
|
||||
);
|
||||
const handleCreateCollection = useCallback(() => {
|
||||
openPromptModal({
|
||||
title: t['com.affine.editCollection.saveCollection'](),
|
||||
label: t['com.affine.editCollectionName.name'](),
|
||||
inputOptions: {
|
||||
placeholder: t['com.affine.editCollectionName.name.placeholder'](),
|
||||
},
|
||||
children: (
|
||||
<div className={styles.createTips}>
|
||||
{t['com.affine.editCollectionName.createTips']()}
|
||||
</div>
|
||||
),
|
||||
confirmText: t['com.affine.editCollection.save'](),
|
||||
cancelText: t['com.affine.editCollection.button.cancel'](),
|
||||
confirmButtonOptions: {
|
||||
variant: 'primary',
|
||||
},
|
||||
onConfirm(name) {
|
||||
const id = nanoid();
|
||||
collectionService.addCollection(createEmptyCollection(id, { name }));
|
||||
track.$.navigationPanel.organize.createOrganizeItem({
|
||||
type: 'collection',
|
||||
});
|
||||
workbenchService.workbench.openCollection(id);
|
||||
explorerSection.setCollapsed(false);
|
||||
},
|
||||
});
|
||||
}, [
|
||||
collectionService,
|
||||
explorerSection,
|
||||
openPromptModal,
|
||||
t,
|
||||
workbenchService.workbench,
|
||||
]);
|
||||
|
||||
return (
|
||||
<CollapsibleSection
|
||||
@@ -56,13 +77,7 @@ export const ExplorerCollections = () => {
|
||||
<AddItemPlaceholder
|
||||
data-testid="explorer-bar-add-collection-button"
|
||||
label={t['com.affine.rootAppSidebar.collection.new']()}
|
||||
onClick={() => setShowCreateCollectionModal(true)}
|
||||
/>
|
||||
<CollectionRenameDialog
|
||||
title={t['com.affine.m.explorer.collection.new-dialog-title']()}
|
||||
open={showCreateCollectionModal}
|
||||
onOpenChange={setShowCreateCollectionModal}
|
||||
onConfirm={handleCreateCollection}
|
||||
onClick={() => handleCreateCollection()}
|
||||
/>
|
||||
</ExplorerTreeRoot>
|
||||
</CollapsibleSection>
|
||||
|
||||
@@ -4,7 +4,6 @@ export * from './page-header';
|
||||
export * from './rename';
|
||||
export * from './search-input';
|
||||
export * from './search-result';
|
||||
export * from './selector';
|
||||
export * from './skeletons';
|
||||
export * from './user-plan-tag';
|
||||
export * from './workspace-selector';
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import type { BaseSelectorDialogProps } from '@affine/core/components/page-list/selector';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import { ViewLayersIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import type { DocsSelectorProps } from './doc-selector';
|
||||
import { GenericSelector, type GenericSelectorProps } from './generic-selector';
|
||||
|
||||
export interface CollectionsSelectorProps
|
||||
extends BaseSelectorDialogProps<string[]>,
|
||||
Pick<GenericSelectorProps, 'where' | 'type'> {}
|
||||
|
||||
export const CollectionsSelector = ({
|
||||
init = [],
|
||||
onCancel,
|
||||
onConfirm,
|
||||
...otherProps
|
||||
}: DocsSelectorProps) => {
|
||||
const collectionService = useService(CollectionService);
|
||||
const collections = useLiveData(collectionService.collections$);
|
||||
|
||||
const list = useMemo(() => {
|
||||
return collections.map(collection => ({
|
||||
id: collection.id,
|
||||
icon: <ViewLayersIcon />,
|
||||
label: collection.name,
|
||||
}));
|
||||
}, [collections]);
|
||||
|
||||
return (
|
||||
<GenericSelector
|
||||
onBack={onCancel}
|
||||
onConfirm={onConfirm}
|
||||
initial={init}
|
||||
data={list}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,47 +0,0 @@
|
||||
import { useSelectDialog } from '@affine/core/components/page-list/selector';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
|
||||
import {
|
||||
CollectionsSelector,
|
||||
type CollectionsSelectorProps,
|
||||
} from './collection-selector';
|
||||
import { DocsSelector, type DocsSelectorProps } from './doc-selector';
|
||||
import { TagsSelector, type TagsSelectorProps } from './tag-selector';
|
||||
|
||||
const options: Parameters<typeof useSelectDialog>[2] = {
|
||||
modalProps: {
|
||||
fullScreen: true,
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
contentOptions: {
|
||||
style: {
|
||||
background: cssVarV2('layer/background/secondary'),
|
||||
padding: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const useSelectDoc = () => {
|
||||
return useSelectDialog<string[], DocsSelectorProps>(
|
||||
DocsSelector,
|
||||
'select-doc-dialog',
|
||||
options
|
||||
);
|
||||
};
|
||||
|
||||
export const useSelectCollection = () => {
|
||||
return useSelectDialog<string[], CollectionsSelectorProps>(
|
||||
CollectionsSelector,
|
||||
'select-collection-dialog',
|
||||
options
|
||||
);
|
||||
};
|
||||
|
||||
export const useSelectTag = () => {
|
||||
return useSelectDialog<string[], TagsSelectorProps>(
|
||||
TagsSelector,
|
||||
'select-tag-dialog',
|
||||
options
|
||||
);
|
||||
};
|
||||
90
packages/frontend/core/src/mobile/dialogs/index.tsx
Normal file
90
packages/frontend/core/src/mobile/dialogs/index.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { AuthModal } from '@affine/core/components/affine/auth';
|
||||
import {
|
||||
type DialogComponentProps,
|
||||
type GLOBAL_DIALOG_SCHEMA,
|
||||
GlobalDialogService,
|
||||
WorkspaceDialogService,
|
||||
} from '@affine/core/modules/dialogs';
|
||||
import type { WORKSPACE_DIALOG_SCHEMA } from '@affine/core/modules/dialogs/constant';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
|
||||
import { CollectionSelectorDialog } from './selectors/collection-selector';
|
||||
import { DocSelectorDialog } from './selectors/doc-selector';
|
||||
import { TagSelectorDialog } from './selectors/tag-selector';
|
||||
import { SettingDialog } from './setting';
|
||||
|
||||
const GLOBAL_DIALOGS = {
|
||||
// 'create-workspace': CreateWorkspaceDialog,
|
||||
// 'import-workspace': ImportWorkspaceDialog,
|
||||
// 'import-template': ImportTemplateDialog,
|
||||
setting: SettingDialog,
|
||||
// import: ImportDialog,
|
||||
} satisfies {
|
||||
[key in keyof GLOBAL_DIALOG_SCHEMA]?: React.FC<
|
||||
DialogComponentProps<GLOBAL_DIALOG_SCHEMA[key]>
|
||||
>;
|
||||
};
|
||||
|
||||
const WORKSPACE_DIALOGS = {
|
||||
// 'doc-info': DocInfoDialog,
|
||||
// 'collection-editor': CollectionEditorDialog,
|
||||
'tag-selector': TagSelectorDialog,
|
||||
'doc-selector': DocSelectorDialog,
|
||||
'collection-selector': CollectionSelectorDialog,
|
||||
} satisfies {
|
||||
[key in keyof WORKSPACE_DIALOG_SCHEMA]?: React.FC<
|
||||
DialogComponentProps<WORKSPACE_DIALOG_SCHEMA[key]>
|
||||
>;
|
||||
};
|
||||
|
||||
export const GlobalDialogs = () => {
|
||||
const globalDialogService = useService(GlobalDialogService);
|
||||
const dialogs = useLiveData(globalDialogService.dialogs$);
|
||||
return (
|
||||
<>
|
||||
{dialogs.map(dialog => {
|
||||
const DialogComponent =
|
||||
GLOBAL_DIALOGS[dialog.type as keyof typeof GLOBAL_DIALOGS];
|
||||
if (!DialogComponent) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<DialogComponent
|
||||
key={dialog.id}
|
||||
{...(dialog.props as any)}
|
||||
close={(result?: unknown) => {
|
||||
globalDialogService.close(dialog.id, result);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
<AuthModal />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkspaceDialogs = () => {
|
||||
const workspaceDialogService = useService(WorkspaceDialogService);
|
||||
const dialogs = useLiveData(workspaceDialogService.dialogs$);
|
||||
return (
|
||||
<>
|
||||
{dialogs.map(dialog => {
|
||||
const DialogComponent =
|
||||
WORKSPACE_DIALOGS[dialog.type as keyof typeof WORKSPACE_DIALOGS];
|
||||
if (!DialogComponent) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<DialogComponent
|
||||
key={dialog.id}
|
||||
{...(dialog.props as any)}
|
||||
close={(result?: unknown) => {
|
||||
workspaceDialogService.close(dialog.id, result);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Modal } from '@affine/component';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import type {
|
||||
DialogComponentProps,
|
||||
WORKSPACE_DIALOG_SCHEMA,
|
||||
} from '@affine/core/modules/dialogs';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { ViewLayersIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { GenericSelector } from './generic-selector';
|
||||
|
||||
export const CollectionSelectorDialog = ({
|
||||
close,
|
||||
init,
|
||||
onBeforeConfirm,
|
||||
}: DialogComponentProps<WORKSPACE_DIALOG_SCHEMA['collection-selector']>) => {
|
||||
const t = useI18n();
|
||||
const collectionService = useService(CollectionService);
|
||||
const collections = useLiveData(collectionService.collections$);
|
||||
|
||||
const list = useMemo(() => {
|
||||
return collections.map(collection => ({
|
||||
id: collection.id,
|
||||
icon: <ViewLayersIcon />,
|
||||
label: collection.name,
|
||||
}));
|
||||
}, [collections]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open
|
||||
onOpenChange={() => close()}
|
||||
withoutCloseButton
|
||||
fullScreen
|
||||
contentOptions={{
|
||||
style: {
|
||||
background: cssVarV2('layer/background/secondary'),
|
||||
padding: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<GenericSelector
|
||||
onBack={close}
|
||||
onConfirm={close}
|
||||
onBeforeConfirm={onBeforeConfirm}
|
||||
initial={init}
|
||||
data={list}
|
||||
typeName={t[`com.affine.m.selector.type-collection`]()}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -1,14 +1,15 @@
|
||||
import type { BaseSelectorDialogProps } from '@affine/core/components/page-list/selector';
|
||||
import { Modal } from '@affine/component';
|
||||
import type {
|
||||
DialogComponentProps,
|
||||
WORKSPACE_DIALOG_SCHEMA,
|
||||
} from '@affine/core/modules/dialogs';
|
||||
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { DocsService, useLiveData, useService } from '@toeverything/infra';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { GenericSelector, type GenericSelectorProps } from './generic-selector';
|
||||
|
||||
export interface DocsSelectorProps
|
||||
extends BaseSelectorDialogProps<string[]>,
|
||||
Pick<GenericSelectorProps, 'where' | 'type'> {}
|
||||
import { GenericSelector } from './generic-selector';
|
||||
|
||||
const DocIcon = ({ docId }: { docId: string }) => {
|
||||
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||
@@ -25,12 +26,12 @@ const DocLabel = ({ docId }: { docId: string }) => {
|
||||
return typeof label === 'string' ? label : t[label.i18nKey]();
|
||||
};
|
||||
|
||||
export const DocsSelector = ({
|
||||
init = [],
|
||||
onCancel,
|
||||
onConfirm,
|
||||
...otherProps
|
||||
}: DocsSelectorProps) => {
|
||||
export const DocSelectorDialog = ({
|
||||
close,
|
||||
init,
|
||||
onBeforeConfirm,
|
||||
}: DialogComponentProps<WORKSPACE_DIALOG_SCHEMA['doc-selector']>) => {
|
||||
const t = useI18n();
|
||||
const docsService = useService(DocsService);
|
||||
const docRecords = useLiveData(docsService.list.docs$);
|
||||
|
||||
@@ -47,12 +48,26 @@ export const DocsSelector = ({
|
||||
}, [docRecords]);
|
||||
|
||||
return (
|
||||
<GenericSelector
|
||||
onBack={onCancel}
|
||||
onConfirm={onConfirm}
|
||||
initial={init}
|
||||
data={list}
|
||||
{...otherProps}
|
||||
/>
|
||||
<Modal
|
||||
open
|
||||
onOpenChange={() => close()}
|
||||
withoutCloseButton
|
||||
fullScreen
|
||||
contentOptions={{
|
||||
style: {
|
||||
background: cssVarV2('layer/background/secondary'),
|
||||
padding: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<GenericSelector
|
||||
onBack={close}
|
||||
onConfirm={close}
|
||||
onBeforeConfirm={onBeforeConfirm}
|
||||
initial={init}
|
||||
data={list}
|
||||
typeName={t[`com.affine.m.selector.type-doc`]()}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -3,12 +3,10 @@ import {
|
||||
Checkbox,
|
||||
SafeArea,
|
||||
Scrollable,
|
||||
useConfirmModal,
|
||||
useThemeColorMeta,
|
||||
} from '@affine/component';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { ArrowRightSmallIcon } from '@blocksuite/icons/rc';
|
||||
import { GlobalCacheService, useService } from '@toeverything/infra';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import {
|
||||
type ReactNode,
|
||||
@@ -20,7 +18,7 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { PageHeader } from '../page-header';
|
||||
import { PageHeader } from '../../components/page-header';
|
||||
import * as styles from './generic.css';
|
||||
|
||||
export interface GenericSelectorProps {
|
||||
@@ -34,10 +32,9 @@ export interface GenericSelectorProps {
|
||||
// changedRenderer?: (props: { added: number; removed: number }) => ReactNode;
|
||||
// removeWarningType?: string;
|
||||
// removeWarningWhere?: string;
|
||||
type: 'doc' | 'tag' | 'collection';
|
||||
where: 'tag' | 'folder' | 'collection';
|
||||
typeName: string;
|
||||
onBeforeConfirm?: (ids: string[], cb: () => void) => void;
|
||||
}
|
||||
const WILL_BE_REMOVED_WARNING_KEY = 'willBeRemovedWarningRead';
|
||||
|
||||
const ChangedRenderer = ({
|
||||
type,
|
||||
@@ -68,24 +65,18 @@ export const GenericSelector = ({
|
||||
data,
|
||||
title,
|
||||
confirmText,
|
||||
type,
|
||||
where,
|
||||
typeName,
|
||||
onBack,
|
||||
onConfirm,
|
||||
onBeforeConfirm,
|
||||
}: GenericSelectorProps) => {
|
||||
const t = useI18n();
|
||||
useThemeColorMeta(cssVarV2('layer/background/secondary'));
|
||||
const listRef = useRef<HTMLUListElement>(null);
|
||||
const quickScrollRef = useRef<HTMLDivElement>(null);
|
||||
const globalCache = useService(GlobalCacheService).globalCache;
|
||||
const { openConfirmModal } = useConfirmModal();
|
||||
|
||||
const whereText = t[`com.affine.m.selector.where-${where}`]();
|
||||
const typeText = t[`com.affine.m.selector.type-${type}`]();
|
||||
const typeText = typeName;
|
||||
|
||||
const [willBeRemovedWarningRead] = useState(
|
||||
globalCache.get<boolean>(WILL_BE_REMOVED_WARNING_KEY)
|
||||
);
|
||||
// make sure "initial ids" exist in list
|
||||
const [initial] = useState(
|
||||
originalInitial.filter(id => data.some(el => el.id === id))
|
||||
@@ -111,39 +102,15 @@ export const GenericSelector = ({
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const handleReadWillBeRemovedWarning = useCallback(() => {
|
||||
globalCache.set(WILL_BE_REMOVED_WARNING_KEY, true);
|
||||
}, [globalCache]);
|
||||
const handleConfirm = useCallback(() => {
|
||||
if (!willBeRemovedWarningRead && removed.length > 0) {
|
||||
openConfirmModal({
|
||||
title: t['com.affine.m.selector.remove-warning.title'](),
|
||||
description: t['com.affine.m.selector.remove-warning.message']({
|
||||
type: typeText,
|
||||
where: whereText,
|
||||
}),
|
||||
cancelText: t['com.affine.m.selector.remove-warning.cancel'](),
|
||||
confirmText: t['com.affine.m.selector.remove-warning.confirm'](),
|
||||
reverseFooter: true,
|
||||
onConfirm: () => {
|
||||
handleReadWillBeRemovedWarning();
|
||||
onConfirm?.(selected);
|
||||
},
|
||||
if (onBeforeConfirm) {
|
||||
onBeforeConfirm(selected, () => {
|
||||
onConfirm?.(selected);
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
onConfirm?.(selected);
|
||||
}
|
||||
onConfirm?.(selected);
|
||||
}, [
|
||||
handleReadWillBeRemovedWarning,
|
||||
onConfirm,
|
||||
openConfirmModal,
|
||||
removed,
|
||||
selected,
|
||||
t,
|
||||
typeText,
|
||||
whereText,
|
||||
willBeRemovedWarningRead,
|
||||
]);
|
||||
}, [onBeforeConfirm, onConfirm, selected]);
|
||||
|
||||
// touch & move to select
|
||||
useEffect(() => {
|
||||
@@ -273,7 +240,6 @@ export const GenericSelector = ({
|
||||
<div className={styles.totalInfo}>
|
||||
{t['com.affine.m.selector.info-total']({
|
||||
total: initial.length + '',
|
||||
where: whereText,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { BaseSelectorDialogProps } from '@affine/core/components/page-list/selector';
|
||||
import { Modal } from '@affine/component';
|
||||
import type {
|
||||
DialogComponentProps,
|
||||
WORKSPACE_DIALOG_SCHEMA,
|
||||
} from '@affine/core/modules/dialogs';
|
||||
import { TagService } from '@affine/core/modules/tag';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { GenericSelector, type GenericSelectorProps } from './generic-selector';
|
||||
|
||||
export interface TagsSelectorProps
|
||||
extends BaseSelectorDialogProps<string[]>,
|
||||
Pick<GenericSelectorProps, 'where' | 'type'> {}
|
||||
import { GenericSelector } from './generic-selector';
|
||||
|
||||
const TagIcon = ({ tagId }: { tagId: string }) => {
|
||||
const tagService = useService(TagService);
|
||||
@@ -35,12 +37,12 @@ const TagLabel = ({ tagId }: { tagId: string }) => {
|
||||
return name;
|
||||
};
|
||||
|
||||
export const TagsSelector = ({
|
||||
init = [],
|
||||
onCancel,
|
||||
onConfirm,
|
||||
...otherProps
|
||||
}: TagsSelectorProps) => {
|
||||
export const TagSelectorDialog = ({
|
||||
close,
|
||||
init,
|
||||
onBeforeConfirm,
|
||||
}: DialogComponentProps<WORKSPACE_DIALOG_SCHEMA['tag-selector']>) => {
|
||||
const t = useI18n();
|
||||
const tagService = useService(TagService);
|
||||
const tags = useLiveData(tagService.tagList.tags$);
|
||||
|
||||
@@ -53,12 +55,26 @@ export const TagsSelector = ({
|
||||
}, [tags]);
|
||||
|
||||
return (
|
||||
<GenericSelector
|
||||
onBack={onCancel}
|
||||
onConfirm={onConfirm}
|
||||
initial={init}
|
||||
data={list}
|
||||
{...otherProps}
|
||||
/>
|
||||
<Modal
|
||||
open
|
||||
onOpenChange={() => close()}
|
||||
withoutCloseButton
|
||||
fullScreen
|
||||
contentOptions={{
|
||||
style: {
|
||||
background: cssVarV2('layer/background/secondary'),
|
||||
padding: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<GenericSelector
|
||||
onBack={close}
|
||||
onConfirm={close}
|
||||
onBeforeConfirm={onBeforeConfirm}
|
||||
initial={init}
|
||||
data={list}
|
||||
typeName={t[`com.affine.m.selector.type-tag`]()}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getBaseFontStyleOptions } from '@affine/core/components/affine/setting-modal/general-setting/editor/general';
|
||||
import { getBaseFontStyleOptions } from '@affine/core/desktop/dialogs/setting/general-setting/editor/general';
|
||||
import {
|
||||
EditorSettingService,
|
||||
type FontFamily,
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getThemeOptions } from '@affine/core/components/affine/setting-modal/general-setting/appearance';
|
||||
import { getThemeOptions } from '@affine/core/desktop/dialogs/setting/general-setting/appearance';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useMemo } from 'react';
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Modal } from '@affine/component';
|
||||
import { openSettingModalAtom } from '@affine/core/components/atoms';
|
||||
import { AuthService } from '@affine/core/modules/cloud';
|
||||
import type {
|
||||
DialogComponentProps,
|
||||
GLOBAL_DIALOG_SCHEMA,
|
||||
} from '@affine/core/modules/dialogs';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { PageHeader } from '../../components';
|
||||
import { AboutGroup } from './about';
|
||||
@@ -15,35 +17,6 @@ import * as styles from './style.css';
|
||||
import { UserProfile } from './user-profile';
|
||||
import { UserUsage } from './user-usage';
|
||||
|
||||
export const MobileSettingModal = () => {
|
||||
const [{ open }, setOpen] = useAtom(openSettingModalAtom);
|
||||
|
||||
const onOpenChange = useCallback(
|
||||
(open: boolean) => setOpen(prev => ({ ...prev, open })),
|
||||
[setOpen]
|
||||
);
|
||||
const closeModal = useCallback(() => onOpenChange(false), [onOpenChange]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
fullScreen
|
||||
animation="slideBottom"
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
contentOptions={{
|
||||
style: {
|
||||
padding: 0,
|
||||
overflowY: 'auto',
|
||||
backgroundColor: cssVarV2('layer/background/secondary'),
|
||||
},
|
||||
}}
|
||||
withoutCloseButton
|
||||
>
|
||||
<MobileSetting onClose={closeModal} />
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const MobileSetting = ({ onClose }: { onClose: () => void }) => {
|
||||
const t = useI18n();
|
||||
const session = useService(AuthService).session;
|
||||
@@ -68,3 +41,26 @@ const MobileSetting = ({ onClose }: { onClose: () => void }) => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const SettingDialog = ({
|
||||
close,
|
||||
}: DialogComponentProps<GLOBAL_DIALOG_SCHEMA['setting']>) => {
|
||||
return (
|
||||
<Modal
|
||||
fullScreen
|
||||
animation="slideBottom"
|
||||
open
|
||||
onOpenChange={() => close()}
|
||||
contentOptions={{
|
||||
style: {
|
||||
padding: 0,
|
||||
overflowY: 'auto',
|
||||
backgroundColor: cssVarV2('layer/background/secondary'),
|
||||
},
|
||||
}}
|
||||
withoutCloseButton
|
||||
>
|
||||
<MobileSetting onClose={close} />
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -3,8 +3,8 @@ import {
|
||||
type DefaultOpenProperty,
|
||||
DocPropertiesTable,
|
||||
} from '@affine/core/components/doc-properties';
|
||||
import { LinksRow } from '@affine/core/components/doc-properties/info-modal/links-row';
|
||||
import { TimeRow } from '@affine/core/components/doc-properties/info-modal/time-row';
|
||||
import { LinksRow } from '@affine/core/desktop/dialogs/doc-info/links-row';
|
||||
import { TimeRow } from '@affine/core/desktop/dialogs/doc-info/time-row';
|
||||
import { DocsSearchService } from '@affine/core/modules/docs-search';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { LiveData, useLiveData, useService } from '@toeverything/infra';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { AffineErrorBoundary } from '@affine/core/components/affine/affine-error-boundary';
|
||||
import { AffineErrorComponent } from '@affine/core/components/affine/affine-error-boundary/affine-error-fallback';
|
||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
||||
import { PageNotFound } from '@affine/core/desktop/pages/404';
|
||||
import { MobileWorkbenchRoot } from '@affine/core/desktop/pages/workspace/workbench-root';
|
||||
import { workbenchRoutes } from '@affine/core/mobile/workbench-router';
|
||||
@@ -136,7 +135,7 @@ export const Component = () => {
|
||||
return <PageNotFound noPermission />;
|
||||
}
|
||||
if (!meta) {
|
||||
return <AppFallback key="workspaceLoading" />;
|
||||
return;
|
||||
}
|
||||
return (
|
||||
<WorkspaceLayout meta={meta}>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { AffineErrorBoundary } from '@affine/core/components/affine/affine-error-boundary';
|
||||
import { WorkspaceLayoutProviders } from '@affine/core/components/layouts/workspace-layout';
|
||||
import { AiLoginRequiredModal } from '@affine/core/components/affine/auth/ai-login-required';
|
||||
import {
|
||||
CloudQuotaModal,
|
||||
LocalQuotaModal,
|
||||
} from '@affine/core/components/affine/quota-reached-modal';
|
||||
import { SWRConfigProvider } from '@affine/core/components/providers/swr-config-provider';
|
||||
import { WorkspaceSideEffects } from '@affine/core/components/providers/workspace-side-effects';
|
||||
import { PeekViewManagerModal } from '@affine/core/modules/peek-view';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import type { Workspace, WorkspaceMetadata } from '@toeverything/infra';
|
||||
import {
|
||||
FrameworkScope,
|
||||
@@ -17,7 +24,7 @@ import {
|
||||
} from 'react';
|
||||
|
||||
import { AppFallback } from '../../components';
|
||||
import { MobileCurrentWorkspaceModals } from '../../provider/model-provider';
|
||||
import { WorkspaceDialogs } from '../../dialogs';
|
||||
|
||||
// TODO(@forehalo): reuse the global context with [core/electron]
|
||||
declare global {
|
||||
@@ -84,19 +91,24 @@ export const WorkspaceLayout = ({
|
||||
}
|
||||
|
||||
if (!isRootDocReady) {
|
||||
return (
|
||||
<FrameworkScope scope={workspace.scope}>
|
||||
<AppFallback />
|
||||
</FrameworkScope>
|
||||
);
|
||||
return <AppFallback />;
|
||||
}
|
||||
|
||||
return (
|
||||
<FrameworkScope scope={workspace.scope}>
|
||||
<AffineErrorBoundary height="100dvh">
|
||||
<SWRConfigProvider>
|
||||
<MobileCurrentWorkspaceModals />
|
||||
<WorkspaceLayoutProviders>{children}</WorkspaceLayoutProviders>
|
||||
<WorkspaceDialogs />
|
||||
|
||||
{/* ---- some side-effect components ---- */}
|
||||
<PeekViewManagerModal />
|
||||
{workspace?.flavour === WorkspaceFlavour.LOCAL && <LocalQuotaModal />}
|
||||
{workspace?.flavour === WorkspaceFlavour.AFFINE_CLOUD && (
|
||||
<CloudQuotaModal />
|
||||
)}
|
||||
<AiLoginRequiredModal />
|
||||
<WorkspaceSideEffects />
|
||||
{children}
|
||||
</SWRConfigProvider>
|
||||
</AffineErrorBoundary>
|
||||
</FrameworkScope>
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
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 {
|
||||
CloudQuotaModal,
|
||||
LocalQuotaModal,
|
||||
} from '@affine/core/components/affine/quota-reached-modal';
|
||||
import { StarAFFiNEModal } from '@affine/core/components/affine/star-affine-modal';
|
||||
import { InfoModal } from '@affine/core/components/doc-properties';
|
||||
import { useTrashModalHelper } from '@affine/core/components/hooks/affine/use-trash-modal-helper';
|
||||
import { MoveToTrash } from '@affine/core/components/page-list';
|
||||
import { SignOutConfirmModal } from '@affine/core/components/providers/modal-provider';
|
||||
import { CreateWorkspaceDialogProvider } from '@affine/core/modules/create-workspace';
|
||||
import { PeekViewManagerModal } from '@affine/core/modules/peek-view';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { MobileSettingModal } from '../views';
|
||||
import { MobileSignInModal } from '../views/sign-in/modal';
|
||||
|
||||
export function MobileCurrentWorkspaceModals() {
|
||||
const currentWorkspace = useService(WorkspaceService).workspace;
|
||||
|
||||
const { trashModal, setTrashModal, handleOnConfirm } = useTrashModalHelper();
|
||||
const deletePageTitles = trashModal.pageTitles;
|
||||
const trashConfirmOpen = trashModal.open;
|
||||
const onTrashConfirmOpenChange = useCallback(
|
||||
(open: boolean) => {
|
||||
setTrashModal({
|
||||
...trashModal,
|
||||
open,
|
||||
});
|
||||
},
|
||||
[trashModal, setTrashModal]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StarAFFiNEModal />
|
||||
<IssueFeedbackModal />
|
||||
{currentWorkspace ? <MobileSettingModal /> : null}
|
||||
{currentWorkspace?.flavour === WorkspaceFlavour.LOCAL && (
|
||||
<>
|
||||
<LocalQuotaModal />
|
||||
<HistoryTipsModal />
|
||||
</>
|
||||
)}
|
||||
{currentWorkspace?.flavour === WorkspaceFlavour.AFFINE_CLOUD && (
|
||||
<CloudQuotaModal />
|
||||
)}
|
||||
<AiLoginRequiredModal />
|
||||
<PeekViewManagerModal />
|
||||
<MoveToTrash.ConfirmModal
|
||||
open={trashConfirmOpen}
|
||||
onConfirm={handleOnConfirm}
|
||||
onOpenChange={onTrashConfirmOpenChange}
|
||||
titles={deletePageTitles}
|
||||
/>
|
||||
{currentWorkspace ? <InfoModal /> : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// I don't like the name, but let's keep it for now
|
||||
export const AllWorkspaceModals = () => {
|
||||
return (
|
||||
<>
|
||||
<NotificationCenter />
|
||||
<CreateWorkspaceDialogProvider />
|
||||
<MobileSignInModal />
|
||||
<SignOutConfirmModal />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
import { NotificationCenter } from '@affine/component';
|
||||
import { NavigateContext } from '@affine/core/components/hooks/use-navigate-helper';
|
||||
import { wrapCreateBrowserRouter } from '@sentry/react';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -10,7 +11,8 @@ import {
|
||||
useNavigate,
|
||||
} from 'react-router-dom';
|
||||
|
||||
import { AllWorkspaceModals } from './provider/model-provider';
|
||||
import { GlobalDialogs } from './dialogs';
|
||||
import { MobileSignInModal } from './views/sign-in/modal';
|
||||
|
||||
function RootRouter() {
|
||||
const navigate = useNavigate();
|
||||
@@ -23,7 +25,9 @@ function RootRouter() {
|
||||
return (
|
||||
ready && (
|
||||
<NavigateContext.Provider value={navigate}>
|
||||
<AllWorkspaceModals />
|
||||
<GlobalDialogs />
|
||||
<NotificationCenter />
|
||||
<MobileSignInModal />
|
||||
<Outlet />
|
||||
</NavigateContext.Provider>
|
||||
)
|
||||
|
||||
@@ -3,13 +3,12 @@ import {
|
||||
SafeArea,
|
||||
startScopedViewTransition,
|
||||
} from '@affine/component';
|
||||
import { openSettingModalAtom } from '@affine/core/components/atoms';
|
||||
import { GlobalDialogService } from '@affine/core/modules/dialogs';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { SettingsIcon } from '@blocksuite/icons/rc';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { SearchInput, WorkspaceSelector } from '../../components';
|
||||
@@ -26,7 +25,7 @@ import * as styles from './styles.css';
|
||||
export const HomeHeader = () => {
|
||||
const t = useI18n();
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
const openSetting = useSetAtom(openSettingModalAtom);
|
||||
const globalDialogService = useService(GlobalDialogService);
|
||||
|
||||
const [dense, setDense] = useState(false);
|
||||
|
||||
@@ -53,7 +52,9 @@ export const HomeHeader = () => {
|
||||
<div className={styles.settingWrapper}>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
openSetting({ open: true, activeTab: 'appearance' });
|
||||
globalDialogService.open('setting', {
|
||||
activeTab: 'appearance',
|
||||
});
|
||||
}}
|
||||
size="24"
|
||||
style={{ padding: 10 }}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './all-docs';
|
||||
export * from './home-header';
|
||||
export * from './recent-docs';
|
||||
export * from './settings';
|
||||
|
||||
Reference in New Issue
Block a user