mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 12:36:24 +08:00
refactor(core): remove collection atom (#5832)
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { IconButton } from '@affine/component';
|
||||
import { Header } from '@affine/core/components/pure/header';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab';
|
||||
import { PlusIcon } from '@blocksuite/icons';
|
||||
import clsx from 'clsx';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import * as styles from '../all-page/all-page.css';
|
||||
|
||||
export const AllCollectionHeader = ({
|
||||
showCreateNew,
|
||||
onCreateCollection,
|
||||
}: {
|
||||
showCreateNew: boolean;
|
||||
onCreateCollection?: () => void;
|
||||
}) => {
|
||||
const isWindowsDesktop = environment.isDesktop && environment.isWindows;
|
||||
|
||||
const renderRightItem = useMemo(() => {
|
||||
return (
|
||||
<IconButton
|
||||
type="default"
|
||||
icon={<PlusIcon fontSize={16} />}
|
||||
onClick={onCreateCollection}
|
||||
className={clsx(
|
||||
styles.headerCreateNewButton,
|
||||
styles.headerCreateNewCollectionIconButton,
|
||||
!showCreateNew && styles.headerCreateNewButtonHidden
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}, [onCreateCollection, showCreateNew]);
|
||||
|
||||
return (
|
||||
<Header
|
||||
right={
|
||||
<div
|
||||
className={styles.headerRightWindows}
|
||||
data-is-windows-desktop={isWindowsDesktop}
|
||||
>
|
||||
{renderRightItem}
|
||||
{isWindowsDesktop ? <WindowsAppControls /> : null}
|
||||
</div>
|
||||
}
|
||||
center={<WorkspaceModeFilterTab activeFilter={'collections'} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
import { HubIsland } from '@affine/core/components/affine/hub-island';
|
||||
import {
|
||||
CollectionListHeader,
|
||||
type CollectionMeta,
|
||||
createEmptyCollection,
|
||||
useEditCollectionName,
|
||||
VirtualizedCollectionList,
|
||||
} from '@affine/core/components/page-list';
|
||||
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useLiveData } from '@toeverything/infra';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { CollectionService } from '../../../modules/collection';
|
||||
import * as styles from '../all-page/all-page.css';
|
||||
import { EmptyCollectionList } from '../page-list-empty';
|
||||
import { AllCollectionHeader } from './header';
|
||||
|
||||
export const AllCollection = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const [hideHeaderCreateNew, setHideHeaderCreateNew] = useState(true);
|
||||
|
||||
const collectionService = useService(CollectionService);
|
||||
const collections = useLiveData(collectionService.collections);
|
||||
const config = useAllPageListConfig();
|
||||
|
||||
const collectionMetas = useMemo(() => {
|
||||
const collectionsList: CollectionMeta[] = collections.map(collection => {
|
||||
return {
|
||||
...collection,
|
||||
title: collection.name,
|
||||
};
|
||||
});
|
||||
return collectionsList;
|
||||
}, [collections]);
|
||||
|
||||
const navigateHelper = useNavigateHelper();
|
||||
const { open, node } = useEditCollectionName({
|
||||
title: t['com.affine.editCollection.createCollection'](),
|
||||
showTips: true,
|
||||
});
|
||||
|
||||
const handleCreateCollection = useCallback(() => {
|
||||
open('')
|
||||
.then(name => {
|
||||
const id = nanoid();
|
||||
collectionService.addCollection(createEmptyCollection(id, { name }));
|
||||
navigateHelper.jumpToCollection(currentWorkspace.id, id);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}, [collectionService, currentWorkspace, navigateHelper, open]);
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<AllCollectionHeader
|
||||
showCreateNew={!hideHeaderCreateNew}
|
||||
onCreateCollection={handleCreateCollection}
|
||||
/>
|
||||
{collectionMetas.length > 0 ? (
|
||||
<VirtualizedCollectionList
|
||||
collections={collections}
|
||||
collectionMetas={collectionMetas}
|
||||
setHideHeaderCreateNewCollection={setHideHeaderCreateNew}
|
||||
node={node}
|
||||
config={config}
|
||||
handleCreateCollection={handleCreateCollection}
|
||||
/>
|
||||
) : (
|
||||
<EmptyCollectionList
|
||||
heading={
|
||||
<CollectionListHeader
|
||||
node={node}
|
||||
onCreate={handleCreateCollection}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
<HubIsland />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Component = () => {
|
||||
return <AllCollection />;
|
||||
};
|
||||
@@ -8,36 +8,31 @@ import { filterContainerStyle } from '../../../components/filter-container.css';
|
||||
import {
|
||||
FilterList,
|
||||
SaveAsCollectionButton,
|
||||
useCollectionManager,
|
||||
} from '../../../components/page-list';
|
||||
import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
|
||||
|
||||
export const FilterContainer = () => {
|
||||
export const FilterContainer = ({
|
||||
filters,
|
||||
onChangeFilters,
|
||||
}: {
|
||||
filters: Filter[];
|
||||
onChangeFilters: (filters: Filter[]) => void;
|
||||
}) => {
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const navigateHelper = useNavigateHelper();
|
||||
const setting = useCollectionManager(useService(CollectionService));
|
||||
const collectionService = useService(CollectionService);
|
||||
const saveToCollection = useCallback(
|
||||
(collection: Collection) => {
|
||||
setting.createCollection({
|
||||
collectionService.addCollection({
|
||||
...collection,
|
||||
filterList: setting.currentCollection.filterList,
|
||||
filterList: filters,
|
||||
});
|
||||
navigateHelper.jumpToCollection(currentWorkspace.id, collection.id);
|
||||
},
|
||||
[setting, navigateHelper, currentWorkspace.id]
|
||||
[collectionService, filters, navigateHelper, currentWorkspace.id]
|
||||
);
|
||||
|
||||
const onFilterChange = useCallback(
|
||||
(filterList: Filter[]) => {
|
||||
setting.updateCollection({
|
||||
...setting.currentCollection,
|
||||
filterList,
|
||||
});
|
||||
},
|
||||
[setting]
|
||||
);
|
||||
|
||||
if (!setting.isDefault || !setting.currentCollection.filterList.length) {
|
||||
if (!filters.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -46,12 +41,12 @@ export const FilterContainer = () => {
|
||||
<div style={{ flex: 1 }}>
|
||||
<FilterList
|
||||
propertiesMeta={currentWorkspace.blockSuiteWorkspace.meta.properties}
|
||||
value={setting.currentCollection.filterList}
|
||||
onChange={onFilterChange}
|
||||
value={filters}
|
||||
onChange={onChangeFilters}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{setting.currentCollection.filterList.length > 0 ? (
|
||||
{filters.length > 0 ? (
|
||||
<SaveAsCollectionButton onConfirm={saveToCollection} />
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@@ -1,69 +1,33 @@
|
||||
import { IconButton } from '@affine/component';
|
||||
import type { AllPageFilterOption } from '@affine/core/atoms';
|
||||
import {
|
||||
CollectionList,
|
||||
AllPageListOperationsMenu,
|
||||
PageListNewPageButton,
|
||||
useCollectionManager,
|
||||
} from '@affine/core/components/page-list';
|
||||
import { Header } from '@affine/core/components/pure/header';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab';
|
||||
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
||||
import { useDeleteCollectionInfo } from '@affine/core/hooks/affine/use-delete-collection-info';
|
||||
import type { Filter } from '@affine/env/filter';
|
||||
import { PlusIcon } from '@blocksuite/icons';
|
||||
import type { Workspace } from '@blocksuite/store';
|
||||
import { useService } from '@toeverything/infra/di';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { CollectionService } from '../../../modules/collection';
|
||||
import * as styles from './all-page.css';
|
||||
import { FilterContainer } from './all-page-filter';
|
||||
|
||||
export const AllPageHeader = ({
|
||||
workspace,
|
||||
showCreateNew,
|
||||
isDefaultFilter,
|
||||
activeFilter,
|
||||
onCreateCollection,
|
||||
filters,
|
||||
onChangeFilters,
|
||||
}: {
|
||||
workspace: Workspace;
|
||||
showCreateNew: boolean;
|
||||
isDefaultFilter: boolean;
|
||||
activeFilter: AllPageFilterOption;
|
||||
onCreateCollection?: () => void;
|
||||
filters: Filter[];
|
||||
onChangeFilters: (filters: Filter[]) => void;
|
||||
}) => {
|
||||
const setting = useCollectionManager(useService(CollectionService));
|
||||
const config = useAllPageListConfig();
|
||||
const userInfo = useDeleteCollectionInfo();
|
||||
const workspace = useService(Workspace);
|
||||
const isWindowsDesktop = environment.isDesktop && environment.isWindows;
|
||||
|
||||
const disableFilterButton = useMemo(() => {
|
||||
return activeFilter !== 'docs' && isDefaultFilter;
|
||||
}, [activeFilter, isDefaultFilter]);
|
||||
|
||||
const renderRightItem = useMemo(() => {
|
||||
if (activeFilter === 'tags') {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
activeFilter === 'collections' &&
|
||||
isDefaultFilter &&
|
||||
onCreateCollection
|
||||
) {
|
||||
return (
|
||||
<IconButton
|
||||
type="default"
|
||||
icon={<PlusIcon fontSize={16} />}
|
||||
onClick={onCreateCollection}
|
||||
className={clsx(
|
||||
styles.headerCreateNewButton,
|
||||
styles.headerCreateNewCollectionIconButton,
|
||||
!showCreateNew && styles.headerCreateNewButtonHidden
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<PageListNewPageButton
|
||||
size="small"
|
||||
@@ -75,18 +39,16 @@ export const AllPageHeader = ({
|
||||
<PlusIcon />
|
||||
</PageListNewPageButton>
|
||||
);
|
||||
}, [activeFilter, isDefaultFilter, onCreateCollection, showCreateNew]);
|
||||
}, [showCreateNew]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
left={
|
||||
<CollectionList
|
||||
userInfo={userInfo}
|
||||
allPageListConfig={config}
|
||||
setting={setting}
|
||||
propertiesMeta={workspace.meta.properties}
|
||||
disable={disableFilterButton}
|
||||
<AllPageListOperationsMenu
|
||||
filterList={filters}
|
||||
onChangeFilterList={onChangeFilters}
|
||||
propertiesMeta={workspace.blockSuiteWorkspace.meta.properties}
|
||||
/>
|
||||
}
|
||||
right={
|
||||
@@ -98,14 +60,9 @@ export const AllPageHeader = ({
|
||||
{isWindowsDesktop ? <WindowsAppControls /> : null}
|
||||
</div>
|
||||
}
|
||||
center={
|
||||
<WorkspaceModeFilterTab
|
||||
workspaceId={workspace.id}
|
||||
activeFilter={activeFilter}
|
||||
/>
|
||||
}
|
||||
center={<WorkspaceModeFilterTab activeFilter={'docs'} />}
|
||||
/>
|
||||
<FilterContainer />
|
||||
<FilterContainer filters={filters} onChangeFilters={onChangeFilters} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,211 +1,50 @@
|
||||
import type { AllPageFilterOption } from '@affine/core/atoms';
|
||||
import { HubIsland } from '@affine/core/components/affine/hub-island';
|
||||
import {
|
||||
CollectionListHeader,
|
||||
type CollectionMeta,
|
||||
createEmptyCollection,
|
||||
currentCollectionAtom,
|
||||
PageListHeader,
|
||||
useCollectionManager,
|
||||
useEditCollectionName,
|
||||
useFilteredPageMetas,
|
||||
useTagMetas,
|
||||
VirtualizedCollectionList,
|
||||
VirtualizedPageList,
|
||||
} from '@affine/core/components/page-list';
|
||||
import {
|
||||
TagListHeader,
|
||||
VirtualizedTagList,
|
||||
} from '@affine/core/components/page-list/tags';
|
||||
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import { performanceRenderLogger } from '@affine/core/shared';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { Filter } from '@affine/env/filter';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useLiveData } from '@toeverything/infra';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { NIL } from 'uuid';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { CollectionService } from '../../../modules/collection';
|
||||
import {
|
||||
EmptyCollectionList,
|
||||
EmptyPageList,
|
||||
EmptyTagList,
|
||||
} from '../page-list-empty';
|
||||
import { EmptyPageList } from '../page-list-empty';
|
||||
import * as styles from './all-page.css';
|
||||
import { AllPageHeader } from './all-page-header';
|
||||
|
||||
// even though it is called all page, it is also being used for collection route as well
|
||||
export const AllPage = ({
|
||||
activeFilter,
|
||||
}: {
|
||||
activeFilter: AllPageFilterOption;
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const params = useParams();
|
||||
export const AllPage = () => {
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace);
|
||||
const [hideHeaderCreateNew, setHideHeaderCreateNew] = useState(true);
|
||||
|
||||
const collectionService = useService(CollectionService);
|
||||
const collections = useLiveData(collectionService.collections);
|
||||
const setting = useCollectionManager(collectionService);
|
||||
const config = useAllPageListConfig();
|
||||
const { tags, tagMetas, filterPageMetaByTag, deleteTags } = useTagMetas(
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
pageMetas
|
||||
);
|
||||
const filteredPageMetas = useFilteredPageMetas(
|
||||
'all',
|
||||
pageMetas,
|
||||
currentWorkspace
|
||||
);
|
||||
const tagPageMetas = useMemo(() => {
|
||||
if (params.tagId) {
|
||||
return filterPageMetaByTag(params.tagId);
|
||||
}
|
||||
return [];
|
||||
}, [filterPageMetaByTag, params.tagId]);
|
||||
|
||||
const collectionMetas = useMemo(() => {
|
||||
const collectionsList: CollectionMeta[] = collections.map(collection => {
|
||||
return {
|
||||
...collection,
|
||||
title: collection.name,
|
||||
};
|
||||
});
|
||||
return collectionsList;
|
||||
}, [collections]);
|
||||
|
||||
const navigateHelper = useNavigateHelper();
|
||||
const { open, node } = useEditCollectionName({
|
||||
title: t['com.affine.editCollection.createCollection'](),
|
||||
showTips: true,
|
||||
const [filters, setFilters] = useState<Filter[]>([]);
|
||||
const filteredPageMetas = useFilteredPageMetas(currentWorkspace, pageMetas, {
|
||||
filters: filters,
|
||||
});
|
||||
|
||||
const handleCreateCollection = useCallback(() => {
|
||||
open('')
|
||||
.then(name => {
|
||||
const id = nanoid();
|
||||
setting.createCollection(createEmptyCollection(id, { name }));
|
||||
navigateHelper.jumpToCollection(currentWorkspace.id, id);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}, [currentWorkspace.id, navigateHelper, open, setting]);
|
||||
|
||||
const currentTag = useMemo(() => {
|
||||
if (params.tagId) {
|
||||
return tags.find(tag => tag.id === params.tagId);
|
||||
}
|
||||
return;
|
||||
}, [params.tagId, tags]);
|
||||
|
||||
const content = useMemo(() => {
|
||||
if (filteredPageMetas.length > 0 && activeFilter === 'docs') {
|
||||
return (
|
||||
<VirtualizedPageList
|
||||
setHideHeaderCreateNewPage={setHideHeaderCreateNew}
|
||||
/>
|
||||
);
|
||||
} else if (activeFilter === 'collections' && !setting.isDefault) {
|
||||
return (
|
||||
<VirtualizedPageList
|
||||
collection={setting.currentCollection}
|
||||
config={config}
|
||||
setHideHeaderCreateNewPage={setHideHeaderCreateNew}
|
||||
/>
|
||||
);
|
||||
} else if (activeFilter === 'collections' && setting.isDefault) {
|
||||
return collectionMetas.length > 0 ? (
|
||||
<VirtualizedCollectionList
|
||||
collections={collections}
|
||||
collectionMetas={collectionMetas}
|
||||
setHideHeaderCreateNewCollection={setHideHeaderCreateNew}
|
||||
node={node}
|
||||
config={config}
|
||||
handleCreateCollection={handleCreateCollection}
|
||||
/>
|
||||
) : (
|
||||
<EmptyCollectionList
|
||||
heading={
|
||||
<CollectionListHeader
|
||||
node={node}
|
||||
onCreate={handleCreateCollection}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
} else if (activeFilter === 'tags') {
|
||||
if (params.tagId) {
|
||||
return tagPageMetas.length > 0 ? (
|
||||
<VirtualizedPageList
|
||||
tag={currentTag}
|
||||
listItem={tagPageMetas}
|
||||
setHideHeaderCreateNewPage={setHideHeaderCreateNew}
|
||||
/>
|
||||
) : (
|
||||
<EmptyPageList
|
||||
type="all"
|
||||
heading={<PageListHeader workspaceId={currentWorkspace.id} />}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return tags.length > 0 ? (
|
||||
<VirtualizedTagList
|
||||
tags={tags}
|
||||
tagMetas={tagMetas}
|
||||
setHideHeaderCreateNewTag={setHideHeaderCreateNew}
|
||||
onTagDelete={deleteTags}
|
||||
/>
|
||||
) : (
|
||||
<EmptyTagList heading={<TagListHeader />} />
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EmptyPageList
|
||||
type="all"
|
||||
heading={<PageListHeader workspaceId={currentWorkspace.id} />}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
activeFilter,
|
||||
collectionMetas,
|
||||
collections,
|
||||
config,
|
||||
currentTag,
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
currentWorkspace.id,
|
||||
deleteTags,
|
||||
filteredPageMetas.length,
|
||||
handleCreateCollection,
|
||||
node,
|
||||
params.tagId,
|
||||
setting.currentCollection,
|
||||
setting.isDefault,
|
||||
tagMetas,
|
||||
tagPageMetas,
|
||||
tags,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<AllPageHeader
|
||||
workspace={currentWorkspace.blockSuiteWorkspace}
|
||||
showCreateNew={!hideHeaderCreateNew}
|
||||
isDefaultFilter={setting.isDefault}
|
||||
activeFilter={activeFilter}
|
||||
onCreateCollection={handleCreateCollection}
|
||||
filters={filters}
|
||||
onChangeFilters={setFilters}
|
||||
/>
|
||||
{content}
|
||||
{filteredPageMetas.length > 0 ? (
|
||||
<VirtualizedPageList
|
||||
setHideHeaderCreateNewPage={setHideHeaderCreateNew}
|
||||
filters={filters}
|
||||
/>
|
||||
) : (
|
||||
<EmptyPageList
|
||||
type="all"
|
||||
heading={<PageListHeader />}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
/>
|
||||
)}
|
||||
<HubIsland />
|
||||
</div>
|
||||
);
|
||||
@@ -215,21 +54,8 @@ export const Component = () => {
|
||||
performanceRenderLogger.info('AllPage');
|
||||
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const currentCollection = useSetAtom(currentCollectionAtom);
|
||||
const navigateHelper = useNavigateHelper();
|
||||
|
||||
const location = useLocation();
|
||||
const activeFilter = useMemo(() => {
|
||||
const query = new URLSearchParams(location.search);
|
||||
const filterMode = query.get('filterMode');
|
||||
if (filterMode === 'collections') {
|
||||
return 'collections';
|
||||
} else if (filterMode === 'tags') {
|
||||
return 'tags';
|
||||
}
|
||||
return 'docs';
|
||||
}, [location.search]);
|
||||
|
||||
useEffect(() => {
|
||||
function checkJumpOnce() {
|
||||
for (const [pageId] of currentWorkspace.blockSuiteWorkspace.pages) {
|
||||
@@ -252,9 +78,5 @@ export const Component = () => {
|
||||
navigateHelper,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
currentCollection(NIL);
|
||||
}, [currentCollection]);
|
||||
|
||||
return <AllPage activeFilter={activeFilter} />;
|
||||
return <AllPage />;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Header } from '@affine/core/components/pure/header';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab';
|
||||
|
||||
import * as styles from '../all-page/all-page.css';
|
||||
|
||||
export const AllTagHeader = () => {
|
||||
const isWindowsDesktop = environment.isDesktop && environment.isWindows;
|
||||
|
||||
return (
|
||||
<Header
|
||||
right={
|
||||
<div
|
||||
className={styles.headerRightWindows}
|
||||
data-is-windows-desktop={isWindowsDesktop}
|
||||
>
|
||||
{isWindowsDesktop ? <WindowsAppControls /> : null}
|
||||
</div>
|
||||
}
|
||||
center={<WorkspaceModeFilterTab activeFilter={'tags'} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import { HubIsland } from '@affine/core/components/affine/hub-island';
|
||||
import { useTagMetas } from '@affine/core/components/page-list';
|
||||
import {
|
||||
TagListHeader,
|
||||
VirtualizedTagList,
|
||||
} from '@affine/core/components/page-list/tags';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
|
||||
import * as styles from '../all-page/all-page.css';
|
||||
import { EmptyTagList } from '../page-list-empty';
|
||||
import { AllTagHeader } from './header';
|
||||
|
||||
export const AllTag = () => {
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace);
|
||||
|
||||
const { tags, tagMetas, deleteTags } = useTagMetas(
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
pageMetas
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<AllTagHeader />
|
||||
{tags.length > 0 ? (
|
||||
<VirtualizedTagList
|
||||
tags={tags}
|
||||
tagMetas={tagMetas}
|
||||
onTagDelete={deleteTags}
|
||||
/>
|
||||
) : (
|
||||
<EmptyTagList heading={<TagListHeader />} />
|
||||
)}
|
||||
<HubIsland />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Component = () => {
|
||||
return <AllTag />;
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
import { IconButton } from '@affine/component';
|
||||
import { Header } from '@affine/core/components/pure/header';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab';
|
||||
import { PlusIcon } from '@blocksuite/icons';
|
||||
import clsx from 'clsx';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import * as styles from '../all-page/all-page.css';
|
||||
|
||||
export const CollectionDetailHeader = ({
|
||||
showCreateNew,
|
||||
onCreate,
|
||||
}: {
|
||||
showCreateNew: boolean;
|
||||
onCreate: () => void;
|
||||
}) => {
|
||||
const isWindowsDesktop = environment.isDesktop && environment.isWindows;
|
||||
|
||||
const renderRightItem = useMemo(() => {
|
||||
return (
|
||||
<IconButton
|
||||
type="default"
|
||||
icon={<PlusIcon fontSize={16} />}
|
||||
onClick={onCreate}
|
||||
className={clsx(
|
||||
styles.headerCreateNewButton,
|
||||
styles.headerCreateNewCollectionIconButton,
|
||||
!showCreateNew && styles.headerCreateNewButtonHidden
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}, [onCreate, showCreateNew]);
|
||||
|
||||
return (
|
||||
<Header
|
||||
right={
|
||||
<div
|
||||
className={styles.headerRightWindows}
|
||||
data-is-windows-desktop={isWindowsDesktop}
|
||||
>
|
||||
{renderRightItem}
|
||||
{isWindowsDesktop ? <WindowsAppControls /> : null}
|
||||
</div>
|
||||
}
|
||||
center={<WorkspaceModeFilterTab activeFilter={'collections'} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
+42
-18
@@ -3,11 +3,11 @@ import {
|
||||
SidebarSwitch,
|
||||
} from '@affine/component/app-sidebar';
|
||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
||||
import { HubIsland } from '@affine/core/components/affine/hub-island';
|
||||
import {
|
||||
AffineShapeIcon,
|
||||
currentCollectionAtom,
|
||||
useCollectionManager,
|
||||
useEditCollection,
|
||||
VirtualizedPageList,
|
||||
} from '@affine/core/components/page-list';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
||||
@@ -23,30 +23,54 @@ import {
|
||||
ViewLayersIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import { useService } from '@toeverything/infra/di';
|
||||
import { useLiveData } from '@toeverything/infra/livedata';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { type LoaderFunction, redirect, useParams } from 'react-router-dom';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { useNavigateHelper } from '../../hooks/use-navigate-helper';
|
||||
import { WorkspaceSubPath } from '../../shared';
|
||||
import { AllPage } from './all-page/all-page';
|
||||
import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
|
||||
import { WorkspaceSubPath } from '../../../shared';
|
||||
import * as allPageStyles from '../all-page/all-page.css';
|
||||
import * as styles from './collection.css';
|
||||
import { CollectionDetailHeader } from './header';
|
||||
|
||||
export const loader: LoaderFunction = async args => {
|
||||
const rootStore = getCurrentStore();
|
||||
if (!args.params.collectionId) {
|
||||
return redirect('/404');
|
||||
}
|
||||
rootStore.set(currentCollectionAtom, args.params.collectionId);
|
||||
return null;
|
||||
export const CollectionDetail = ({
|
||||
collection,
|
||||
}: {
|
||||
collection: Collection;
|
||||
}) => {
|
||||
const config = useAllPageListConfig();
|
||||
const { node, open } = useEditCollection(useAllPageListConfig());
|
||||
const collectionService = useService(CollectionService);
|
||||
const [hideHeaderCreateNew, setHideHeaderCreateNew] = useState(true);
|
||||
|
||||
const handleEditCollection = useAsyncCallback(async () => {
|
||||
const ret = await open({ ...collection }, 'page');
|
||||
collectionService.updateCollection(ret.id, () => ret);
|
||||
}, [collection, collectionService, open]);
|
||||
|
||||
return (
|
||||
<div className={allPageStyles.root}>
|
||||
<CollectionDetailHeader
|
||||
showCreateNew={!hideHeaderCreateNew}
|
||||
onCreate={handleEditCollection}
|
||||
/>
|
||||
<VirtualizedPageList
|
||||
collection={collection}
|
||||
config={config}
|
||||
setHideHeaderCreateNewPage={setHideHeaderCreateNew}
|
||||
/>
|
||||
<HubIsland />
|
||||
{node}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Component = function CollectionPage() {
|
||||
const collectionService = useService(CollectionService);
|
||||
|
||||
const collections = useLiveData(collectionService.collections);
|
||||
const navigate = useNavigateHelper();
|
||||
const params = useParams();
|
||||
@@ -87,7 +111,7 @@ export const Component = function CollectionPage() {
|
||||
return isEmpty(collection) ? (
|
||||
<Placeholder collection={collection} />
|
||||
) : (
|
||||
<AllPage activeFilter="collections" />
|
||||
<CollectionDetail collection={collection} />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -95,16 +119,16 @@ const isWindowsDesktop = environment.isDesktop && environment.isWindows;
|
||||
|
||||
const Placeholder = ({ collection }: { collection: Collection }) => {
|
||||
const workspace = useService(Workspace);
|
||||
const collectionService = useCollectionManager(useService(CollectionService));
|
||||
const collectionService = useService(CollectionService);
|
||||
const { node, open } = useEditCollection(useAllPageListConfig());
|
||||
const { jumpToCollections } = useNavigateHelper();
|
||||
const openPageEdit = useAsyncCallback(async () => {
|
||||
const ret = await open({ ...collection }, 'page');
|
||||
collectionService.updateCollection(ret);
|
||||
collectionService.updateCollection(ret.id, () => ret);
|
||||
}, [open, collection, collectionService]);
|
||||
const openRuleEdit = useAsyncCallback(async () => {
|
||||
const ret = await open({ ...collection }, 'rule');
|
||||
collectionService.updateCollection(ret);
|
||||
collectionService.updateCollection(ret.id, () => ret);
|
||||
}, [collection, open, collectionService]);
|
||||
const [showTips, setShowTips] = useState(false);
|
||||
useEffect(() => {
|
||||
@@ -2,7 +2,6 @@ import { Scrollable } from '@affine/component';
|
||||
import { PageDetailSkeleton } from '@affine/component/page-detail-skeleton';
|
||||
import { ResizePanel } from '@affine/component/resize-panel';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import type { PageService } from '@blocksuite/blocks';
|
||||
import {
|
||||
BookmarkService,
|
||||
@@ -42,17 +41,13 @@ import { HubIsland } from '../../../components/affine/hub-island';
|
||||
import { GlobalPageHistoryModal } from '../../../components/affine/page-history-modal';
|
||||
import { ImagePreviewModal } from '../../../components/image-preview';
|
||||
import { PageDetailEditor } from '../../../components/page-detail-editor';
|
||||
import {
|
||||
createTagFilter,
|
||||
useCollectionManager,
|
||||
} from '../../../components/page-list';
|
||||
import { TrashPageFooter } from '../../../components/pure/trash-page-footer';
|
||||
import { TopTip } from '../../../components/top-tip';
|
||||
import { useRegisterBlocksuiteEditorCommands } from '../../../hooks/affine/use-register-blocksuite-editor-commands';
|
||||
import { usePageDocumentTitle } from '../../../hooks/use-global-state';
|
||||
import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
|
||||
import { CurrentPageService } from '../../../modules/page';
|
||||
import { performanceRenderLogger, WorkspaceSubPath } from '../../../shared';
|
||||
import { performanceRenderLogger } from '../../../shared';
|
||||
import { PageNotFound } from '../../404';
|
||||
import * as styles from './detail-page.css';
|
||||
import { DetailPageHeader, RightSidebarHeader } from './detail-page-header';
|
||||
@@ -117,7 +112,7 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
||||
const page = useService(Page);
|
||||
const pageRecordList = useService(PageRecordList);
|
||||
const currentPageId = page.id;
|
||||
const { openPage, jumpToSubPath } = useNavigateHelper();
|
||||
const { openPage, jumpToTag } = useNavigateHelper();
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const blockSuiteWorkspace = currentWorkspace.blockSuiteWorkspace;
|
||||
|
||||
@@ -127,8 +122,6 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
||||
|
||||
const isInTrash = pageMeta?.trash;
|
||||
|
||||
const collectionService = useService(CollectionService);
|
||||
const { setTemporaryFilter } = useCollectionManager(collectionService);
|
||||
const mode = useLiveData(page.mode);
|
||||
useRegisterBlocksuiteEditorCommands();
|
||||
const title = useLiveData(page.title);
|
||||
@@ -191,9 +184,8 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
||||
const dispose = editor.slots.pageLinkClicked.on(({ pageId }) => {
|
||||
return openPage(blockSuiteWorkspace.id, pageId);
|
||||
});
|
||||
const disposeTagClick = editor.slots.tagClicked.on(async ({ tagId }) => {
|
||||
jumpToSubPath(currentWorkspace.id, WorkspaceSubPath.ALL);
|
||||
setTemporaryFilter([createTagFilter(tagId)]);
|
||||
const disposeTagClick = editor.slots.tagClicked.on(({ tagId }) => {
|
||||
jumpToTag(currentWorkspace.id, tagId);
|
||||
});
|
||||
return () => {
|
||||
dispose.dispose();
|
||||
@@ -201,14 +193,13 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
||||
};
|
||||
},
|
||||
[
|
||||
page,
|
||||
mode,
|
||||
pageRecordList,
|
||||
openPage,
|
||||
blockSuiteWorkspace.id,
|
||||
jumpToSubPath,
|
||||
currentWorkspace.id,
|
||||
setTemporaryFilter,
|
||||
jumpToTag,
|
||||
mode,
|
||||
openPage,
|
||||
page,
|
||||
pageRecordList,
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { TagListHeader, useTagMetas } from '@affine/core/components/page-list';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useService, Workspace } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
import { type LoaderFunction, redirect, useParams } from 'react-router-dom';
|
||||
|
||||
import { AllPage } from './all-page/all-page';
|
||||
import { AllPageHeader } from './all-page/all-page-header';
|
||||
import { EmptyPageList } from './page-list-empty';
|
||||
|
||||
export const loader: LoaderFunction = async args => {
|
||||
if (!args.params.tagId) {
|
||||
return redirect('/404');
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const Component = function TagPage() {
|
||||
const params = useParams();
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace);
|
||||
const { tagUsageCounts } = useTagMetas(
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
pageMetas
|
||||
);
|
||||
const isEmpty = useMemo(() => {
|
||||
if (params.tagId) {
|
||||
return tagUsageCounts[params.tagId] === 0;
|
||||
}
|
||||
return true;
|
||||
}, [params.tagId, tagUsageCounts]);
|
||||
|
||||
return isEmpty ? (
|
||||
<>
|
||||
<AllPageHeader
|
||||
workspace={currentWorkspace.blockSuiteWorkspace}
|
||||
showCreateNew={false}
|
||||
isDefaultFilter={true}
|
||||
activeFilter={'tags'}
|
||||
/>
|
||||
<EmptyPageList
|
||||
type="all"
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
heading={<TagListHeader />}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<AllPage activeFilter="tags" />
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Header } from '@affine/core/components/pure/header';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab';
|
||||
|
||||
import * as styles from '../all-page/all-page.css';
|
||||
|
||||
export const TagDetailHeader = () => {
|
||||
const isWindowsDesktop = environment.isDesktop && environment.isWindows;
|
||||
|
||||
return (
|
||||
<Header
|
||||
right={
|
||||
<div
|
||||
className={styles.headerRightWindows}
|
||||
data-is-windows-desktop={isWindowsDesktop}
|
||||
>
|
||||
{isWindowsDesktop ? <WindowsAppControls /> : null}
|
||||
</div>
|
||||
}
|
||||
center={<WorkspaceModeFilterTab activeFilter={'tags'} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
import { HubIsland } from '@affine/core/components/affine/hub-island';
|
||||
import {
|
||||
PageListHeader,
|
||||
useTagMetas,
|
||||
VirtualizedPageList,
|
||||
} from '@affine/core/components/page-list';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { PageNotFound } from '../../404';
|
||||
import * as styles from '../all-page/all-page.css';
|
||||
import { EmptyPageList } from '../page-list-empty';
|
||||
import { TagDetailHeader } from './header';
|
||||
|
||||
export const TagDetail = ({ tagId }: { tagId?: string }) => {
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace);
|
||||
|
||||
const { tags, filterPageMetaByTag } = useTagMetas(
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
pageMetas
|
||||
);
|
||||
const tagPageMetas = useMemo(() => {
|
||||
if (tagId) {
|
||||
return filterPageMetaByTag(tagId);
|
||||
}
|
||||
return [];
|
||||
}, [filterPageMetaByTag, tagId]);
|
||||
|
||||
const currentTag = useMemo(
|
||||
() => tags.find(tag => tag.id === tagId),
|
||||
[tagId, tags]
|
||||
);
|
||||
|
||||
if (!currentTag) {
|
||||
return <PageNotFound />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<TagDetailHeader />
|
||||
{tagPageMetas.length > 0 ? (
|
||||
<VirtualizedPageList tag={currentTag} listItem={tagPageMetas} />
|
||||
) : (
|
||||
<EmptyPageList
|
||||
type="all"
|
||||
heading={<PageListHeader />}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
/>
|
||||
)}
|
||||
<HubIsland />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Component = () => {
|
||||
const params = useParams();
|
||||
|
||||
return <TagDetail tagId={params.tagId} />;
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils';
|
||||
import {
|
||||
currentCollectionAtom,
|
||||
type ListItem,
|
||||
ListTableHeader,
|
||||
PageListItemRenderer,
|
||||
@@ -19,11 +18,8 @@ import { assertExists } from '@blocksuite/global/utils';
|
||||
import { DeleteIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import { useService } from '@toeverything/infra/di';
|
||||
import { useCallback } from 'react';
|
||||
import { type LoaderFunction } from 'react-router-dom';
|
||||
import { NIL } from 'uuid';
|
||||
|
||||
import { EmptyPageList } from './page-list-empty';
|
||||
import * as styles from './trash-page.css';
|
||||
@@ -50,27 +46,15 @@ const TrashHeader = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const loader: LoaderFunction = async () => {
|
||||
// to fix the bug that the trash page list is not updated when route from collection to trash
|
||||
// but it's not a good solution, the page will jitter when collection and trash are switched between each other.
|
||||
// TODO: fix this bug
|
||||
|
||||
const rootStore = getCurrentStore();
|
||||
rootStore.set(currentCollectionAtom, NIL);
|
||||
return null;
|
||||
};
|
||||
|
||||
export const TrashPage = () => {
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const blockSuiteWorkspace = currentWorkspace.blockSuiteWorkspace;
|
||||
assertExists(blockSuiteWorkspace);
|
||||
|
||||
const pageMetas = useBlockSuitePageMeta(blockSuiteWorkspace);
|
||||
const filteredPageMetas = useFilteredPageMetas(
|
||||
'trash',
|
||||
pageMetas,
|
||||
currentWorkspace
|
||||
);
|
||||
const filteredPageMetas = useFilteredPageMetas(currentWorkspace, pageMetas, {
|
||||
trash: true,
|
||||
});
|
||||
|
||||
const { restoreFromTrash, permanentlyDeletePage } =
|
||||
useBlockSuiteMetaHelper(blockSuiteWorkspace);
|
||||
|
||||
Reference in New Issue
Block a user