refactor(group): split group menu

This commit is contained in:
lawvs
2022-07-27 18:31:20 +08:00
parent 196fe993b3
commit 5b52daa030
7 changed files with 259 additions and 54 deletions

View File

@@ -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';

View File

@@ -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>
);
};

View File

@@ -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 && (

View File

@@ -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>
))}
</>
);
};

View File

@@ -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" />,
};

View File

@@ -0,0 +1 @@
export { GroupMenuWrapper } from './MainMenu';

View File

@@ -0,0 +1,10 @@
import { styled } from '@toeverything/components/ui';
export const PanelItem = styled('div')({
display: 'flex',
userSelect: 'none',
'& + &': {
marginTop: '8px',
},
});