mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-21 03:56:23 +08:00
feat(core): new favorite (#7590)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const root = style({
|
||||
fontSize: cssVar('fontXs'),
|
||||
minHeight: '16px',
|
||||
@@ -10,6 +11,7 @@ export const root = style({
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: '4px',
|
||||
padding: '0 8px',
|
||||
gap: '8px',
|
||||
selectors: {
|
||||
'&:not(:first-of-type)': {
|
||||
marginTop: '16px',
|
||||
@@ -18,4 +20,5 @@ export const root = style({
|
||||
});
|
||||
export const label = style({
|
||||
color: cssVar('black30'),
|
||||
flex: '1',
|
||||
});
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { FavoriteTag } from '@affine/core/components/page-list';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { toast } from '@affine/core/utils';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
@@ -11,7 +11,7 @@ export interface FavoriteButtonProps {
|
||||
|
||||
export const useFavorite = (pageId: string) => {
|
||||
const t = useI18n();
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
|
||||
const favorite = useLiveData(favAdapter.isFavorite$(pageId, 'doc'));
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import type { Tag } from '@affine/core/modules/tag';
|
||||
import { TagService } from '@affine/core/modules/tag';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -131,9 +131,9 @@ export const useTagGroupDefinitions = (): ItemGroupDefinition<ListItem>[] => {
|
||||
const sortedTagsLiveData$ = useMemo(
|
||||
() =>
|
||||
LiveData.computed(get =>
|
||||
get(tagList.tags$).sort((a, b) =>
|
||||
get(a.value$).localeCompare(get(b.value$))
|
||||
)
|
||||
get(tagList.tags$)
|
||||
.slice()
|
||||
.sort((a, b) => get(a.value$).localeCompare(get(b.value$)))
|
||||
),
|
||||
[tagList.tags$]
|
||||
);
|
||||
@@ -174,7 +174,7 @@ export const useFavoriteGroupDefinitions = <
|
||||
T extends ListItem,
|
||||
>(): ItemGroupDefinition<T>[] => {
|
||||
const t = useI18n();
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
const favourites = useLiveData(favAdapter.favorites$);
|
||||
return useMemo(
|
||||
() => [
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createContainer, style } from '@vanilla-extract/css';
|
||||
|
||||
import { root as collectionItemRoot } from './collections/collection-list-item.css';
|
||||
import { root as pageItemRoot } from './docs/page-list-item.css';
|
||||
import { root as tagItemRoot } from './tags/tag-list-item.css';
|
||||
export const listRootContainer = createContainer('list-root-container');
|
||||
export const pageListScrollContainer = style({
|
||||
width: '100%',
|
||||
@@ -49,7 +50,7 @@ export const favoriteCell = style({
|
||||
flexShrink: 0,
|
||||
opacity: 0,
|
||||
selectors: {
|
||||
[`&[data-favorite], ${pageItemRoot}:hover &, ${collectionItemRoot}:hover &`]:
|
||||
[`&[data-favorite], ${pageItemRoot}:hover &, ${collectionItemRoot}:hover &, ${tagItemRoot}:hover &`]:
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
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 { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { FavoriteService } from '@affine/core/modules/favorite';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import type { Collection, DeleteCollectionInfo } from '@affine/env/filter';
|
||||
@@ -32,7 +33,12 @@ import {
|
||||
SplitViewIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
||||
import {
|
||||
useLiveData,
|
||||
useService,
|
||||
useServices,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
@@ -63,7 +69,7 @@ export const PageOperationCell = ({
|
||||
const { appSettings } = useAppSettingHelper();
|
||||
const { setTrashModal } = useTrashModalHelper(currentWorkspace.docCollection);
|
||||
const [openDisableShared, setOpenDisableShared] = useState(false);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
const favourite = useLiveData(favAdapter.isFavorite$(page.id, 'doc'));
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
const { duplicate } = useBlockSuiteMetaHelper(currentWorkspace.docCollection);
|
||||
@@ -215,14 +221,16 @@ export const PageOperationCell = ({
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<ColWrapper
|
||||
hideInSmallContainer
|
||||
data-testid="page-list-item-favorite"
|
||||
data-favorite={favourite ? true : undefined}
|
||||
className={styles.favoriteCell}
|
||||
>
|
||||
<FavoriteTag onClick={onToggleFavoritePage} active={favourite} />
|
||||
</ColWrapper>
|
||||
{runtimeConfig.enableNewFavorite && (
|
||||
<ColWrapper
|
||||
hideInSmallContainer
|
||||
data-testid="page-list-item-favorite"
|
||||
data-favorite={favourite ? true : undefined}
|
||||
className={styles.favoriteCell}
|
||||
>
|
||||
<FavoriteTag onClick={onToggleFavoritePage} active={favourite} />
|
||||
</ColWrapper>
|
||||
)}
|
||||
<ColWrapper alignment="start">
|
||||
<Menu
|
||||
items={OperationMenu}
|
||||
@@ -319,7 +327,7 @@ export const CollectionOperationCell = ({
|
||||
}: CollectionOperationCellProps) => {
|
||||
const t = useI18n();
|
||||
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
const docCollection = useService(WorkspaceService).workspace.docCollection;
|
||||
const { createPage } = usePageHelper(docCollection);
|
||||
const { openConfirmModal } = useConfirmModal();
|
||||
@@ -482,12 +490,31 @@ export const TagOperationCell = ({
|
||||
}: TagOperationCellProps) => {
|
||||
const t = useI18n();
|
||||
const [open, setOpen] = useState(false);
|
||||
const { favoriteService } = useServices({
|
||||
FavoriteService,
|
||||
});
|
||||
const favourite = useLiveData(
|
||||
favoriteService.favoriteList.isFavorite$('tag', tag.id)
|
||||
);
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
onTagDelete([tag.id]);
|
||||
}, [onTagDelete, tag.id]);
|
||||
|
||||
const onToggleFavoriteCollection = useCallback(() => {
|
||||
favoriteService.favoriteList.toggle('tag', tag.id);
|
||||
}, [favoriteService, tag.id]);
|
||||
return (
|
||||
<>
|
||||
<ColWrapper
|
||||
hideInSmallContainer
|
||||
data-testid="page-list-item-favorite"
|
||||
data-favorite={favourite ? true : undefined}
|
||||
className={styles.favoriteCell}
|
||||
>
|
||||
<FavoriteTag onClick={onToggleFavoriteCollection} active={favourite} />
|
||||
</ColWrapper>
|
||||
|
||||
<div className={styles.editTagWrapper} data-show={open}>
|
||||
<div style={{ width: '100%' }}>
|
||||
<CreateOrEditTag open={open} onOpenChange={setOpen} tagMeta={tag} />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { ShareDocsService } from '@affine/core/modules/share-doc';
|
||||
import type { Collection, Filter } from '@affine/env/filter';
|
||||
import { PublicPageMode } from '@affine/graphql';
|
||||
@@ -36,7 +36,7 @@ export const useFilteredPageMetas = (
|
||||
shareDocsService.shareDocs?.revalidate();
|
||||
}, [shareDocsService]);
|
||||
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
const favoriteItems = useLiveData(favAdapter.favorites$);
|
||||
|
||||
const filteredPageMetas = useMemo(
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { MenuItemProps } from '@affine/component';
|
||||
import { Menu, MenuIcon, MenuItem } from '@affine/component';
|
||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
||||
import { useDeleteCollectionInfo } from '@affine/core/hooks/affine/use-delete-collection-info';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -79,7 +79,7 @@ export const CollectionOperations = ({
|
||||
workbench.openCollection(collection.id, { at: 'tail' });
|
||||
}, [collection.id, workbench]);
|
||||
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
|
||||
const onToggleFavoritePage = useCallback(() => {
|
||||
favAdapter.toggle(collection.id, 'collection');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Tooltip } from '@affine/component';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import {
|
||||
@@ -42,7 +42,7 @@ export const RulesMode = ({
|
||||
const [showPreview, setShowPreview] = useState(true);
|
||||
const allowListPages: DocMeta[] = [];
|
||||
const rulesPages: DocMeta[] = [];
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
const favorites = useLiveData(favAdapter.favorites$);
|
||||
allPageListConfig.allPages.forEach(meta => {
|
||||
if (meta.trash) {
|
||||
|
||||
+6
-6
@@ -1,6 +1,6 @@
|
||||
import { Menu, toast } from '@affine/component';
|
||||
import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { ShareDocsService } from '@affine/core/modules/share-doc';
|
||||
import { PublicPageMode } from '@affine/graphql';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
@@ -60,20 +60,20 @@ export const SelectPage = ({
|
||||
}, [onChange]);
|
||||
const {
|
||||
workspaceService,
|
||||
favoriteItemsAdapter,
|
||||
compatibleFavoriteItemsAdapter,
|
||||
shareDocsService,
|
||||
docsService,
|
||||
} = useServices({
|
||||
DocsService,
|
||||
ShareDocsService,
|
||||
WorkspaceService,
|
||||
FavoriteItemsAdapter,
|
||||
CompatibleFavoriteItemsAdapter,
|
||||
});
|
||||
const shareDocs = useLiveData(shareDocsService.shareDocs?.list$);
|
||||
const workspace = workspaceService.workspace;
|
||||
const docCollection = workspace.docCollection;
|
||||
const pageMetas = useBlockSuiteDocMeta(docCollection);
|
||||
const favourites = useLiveData(favoriteItemsAdapter.favorites$);
|
||||
const favourites = useLiveData(compatibleFavoriteItemsAdapter.favorites$);
|
||||
|
||||
useEffect(() => {
|
||||
shareDocsService.shareDocs?.revalidate();
|
||||
@@ -108,14 +108,14 @@ export const SelectPage = ({
|
||||
const onToggleFavoritePage = useCallback(
|
||||
(page: DocMeta) => {
|
||||
const status = isFavorite(page);
|
||||
favoriteItemsAdapter.toggle(page.id, 'doc');
|
||||
compatibleFavoriteItemsAdapter.toggle(page.id, 'doc');
|
||||
toast(
|
||||
status
|
||||
? t['com.affine.toastMessage.removedFavorites']()
|
||||
: t['com.affine.toastMessage.addedFavorites']()
|
||||
);
|
||||
},
|
||||
[favoriteItemsAdapter, isFavorite, t]
|
||||
[compatibleFavoriteItemsAdapter, isFavorite, t]
|
||||
);
|
||||
|
||||
const pageHeaderColsDef = usePageHeaderColsDef();
|
||||
|
||||
@@ -2,6 +2,8 @@ import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import {
|
||||
ExplorerCollections,
|
||||
ExplorerFavorites,
|
||||
ExplorerMigrationFavorites,
|
||||
ExplorerOldFavorites,
|
||||
ExplorerOrganize,
|
||||
} from '@affine/core/modules/explorer';
|
||||
import { ExplorerTags } from '@affine/core/modules/explorer/views/sections/tags';
|
||||
@@ -161,8 +163,10 @@ export const RootAppSidebar = memo(
|
||||
</MenuItem>
|
||||
</SidebarContainer>
|
||||
<SidebarScrollableContainer>
|
||||
{runtimeConfig.enableNewFavorite && <ExplorerFavorites />}
|
||||
{runtimeConfig.enableOrganize && <ExplorerOrganize />}
|
||||
<ExplorerFavorites />
|
||||
{runtimeConfig.enableNewFavorite && <ExplorerMigrationFavorites />}
|
||||
{runtimeConfig.enableOldFavorite && <ExplorerOldFavorites />}
|
||||
<ExplorerCollections />
|
||||
<ExplorerTags />
|
||||
<CategoryDivider label={t['com.affine.rootAppSidebar.others']()} />
|
||||
|
||||
Reference in New Issue
Block a user