mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
feat(component): support sort workspace card (#1837)
This commit is contained in:
@@ -17,11 +17,14 @@
|
||||
"@affine/debug": "workspace:*",
|
||||
"@affine/i18n": "workspace:*",
|
||||
"@affine/jotai": "workspace:*",
|
||||
"@affine/workspace": "workspace:^",
|
||||
"@blocksuite/blocks": "0.0.0-20230406032111-01cf598b-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230406032111-01cf598b-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230406032111-01cf598b-nightly",
|
||||
"@blocksuite/icons": "2.1.5",
|
||||
"@blocksuite/store": "0.0.0-20230406032111-01cf598b-nightly",
|
||||
"@dnd-kit/core": "^6.0.8",
|
||||
"@dnd-kit/sortable": "^7.0.2",
|
||||
"@emotion/cache": "^11.10.7",
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@emotion/server": "^11.10.0",
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { SettingsIcon } from '@blocksuite/icons';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name';
|
||||
import type React from 'react';
|
||||
import type { FC, MouseEvent } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { WorkspaceAvatar } from '../workspace-avatar';
|
||||
@@ -45,7 +45,7 @@ const PublishIcon = () => {
|
||||
return <DefaultPublishIcon style={{ color: '#8699FF' }} />;
|
||||
};
|
||||
|
||||
const WorkspaceType: React.FC<WorkspaceTypeProps> = ({ workspace }) => {
|
||||
const WorkspaceType: FC<WorkspaceTypeProps> = ({ workspace }) => {
|
||||
const { t } = useTranslation();
|
||||
let isOwner = true;
|
||||
if (workspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
@@ -83,7 +83,7 @@ export type WorkspaceCardProps = {
|
||||
onSettingClick: (workspace: AffineWorkspace | LocalWorkspace) => void;
|
||||
};
|
||||
|
||||
export const WorkspaceCard: React.FC<WorkspaceCardProps> = ({
|
||||
export const WorkspaceCard: FC<WorkspaceCardProps> = ({
|
||||
workspace,
|
||||
onClick,
|
||||
onSettingClick,
|
||||
@@ -95,9 +95,12 @@ export const WorkspaceCard: React.FC<WorkspaceCardProps> = ({
|
||||
return (
|
||||
<StyledCard
|
||||
data-testid="workspace-card"
|
||||
onClick={useCallback(() => {
|
||||
onClick(workspace);
|
||||
}, [onClick, workspace])}
|
||||
onClick={useCallback(
|
||||
(event: MouseEvent) => {
|
||||
onClick(workspace);
|
||||
},
|
||||
[onClick, workspace]
|
||||
)}
|
||||
active={workspace.id === currentWorkspaceId}
|
||||
>
|
||||
<WorkspaceAvatar size={58} workspace={workspace} />
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { arrayMove } from '@dnd-kit/sortable';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import type { WorkspaceListProps } from './index';
|
||||
import { WorkspaceList } from './index';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/WorkspaceList',
|
||||
component: WorkspaceList,
|
||||
} satisfies Meta<WorkspaceListProps>;
|
||||
|
||||
export const Default = () => {
|
||||
const [items, setItems] = useState(() => {
|
||||
const items = [
|
||||
{
|
||||
id: '1',
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
blockSuiteWorkspace: createEmptyBlockSuiteWorkspace('1'),
|
||||
providers: [],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
blockSuiteWorkspace: createEmptyBlockSuiteWorkspace('2'),
|
||||
providers: [],
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
blockSuiteWorkspace: createEmptyBlockSuiteWorkspace('3'),
|
||||
providers: [],
|
||||
},
|
||||
] satisfies WorkspaceListProps['items'];
|
||||
|
||||
items.forEach(item => {
|
||||
item.blockSuiteWorkspace.meta.setName(item.id);
|
||||
});
|
||||
|
||||
return items;
|
||||
});
|
||||
return (
|
||||
<WorkspaceList
|
||||
currentWorkspaceId={null}
|
||||
items={items}
|
||||
onClick={() => {}}
|
||||
onSettingClick={() => {}}
|
||||
onDragEnd={event => {
|
||||
const { active, over } = event;
|
||||
|
||||
if (active.id !== over?.id) {
|
||||
setItems(items => {
|
||||
const oldIndex = items.findIndex(item => item.id === active.id);
|
||||
const newIndex = items.findIndex(item => item.id === over?.id);
|
||||
|
||||
return arrayMove(items, oldIndex, newIndex);
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
70
packages/component/src/components/workspace-list/index.tsx
Normal file
70
packages/component/src/components/workspace-list/index.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import {
|
||||
DndContext,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
import { SortableContext, useSortable } from '@dnd-kit/sortable';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { WorkspaceCard } from '../workspace-card';
|
||||
|
||||
export type WorkspaceListProps = {
|
||||
currentWorkspaceId: string | null;
|
||||
items: (AffineWorkspace | LocalWorkspace)[];
|
||||
onClick: (workspace: AffineWorkspace | LocalWorkspace) => void;
|
||||
onSettingClick: (workspace: AffineWorkspace | LocalWorkspace) => void;
|
||||
onDragEnd: (event: DragEndEvent) => void;
|
||||
};
|
||||
|
||||
const SortableWorkspaceItem: FC<
|
||||
Omit<WorkspaceListProps, 'items'> & {
|
||||
item: AffineWorkspace | LocalWorkspace;
|
||||
}
|
||||
> = props => {
|
||||
const { setNodeRef, attributes, listeners, transform } = useSortable({
|
||||
id: props.item.id,
|
||||
});
|
||||
const style = transform
|
||||
? {
|
||||
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
|
||||
}
|
||||
: undefined;
|
||||
return (
|
||||
<div
|
||||
data-testid="draggable-item"
|
||||
style={style}
|
||||
ref={setNodeRef}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
>
|
||||
<WorkspaceCard
|
||||
currentWorkspaceId={props.currentWorkspaceId}
|
||||
workspace={props.item}
|
||||
onClick={props.onClick}
|
||||
onSettingClick={props.onSettingClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkspaceList: FC<WorkspaceListProps> = props => {
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
activationConstraint: {
|
||||
distance: 8,
|
||||
},
|
||||
})
|
||||
);
|
||||
return (
|
||||
<DndContext sensors={sensors} onDragEnd={props.onDragEnd}>
|
||||
<SortableContext items={props.items}>
|
||||
{props.items.map(item => (
|
||||
<SortableWorkspaceItem {...props} item={item} key={item.id} />
|
||||
))}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user