mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-24 03:01:32 +03:00
feat: add new collection button to slider bar (#3369)
This commit is contained in:
parent
8334ac031b
commit
2c249781a2
@ -0,0 +1,56 @@
|
|||||||
|
import { IconButton } from '@affine/component';
|
||||||
|
import {
|
||||||
|
EditCollectionModel,
|
||||||
|
useCollectionManager,
|
||||||
|
} from '@affine/component/page-list';
|
||||||
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
|
import { PlusIcon } from '@blocksuite/icons';
|
||||||
|
import type { Workspace } from '@blocksuite/store';
|
||||||
|
import { uuidv4 } from '@blocksuite/store';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import { useGetPageInfoById } from '../../../../hooks/use-get-page-info';
|
||||||
|
|
||||||
|
type AddCollectionButtonProps = {
|
||||||
|
workspace: Workspace;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AddCollectionButton = ({
|
||||||
|
workspace,
|
||||||
|
}: AddCollectionButtonProps) => {
|
||||||
|
const getPageInfo = useGetPageInfoById(workspace);
|
||||||
|
const setting = useCollectionManager(workspace.id);
|
||||||
|
const t = useAFFiNEI18N();
|
||||||
|
const [show, showUpdateCollection] = useState(false);
|
||||||
|
const defaultCollection = useMemo(
|
||||||
|
() => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
name: '',
|
||||||
|
pinned: true,
|
||||||
|
filterList: [],
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
}),
|
||||||
|
[workspace.id]
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<IconButton
|
||||||
|
data-testid="slider-bar-add-collection-button"
|
||||||
|
onClick={() => showUpdateCollection(true)}
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<PlusIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<EditCollectionModel
|
||||||
|
propertiesMeta={workspace.meta.properties}
|
||||||
|
getPageInfo={getPageInfo}
|
||||||
|
onConfirm={setting.saveCollection}
|
||||||
|
open={show}
|
||||||
|
onClose={() => showUpdateCollection(false)}
|
||||||
|
title={t['Save As New Collection']()}
|
||||||
|
init={defaultCollection}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -12,6 +12,7 @@ import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
|||||||
import {
|
import {
|
||||||
DeleteIcon,
|
DeleteIcon,
|
||||||
FilterIcon,
|
FilterIcon,
|
||||||
|
InformationIcon,
|
||||||
MoreHorizontalIcon,
|
MoreHorizontalIcon,
|
||||||
UnpinIcon,
|
UnpinIcon,
|
||||||
ViewLayersIcon,
|
ViewLayersIcon,
|
||||||
@ -251,21 +252,34 @@ export const CollectionsList = ({ workspace }: CollectionsListProps) => {
|
|||||||
const metas = useBlockSuitePageMeta(workspace);
|
const metas = useBlockSuitePageMeta(workspace);
|
||||||
const { savedCollections } = useSavedCollections(workspace.id);
|
const { savedCollections } = useSavedCollections(workspace.id);
|
||||||
const getPageInfo = useGetPageInfoById(workspace);
|
const getPageInfo = useGetPageInfoById(workspace);
|
||||||
|
const pinedCollections = useMemo(
|
||||||
|
() => savedCollections.filter(v => v.pinned),
|
||||||
|
[savedCollections]
|
||||||
|
);
|
||||||
|
if (pinedCollections.length === 0) {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
data-testid="slider-bar-collection-null-description"
|
||||||
|
icon={<InformationIcon />}
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<span>Create a collection</span>
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div data-testid="collections" className={styles.wrapper}>
|
<div data-testid="collections" className={styles.wrapper}>
|
||||||
{savedCollections
|
{pinedCollections.map(view => {
|
||||||
.filter(v => v.pinned)
|
return (
|
||||||
.map(view => {
|
<CollectionRenderer
|
||||||
return (
|
getPageInfo={getPageInfo}
|
||||||
<CollectionRenderer
|
key={view.id}
|
||||||
getPageInfo={getPageInfo}
|
collection={view}
|
||||||
key={view.id}
|
pages={metas}
|
||||||
collection={view}
|
workspace={workspace}
|
||||||
pages={metas}
|
/>
|
||||||
workspace={workspace}
|
);
|
||||||
/>
|
})}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -29,6 +29,7 @@ import { useHistoryAtom } from '../../atoms/history';
|
|||||||
import { useAppSetting } from '../../atoms/settings';
|
import { useAppSetting } from '../../atoms/settings';
|
||||||
import type { AllWorkspace } from '../../shared';
|
import type { AllWorkspace } from '../../shared';
|
||||||
import { CollectionsList } from '../pure/workspace-slider-bar/collections';
|
import { CollectionsList } from '../pure/workspace-slider-bar/collections';
|
||||||
|
import { AddCollectionButton } from '../pure/workspace-slider-bar/collections/add-collection-button';
|
||||||
import FavoriteList from '../pure/workspace-slider-bar/favorite/favorite-list';
|
import FavoriteList from '../pure/workspace-slider-bar/favorite/favorite-list';
|
||||||
import { WorkspaceSelector } from '../pure/workspace-slider-bar/WorkspaceSelector';
|
import { WorkspaceSelector } from '../pure/workspace-slider-bar/WorkspaceSelector';
|
||||||
import ImportPage from './import-page';
|
import ImportPage from './import-page';
|
||||||
@ -190,7 +191,9 @@ export const RootAppSidebar = ({
|
|||||||
<SidebarScrollableContainer>
|
<SidebarScrollableContainer>
|
||||||
<CategoryDivider label={t['Favorites']()} />
|
<CategoryDivider label={t['Favorites']()} />
|
||||||
<FavoriteList workspace={blockSuiteWorkspace} />
|
<FavoriteList workspace={blockSuiteWorkspace} />
|
||||||
<CategoryDivider label={t['Collections']()} />
|
<CategoryDivider label={t['Collections']()}>
|
||||||
|
<AddCollectionButton workspace={blockSuiteWorkspace} />
|
||||||
|
</CategoryDivider>
|
||||||
<CollectionsList workspace={blockSuiteWorkspace} />
|
<CollectionsList workspace={blockSuiteWorkspace} />
|
||||||
<CategoryDivider label={t['others']()} />
|
<CategoryDivider label={t['others']()} />
|
||||||
<RouteMenuLinkItem
|
<RouteMenuLinkItem
|
||||||
|
@ -2,8 +2,11 @@ import { style } from '@vanilla-extract/css';
|
|||||||
|
|
||||||
export const root = style({
|
export const root = style({
|
||||||
fontSize: 'var(--affine-font-xs)',
|
fontSize: 'var(--affine-font-xs)',
|
||||||
height: '16px',
|
minHeight: '16px',
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
selectors: {
|
selectors: {
|
||||||
'&:not(:first-of-type)': {
|
'&:not(:first-of-type)': {
|
||||||
marginTop: '10px',
|
marginTop: '10px',
|
||||||
|
@ -21,7 +21,6 @@ export const viewButton = style({
|
|||||||
fontSize: 'var(--affine-font-xs)',
|
fontSize: 'var(--affine-font-xs)',
|
||||||
background: 'var(--affine-white)',
|
background: 'var(--affine-white)',
|
||||||
maxWidth: '200px',
|
maxWidth: '200px',
|
||||||
overflow: 'hidden',
|
|
||||||
color: 'var(--affine-text-secondary-color)',
|
color: 'var(--affine-text-secondary-color)',
|
||||||
border: '1px solid var(--affine-border-color)',
|
border: '1px solid var(--affine-border-color)',
|
||||||
transition: 'margin-left 0.2s ease-in-out',
|
transition: 'margin-left 0.2s ease-in-out',
|
||||||
@ -41,6 +40,8 @@ export const viewButton = style({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
globalStyle(`${viewButton} > span`, {
|
globalStyle(`${viewButton} > span`, {
|
||||||
|
display: 'block',
|
||||||
|
width: '100%',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
@ -75,6 +76,9 @@ export const filterButton = style({
|
|||||||
padding: '4px 8px',
|
padding: '4px 8px',
|
||||||
fontSize: 'var(--affine-font-xs)',
|
fontSize: 'var(--affine-font-xs)',
|
||||||
background: 'var(--affine-white)',
|
background: 'var(--affine-white)',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
color: 'var(--affine-text-secondary-color)',
|
color: 'var(--affine-text-secondary-color)',
|
||||||
border: '1px solid var(--affine-border-color)',
|
border: '1px solid var(--affine-border-color)',
|
||||||
transition: 'margin-left 0.2s ease-in-out',
|
transition: 'margin-left 0.2s ease-in-out',
|
||||||
|
@ -243,14 +243,14 @@ export const EditCollection = ({
|
|||||||
marginTop: 40,
|
marginTop: 40,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button className={styles.cancelButton} onClick={onCancel}>
|
<Button size="large" onClick={onCancel}>
|
||||||
{t['Cancel']()}
|
{t['Cancel']()}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 20,
|
marginLeft: 20,
|
||||||
borderRadius: '8px',
|
|
||||||
}}
|
}}
|
||||||
|
size="large"
|
||||||
data-testid="save-collection"
|
data-testid="save-collection"
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -276,17 +276,13 @@ export const SaveCollectionButton = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
className={styles.saveButton}
|
|
||||||
onClick={() => changeShow(true)}
|
onClick={() => changeShow(true)}
|
||||||
size="large"
|
|
||||||
data-testid="save-as-collection"
|
data-testid="save-as-collection"
|
||||||
|
icon={<SaveIcon />}
|
||||||
|
size="large"
|
||||||
|
style={{ padding: '7px 8px' }}
|
||||||
>
|
>
|
||||||
<div className={styles.saveButtonContainer}>
|
Save As Collection
|
||||||
<div className={styles.saveIcon}>
|
|
||||||
<SaveIcon />
|
|
||||||
</div>
|
|
||||||
<div className={styles.saveText}>Save As Collection</div>
|
|
||||||
</div>
|
|
||||||
</Button>
|
</Button>
|
||||||
<EditCollectionModel
|
<EditCollectionModel
|
||||||
title={t['Save As New Collection']()}
|
title={t['Save As New Collection']()}
|
||||||
|
@ -67,7 +67,7 @@ export const button = style({
|
|||||||
},
|
},
|
||||||
|
|
||||||
'&.primary': {
|
'&.primary': {
|
||||||
color: 'var(--affine-white)',
|
color: 'var(--affine-pure-white)',
|
||||||
background: 'var(--affine-primary-color)',
|
background: 'var(--affine-primary-color)',
|
||||||
borderColor: 'var(--affine-black-10)',
|
borderColor: 'var(--affine-black-10)',
|
||||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||||
|
@ -154,3 +154,30 @@ test('create temporary filter by click tag', async ({ page }) => {
|
|||||||
await page.getByRole('tooltip').getByText('TODO Tag').click();
|
await page.getByRole('tooltip').getByText('TODO Tag').click();
|
||||||
expect(await page.getByTestId('title').count()).toBe(2);
|
expect(await page.getByTestId('title').count()).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('add collection from sidebar', async ({ page }) => {
|
||||||
|
await openHomePage(page);
|
||||||
|
await waitEditorLoad(page);
|
||||||
|
await newPage(page);
|
||||||
|
await getBlockSuiteEditorTitle(page).click();
|
||||||
|
await getBlockSuiteEditorTitle(page).fill('test page');
|
||||||
|
await page.getByTestId('all-pages').click();
|
||||||
|
const cell = page.getByRole('cell', {
|
||||||
|
name: 'test page',
|
||||||
|
});
|
||||||
|
await expect(cell).toBeVisible();
|
||||||
|
const nullCollection = page.getByTestId(
|
||||||
|
'slider-bar-collection-null-description'
|
||||||
|
);
|
||||||
|
await expect(nullCollection).toBeVisible();
|
||||||
|
await page.getByTestId('slider-bar-add-collection-button').click();
|
||||||
|
const title = page.getByTestId('input-collection-title');
|
||||||
|
await title.isVisible();
|
||||||
|
await title.fill('test collection');
|
||||||
|
await page.getByTestId('save-collection').click();
|
||||||
|
await page.waitForTimeout(100);
|
||||||
|
const collections = page.getByTestId('collections');
|
||||||
|
const items = collections.getByTestId('collection-item');
|
||||||
|
expect(await items.count()).toBe(1);
|
||||||
|
await expect(nullCollection).not.toBeVisible();
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user