feat(core): adjust empty collection style (#5239)
<img width="270" alt="image" src="https://github.com/toeverything/AFFiNE/assets/102217452/18ac2de8-51c0-447e-9c81-787f579eab4e">
This commit is contained in:
@@ -87,17 +87,9 @@ const CloudShareMenu = (props: ShareMenuProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button data-testid="cloud-share-menu-button" type="primary">
|
<Button data-testid="cloud-share-menu-button" type="primary">
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
color: isSharedPage
|
|
||||||
? 'var(--affine-link-color)'
|
|
||||||
: 'var(--affine-text-primary-color)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isSharedPage
|
{isSharedPage
|
||||||
? t['com.affine.share-menu.sharedButton']()
|
? t['com.affine.share-menu.sharedButton']()
|
||||||
: t['com.affine.share-menu.shareButton']()}
|
: t['com.affine.share-menu.shareButton']()}
|
||||||
</div>
|
|
||||||
</Button>
|
</Button>
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,46 +1,19 @@
|
|||||||
import {
|
|
||||||
createEmptyCollection,
|
|
||||||
useCollectionManager,
|
|
||||||
useEditCollectionName,
|
|
||||||
} from '@affine/component/page-list';
|
|
||||||
import { IconButton } from '@affine/component/ui/button';
|
import { IconButton } from '@affine/component/ui/button';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
|
||||||
import { PlusIcon } from '@blocksuite/icons';
|
import { PlusIcon } from '@blocksuite/icons';
|
||||||
import { nanoid } from 'nanoid';
|
import type { ReactElement } from 'react';
|
||||||
import { useCallback } from 'react';
|
|
||||||
|
|
||||||
import { collectionsCRUDAtom } from '../../../../atoms/collections';
|
export const AddCollectionButton = ({
|
||||||
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
|
node,
|
||||||
import { useNavigateHelper } from '../../../../hooks/use-navigate-helper';
|
onClick,
|
||||||
|
}: {
|
||||||
export const AddCollectionButton = () => {
|
node: ReactElement | null;
|
||||||
const setting = useCollectionManager(collectionsCRUDAtom);
|
onClick: () => void;
|
||||||
const t = useAFFiNEI18N();
|
}) => {
|
||||||
const { node, open } = useEditCollectionName({
|
|
||||||
title: t['com.affine.editCollection.createCollection'](),
|
|
||||||
showTips: true,
|
|
||||||
});
|
|
||||||
const navigateHelper = useNavigateHelper();
|
|
||||||
const [workspace] = useCurrentWorkspace();
|
|
||||||
const handleClick = useCallback(() => {
|
|
||||||
open('')
|
|
||||||
.then(name => {
|
|
||||||
const id = nanoid();
|
|
||||||
return setting
|
|
||||||
.createCollection(createEmptyCollection(id, { name }))
|
|
||||||
.then(() => {
|
|
||||||
navigateHelper.jumpToCollection(workspace.id, id);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}, [navigateHelper, open, setting, workspace.id]);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconButton
|
<IconButton
|
||||||
data-testid="slider-bar-add-collection-button"
|
data-testid="slider-bar-add-collection-button"
|
||||||
onClick={handleClick}
|
onClick={onClick}
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<PlusIcon />
|
<PlusIcon />
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { AnimatedCollectionsIcon, toast } from '@affine/component';
|
import { AnimatedCollectionsIcon, toast } from '@affine/component';
|
||||||
import {
|
import { MenuLinkItem as SidebarMenuLinkItem } from '@affine/component/app-sidebar';
|
||||||
MenuItem as SidebarMenuItem,
|
|
||||||
MenuLinkItem as SidebarMenuLinkItem,
|
|
||||||
} from '@affine/component/app-sidebar';
|
|
||||||
import {
|
import {
|
||||||
CollectionOperations,
|
CollectionOperations,
|
||||||
filterPage,
|
filterPage,
|
||||||
@@ -10,10 +7,10 @@ import {
|
|||||||
useCollectionManager,
|
useCollectionManager,
|
||||||
useSavedCollections,
|
useSavedCollections,
|
||||||
} from '@affine/component/page-list';
|
} from '@affine/component/page-list';
|
||||||
import { IconButton } from '@affine/component/ui/button';
|
import { Button, IconButton } from '@affine/component/ui/button';
|
||||||
import type { Collection, DeleteCollectionInfo } from '@affine/env/filter';
|
import type { Collection, DeleteCollectionInfo } from '@affine/env/filter';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { InformationIcon, MoreHorizontalIcon } from '@blocksuite/icons';
|
import { MoreHorizontalIcon, ViewLayersIcon } from '@blocksuite/icons';
|
||||||
import type { PageMeta, Workspace } from '@blocksuite/store';
|
import type { PageMeta, Workspace } from '@blocksuite/store';
|
||||||
import type { DragEndEvent } from '@dnd-kit/core';
|
import type { DragEndEvent } from '@dnd-kit/core';
|
||||||
import { useDroppable } from '@dnd-kit/core';
|
import { useDroppable } from '@dnd-kit/core';
|
||||||
@@ -155,19 +152,32 @@ const CollectionRenderer = ({
|
|||||||
</Collapsible.Root>
|
</Collapsible.Root>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export const CollectionsList = ({ workspace, info }: CollectionsListProps) => {
|
export const CollectionsList = ({
|
||||||
|
workspace,
|
||||||
|
info,
|
||||||
|
onCreate,
|
||||||
|
}: CollectionsListProps) => {
|
||||||
const metas = useBlockSuitePageMeta(workspace);
|
const metas = useBlockSuitePageMeta(workspace);
|
||||||
const { collections } = useSavedCollections(collectionsCRUDAtom);
|
const { collections } = useSavedCollections(collectionsCRUDAtom);
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
if (collections.length === 0) {
|
if (collections.length === 0) {
|
||||||
return (
|
return (
|
||||||
<SidebarMenuItem
|
<div className={styles.emptyCollectionWrapper}>
|
||||||
|
<div className={styles.emptyCollectionContent}>
|
||||||
|
<div className={styles.emptyCollectionIconWrapper}>
|
||||||
|
<ViewLayersIcon className={styles.emptyCollectionIcon} />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
data-testid="slider-bar-collection-null-description"
|
data-testid="slider-bar-collection-null-description"
|
||||||
icon={<InformationIcon />}
|
className={styles.emptyCollectionMessage}
|
||||||
disabled
|
|
||||||
>
|
>
|
||||||
<span>{t['Create a collection']()}</span>
|
{t['com.affine.collections.empty.message']()}
|
||||||
</SidebarMenuItem>
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button className={styles.emptyCollectionNewButton} onClick={onCreate}>
|
||||||
|
{t['com.affine.collections.empty.new-collection-button']()}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -87,3 +87,45 @@ export const collapsibleContent = style({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const emptyCollectionWrapper = style({
|
||||||
|
padding: '9px 0',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 8,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const emptyCollectionContent = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 6,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const emptyCollectionIconWrapper = style({
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
borderRadius: '50%',
|
||||||
|
backgroundColor: 'var(--affine-background-secondary-color)',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const emptyCollectionIcon = style({
|
||||||
|
fontSize: 20,
|
||||||
|
color: 'var(--affine-icon-secondary)',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const emptyCollectionMessage = style({
|
||||||
|
fontSize: 'var(--affine-font-sm)',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: 'var(--affine-text-secondary-color)',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const emptyCollectionNewButton = style({
|
||||||
|
padding: '0 8px',
|
||||||
|
height: '30px',
|
||||||
|
fontSize: 'var(--affine-font-sm)',
|
||||||
|
});
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ export type FavoriteListProps = {
|
|||||||
export type CollectionsListProps = {
|
export type CollectionsListProps = {
|
||||||
workspace: Workspace;
|
workspace: Workspace;
|
||||||
info: DeleteCollectionInfo;
|
info: DeleteCollectionInfo;
|
||||||
|
onCreate?: () => void;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,15 +12,22 @@ import {
|
|||||||
SidebarContainer,
|
SidebarContainer,
|
||||||
SidebarScrollableContainer,
|
SidebarScrollableContainer,
|
||||||
} from '@affine/component/app-sidebar';
|
} from '@affine/component/app-sidebar';
|
||||||
import { MoveToTrash } from '@affine/component/page-list';
|
import {
|
||||||
|
createEmptyCollection,
|
||||||
|
MoveToTrash,
|
||||||
|
useCollectionManager,
|
||||||
|
useEditCollectionName,
|
||||||
|
} from '@affine/component/page-list';
|
||||||
import { Menu } from '@affine/component/ui/menu';
|
import { Menu } from '@affine/component/ui/menu';
|
||||||
|
import { collectionsCRUDAtom } from '@affine/core/atoms/collections';
|
||||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { FolderIcon, SettingsIcon } from '@blocksuite/icons';
|
import { FolderIcon, SettingsIcon } from '@blocksuite/icons';
|
||||||
import type { Page } from '@blocksuite/store';
|
import { type Page } from '@blocksuite/store';
|
||||||
import { useDroppable } from '@dnd-kit/core';
|
import { useDroppable } from '@dnd-kit/core';
|
||||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||||
import { useAtom, useAtomValue } from 'jotai';
|
import { useAtom, useAtomValue } from 'jotai';
|
||||||
|
import { nanoid } from 'nanoid';
|
||||||
import type { HTMLAttributes, ReactElement } from 'react';
|
import type { HTMLAttributes, ReactElement } from 'react';
|
||||||
import { forwardRef, useCallback, useEffect, useMemo } from 'react';
|
import { forwardRef, useCallback, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
@@ -171,6 +178,24 @@ export const RootAppSidebar = ({
|
|||||||
}, [setOpenUserWorkspaceList]);
|
}, [setOpenUserWorkspaceList]);
|
||||||
useRegisterBrowserHistoryCommands(router.back, router.forward);
|
useRegisterBrowserHistoryCommands(router.back, router.forward);
|
||||||
const userInfo = useDeleteCollectionInfo();
|
const userInfo = useDeleteCollectionInfo();
|
||||||
|
|
||||||
|
const setting = useCollectionManager(collectionsCRUDAtom);
|
||||||
|
const { node, open } = useEditCollectionName({
|
||||||
|
title: t['com.affine.editCollection.createCollection'](),
|
||||||
|
showTips: true,
|
||||||
|
});
|
||||||
|
const handleCreateCollection = useCallback(() => {
|
||||||
|
open('')
|
||||||
|
.then(async name => {
|
||||||
|
const id = nanoid();
|
||||||
|
await setting.createCollection(createEmptyCollection(id, { name }));
|
||||||
|
navigateHelper.jumpToCollection(blockSuiteWorkspace.id, id);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}, [blockSuiteWorkspace.id, navigateHelper, open, setting]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppSidebar
|
<AppSidebar
|
||||||
router={router}
|
router={router}
|
||||||
@@ -245,9 +270,13 @@ export const RootAppSidebar = ({
|
|||||||
</CategoryDivider>
|
</CategoryDivider>
|
||||||
<FavoriteList workspace={blockSuiteWorkspace} />
|
<FavoriteList workspace={blockSuiteWorkspace} />
|
||||||
<CategoryDivider label={t['com.affine.rootAppSidebar.collections']()}>
|
<CategoryDivider label={t['com.affine.rootAppSidebar.collections']()}>
|
||||||
<AddCollectionButton />
|
<AddCollectionButton node={node} onClick={handleCreateCollection} />
|
||||||
</CategoryDivider>
|
</CategoryDivider>
|
||||||
<CollectionsList workspace={blockSuiteWorkspace} info={userInfo} />
|
<CollectionsList
|
||||||
|
workspace={blockSuiteWorkspace}
|
||||||
|
info={userInfo}
|
||||||
|
onCreate={handleCreateCollection}
|
||||||
|
/>
|
||||||
<CategoryDivider label={t['com.affine.rootAppSidebar.others']()} />
|
<CategoryDivider label={t['com.affine.rootAppSidebar.others']()} />
|
||||||
{/* fixme: remove the following spacer */}
|
{/* fixme: remove the following spacer */}
|
||||||
<div style={{ height: '4px' }} />
|
<div style={{ height: '4px' }} />
|
||||||
|
|||||||
@@ -553,6 +553,8 @@
|
|||||||
"com.affine.collection.menu.rename": "Rename",
|
"com.affine.collection.menu.rename": "Rename",
|
||||||
"com.affine.collectionBar.backToAll": "Back to all",
|
"com.affine.collectionBar.backToAll": "Back to all",
|
||||||
"com.affine.collections.header": "Collections",
|
"com.affine.collections.header": "Collections",
|
||||||
|
"com.affine.collections.empty.message": "No collections",
|
||||||
|
"com.affine.collections.empty.new-collection-button": "New collection",
|
||||||
"com.affine.confirmModal.button.cancel": "Cancel",
|
"com.affine.confirmModal.button.cancel": "Cancel",
|
||||||
"com.affine.currentYear": "Current Year",
|
"com.affine.currentYear": "Current Year",
|
||||||
"com.affine.deleteLeaveWorkspace.description": "Delete workspace from this device and optionally delete all data.",
|
"com.affine.deleteLeaveWorkspace.description": "Delete workspace from this device and optionally delete all data.",
|
||||||
|
|||||||
Reference in New Issue
Block a user