feat(core): support sidebar collapse (#7630)

This commit is contained in:
EYHN
2024-07-29 09:57:33 +00:00
parent c5cf8480fc
commit 0472ffe569
17 changed files with 257 additions and 129 deletions

View File

@@ -7,20 +7,26 @@ 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 } from 'react';
import { useCallback, useState } from 'react';
import { ExplorerCollectionNode } from '../../nodes/collection';
import { RootEmpty } from './empty';
import * as styles from './styles.css';
export const ExplorerCollections = () => {
export const ExplorerCollections = ({
defaultCollapsed = false,
}: {
defaultCollapsed?: boolean;
}) => {
const t = useI18n();
const { collectionService, workbenchService } = useServices({
CollectionService,
WorkbenchService,
});
const [collapsed, setCollapsed] = useState(defaultCollapsed);
const collections = useLiveData(collectionService.collections$);
const { node, open: openCreateCollectionModel } = useEditCollectionName({
title: t['com.affine.editCollection.createCollection'](),
@@ -33,6 +39,7 @@ export const ExplorerCollections = () => {
const id = nanoid();
collectionService.addCollection(createEmptyCollection(id, { name }));
workbenchService.workbench.openCollection(id);
setCollapsed(false);
})
.catch(err => {
console.error(err);
@@ -41,8 +48,16 @@ export const ExplorerCollections = () => {
return (
<>
<div className={styles.container} data-testid="explorer-collections">
<CategoryDivider label={t['com.affine.rootAppSidebar.collections']()}>
<Collapsible.Root
className={styles.container}
data-testid="explorer-collections"
open={!collapsed}
>
<CategoryDivider
label={t['com.affine.rootAppSidebar.collections']()}
setCollapsed={setCollapsed}
collapsed={collapsed}
>
<IconButton
data-testid="explorer-bar-add-collection-button"
onClick={handleCreateCollection}
@@ -51,21 +66,23 @@ export const ExplorerCollections = () => {
<PlusIcon />
</IconButton>
</CategoryDivider>
<ExplorerTreeRoot
placeholder={<RootEmpty onClickCreate={handleCreateCollection} />}
>
{collections.map(collection => (
<ExplorerCollectionNode
key={collection.id}
collectionId={collection.id}
reorderable={false}
location={{
at: 'explorer:collection:list',
}}
/>
))}
</ExplorerTreeRoot>
</div>
<Collapsible.Content>
<ExplorerTreeRoot
placeholder={<RootEmpty onClickCreate={handleCreateCollection} />}
>
{collections.map(collection => (
<ExplorerCollectionNode
key={collection.id}
collectionId={collection.id}
reorderable={false}
location={{
at: 'explorer:collection:list',
}}
/>
))}
</ExplorerTreeRoot>
</Collapsible.Content>
</Collapsible.Root>
{node}
</>
);

View File

@@ -1,5 +1,5 @@
import { style } from '@vanilla-extract/css';
export const container = style({
marginTop: '16px',
marginTop: '8px',
});

View File

@@ -19,8 +19,9 @@ 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 } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { ExplorerCollectionNode } from '../../nodes/collection';
import { ExplorerDocNode } from '../../nodes/doc';
@@ -29,12 +30,17 @@ import { ExplorerTagNode } from '../../nodes/tag';
import { RootEmpty } from './empty';
import * as styles from './styles.css';
export const ExplorerFavorites = () => {
export const ExplorerFavorites = ({
defaultCollapsed = false,
}: {
defaultCollapsed?: boolean;
}) => {
const { favoriteService, docsService, workbenchService } = useServices({
FavoriteService,
DocsService,
WorkbenchService,
});
const [collapsed, setCollapsed] = useState(defaultCollapsed);
const favorites = useLiveData(favoriteService.favoriteList.sortedList$);
@@ -51,6 +57,7 @@ export const ExplorerFavorites = () => {
data.source.data.entity.id,
favoriteService.favoriteList.indexAt('before')
);
setCollapsed(false);
}
},
[favoriteService]
@@ -83,6 +90,7 @@ export const ExplorerFavorites = () => {
favoriteService.favoriteList.indexAt('before')
);
workbenchService.workbench.openDoc(newDoc.id);
setCollapsed(false);
}, [docsService, favoriteService, workbenchService]);
const handleOnChildrenDrop = useCallback(
@@ -179,12 +187,18 @@ export const ExplorerFavorites = () => {
);
return (
<div className={styles.container} data-testid="explorer-favorites">
<Collapsible.Root
className={styles.container}
data-testid="explorer-favorites"
open={!collapsed}
>
<CategoryDivider
className={styles.draggedOverHighlight}
label={t['com.affine.rootAppSidebar.favorites']()}
ref={dropTargetRef}
data-testid="explorer-favorite-category-divider"
setCollapsed={setCollapsed}
collapsed={collapsed}
>
<IconButton
data-testid="explorer-bar-add-favorite-button"
@@ -206,26 +220,28 @@ export const ExplorerFavorites = () => {
/>
)}
</CategoryDivider>
<ExplorerTreeRoot
placeholder={
<RootEmpty
onDrop={handleDrop}
canDrop={handleCanDrop}
dropEffect={handleDropEffect}
/>
}
>
{favorites.map(favorite => (
<ExplorerFavoriteNode
key={favorite.id}
favorite={favorite}
onDrop={handleOnChildrenDrop}
dropEffect={handleChildrenDropEffect}
canDrop={handleChildrenCanDrop}
/>
))}
</ExplorerTreeRoot>
</div>
<Collapsible.Content>
<ExplorerTreeRoot
placeholder={
<RootEmpty
onDrop={handleDrop}
canDrop={handleCanDrop}
dropEffect={handleDropEffect}
/>
}
>
{favorites.map(favorite => (
<ExplorerFavoriteNode
key={favorite.id}
favorite={favorite}
onDrop={handleOnChildrenDrop}
dropEffect={handleChildrenDropEffect}
canDrop={handleChildrenCanDrop}
/>
))}
</ExplorerTreeRoot>
</Collapsible.Content>
</Collapsible.Root>
);
};

View File

@@ -2,7 +2,7 @@ import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';
export const container = style({
marginTop: '16px',
marginTop: '8px',
});
export const draggedOverHighlight = style({

View File

@@ -4,14 +4,21 @@ 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 } from 'react';
import { useCallback, useState } from 'react';
import { ExplorerCollectionNode } from '../../nodes/collection';
import { ExplorerDocNode } from '../../nodes/doc';
import * as styles from './styles.css';
export const ExplorerMigrationFavorites = () => {
export const ExplorerMigrationFavorites = ({
defaultCollapsed = false,
}: {
defaultCollapsed?: boolean;
}) => {
const [collapsed, setCollapsed] = useState(defaultCollapsed);
const t = useI18n();
const { favoriteItemsAdapter, docsService } = useServices({
@@ -89,8 +96,12 @@ export const ExplorerMigrationFavorites = () => {
}
return (
<div className={styles.container}>
<CategoryDivider label={t['com.affine.rootAppSidebar.migration-data']()}>
<Collapsible.Root className={styles.container} open={!collapsed}>
<CategoryDivider
label={t['com.affine.rootAppSidebar.migration-data']()}
setCollapsed={setCollapsed}
collapsed={collapsed}
>
<IconButton
data-testid="explorer-bar-favorite-migration-clear-button"
onClick={handleClickClear}
@@ -106,15 +117,17 @@ export const ExplorerMigrationFavorites = () => {
<HelpIcon />
</IconButton>
</CategoryDivider>
<ExplorerTreeRoot>
{favorites.map((favorite, i) => (
<ExplorerMigrationFavoriteNode
key={favorite.id + ':' + i}
favorite={favorite}
/>
))}
</ExplorerTreeRoot>
</div>
<Collapsible.Content>
<ExplorerTreeRoot>
{favorites.map((favorite, i) => (
<ExplorerMigrationFavoriteNode
key={favorite.id + ':' + i}
favorite={favorite}
/>
))}
</ExplorerTreeRoot>
</Collapsible.Content>
</Collapsible.Root>
);
};

View File

@@ -2,7 +2,7 @@ import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';
export const container = style({
marginTop: '16px',
marginTop: '8px',
position: 'relative',
selectors: {
'&:after': {

View File

@@ -13,8 +13,9 @@ 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 } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { ExplorerCollectionNode } from '../../nodes/collection';
import { ExplorerDocNode } from '../../nodes/doc';
@@ -24,12 +25,17 @@ import * as styles from './styles.css';
/**
* @deprecated remove this after 0.17 released
*/
export const ExplorerOldFavorites = () => {
export const ExplorerOldFavorites = ({
defaultCollapsed = false,
}: {
defaultCollapsed?: boolean;
}) => {
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$);
@@ -174,7 +180,7 @@ export const ExplorerOldFavorites = () => {
);
return (
<div className={styles.container}>
<Collapsible.Root className={styles.container} open={!collapsed}>
<CategoryDivider
className={styles.draggedOverHighlight}
label={
@@ -182,6 +188,8 @@ export const ExplorerOldFavorites = () => {
? `${t['com.affine.rootAppSidebar.favorites']()} (OLD)`
: t['com.affine.rootAppSidebar.favorites']()
}
setCollapsed={setCollapsed}
collapsed={collapsed}
>
<IconButton
data-testid="explorer-bar-add-old-favorite-button"
@@ -191,26 +199,28 @@ export const ExplorerOldFavorites = () => {
<PlusIcon />
</IconButton>
</CategoryDivider>
<ExplorerTreeRoot
placeholder={
<RootEmpty
onDrop={handleDrop}
canDrop={handleCanDrop}
dropEffect={handleDropEffect}
/>
}
>
{favorites.map((favorite, i) => (
<ExplorerFavoriteNode
key={favorite.id + ':' + i}
favorite={favorite}
onDrop={handleOnChildrenDrop}
dropEffect={handleChildrenDropEffect}
canDrop={handleChildrenCanDrop}
/>
))}
</ExplorerTreeRoot>
</div>
<Collapsible.Content>
<ExplorerTreeRoot
placeholder={
<RootEmpty
onDrop={handleDrop}
canDrop={handleCanDrop}
dropEffect={handleDropEffect}
/>
}
>
{favorites.map((favorite, i) => (
<ExplorerFavoriteNode
key={favorite.id + ':' + i}
favorite={favorite}
onDrop={handleOnChildrenDrop}
dropEffect={handleChildrenDropEffect}
canDrop={handleChildrenCanDrop}
/>
))}
</ExplorerTreeRoot>
</Collapsible.Content>
</Collapsible.Root>
);
};

View File

@@ -2,7 +2,7 @@ import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';
export const container = style({
marginTop: '16px',
marginTop: '8px',
});
export const draggedOverHighlight = style({

View File

@@ -16,6 +16,7 @@ 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';
@@ -23,9 +24,14 @@ import { ExplorerFolderNode } from '../../nodes/folder';
import { RootEmpty } from './empty';
import * as styles from './styles.css';
export const ExplorerOrganize = () => {
export const ExplorerOrganize = ({
defaultCollapsed = false,
}: {
defaultCollapsed?: boolean;
}) => {
const { organizeService } = useServices({ OrganizeService });
const [newFolderId, setNewFolderId] = useState<string | null>(null);
const [collapsed, setCollapsed] = useState(defaultCollapsed);
const t = useI18n();
@@ -39,6 +45,7 @@ export const ExplorerOrganize = () => {
rootFolder.indexAt('before')
);
setNewFolderId(newFolderId);
setCollapsed(false);
}, [rootFolder]);
const handleOnChildrenDrop = useCallback(
@@ -89,10 +96,12 @@ export const ExplorerOrganize = () => {
>(() => args => args.source.data.entity?.type === 'folder', []);
return (
<div className={styles.container}>
<Collapsible.Root className={styles.container} open={!collapsed}>
<CategoryDivider
className={styles.draggedOverHighlight}
label={t['com.affine.rootAppSidebar.organize']()}
setCollapsed={setCollapsed}
collapsed={collapsed}
>
<IconButton
data-testid="explorer-bar-add-organize-button"
@@ -102,24 +111,26 @@ export const ExplorerOrganize = () => {
<PlusIcon />
</IconButton>
</CategoryDivider>
<ExplorerTreeRoot
placeholder={<RootEmpty onClickCreate={handleCreateFolder} />}
>
{folders.map(child => (
<ExplorerFolderNode
key={child.id}
nodeId={child.id as string}
defaultRenaming={child.id === newFolderId}
onDrop={handleOnChildrenDrop}
dropEffect={handleChildrenDropEffect}
canDrop={handleChildrenCanDrop}
location={{
at: 'explorer:organize:folder-node',
nodeId: child.id as string,
}}
/>
))}
</ExplorerTreeRoot>
</div>
<Collapsible.Content>
<ExplorerTreeRoot
placeholder={<RootEmpty onClickCreate={handleCreateFolder} />}
>
{folders.map(child => (
<ExplorerFolderNode
key={child.id}
nodeId={child.id as string}
defaultRenaming={child.id === newFolderId}
onDrop={handleOnChildrenDrop}
dropEffect={handleChildrenDropEffect}
canDrop={handleChildrenCanDrop}
location={{
at: 'explorer:organize:folder-node',
nodeId: child.id as string,
}}
/>
))}
</ExplorerTreeRoot>
</Collapsible.Content>
</Collapsible.Root>
);
};

View File

@@ -2,7 +2,7 @@ import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';
export const container = style({
marginTop: '16px',
marginTop: '8px',
});
export const draggedOverHighlight = style({

View File

@@ -5,6 +5,7 @@ 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';
@@ -12,12 +13,17 @@ import { ExplorerTagNode } from '../../nodes/tag';
import { RootEmpty } from './empty';
import * as styles from './styles.css';
export const ExplorerTags = () => {
export const ExplorerTags = ({
defaultCollapsed = false,
}: {
defaultCollapsed?: boolean;
}) => {
const { tagService } = useServices({
TagService,
});
const [createdTag, setCreatedTag] = useState<Tag | null>(null);
const [collapsed, setCollapsed] = useState(defaultCollapsed);
const tags = useLiveData(tagService.tagList.tags$);
const t = useI18n();
@@ -28,13 +34,16 @@ export const ExplorerTags = () => {
tagService.randomTagColor()
);
setCreatedTag(newTags);
setCollapsed(false);
}, [t, tagService]);
return (
<div className={styles.container}>
<Collapsible.Root className={styles.container} open={!collapsed}>
<CategoryDivider
className={styles.draggedOverHighlight}
label={t['com.affine.rootAppSidebar.tags']()}
setCollapsed={setCollapsed}
collapsed={collapsed}
>
<IconButton
data-testid="explorer-bar-add-favorite-button"
@@ -44,21 +53,23 @@ export const ExplorerTags = () => {
<PlusIcon />
</IconButton>
</CategoryDivider>
<ExplorerTreeRoot
placeholder={<RootEmpty onClickCreate={handleCreateNewFavoriteDoc} />}
>
{tags.map(tag => (
<ExplorerTagNode
key={tag.id}
tagId={tag.id}
reorderable={false}
location={{
at: 'explorer:tags:list',
}}
defaultRenaming={createdTag?.id === tag.id}
/>
))}
</ExplorerTreeRoot>
</div>
<Collapsible.Content>
<ExplorerTreeRoot
placeholder={<RootEmpty onClickCreate={handleCreateNewFavoriteDoc} />}
>
{tags.map(tag => (
<ExplorerTagNode
key={tag.id}
tagId={tag.id}
reorderable={false}
location={{
at: 'explorer:tags:list',
}}
defaultRenaming={createdTag?.id === tag.id}
/>
))}
</ExplorerTreeRoot>
</Collapsible.Content>
</Collapsible.Root>
);
};

View File

@@ -2,7 +2,7 @@ import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';
export const container = style({
marginTop: '16px',
marginTop: '8px',
});
export const draggedOverHighlight = style({