mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
refactor(group): split group menu
This commit is contained in:
@@ -8,7 +8,7 @@ import { styled } from '@toeverything/components/ui';
|
||||
import type { CreateView } from '@toeverything/framework/virgo';
|
||||
import type { ComponentType, FC } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { GroupMenuWrapper } from './GroupMenu';
|
||||
import { GroupMenuWrapper } from './group-menu';
|
||||
import { SceneKanban } from './scene-kanban';
|
||||
import { ScenePage } from './ScenePage';
|
||||
import { SceneTable } from './SceneTable';
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import {
|
||||
RecastScene,
|
||||
useRecastView,
|
||||
} from '@toeverything/components/editor-core';
|
||||
import { AddViewIcon, DoneIcon } from '@toeverything/components/icons';
|
||||
import { Input, MuiClickAwayListener } from '@toeverything/components/ui';
|
||||
import type { ChangeEvent, KeyboardEvent } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { IconButton } from '../components/IconButton';
|
||||
import { Panel } from '../components/Panel';
|
||||
import { VIEW_ICON_MAP } from './constant';
|
||||
import { PanelItem } from './styles';
|
||||
|
||||
export const AddViewMenu = () => {
|
||||
const [viewName, setViewName] = useState('');
|
||||
const [viewType, setViewType] = useState<RecastScene>(RecastScene.Page);
|
||||
const [activePanel, setActivePanel] = useState(false);
|
||||
const { addView, setCurrentView } = useRecastView();
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setViewName(e.target.value.trim());
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key !== 'Enter') {
|
||||
return;
|
||||
}
|
||||
handleAddView();
|
||||
};
|
||||
|
||||
const handleAddView = async () => {
|
||||
const newView = await addView({ name: viewName, type: viewType });
|
||||
await setCurrentView(newView);
|
||||
setActivePanel(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<MuiClickAwayListener onClickAway={() => setActivePanel(false)}>
|
||||
<IconButton
|
||||
active={activePanel}
|
||||
onClick={() => setActivePanel(!activePanel)}
|
||||
>
|
||||
<AddViewIcon fontSize="small" />
|
||||
<span>Add View</span>
|
||||
{activePanel && (
|
||||
<Panel>
|
||||
<PanelItem>
|
||||
<Input
|
||||
placeholder="View Name"
|
||||
autoFocus
|
||||
style={{ flex: 1 }}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<IconButton
|
||||
aria-label="done"
|
||||
onClick={handleAddView}
|
||||
>
|
||||
<DoneIcon />
|
||||
</IconButton>
|
||||
</PanelItem>
|
||||
|
||||
<PanelItem>
|
||||
{Object.entries(VIEW_ICON_MAP).map(
|
||||
([name, icon]) => (
|
||||
<IconButton
|
||||
key={name}
|
||||
active={
|
||||
viewType === (name as RecastScene)
|
||||
}
|
||||
onClick={() => {
|
||||
if (name === 'table') {
|
||||
// The table view is under progress
|
||||
return;
|
||||
}
|
||||
setViewType(name as RecastScene);
|
||||
}}
|
||||
>
|
||||
{VIEW_ICON_MAP[name as RecastScene]}
|
||||
{name.toUpperCase()}
|
||||
</IconButton>
|
||||
)
|
||||
)}
|
||||
</PanelItem>
|
||||
</Panel>
|
||||
)}
|
||||
</IconButton>
|
||||
</MuiClickAwayListener>
|
||||
);
|
||||
};
|
||||
@@ -1,13 +1,14 @@
|
||||
import { CommingSoon } from '@toeverything/components/common';
|
||||
import type {
|
||||
AsyncBlock,
|
||||
BlockEditor,
|
||||
} from '@toeverything/components/editor-core';
|
||||
import {
|
||||
mergeToPreviousGroup,
|
||||
RecastScene,
|
||||
RecastView,
|
||||
useCurrentView,
|
||||
useRecastView,
|
||||
} from '@toeverything/components/editor-core';
|
||||
import {
|
||||
AddViewIcon,
|
||||
FilterIcon,
|
||||
FullScreenIcon,
|
||||
GroupByIcon,
|
||||
@@ -15,45 +16,21 @@ import {
|
||||
KanBanIcon,
|
||||
SortIcon,
|
||||
TableIcon,
|
||||
TodoListIcon,
|
||||
} from '@toeverything/components/icons';
|
||||
import { Popover, useTheme } from '@toeverything/components/ui';
|
||||
import { useFlag } from '@toeverything/datasource/feature-flags';
|
||||
import type { AsyncBlock, BlockEditor } from '@toeverything/framework/virgo';
|
||||
import type { ReactElement, ReactNode } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { Filter } from './components/filter';
|
||||
import { GroupBy } from './components/group-by/GroupBy';
|
||||
import { GroupPanel } from './components/group-panel/GroupPanel';
|
||||
import { IconButton } from './components/IconButton';
|
||||
import { Line } from './components/Line';
|
||||
import { Sorter } from './components/sorter';
|
||||
import { PANEL_CONFIG } from './config';
|
||||
import type { ActivePanel } from './types';
|
||||
|
||||
const VIEW_ICON_MAP: Record<RecastView['type'], ReactElement> = {
|
||||
page: <TodoListIcon fontSize="small" />,
|
||||
kanban: <KanBanIcon fontSize="small" />,
|
||||
table: <TableIcon fontSize="small" />,
|
||||
};
|
||||
|
||||
const ViewsMenu = () => {
|
||||
const { currentView, recastViews, setCurrentView } = useRecastView();
|
||||
return (
|
||||
<>
|
||||
{recastViews.map(view => (
|
||||
<IconButton
|
||||
key={view.id}
|
||||
active={view.id === currentView.id}
|
||||
onClick={() => setCurrentView(view)}
|
||||
>
|
||||
{VIEW_ICON_MAP[view.type]}
|
||||
{view.name}
|
||||
</IconButton>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
import { Filter } from '../components/filter';
|
||||
import { GroupBy } from '../components/group-by/GroupBy';
|
||||
import { GroupPanel } from '../components/group-panel/GroupPanel';
|
||||
import { IconButton } from '../components/IconButton';
|
||||
import { Line } from '../components/Line';
|
||||
import { Sorter } from '../components/sorter';
|
||||
import { PANEL_CONFIG } from '../config';
|
||||
import type { ActivePanel } from '../types';
|
||||
import { AddViewMenu } from './AddViewMenu';
|
||||
import { ViewsMenu } from './ViewsMenu';
|
||||
|
||||
const GroupMenuWrapper = ({
|
||||
block,
|
||||
@@ -105,21 +82,7 @@ const GroupMenuWrapper = ({
|
||||
content={
|
||||
<GroupPanel>
|
||||
<ViewsMenu />
|
||||
|
||||
{filterSorterFlag && (
|
||||
<IconButton
|
||||
active={activePanel === PANEL_CONFIG.ADD_VIEW}
|
||||
onClick={() =>
|
||||
setActivePanel(
|
||||
PANEL_CONFIG.ADD_VIEW as ActivePanel
|
||||
)
|
||||
}
|
||||
>
|
||||
<AddViewIcon fontSize="small" />
|
||||
Add View
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
<AddViewMenu />
|
||||
{
|
||||
// // Closed beta period temporarily
|
||||
// filterSorterFlag && (
|
||||
@@ -0,0 +1,128 @@
|
||||
import {
|
||||
RecastScene,
|
||||
RecastView,
|
||||
useRecastView,
|
||||
} from '@toeverything/components/editor-core';
|
||||
import { DeleteCashBinIcon, DoneIcon } from '@toeverything/components/icons';
|
||||
import { Input } from '@toeverything/components/ui';
|
||||
import type { ChangeEvent, KeyboardEvent } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { IconButton } from '../components/IconButton';
|
||||
import { Panel } from '../components/Panel';
|
||||
import { VIEW_ICON_MAP } from './constant';
|
||||
import { PanelItem } from './styles';
|
||||
|
||||
export const ViewsMenu = () => {
|
||||
const [viewName, setViewName] = useState('');
|
||||
const [viewType, setViewType] = useState<RecastScene>(RecastScene.Page);
|
||||
const [activeView, setActiveView] = useState<RecastView | null>(null);
|
||||
const { currentView, recastViews, setCurrentView, updateView, removeView } =
|
||||
useRecastView();
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setViewName(e.target.value.trim());
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key !== 'Enter') {
|
||||
return;
|
||||
}
|
||||
handleUpdateView();
|
||||
};
|
||||
|
||||
const handleUpdateView = async () => {
|
||||
if (!activeView) {
|
||||
return;
|
||||
}
|
||||
await updateView({
|
||||
...activeView,
|
||||
name: viewName,
|
||||
type: viewType,
|
||||
});
|
||||
setActiveView(null);
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (!activeView) {
|
||||
return;
|
||||
}
|
||||
await removeView(activeView.id);
|
||||
|
||||
setActiveView(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{recastViews.map(view => (
|
||||
<IconButton
|
||||
key={view.id}
|
||||
active={view.id === currentView.id}
|
||||
onClick={() => setCurrentView(view)}
|
||||
onContextMenu={e => {
|
||||
setViewName(view.name);
|
||||
setViewType(view.type);
|
||||
setActiveView(view);
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
{VIEW_ICON_MAP[view.type]}
|
||||
<span style={{ userSelect: 'none' }}>{view.name}</span>
|
||||
|
||||
{activeView === view && (
|
||||
<Panel>
|
||||
<PanelItem>
|
||||
<Input
|
||||
placeholder="View Name"
|
||||
autoFocus
|
||||
style={{ flex: 1 }}
|
||||
value={viewName}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<IconButton
|
||||
aria-label="delete"
|
||||
onClick={handleDelete}
|
||||
>
|
||||
<DeleteCashBinIcon />
|
||||
</IconButton>
|
||||
|
||||
<IconButton
|
||||
aria-label="done"
|
||||
onClick={handleUpdateView}
|
||||
>
|
||||
<DoneIcon />
|
||||
</IconButton>
|
||||
</PanelItem>
|
||||
|
||||
<PanelItem>
|
||||
{Object.entries(VIEW_ICON_MAP).map(
|
||||
([name, icon]) => (
|
||||
<IconButton
|
||||
key={name}
|
||||
active={
|
||||
viewType ===
|
||||
(name as RecastScene)
|
||||
}
|
||||
onClick={() => {
|
||||
if (name === 'table') {
|
||||
// The table view is under progress
|
||||
return;
|
||||
}
|
||||
setViewType(
|
||||
name as RecastScene
|
||||
);
|
||||
}}
|
||||
>
|
||||
{VIEW_ICON_MAP[name as RecastScene]}
|
||||
{name.toUpperCase()}
|
||||
</IconButton>
|
||||
)
|
||||
)}
|
||||
</PanelItem>
|
||||
</Panel>
|
||||
)}
|
||||
</IconButton>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import { RecastView } from '@toeverything/components/editor-core';
|
||||
import {
|
||||
KanBanIcon,
|
||||
TableIcon,
|
||||
TodoListIcon,
|
||||
} from '@toeverything/components/icons';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
export const VIEW_ICON_MAP: Record<RecastView['type'], ReactElement> = {
|
||||
page: <TodoListIcon fontSize="small" />,
|
||||
kanban: <KanBanIcon fontSize="small" />,
|
||||
table: <TableIcon fontSize="small" />,
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { GroupMenuWrapper } from './MainMenu';
|
||||
@@ -0,0 +1,10 @@
|
||||
import { styled } from '@toeverything/components/ui';
|
||||
|
||||
export const PanelItem = styled('div')({
|
||||
display: 'flex',
|
||||
userSelect: 'none',
|
||||
|
||||
'& + &': {
|
||||
marginTop: '8px',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user