mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-25 06:18:45 +08:00
refactor(core): favorite adapter (#6285)
1. abstraction over favourites that supports different type of resources 2. sorting abstraction
This commit is contained in:
+23
-27
@@ -5,8 +5,8 @@ import type {
|
||||
PageInfoCustomPropertyMeta,
|
||||
} from '@affine/core/modules/workspace/properties/schema';
|
||||
import { PagePropertyType } from '@affine/core/modules/workspace/properties/schema';
|
||||
import { createFractionalIndexingSortableHelper } from '@affine/core/utils';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { generateKeyBetween } from 'fractional-indexing';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
import { getDefaultIconName } from './icons-mapping';
|
||||
@@ -147,6 +147,11 @@ export class PagePropertiesManager {
|
||||
this.ensureRequiredProperties();
|
||||
}
|
||||
|
||||
readonly sorter = createFractionalIndexingSortableHelper<
|
||||
PageInfoCustomProperty,
|
||||
string | number
|
||||
>(this);
|
||||
|
||||
// prevent infinite loop
|
||||
private ensuring = false;
|
||||
ensureRequiredProperties() {
|
||||
@@ -163,6 +168,22 @@ export class PagePropertiesManager {
|
||||
this.ensuring = false;
|
||||
}
|
||||
|
||||
getItems() {
|
||||
return Object.values(this.getCustomProperties());
|
||||
}
|
||||
|
||||
getItemOrder(item: PageInfoCustomProperty): string {
|
||||
return item.order;
|
||||
}
|
||||
|
||||
setItemOrder(item: PageInfoCustomProperty, order: string) {
|
||||
item.order = order;
|
||||
}
|
||||
|
||||
getItemId(item: PageInfoCustomProperty) {
|
||||
return item.id;
|
||||
}
|
||||
|
||||
get workspace() {
|
||||
return this.adapter.workspace;
|
||||
}
|
||||
@@ -204,16 +225,6 @@ export class PagePropertiesManager {
|
||||
: {};
|
||||
}
|
||||
|
||||
getOrderedCustomProperties() {
|
||||
return Object.values(this.getCustomProperties()).sort((a, b) =>
|
||||
a.order > b.order ? 1 : a.order < b.order ? -1 : 0
|
||||
);
|
||||
}
|
||||
|
||||
largestOrder() {
|
||||
return this.getOrderedCustomProperties().at(-1)?.order ?? null;
|
||||
}
|
||||
|
||||
getCustomPropertyMeta(id: string): PageInfoCustomPropertyMeta | undefined {
|
||||
return this.metaManager.customPropertiesSchema[id];
|
||||
}
|
||||
@@ -234,7 +245,7 @@ export class PagePropertiesManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const newOrder = generateKeyBetween(this.largestOrder(), null);
|
||||
const newOrder = this.sorter.getNewItemOrder();
|
||||
if (this.properties!.custom[id]) {
|
||||
logger.warn(`custom property ${id} already exists`);
|
||||
}
|
||||
@@ -247,21 +258,6 @@ export class PagePropertiesManager {
|
||||
};
|
||||
}
|
||||
|
||||
moveCustomProperty(from: number, to: number) {
|
||||
this.ensureRequiredProperties();
|
||||
// move from -> to means change from's order to a new order between to and to -1/+1
|
||||
const properties = this.getOrderedCustomProperties();
|
||||
const fromProperty = properties[from];
|
||||
const toProperty = properties[to];
|
||||
const toNextProperty = properties[from < to ? to + 1 : to - 1];
|
||||
const args: [string?, string?] =
|
||||
from < to
|
||||
? [toProperty.order, toNextProperty?.order ?? null]
|
||||
: [toNextProperty?.order ?? null, toProperty.order];
|
||||
const newOrder = generateKeyBetween(...args);
|
||||
this.properties!.custom[fromProperty.id].order = newOrder;
|
||||
}
|
||||
|
||||
hasCustomProperty(id: string) {
|
||||
return !!this.properties?.custom[id];
|
||||
}
|
||||
|
||||
@@ -101,10 +101,7 @@ interface SortablePropertiesProps {
|
||||
|
||||
const SortableProperties = ({ children }: SortablePropertiesProps) => {
|
||||
const manager = useContext(managerContext);
|
||||
const properties = useMemo(
|
||||
() => manager.getOrderedCustomProperties(),
|
||||
[manager]
|
||||
);
|
||||
const properties = useMemo(() => manager.sorter.getOrderedItems(), [manager]);
|
||||
const editingItem = useAtomValue(editingPropertyAtom);
|
||||
const draggable = !manager.readonly && !editingItem;
|
||||
const sensors = useSensors(
|
||||
@@ -128,15 +125,12 @@ const SortableProperties = ({ children }: SortablePropertiesProps) => {
|
||||
return;
|
||||
}
|
||||
const { active, over } = event;
|
||||
const fromIndex = properties.findIndex(p => p.id === active.id);
|
||||
const toIndex = properties.findIndex(p => p.id === over?.id);
|
||||
|
||||
if (fromIndex !== -1 && toIndex !== -1 && fromIndex !== toIndex) {
|
||||
manager.moveCustomProperty(fromIndex, toIndex);
|
||||
setLocalProperties(manager.getOrderedCustomProperties());
|
||||
if (over) {
|
||||
manager.sorter.move(active.id, over.id);
|
||||
}
|
||||
setLocalProperties(manager.sorter.getOrderedItems());
|
||||
},
|
||||
[manager, properties, draggable]
|
||||
[manager, draggable]
|
||||
);
|
||||
|
||||
const filteredProperties = useMemo(
|
||||
@@ -636,7 +630,7 @@ export const PagePropertiesTableHeader = ({
|
||||
onOpenChange(!open);
|
||||
}, [onOpenChange, open]);
|
||||
|
||||
const properties = manager.getOrderedCustomProperties();
|
||||
const properties = manager.sorter.getOrderedItems();
|
||||
|
||||
return (
|
||||
<div className={clsx(styles.tableHeader, className)} style={style}>
|
||||
|
||||
+6
-12
@@ -1,10 +1,9 @@
|
||||
import { FavoriteTag } from '@affine/core/components/page-list';
|
||||
import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper';
|
||||
import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import { toast } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { useService, Workspace } from '@toeverything/infra';
|
||||
import { useLiveData, useService, Workspace } from '@toeverything/infra';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export interface FavoriteButtonProps {
|
||||
@@ -16,24 +15,19 @@ export const useFavorite = (pageId: string) => {
|
||||
const workspace = useService(Workspace);
|
||||
const docCollection = workspace.docCollection;
|
||||
const currentPage = docCollection.getDoc(pageId);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
assertExists(currentPage);
|
||||
|
||||
const pageMeta = useBlockSuiteDocMeta(docCollection).find(
|
||||
meta => meta.id === pageId
|
||||
);
|
||||
const favorite = pageMeta?.favorite ?? false;
|
||||
|
||||
const { toggleFavorite: _toggleFavorite } =
|
||||
useBlockSuiteMetaHelper(docCollection);
|
||||
const favorite = useLiveData(favAdapter.isFavorite$(pageId, 'doc'));
|
||||
|
||||
const toggleFavorite = useCallback(() => {
|
||||
_toggleFavorite(pageId);
|
||||
favAdapter.toggle(pageId, 'doc');
|
||||
toast(
|
||||
favorite
|
||||
? t['com.affine.toastMessage.removedFavorites']()
|
||||
: t['com.affine.toastMessage.addedFavorites']()
|
||||
);
|
||||
}, [favorite, pageId, t, _toggleFavorite]);
|
||||
}, [favorite, pageId, t, favAdapter]);
|
||||
|
||||
return { favorite, toggleFavorite };
|
||||
};
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper';
|
||||
import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper';
|
||||
import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import type { Tag } from '@affine/core/modules/tag';
|
||||
import { Workbench } from '@affine/core/modules/workbench';
|
||||
import type { Collection, Filter } from '@affine/env/filter';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -30,13 +28,7 @@ import {
|
||||
} from './page-list-header';
|
||||
|
||||
const usePageOperationsRenderer = () => {
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const { setTrashModal } = useTrashModalHelper(currentWorkspace.docCollection);
|
||||
const { toggleFavorite, duplicate } = useBlockSuiteMetaHelper(
|
||||
currentWorkspace.docCollection
|
||||
);
|
||||
const t = useAFFiNEI18N();
|
||||
const workbench = useService(Workbench);
|
||||
const collectionService = useService(CollectionService);
|
||||
const removeFromAllowList = useCallback(
|
||||
(id: string) => {
|
||||
@@ -45,57 +37,18 @@ const usePageOperationsRenderer = () => {
|
||||
},
|
||||
[collectionService, t]
|
||||
);
|
||||
|
||||
const pageOperationsRenderer = useCallback(
|
||||
(page: DocMeta, isInAllowList?: boolean) => {
|
||||
const onDisablePublicSharing = () => {
|
||||
toast('Successfully disabled', {
|
||||
portal: document.body,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<PageOperationCell
|
||||
favorite={!!page.favorite}
|
||||
isPublic={!!page.isPublic}
|
||||
page={page}
|
||||
isInAllowList={isInAllowList}
|
||||
onDisablePublicSharing={onDisablePublicSharing}
|
||||
link={`/workspace/${currentWorkspace.id}/${page.id}`}
|
||||
onOpenInSplitView={() => workbench.openPage(page.id, { at: 'tail' })}
|
||||
onDuplicate={() => {
|
||||
duplicate(page.id, false);
|
||||
}}
|
||||
onRemoveToTrash={() =>
|
||||
setTrashModal({
|
||||
open: true,
|
||||
pageIds: [page.id],
|
||||
pageTitles: [page.title],
|
||||
})
|
||||
}
|
||||
onToggleFavoritePage={() => {
|
||||
const status = page.favorite;
|
||||
toggleFavorite(page.id);
|
||||
toast(
|
||||
status
|
||||
? t['com.affine.toastMessage.removedFavorites']()
|
||||
: t['com.affine.toastMessage.addedFavorites']()
|
||||
);
|
||||
}}
|
||||
onRemoveFromAllowList={() => removeFromAllowList(page.id)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[
|
||||
currentWorkspace.id,
|
||||
workbench,
|
||||
duplicate,
|
||||
setTrashModal,
|
||||
toggleFavorite,
|
||||
t,
|
||||
removeFromAllowList,
|
||||
]
|
||||
[removeFromAllowList]
|
||||
);
|
||||
|
||||
return pageOperationsRenderer;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Tag } from '@affine/core/modules/tag';
|
||||
import { TagService } from '@affine/core/modules/tag';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { FavoritedIcon, FavoriteIcon } from '@blocksuite/icons';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
@@ -154,6 +155,8 @@ export const useFavoriteGroupDefinitions = <
|
||||
T extends ListItem,
|
||||
>(): ItemGroupDefinition<T>[] => {
|
||||
const t = useAFFiNEI18N();
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favourites = useLiveData(favAdapter.favorites$);
|
||||
return useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -166,7 +169,7 @@ export const useFavoriteGroupDefinitions = <
|
||||
icon={<FavoritedIcon className={styles.favouritedIcon} />}
|
||||
/>
|
||||
),
|
||||
match: item => !!(item as DocMeta).favorite,
|
||||
match: item => favourites.some(fav => fav.id === item.id),
|
||||
},
|
||||
{
|
||||
id: 'notFavourited',
|
||||
@@ -178,10 +181,10 @@ export const useFavoriteGroupDefinitions = <
|
||||
icon={<FavoriteIcon className={styles.notFavouritedIcon} />}
|
||||
/>
|
||||
),
|
||||
match: item => !(item as DocMeta).favorite,
|
||||
match: item => !favourites.some(fav => fav.id === item.id),
|
||||
},
|
||||
],
|
||||
[t]
|
||||
[t, favourites]
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,9 +4,14 @@ import {
|
||||
Menu,
|
||||
MenuIcon,
|
||||
MenuItem,
|
||||
toast,
|
||||
Tooltip,
|
||||
} from '@affine/component';
|
||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
||||
import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper';
|
||||
import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper';
|
||||
import { Workbench } from '@affine/core/modules/workbench';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import type { Collection, DeleteCollectionInfo } from '@affine/env/filter';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
@@ -23,6 +28,8 @@ import {
|
||||
ResetIcon,
|
||||
SplitViewIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService, Workspace } from '@toeverything/infra';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
@@ -37,37 +44,61 @@ import type { AllPageListConfig } from './view';
|
||||
import { useEditCollection, useEditCollectionName } from './view';
|
||||
|
||||
export interface PageOperationCellProps {
|
||||
favorite: boolean;
|
||||
isPublic: boolean;
|
||||
link: string;
|
||||
page: DocMeta;
|
||||
isInAllowList?: boolean;
|
||||
onToggleFavoritePage: () => void;
|
||||
onRemoveToTrash: () => void;
|
||||
onDuplicate: () => void;
|
||||
onDisablePublicSharing: () => void;
|
||||
onOpenInSplitView: () => void;
|
||||
onRemoveFromAllowList?: () => void;
|
||||
}
|
||||
|
||||
export const PageOperationCell = ({
|
||||
favorite,
|
||||
isPublic,
|
||||
isInAllowList,
|
||||
link,
|
||||
onToggleFavoritePage,
|
||||
onRemoveToTrash,
|
||||
onDuplicate,
|
||||
onDisablePublicSharing,
|
||||
onOpenInSplitView,
|
||||
page,
|
||||
onRemoveFromAllowList,
|
||||
}: PageOperationCellProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const { appSettings } = useAppSettingHelper();
|
||||
const { setTrashModal } = useTrashModalHelper(currentWorkspace.docCollection);
|
||||
const [openDisableShared, setOpenDisableShared] = useState(false);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favourite = useLiveData(favAdapter.isFavorite$(page.id, 'doc'));
|
||||
const workbench = useService(Workbench);
|
||||
const { duplicate } = useBlockSuiteMetaHelper(currentWorkspace.docCollection);
|
||||
|
||||
const onDisablePublicSharing = useCallback(() => {
|
||||
toast('Successfully disabled', {
|
||||
portal: document.body,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onRemoveToTrash = useCallback(() => {
|
||||
setTrashModal({
|
||||
open: true,
|
||||
pageIds: [page.id],
|
||||
pageTitles: [page.title],
|
||||
});
|
||||
}, [page.id, page.title, setTrashModal]);
|
||||
|
||||
const onOpenInSplitView = useCallback(() => {
|
||||
workbench.openPage(page.id, { at: 'tail' });
|
||||
}, [page.id, workbench]);
|
||||
|
||||
const onToggleFavoritePage = useCallback(() => {
|
||||
const status = favAdapter.isFavorite(page.id, 'doc');
|
||||
favAdapter.toggle(page.id, 'doc');
|
||||
toast(
|
||||
status
|
||||
? t['com.affine.toastMessage.removedFavorites']()
|
||||
: t['com.affine.toastMessage.addedFavorites']()
|
||||
);
|
||||
}, [page.id, favAdapter, t]);
|
||||
|
||||
const onDuplicate = useCallback(() => {
|
||||
duplicate(page.id, false);
|
||||
}, [duplicate, page.id]);
|
||||
|
||||
const OperationMenu = (
|
||||
<>
|
||||
{isPublic && (
|
||||
{page.isPublic && (
|
||||
<DisablePublicSharing
|
||||
data-testid="disable-public-sharing"
|
||||
onSelect={() => {
|
||||
@@ -91,7 +122,7 @@ export const PageOperationCell = ({
|
||||
onClick={onToggleFavoritePage}
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
{favorite ? (
|
||||
{favourite ? (
|
||||
<FavoritedIcon style={{ color: 'var(--affine-primary-color)' }} />
|
||||
) : (
|
||||
<FavoriteIcon />
|
||||
@@ -99,7 +130,7 @@ export const PageOperationCell = ({
|
||||
</MenuIcon>
|
||||
}
|
||||
>
|
||||
{favorite
|
||||
{favourite
|
||||
? t['com.affine.favoritePageOperation.remove']()
|
||||
: t['com.affine.favoritePageOperation.add']()}
|
||||
</MenuItem>
|
||||
@@ -121,7 +152,7 @@ export const PageOperationCell = ({
|
||||
<Link
|
||||
className={styles.clearLinkStyle}
|
||||
onClick={stopPropagationWithoutPrevent}
|
||||
to={link}
|
||||
to={`/workspace/${currentWorkspace.id}/${page.id}`}
|
||||
target={'_blank'}
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
@@ -157,10 +188,10 @@ export const PageOperationCell = ({
|
||||
<ColWrapper
|
||||
hideInSmallContainer
|
||||
data-testid="page-list-item-favorite"
|
||||
data-favorite={favorite ? true : undefined}
|
||||
data-favorite={favourite ? true : undefined}
|
||||
className={styles.favoriteCell}
|
||||
>
|
||||
<FavoriteTag onClick={onToggleFavoritePage} active={favorite} />
|
||||
<FavoriteTag onClick={onToggleFavoritePage} active={favourite} />
|
||||
</ColWrapper>
|
||||
<ColWrapper alignment="start">
|
||||
<Menu
|
||||
|
||||
@@ -21,6 +21,7 @@ export const filterByFilterList = (filterList: Filter[], varMap: VariableMap) =>
|
||||
|
||||
export type PageDataForFilter = {
|
||||
meta: DocMeta;
|
||||
favorite: boolean;
|
||||
publicMode: undefined | 'page' | 'edgeless';
|
||||
};
|
||||
|
||||
@@ -33,13 +34,13 @@ export const filterPage = (collection: Collection, page: PageDataForFilter) => {
|
||||
export const filterPageByRules = (
|
||||
rules: Filter[],
|
||||
allowList: string[],
|
||||
{ meta, publicMode }: PageDataForFilter
|
||||
{ meta, publicMode, favorite }: PageDataForFilter
|
||||
) => {
|
||||
if (allowList?.includes(meta.id)) {
|
||||
return true;
|
||||
}
|
||||
return filterByFilterList(rules, {
|
||||
'Is Favourited': !!meta.favorite,
|
||||
'Is Favourited': !!favorite,
|
||||
'Is Public': !!publicMode,
|
||||
Created: meta.createDate,
|
||||
Updated: meta.updatedDate ?? meta.createDate,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import type { Collection, Filter } from '@affine/env/filter';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import type { Workspace } from '@toeverything/infra';
|
||||
import { useLiveData, useService, type Workspace } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { usePublicPages } from '../../hooks/affine/use-is-shared-page';
|
||||
@@ -16,6 +17,8 @@ export const useFilteredPageMetas = (
|
||||
} = {}
|
||||
) => {
|
||||
const { getPublicMode } = usePublicPages(workspace);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favoriteItems = useLiveData(favAdapter.favorites$);
|
||||
|
||||
const filteredPageMetas = useMemo(
|
||||
() =>
|
||||
@@ -29,6 +32,7 @@ export const useFilteredPageMetas = (
|
||||
}
|
||||
const pageData = {
|
||||
meta: pageMeta,
|
||||
favorite: favoriteItems.some(fav => fav.id === pageMeta.id),
|
||||
publicMode: getPublicMode(pageMeta.id),
|
||||
};
|
||||
if (
|
||||
@@ -49,6 +53,7 @@ export const useFilteredPageMetas = (
|
||||
options.trash,
|
||||
options.filters,
|
||||
options.collection,
|
||||
favoriteItems,
|
||||
getPublicMode,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Menu } from '@affine/component';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { FilterIcon } from '@blocksuite/icons';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
@@ -34,6 +36,8 @@ export const PagesMode = ({
|
||||
allPageListConfig: AllPageListConfig;
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favorites = useLiveData(favAdapter.favorites$);
|
||||
const {
|
||||
showFilter,
|
||||
filters,
|
||||
@@ -45,6 +49,7 @@ export const PagesMode = ({
|
||||
allPageListConfig.allPages.map(meta => ({
|
||||
meta,
|
||||
publicMode: allPageListConfig.getPublicMode(meta.id),
|
||||
favorite: favorites.some(f => f.id === meta.id),
|
||||
}))
|
||||
);
|
||||
const pageHeaderColsDef = usePageHeaderColsDef();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -9,6 +10,7 @@ import {
|
||||
ToggleCollapseIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
@@ -42,6 +44,8 @@ export const RulesMode = ({
|
||||
const allowListPages: DocMeta[] = [];
|
||||
const rulesPages: DocMeta[] = [];
|
||||
const [showTips, setShowTips] = useState(false);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favorites = useLiveData(favAdapter.favorites$);
|
||||
useEffect(() => {
|
||||
setShowTips(!localStorage.getItem('hide-rules-mode-include-page-tips'));
|
||||
}, []);
|
||||
@@ -56,6 +60,7 @@ export const RulesMode = ({
|
||||
const pageData = {
|
||||
meta,
|
||||
publicMode: allPageListConfig.getPublicMode(meta.id),
|
||||
favorite: favorites.some(f => f.id === meta.id),
|
||||
};
|
||||
if (
|
||||
collection.filterList.length &&
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Button, Menu } from '@affine/component';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { FilterIcon } from '@blocksuite/icons';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
@@ -35,6 +37,8 @@ export const SelectPage = ({
|
||||
const clearSelected = useCallback(() => {
|
||||
onChange([]);
|
||||
}, []);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favourites = useLiveData(favAdapter.favorites$);
|
||||
const {
|
||||
clickFilter,
|
||||
createFilter,
|
||||
@@ -46,6 +50,7 @@ export const SelectPage = ({
|
||||
allPageListConfig.allPages.map(meta => ({
|
||||
meta,
|
||||
publicMode: allPageListConfig.getPublicMode(meta.id),
|
||||
favorite: favourites.some(fav => fav.id === meta.id),
|
||||
}))
|
||||
);
|
||||
const { searchText, updateSearchText, searchedList } =
|
||||
|
||||
+5
@@ -7,6 +7,7 @@ import {
|
||||
stopPropagation,
|
||||
} from '@affine/core/components/page-list';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import type { Collection, DeleteCollectionInfo } from '@affine/env/filter';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { MoreHorizontalIcon, ViewLayersIcon } from '@blocksuite/icons';
|
||||
@@ -40,9 +41,12 @@ const CollectionRenderer = ({
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const [open, setOpen] = useState(false);
|
||||
const collectionService = useService(CollectionService);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const t = useAFFiNEI18N();
|
||||
const dragItemId = getDropItemId('collections', collection.id);
|
||||
|
||||
const favourites = useLiveData(favAdapter.favorites$);
|
||||
|
||||
const removeFromAllowList = useCallback(
|
||||
(id: string) => {
|
||||
collectionService.updateCollection(collection.id, () => ({
|
||||
@@ -85,6 +89,7 @@ const CollectionRenderer = ({
|
||||
const pageData = {
|
||||
meta,
|
||||
publicMode: config.getPublicMode(meta.id),
|
||||
favorite: favourites.some(fav => fav.id === meta.id),
|
||||
};
|
||||
return filterPage(collection, pageData);
|
||||
});
|
||||
|
||||
+5
-4
@@ -2,13 +2,13 @@ import { toast } from '@affine/component';
|
||||
import { IconButton } from '@affine/component/ui/button';
|
||||
import { Menu } from '@affine/component/ui/menu';
|
||||
import { Workbench } from '@affine/core/modules/workbench';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { MoreHorizontalIcon } from '@blocksuite/icons';
|
||||
import type { DocCollection } from '@blocksuite/store';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useBlockSuiteMetaHelper } from '../../../../hooks/affine/use-block-suite-meta-helper';
|
||||
import { useTrashModalHelper } from '../../../../hooks/affine/use-trash-modal-helper';
|
||||
import { usePageHelper } from '../../../blocksuite/block-suite-page-list/utils';
|
||||
import { OperationItems } from './operation-item';
|
||||
@@ -38,7 +38,8 @@ export const OperationMenuButton = ({ ...props }: OperationMenuButtonProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const { createLinkedPage } = usePageHelper(docCollection);
|
||||
const { setTrashModal } = useTrashModalHelper(docCollection);
|
||||
const { removeFromFavorite } = useBlockSuiteMetaHelper(docCollection);
|
||||
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const workbench = useService(Workbench);
|
||||
|
||||
const handleRename = useCallback(() => {
|
||||
@@ -51,9 +52,9 @@ export const OperationMenuButton = ({ ...props }: OperationMenuButtonProps) => {
|
||||
}, [createLinkedPage, pageId, t]);
|
||||
|
||||
const handleRemoveFromFavourites = useCallback(() => {
|
||||
removeFromFavorite(pageId);
|
||||
favAdapter.remove(pageId, 'doc');
|
||||
toast(t['com.affine.toastMessage.removedFavorites']());
|
||||
}, [pageId, removeFromFavorite, t]);
|
||||
}, [favAdapter, pageId, t]);
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
setTrashModal({
|
||||
|
||||
+5
-4
@@ -1,8 +1,9 @@
|
||||
import { IconButton } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useDocMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import { PlusIcon } from '@blocksuite/icons';
|
||||
import type { DocCollection } from '@blocksuite/store';
|
||||
import { useService } from '@toeverything/infra';
|
||||
|
||||
import { usePageHelper } from '../../../blocksuite/block-suite-page-list/utils';
|
||||
|
||||
@@ -16,7 +17,7 @@ export const AddFavouriteButton = ({
|
||||
pageId,
|
||||
}: AddFavouriteButtonProps) => {
|
||||
const { createPage, createLinkedPage } = usePageHelper(docCollection);
|
||||
const { setDocMeta } = useDocMetaHelper(docCollection);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const handleAddFavorite = useAsyncCallback(
|
||||
async e => {
|
||||
if (pageId) {
|
||||
@@ -26,10 +27,10 @@ export const AddFavouriteButton = ({
|
||||
} else {
|
||||
const page = createPage();
|
||||
page.load();
|
||||
setDocMeta(page.id, { favorite: true });
|
||||
favAdapter.set(page.id, 'doc', true);
|
||||
}
|
||||
},
|
||||
[pageId, createLinkedPage, createPage, setDocMeta]
|
||||
[pageId, createLinkedPage, createPage, favAdapter]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
+12
-5
@@ -1,6 +1,8 @@
|
||||
import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/workspace';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { getDropItemId } from '../../../../hooks/affine/use-sidebar-drag';
|
||||
@@ -15,11 +17,16 @@ export const FavoriteList = ({
|
||||
docCollection: workspace,
|
||||
}: FavoriteListProps) => {
|
||||
const metas = useBlockSuiteDocMeta(workspace);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const dropItemId = getDropItemId('favorites');
|
||||
|
||||
const favoriteList = useMemo(
|
||||
() => metas.filter(p => p.favorite && !p.trash),
|
||||
[metas]
|
||||
const favourites = useLiveData(
|
||||
favAdapter.favorites$.map(favourites =>
|
||||
favourites.filter(fav => {
|
||||
const meta = metas.find(m => m.id === fav.id);
|
||||
return meta && !meta.trash;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const metaMapping = useMemo(
|
||||
@@ -45,7 +52,7 @@ export const FavoriteList = ({
|
||||
ref={setNodeRef}
|
||||
data-over={isOver}
|
||||
>
|
||||
{favoriteList.map((pageMeta, index) => {
|
||||
{favourites.map((pageMeta, index) => {
|
||||
return (
|
||||
<FavouritePage
|
||||
key={`${pageMeta}-${index}`}
|
||||
@@ -57,7 +64,7 @@ export const FavoriteList = ({
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{favoriteList.length === 0 && <EmptyItem />}
|
||||
{favourites.length === 0 && <EmptyItem />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user