diff --git a/packages/frontend/core/src/components/app-sidebar/category-divider/index.css.ts b/packages/frontend/core/src/components/app-sidebar/category-divider/index.css.ts index f56fb678e9..5380eca67d 100644 --- a/packages/frontend/core/src/components/app-sidebar/category-divider/index.css.ts +++ b/packages/frontend/core/src/components/app-sidebar/category-divider/index.css.ts @@ -1,25 +1,37 @@ import { cssVar } from '@toeverything/theme'; +import { cssVarV2 } from '@toeverything/theme/v2'; import { style } from '@vanilla-extract/css'; +export const actions = style({ + display: 'flex', + gap: 8, +}); export const root = style({ fontSize: cssVar('fontXs'), - minHeight: '16px', - width: 'calc(100% + 6px)', + height: 20, + width: 'calc(100%)', userSelect: 'none', display: 'flex', alignItems: 'center', justifyContent: 'space-between', - marginBottom: '4px', padding: '0 8px', - gap: '8px', + borderRadius: 4, selectors: { - '&:not(:first-of-type)': { - marginTop: '16px', + [`&[data-collapsible="true"]`]: { + cursor: 'pointer', + }, + [`&[data-collapsible="true"]:hover`]: { + backgroundColor: cssVarV2('layer/background/hoverOverlay'), + }, + [`&[data-collapsible="true"]:hover:has(${actions}:hover)`]: { + backgroundColor: 'transparent', }, }, }); export const label = style({ - color: cssVar('black30'), + color: cssVarV2('text/tertiary'), + fontWeight: 500, + lineHeight: '20px', flexGrow: '0', display: 'flex', alignItems: 'center', @@ -30,8 +42,17 @@ export const label = style({ export const collapseButton = style({ selectors: { [`${label} > &`]: { - color: cssVar('black30'), + color: cssVarV2('icon/tertiary'), transform: 'translateY(1px)', }, }, }); +export const collapseIcon = style({ + transform: 'rotate(90deg)', + transition: 'transform 0.2s', + selectors: { + [`${root}[data-collapsed="true"] &`]: { + transform: 'rotate(0deg)', + }, + }, +}); diff --git a/packages/frontend/core/src/components/app-sidebar/category-divider/index.tsx b/packages/frontend/core/src/components/app-sidebar/category-divider/index.tsx index dfc85bf149..55b0d1bf5e 100644 --- a/packages/frontend/core/src/components/app-sidebar/category-divider/index.tsx +++ b/packages/frontend/core/src/components/app-sidebar/category-divider/index.tsx @@ -1,5 +1,5 @@ import { IconButton } from '@affine/component'; -import { ToggleCollapseIcon, ToggleExpandIcon } from '@blocksuite/icons/rc'; +import { ToggleCollapseIcon } from '@blocksuite/icons/rc'; import clsx from 'clsx'; import { type ForwardedRef, forwardRef, type PropsWithChildren } from 'react'; @@ -28,26 +28,33 @@ export const CategoryDivider = forwardRef( }: CategoryDividerProps, ref: ForwardedRef ) => { + const collapsible = collapsed !== undefined; + return ( -
-
setCollapsed?.(!collapsed)} - > +
setCollapsed?.(!collapsed)} + data-collapsed={collapsed} + data-collapsible={collapsible} + {...otherProps} + > +
{label} - {collapsed !== undefined && ( + {collapsible ? ( - {collapsed ? : } + - )} + ) : null} +
+
e.stopPropagation()}> + {children}
-
- {children}
); } diff --git a/packages/frontend/core/src/components/app-sidebar/sidebar-containers/index.css.ts b/packages/frontend/core/src/components/app-sidebar/sidebar-containers/index.css.ts index 658ca6e740..e17755f1f4 100644 --- a/packages/frontend/core/src/components/app-sidebar/sidebar-containers/index.css.ts +++ b/packages/frontend/core/src/components/app-sidebar/sidebar-containers/index.css.ts @@ -39,7 +39,10 @@ export const scrollableContainer = style([ baseContainer, { height: '100%', - padding: '4px 8px', + padding: '0px 8px', + display: 'flex', + flexDirection: 'column', + gap: 8, }, ]); export const scrollbar = style({ diff --git a/packages/frontend/core/src/components/root-app-sidebar/index.tsx b/packages/frontend/core/src/components/root-app-sidebar/index.tsx index 55bf02aa95..3bbc71b442 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/index.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/index.tsx @@ -188,14 +188,10 @@ export const RootAppSidebar = (): ReactElement => { {runtimeConfig.enableNewFavorite && } {runtimeConfig.enableOrganize && } {runtimeConfig.enableNewFavorite && } - {runtimeConfig.enableOldFavorite && ( - - )} - - + {runtimeConfig.enableOldFavorite && } + + - {/* fixme: remove the following spacer */} -
diff --git a/packages/frontend/core/src/modules/explorer/entities/explore-section.ts b/packages/frontend/core/src/modules/explorer/entities/explore-section.ts new file mode 100644 index 0000000000..f9fcced5da --- /dev/null +++ b/packages/frontend/core/src/modules/explorer/entities/explore-section.ts @@ -0,0 +1,35 @@ +import type { GlobalCache } from '@toeverything/infra'; +import { Entity, LiveData } from '@toeverything/infra'; +import { map } from 'rxjs'; + +import type { CollapsibleSectionName } from '../types'; + +const DEFAULT_COLLAPSABLE_STATE: Record = { + favorites: false, + organize: false, + collections: true, + tags: true, + favoritesOld: true, + migrationFavorites: true, +}; + +export class ExplorerSection extends Entity<{ name: CollapsibleSectionName }> { + name: CollapsibleSectionName = this.props.name; + key = `explorer.section.${this.name}`; + defaultValue = DEFAULT_COLLAPSABLE_STATE[this.name]; + + constructor(private readonly globalCache: GlobalCache) { + super(); + } + + collapsed$ = LiveData.from( + this.globalCache + .watch(this.key) + .pipe(map(v => v ?? this.defaultValue)), + this.defaultValue + ); + + setCollapsed(collapsed: boolean) { + this.globalCache.set(this.key, collapsed); + } +} diff --git a/packages/frontend/core/src/modules/explorer/index.ts b/packages/frontend/core/src/modules/explorer/index.ts index 0fc8071e95..fcf3e06e04 100644 --- a/packages/frontend/core/src/modules/explorer/index.ts +++ b/packages/frontend/core/src/modules/explorer/index.ts @@ -1,5 +1,22 @@ +import { + type Framework, + GlobalCache, + WorkspaceScope, +} from '@toeverything/infra'; + +import { ExplorerSection } from './entities/explore-section'; +import { ExplorerService } from './services/explorer'; +export { ExplorerService } from './services/explorer'; +export type { CollapsibleSectionName } from './types'; export { ExplorerCollections } from './views/sections/collections'; export { ExplorerFavorites } from './views/sections/favorites'; export { ExplorerMigrationFavorites } from './views/sections/migration-favorites'; export { ExplorerOldFavorites } from './views/sections/old-favorites'; export { ExplorerOrganize } from './views/sections/organize'; + +export function configureExplorerModule(framework: Framework) { + framework + .scope(WorkspaceScope) + .service(ExplorerService) + .entity(ExplorerSection, [GlobalCache]); +} diff --git a/packages/frontend/core/src/modules/explorer/services/explorer.ts b/packages/frontend/core/src/modules/explorer/services/explorer.ts new file mode 100644 index 0000000000..df5b628faf --- /dev/null +++ b/packages/frontend/core/src/modules/explorer/services/explorer.ts @@ -0,0 +1,23 @@ +import { Service } from '@toeverything/infra'; + +import { ExplorerSection } from '../entities/explore-section'; +import type { CollapsibleSectionName } from '../types'; + +const allSectionName: Array = [ + 'favorites', + 'organize', + 'collections', + 'tags', + 'favoritesOld', + 'migrationFavorites', +]; + +export class ExplorerService extends Service { + readonly sections = allSectionName.reduce( + (prev, name) => + Object.assign(prev, { + [name]: this.framework.createEntity(ExplorerSection, { name }), + }), + {} as Record + ); +} diff --git a/packages/frontend/core/src/modules/explorer/types.ts b/packages/frontend/core/src/modules/explorer/types.ts new file mode 100644 index 0000000000..b6169210df --- /dev/null +++ b/packages/frontend/core/src/modules/explorer/types.ts @@ -0,0 +1,7 @@ +export type CollapsibleSectionName = + | 'collections' + | 'favorites' + | 'tags' + | 'organize' + | 'favoritesOld' + | 'migrationFavorites'; diff --git a/packages/frontend/core/src/modules/explorer/views/layouts/collapsible-section.css.ts b/packages/frontend/core/src/modules/explorer/views/layouts/collapsible-section.css.ts new file mode 100644 index 0000000000..1ec7143720 --- /dev/null +++ b/packages/frontend/core/src/modules/explorer/views/layouts/collapsible-section.css.ts @@ -0,0 +1,6 @@ +import { style } from '@vanilla-extract/css'; + +export const root = style({}); +export const content = style({ + paddingTop: 6, +}); diff --git a/packages/frontend/core/src/modules/explorer/views/layouts/collapsible-section.tsx b/packages/frontend/core/src/modules/explorer/views/layouts/collapsible-section.tsx new file mode 100644 index 0000000000..36c27b39aa --- /dev/null +++ b/packages/frontend/core/src/modules/explorer/views/layouts/collapsible-section.tsx @@ -0,0 +1,79 @@ +import { CategoryDivider } from '@affine/core/components/app-sidebar'; +import * as Collapsible from '@radix-ui/react-collapsible'; +import { useLiveData, useService } from '@toeverything/infra'; +import clsx from 'clsx'; +import { + type PropsWithChildren, + type ReactNode, + type RefObject, + useCallback, +} from 'react'; + +import { ExplorerService } from '../../services/explorer'; +import type { CollapsibleSectionName } from '../../types'; +import { content, root } from './collapsible-section.css'; + +interface CollapsibleSectionProps extends PropsWithChildren { + name: CollapsibleSectionName; + title: string; + actions?: ReactNode; + + className?: string; + testId?: string; + + headerRef?: RefObject; + headerTestId?: string; + headerClassName?: string; + + contentClassName?: string; +} + +export const CollapsibleSection = ({ + name, + title, + actions, + children, + + className, + testId, + + headerRef, + headerTestId, + headerClassName, + + contentClassName, +}: CollapsibleSectionProps) => { + const section = useService(ExplorerService).sections[name]; + + const collapsed = useLiveData(section.collapsed$); + + const setCollapsed = useCallback( + (v: boolean) => { + section.setCollapsed(v); + }, + [section] + ); + + return ( + + + {actions} + + + {children} + + + ); +}; diff --git a/packages/frontend/core/src/modules/explorer/views/sections/collections/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/collections/index.tsx index 0c60d331f0..4cf71a38e8 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/collections/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/collections/index.tsx @@ -1,5 +1,4 @@ import { IconButton } from '@affine/component'; -import { CategoryDivider } from '@affine/core/components/app-sidebar'; import { useEditCollectionName } from '@affine/core/components/page-list'; import { createEmptyCollection } from '@affine/core/components/page-list/use-collection-manager'; import { mixpanel } from '@affine/core/mixpanel'; @@ -8,26 +7,23 @@ import { ExplorerTreeRoot } from '@affine/core/modules/explorer/views/tree'; import { WorkbenchService } from '@affine/core/modules/workbench'; import { useI18n } from '@affine/i18n'; import { PlusIcon } from '@blocksuite/icons/rc'; -import * as Collapsible from '@radix-ui/react-collapsible'; import { useLiveData, useServices } from '@toeverything/infra'; import { nanoid } from 'nanoid'; -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; +import { ExplorerService } from '../../../services/explorer'; +import { CollapsibleSection } from '../../layouts/collapsible-section'; import { ExplorerCollectionNode } from '../../nodes/collection'; import { RootEmpty } from './empty'; -import * as styles from './styles.css'; -export const ExplorerCollections = ({ - defaultCollapsed = false, -}: { - defaultCollapsed?: boolean; -}) => { +export const ExplorerCollections = () => { const t = useI18n(); - const { collectionService, workbenchService } = useServices({ + const { collectionService, workbenchService, explorerService } = useServices({ CollectionService, WorkbenchService, + ExplorerService, }); - const [collapsed, setCollapsed] = useState(defaultCollapsed); + const explorerSection = explorerService.sections.collections; const collections = useLiveData(collectionService.collections$); const { node, open: openCreateCollectionModel } = useEditCollectionName({ title: t['com.affine.editCollection.createCollection'](), @@ -45,25 +41,25 @@ export const ExplorerCollections = ({ control: 'new collection button', }); workbenchService.workbench.openCollection(id); - setCollapsed(false); + explorerSection.setCollapsed(false); }) .catch(err => { console.error(err); }); - }, [collectionService, openCreateCollectionModel, workbenchService]); + }, [ + collectionService, + explorerSection, + openCreateCollectionModel, + workbenchService.workbench, + ]); return ( <> - - + - - - } - > - {collections.map(collection => ( - - ))} - - - + } + > + } + > + {collections.map(collection => ( + + ))} + + {node} ); diff --git a/packages/frontend/core/src/modules/explorer/views/sections/collections/styles.css.ts b/packages/frontend/core/src/modules/explorer/views/sections/collections/styles.css.ts deleted file mode 100644 index 702eb729e8..0000000000 --- a/packages/frontend/core/src/modules/explorer/views/sections/collections/styles.css.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { style } from '@vanilla-extract/css'; - -export const container = style({ - marginTop: '8px', -}); diff --git a/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx index bf6b866ad0..30e2534fab 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx @@ -4,7 +4,6 @@ import { IconButton, useDropTarget, } from '@affine/component'; -import { CategoryDivider } from '@affine/core/components/app-sidebar'; import { mixpanel } from '@affine/core/mixpanel'; import { DropEffect, @@ -20,10 +19,11 @@ import { WorkbenchService } from '@affine/core/modules/workbench'; import type { AffineDNDData } from '@affine/core/types/dnd'; import { useI18n } from '@affine/i18n'; import { PlusIcon } from '@blocksuite/icons/rc'; -import * as Collapsible from '@radix-ui/react-collapsible'; import { DocsService, useLiveData, useServices } from '@toeverything/infra'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useMemo } from 'react'; +import { ExplorerService } from '../../../services/explorer'; +import { CollapsibleSection } from '../../layouts/collapsible-section'; import { ExplorerCollectionNode } from '../../nodes/collection'; import { ExplorerDocNode } from '../../nodes/doc'; import { ExplorerFolderNode } from '../../nodes/folder'; @@ -31,17 +31,16 @@ import { ExplorerTagNode } from '../../nodes/tag'; import { RootEmpty } from './empty'; import * as styles from './styles.css'; -export const ExplorerFavorites = ({ - defaultCollapsed = false, -}: { - defaultCollapsed?: boolean; -}) => { - const { favoriteService, docsService, workbenchService } = useServices({ - FavoriteService, - DocsService, - WorkbenchService, - }); - const [collapsed, setCollapsed] = useState(defaultCollapsed); +export const ExplorerFavorites = () => { + const { favoriteService, docsService, workbenchService, explorerService } = + useServices({ + FavoriteService, + DocsService, + WorkbenchService, + ExplorerService, + }); + + const explorerSection = explorerService.sections.favorites; const favorites = useLiveData(favoriteService.favoriteList.sortedList$); @@ -65,10 +64,10 @@ export const ExplorerFavorites = ({ type: data.source.data.entity.type, id: data.source.data.entity.id, }); - setCollapsed(false); + explorerSection.setCollapsed(false); } }, - [favoriteService] + [explorerSection, favoriteService.favoriteList] ); const handleDropEffect = useCallback(data => { @@ -110,8 +109,13 @@ export const ExplorerFavorites = ({ id: newDoc.id, }); workbenchService.workbench.openDoc(newDoc.id); - setCollapsed(false); - }, [docsService, favoriteService, workbenchService]); + explorerSection.setCollapsed(false); + }, [ + docsService, + explorerSection, + favoriteService.favoriteList, + workbenchService.workbench, + ]); const handleOnChildrenDrop = useCallback( ( @@ -221,61 +225,57 @@ export const ExplorerFavorites = ({ ); return ( - + + + + {draggedOverDraggable && ( + + )} + + } > - - - - - {draggedOverDraggable && ( - - )} - - - - } - > - {favorites.map(favorite => ( - - ))} - - - + } + > + {favorites.map(favorite => ( + + ))} + + ); }; diff --git a/packages/frontend/core/src/modules/explorer/views/sections/favorites/styles.css.ts b/packages/frontend/core/src/modules/explorer/views/sections/favorites/styles.css.ts index 00458330b3..201d5befac 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/favorites/styles.css.ts +++ b/packages/frontend/core/src/modules/explorer/views/sections/favorites/styles.css.ts @@ -1,10 +1,6 @@ import { cssVar } from '@toeverything/theme'; import { style } from '@vanilla-extract/css'; -export const container = style({ - marginTop: '8px', -}); - export const draggedOverHighlight = style({ position: 'relative', selectors: { diff --git a/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx index adfa6bb8df..4033bd6c31 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx @@ -1,25 +1,18 @@ import { IconButton, useConfirmModal } from '@affine/component'; -import { CategoryDivider } from '@affine/core/components/app-sidebar'; import { mixpanel } from '@affine/core/mixpanel'; import { ExplorerTreeRoot } from '@affine/core/modules/explorer/views/tree'; import { FavoriteItemsAdapter } from '@affine/core/modules/properties'; import { Trans, useI18n } from '@affine/i18n'; import { BroomIcon, HelpIcon } from '@blocksuite/icons/rc'; -import * as Collapsible from '@radix-ui/react-collapsible'; import { DocsService, useLiveData, useServices } from '@toeverything/infra'; -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; +import { CollapsibleSection } from '../../layouts/collapsible-section'; import { ExplorerCollectionNode } from '../../nodes/collection'; import { ExplorerDocNode } from '../../nodes/doc'; import * as styles from './styles.css'; -export const ExplorerMigrationFavorites = ({ - defaultCollapsed = false, -}: { - defaultCollapsed?: boolean; -}) => { - const [collapsed, setCollapsed] = useState(defaultCollapsed); - +export const ExplorerMigrationFavorites = () => { const t = useI18n(); const { favoriteItemsAdapter, docsService } = useServices({ @@ -112,38 +105,38 @@ export const ExplorerMigrationFavorites = ({ } return ( - - - - - - - - - - - - {favorites.map((favorite, i) => ( - - ))} - - - + + + + + + + + + } + > + + {favorites.map((favorite, i) => ( + + ))} + + ); }; diff --git a/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/styles.css.ts b/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/styles.css.ts index 86a60389c6..4a72e0b98c 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/styles.css.ts +++ b/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/styles.css.ts @@ -2,10 +2,9 @@ import { cssVar } from '@toeverything/theme'; import { style } from '@vanilla-extract/css'; export const container = style({ - marginTop: '8px', position: 'relative', selectors: { - '&:after': { + '&[data-collapsed="false"]:after': { display: 'block', content: '""', position: 'absolute', diff --git a/packages/frontend/core/src/modules/explorer/views/sections/old-favorites/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/old-favorites/index.tsx index 621bda2fe8..fe92122246 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/old-favorites/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/old-favorites/index.tsx @@ -3,7 +3,6 @@ import { type DropTargetOptions, IconButton, } from '@affine/component'; -import { CategoryDivider } from '@affine/core/components/app-sidebar'; import { type ExplorerTreeNodeDropEffect, ExplorerTreeRoot, @@ -13,29 +12,23 @@ import { WorkbenchService } from '@affine/core/modules/workbench'; import type { AffineDNDData } from '@affine/core/types/dnd'; import { useI18n } from '@affine/i18n'; import { PlusIcon } from '@blocksuite/icons/rc'; -import * as Collapsible from '@radix-ui/react-collapsible'; import { DocsService, useLiveData, useServices } from '@toeverything/infra'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useMemo } from 'react'; +import { CollapsibleSection } from '../../layouts/collapsible-section'; import { ExplorerCollectionNode } from '../../nodes/collection'; import { ExplorerDocNode } from '../../nodes/doc'; import { RootEmpty } from './empty'; -import * as styles from './styles.css'; /** * @deprecated remove this after 0.17 released */ -export const ExplorerOldFavorites = ({ - defaultCollapsed = false, -}: { - defaultCollapsed?: boolean; -}) => { +export const ExplorerOldFavorites = () => { const { favoriteItemsAdapter, docsService, workbenchService } = useServices({ FavoriteItemsAdapter, DocsService, WorkbenchService, }); - const [collapsed, setCollapsed] = useState(defaultCollapsed); const docs = useLiveData(docsService.list.docs$); const trashDocs = useLiveData(docsService.list.trashDocs$); @@ -180,17 +173,14 @@ export const ExplorerOldFavorites = ({ ); return ( - - + - - - - } - > - {favorites.map((favorite, i) => ( - - ))} - - - + } + > + + } + > + {favorites.map((favorite, i) => ( + + ))} + + ); }; diff --git a/packages/frontend/core/src/modules/explorer/views/sections/old-favorites/styles.css.ts b/packages/frontend/core/src/modules/explorer/views/sections/old-favorites/styles.css.ts deleted file mode 100644 index 994b712e90..0000000000 --- a/packages/frontend/core/src/modules/explorer/views/sections/old-favorites/styles.css.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { cssVar } from '@toeverything/theme'; -import { style } from '@vanilla-extract/css'; - -export const container = style({ - marginTop: '8px', -}); - -export const draggedOverHighlight = style({ - selectors: { - '&[data-dragged-over="true"]': { - background: cssVar('--affine-hover-color'), - borderRadius: '4px', - }, - }, -}); diff --git a/packages/frontend/core/src/modules/explorer/views/sections/organize/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/organize/index.tsx index 7c2228f216..afc616e9d4 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/organize/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/organize/index.tsx @@ -4,7 +4,6 @@ import { IconButton, toast, } from '@affine/component'; -import { CategoryDivider } from '@affine/core/components/app-sidebar'; import { mixpanel } from '@affine/core/mixpanel'; import { type ExplorerTreeNodeDropEffect, @@ -17,22 +16,23 @@ import { import type { AffineDNDData } from '@affine/core/types/dnd'; import { useI18n } from '@affine/i18n'; import { PlusIcon } from '@blocksuite/icons/rc'; -import * as Collapsible from '@radix-ui/react-collapsible'; import { useLiveData, useServices } from '@toeverything/infra'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { ExplorerService } from '../../../services/explorer'; +import { CollapsibleSection } from '../../layouts/collapsible-section'; import { ExplorerFolderNode } from '../../nodes/folder'; import { RootEmpty } from './empty'; import * as styles from './styles.css'; -export const ExplorerOrganize = ({ - defaultCollapsed = false, -}: { - defaultCollapsed?: boolean; -}) => { - const { organizeService } = useServices({ OrganizeService }); +export const ExplorerOrganize = () => { + const { organizeService, explorerService } = useServices({ + OrganizeService, + ExplorerService, + }); + const explorerSection = explorerService.sections.organize; + const collapsed = useLiveData(explorerSection.collapsed$); const [newFolderId, setNewFolderId] = useState(null); - const [collapsed, setCollapsed] = useState(defaultCollapsed); const t = useI18n(); @@ -51,8 +51,8 @@ export const ExplorerOrganize = ({ control: 'new folder', }); setNewFolderId(newFolderId); - setCollapsed(false); - }, [rootFolder]); + explorerSection.setCollapsed(false); + }, [explorerSection, rootFolder]); const handleOnChildrenDrop = useCallback( (data: DropTargetDropEvent, node?: FolderNode) => { @@ -108,23 +108,16 @@ export const ExplorerOrganize = ({ DropTargetOptions['canDrop'] >(() => args => args.source.data.entity?.type === 'folder', []); - const handleCollapsedChange = useCallback((collapsed: boolean) => { - if (collapsed) { - setNewFolderId(null); // reset new folder id to clear the renaming state - setCollapsed(true); - } else { - setCollapsed(false); - } - }, []); + useEffect(() => { + if (collapsed) setNewFolderId(null); // reset new folder id to clear the renaming state + }, [collapsed]); return ( - - + - - - } - > - {folders.map(child => ( - - ))} - - - + } + > + } + > + {folders.map(child => ( + + ))} + + ); }; diff --git a/packages/frontend/core/src/modules/explorer/views/sections/organize/styles.css.ts b/packages/frontend/core/src/modules/explorer/views/sections/organize/styles.css.ts index 994b712e90..0fe8f49f21 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/organize/styles.css.ts +++ b/packages/frontend/core/src/modules/explorer/views/sections/organize/styles.css.ts @@ -1,10 +1,6 @@ import { cssVar } from '@toeverything/theme'; import { style } from '@vanilla-extract/css'; -export const container = style({ - marginTop: '8px', -}); - export const draggedOverHighlight = style({ selectors: { '&[data-dragged-over="true"]': { diff --git a/packages/frontend/core/src/modules/explorer/views/sections/tags/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/tags/index.tsx index 1fb3027dc9..b6ae827c8d 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/tags/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/tags/index.tsx @@ -1,30 +1,27 @@ import { IconButton } from '@affine/component'; -import { CategoryDivider } from '@affine/core/components/app-sidebar'; import { mixpanel } from '@affine/core/mixpanel'; import { ExplorerTreeRoot } from '@affine/core/modules/explorer/views/tree'; import type { Tag } from '@affine/core/modules/tag'; import { TagService } from '@affine/core/modules/tag'; import { useI18n } from '@affine/i18n'; import { PlusIcon } from '@blocksuite/icons/rc'; -import * as Collapsible from '@radix-ui/react-collapsible'; import { useLiveData, useServices } from '@toeverything/infra'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; +import { ExplorerService } from '../../../services/explorer'; +import { CollapsibleSection } from '../../layouts/collapsible-section'; import { ExplorerTagNode } from '../../nodes/tag'; import { RootEmpty } from './empty'; import * as styles from './styles.css'; -export const ExplorerTags = ({ - defaultCollapsed = false, -}: { - defaultCollapsed?: boolean; -}) => { - const { tagService } = useServices({ +export const ExplorerTags = () => { + const { tagService, explorerService } = useServices({ TagService, + ExplorerService, }); + const explorerSection = explorerService.sections.tags; + const collapsed = useLiveData(explorerSection.collapsed$); const [createdTag, setCreatedTag] = useState(null); - - const [collapsed, setCollapsed] = useState(defaultCollapsed); const tags = useLiveData(tagService.tagList.tags$); const t = useI18n(); @@ -40,26 +37,19 @@ export const ExplorerTags = ({ module: 'tags', control: 'new tag button', }); - setCollapsed(false); - }, [t, tagService]); + explorerSection.setCollapsed(false); + }, [explorerSection, t, tagService]); - const handleCollapsedChange = useCallback((collapsed: boolean) => { - if (collapsed) { - setCreatedTag(null); // reset created tag to clear the renaming state - setCollapsed(true); - } else { - setCollapsed(false); - } - }, []); + useEffect(() => { + if (collapsed) setCreatedTag(null); // reset created tag to clear the renaming state + }, [collapsed]); return ( - - + - - - }> - {tags.map(tag => ( - - ))} - - - + } + > + }> + {tags.map(tag => ( + + ))} + + ); }; diff --git a/packages/frontend/core/src/modules/explorer/views/sections/tags/styles.css.ts b/packages/frontend/core/src/modules/explorer/views/sections/tags/styles.css.ts index 994b712e90..0fe8f49f21 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/tags/styles.css.ts +++ b/packages/frontend/core/src/modules/explorer/views/sections/tags/styles.css.ts @@ -1,10 +1,6 @@ import { cssVar } from '@toeverything/theme'; import { style } from '@vanilla-extract/css'; -export const container = style({ - marginTop: '8px', -}); - export const draggedOverHighlight = style({ selectors: { '&[data-dragged-over="true"]': { diff --git a/packages/frontend/core/src/modules/explorer/views/tree/node.css.ts b/packages/frontend/core/src/modules/explorer/views/tree/node.css.ts index e5eddb7083..fd8065b6dd 100644 --- a/packages/frontend/core/src/modules/explorer/views/tree/node.css.ts +++ b/packages/frontend/core/src/modules/explorer/views/tree/node.css.ts @@ -1,4 +1,5 @@ import { cssVar } from '@toeverything/theme'; +import { cssVarV2 } from '@toeverything/theme/v2'; import { createVar, keyframes, style } from '@vanilla-extract/css'; export const levelIndent = createVar(); export const linkItemRoot = style({ @@ -41,6 +42,7 @@ export const itemContent = style({ whiteSpace: 'nowrap', alignItems: 'center', flex: 1, + color: cssVarV2('text/primary'), }); export const postfix = style({ display: 'flex', @@ -59,7 +61,7 @@ export const postfix = style({ }, }); export const icon = style({ - color: cssVar('iconColor'), + color: cssVarV2('icon/primary'), fontSize: '20px', }); export const collapsedIconContainer = style({ @@ -70,7 +72,7 @@ export const collapsedIconContainer = style({ justifyContent: 'center', borderRadius: '2px', transition: 'transform 0.2s', - color: 'inherit', + color: cssVarV2('icon/primary'), selectors: { '&[data-collapsed="true"]': { transform: 'rotate(-90deg)', @@ -131,6 +133,7 @@ const draggedOverAnimation = keyframes({ }); export const contentContainer = style({ + marginTop: 2, paddingLeft: levelIndent, position: 'relative', }); diff --git a/packages/frontend/core/src/modules/index.ts b/packages/frontend/core/src/modules/index.ts index 2391a16187..2dbd83e33f 100644 --- a/packages/frontend/core/src/modules/index.ts +++ b/packages/frontend/core/src/modules/index.ts @@ -5,6 +5,7 @@ import { configureCloudModule } from './cloud'; import { configureCollectionModule } from './collection'; import { configureDocLinksModule } from './doc-link'; import { configureDocsSearchModule } from './docs-search'; +import { configureExplorerModule } from './explorer'; import { configureFavoriteModule } from './favorite'; import { configureFindInPageModule } from './find-in-page'; import { configureNavigationModule } from './navigation'; @@ -35,4 +36,5 @@ export function configureCommonModules(framework: Framework) { configureDocLinksModule(framework); configureOrganizeModule(framework); configureFavoriteModule(framework); + configureExplorerModule(framework); }