mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: board toolbar
This commit is contained in:
parent
033a231b67
commit
c3a7f94cb3
@ -37,6 +37,7 @@ import { SortSvg } from '$app/components/_shared/svg/SortSvg';
|
||||
import { TextTypeSvg } from '$app/components/_shared/svg/TextTypeSvg';
|
||||
import { TrashSvg } from '$app/components/_shared/svg/TrashSvg';
|
||||
import { UrlTypeSvg } from '$app/components/_shared/svg/UrlTypeSvg';
|
||||
import { GroupByFieldSvg } from '$app/components/_shared/svg/GroupByFieldSvg';
|
||||
|
||||
export const TestColors = () => {
|
||||
return (
|
||||
@ -110,6 +111,9 @@ export const TestColors = () => {
|
||||
<i className={'h-5 w-5'}>
|
||||
<GridSvg></GridSvg>
|
||||
</i>
|
||||
<i className={'h-5 w-5'}>
|
||||
<GroupByFieldSvg></GroupByFieldSvg>
|
||||
</i>
|
||||
<i className={'h-5 w-5'}>
|
||||
<HideMenuSvg></HideMenuSvg>
|
||||
</i>
|
||||
|
@ -2,7 +2,7 @@ import { MouseEvent, ReactNode, useRef } from 'react';
|
||||
import useOutsideClick from './useOutsideClick';
|
||||
|
||||
export interface IPopupItem {
|
||||
icon: ReactNode;
|
||||
icon: ReactNode | (() => JSX.Element);
|
||||
title: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
@ -31,18 +31,20 @@ export const Popup = ({
|
||||
return (
|
||||
<div ref={ref} className={`${className} rounded-lg bg-white px-2 py-2 shadow-md`} style={style}>
|
||||
<div
|
||||
className={`grid ${columns === 1 && 'grid-cols-1'} ${columns === 2 && 'grid-cols-2'} ${
|
||||
columns === 3 && 'grid-cols-3'
|
||||
} gap-x-4`}
|
||||
className={
|
||||
(columns === 2 ? 'grid grid-cols-2' : '') + (columns === 3 ? 'grid grid-cols-3' : '') + ' w-full gap-x-4'
|
||||
}
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<button
|
||||
key={index}
|
||||
className={'flex cursor-pointer items-center gap-2 rounded-lg px-2 py-2 hover:bg-main-secondary'}
|
||||
className={'flex w-full cursor-pointer items-center gap-2 rounded-lg px-2 py-2 hover:bg-main-secondary'}
|
||||
onClick={(e) => handleClick(e, item)}
|
||||
>
|
||||
{item.icon}
|
||||
<span className={'flex-shrink-0'}>{item.title}</span>
|
||||
<>
|
||||
{typeof item.icon === 'function' ? item.icon() : item.icon}
|
||||
<span className={'flex-shrink-0'}>{item.title}</span>
|
||||
</>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
@ -0,0 +1,26 @@
|
||||
export const GroupByFieldSvg = () => {
|
||||
return (
|
||||
<svg width='100%' height='100%' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M10 2H13C13.5523 2 14 2.44772 14 3V6'
|
||||
stroke='currentColor'
|
||||
strokeLinecap='round'
|
||||
strokeLinejoin='round'
|
||||
/>
|
||||
<path d='M6 2H3C2.44772 2 2 2.44772 2 3V6' stroke='currentColor' strokeLinecap='round' strokeLinejoin='round' />
|
||||
<path
|
||||
d='M6 14H3C2.44772 14 2 13.5523 2 13V10'
|
||||
stroke='currentColor'
|
||||
strokeLinecap='round'
|
||||
strokeLinejoin='round'
|
||||
/>
|
||||
<path
|
||||
d='M10 14H13C13.5523 14 14 13.5523 14 13V10'
|
||||
stroke='currentColor'
|
||||
strokeLinecap='round'
|
||||
strokeLinejoin='round'
|
||||
/>
|
||||
<rect x='6' y='6' width='4' height='4' rx='1' stroke='currentColor' />
|
||||
</svg>
|
||||
);
|
||||
};
|
@ -8,6 +8,7 @@ import { DragDropContext } from 'react-beautiful-dnd';
|
||||
import { useState } from 'react';
|
||||
import { RowInfo } from '$app/stores/effects/database/row/row_cache';
|
||||
import { EditRow } from '$app/components/_shared/EditRow/EditRow';
|
||||
import { BoardToolbar } from '$app/components/board/BoardToolbar';
|
||||
|
||||
export const Board = ({ viewId, title }: { viewId: string; title: string }) => {
|
||||
const { controller, rows, groups, groupByFieldId, onNewRowClick, onDragEnd } = useDatabase(viewId, ViewLayoutPB.Board);
|
||||
@ -22,12 +23,7 @@ export const Board = ({ viewId, title }: { viewId: string; title: string }) => {
|
||||
return (
|
||||
<>
|
||||
<div className='flex w-full items-center justify-between'>
|
||||
<div className={'flex items-center text-xl font-semibold'}>
|
||||
<div>{title}</div>
|
||||
<button className={'ml-2 h-5 w-5'}>
|
||||
<SettingsSvg></SettingsSvg>
|
||||
</button>
|
||||
</div>
|
||||
<BoardToolbar title={title} />
|
||||
|
||||
<div className='flex shrink-0 items-center gap-4'>
|
||||
<SearchInput />
|
||||
|
@ -0,0 +1,36 @@
|
||||
import { useAppSelector } from '$app/stores/store';
|
||||
import { FieldTypeIcon } from '$app/components/_shared/EditRow/FieldTypeIcon';
|
||||
import { Popup } from '$app/components/_shared/Popup';
|
||||
import { useRef } from 'react';
|
||||
import useOutsideClick from '$app/components/_shared/useOutsideClick';
|
||||
import { EyeOpenSvg } from '$app/components/_shared/svg/EyeOpenSvg';
|
||||
|
||||
export const BoardFieldsPopup = ({ hidePopup }: { hidePopup: () => void }) => {
|
||||
const columns = useAppSelector((state) => state.database.columns);
|
||||
const fields = useAppSelector((state) => state.database.fields);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
useOutsideClick(ref, () => hidePopup());
|
||||
|
||||
return (
|
||||
<div ref={ref} className={'absolute top-full left-full z-10 rounded-lg bg-white px-2 py-2 shadow-md'}>
|
||||
{columns.map((column, index) => (
|
||||
<div
|
||||
className={'flex cursor-pointer items-center justify-between rounded-lg px-2 py-2 hover:bg-main-secondary'}
|
||||
key={index}
|
||||
>
|
||||
<div className={'flex items-center gap-2 '}>
|
||||
<i className={'flex h-5 w-5 flex-shrink-0 items-center justify-center'}>
|
||||
<FieldTypeIcon fieldType={fields[column.fieldId].fieldType}></FieldTypeIcon>
|
||||
</i>
|
||||
<span className={'flex-shrink-0'}>{fields[column.fieldId].title}</span>
|
||||
</div>
|
||||
<div className={'ml-12'}>
|
||||
<i className={'block h-5 w-5'}>
|
||||
<EyeOpenSvg></EyeOpenSvg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
export const BoardGroupFieldsPopup = ({ hidePopup }: { hidePopup: () => void }) => {
|
||||
return <></>;
|
||||
};
|
@ -0,0 +1,48 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { PropertiesSvg } from '$app/components/_shared/svg/PropertiesSvg';
|
||||
import { IPopupItem, Popup } from '$app/components/_shared/Popup';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { GroupByFieldSvg } from '$app/components/_shared/svg/GroupByFieldSvg';
|
||||
|
||||
export const BoardSettingsPopup = ({
|
||||
hidePopup,
|
||||
onFieldsClick,
|
||||
onGroupClick,
|
||||
}: {
|
||||
hidePopup: () => void;
|
||||
onFieldsClick: () => void;
|
||||
onGroupClick: () => void;
|
||||
}) => {
|
||||
const [settingsItems, setSettingsItems] = useState<IPopupItem[]>([]);
|
||||
const { t } = useTranslation('');
|
||||
useEffect(() => {
|
||||
setSettingsItems([
|
||||
{
|
||||
icon: (
|
||||
<i className={'h-5 w-5'}>
|
||||
<PropertiesSvg></PropertiesSvg>
|
||||
</i>
|
||||
),
|
||||
title: t('grid.settings.Properties'),
|
||||
onClick: onFieldsClick,
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<i className={'h-5 w-5'}>
|
||||
<GroupByFieldSvg></GroupByFieldSvg>
|
||||
</i>
|
||||
),
|
||||
title: t('grid.settings.group'),
|
||||
onClick: onGroupClick,
|
||||
},
|
||||
]);
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<Popup
|
||||
onOutsideClick={() => hidePopup()}
|
||||
items={settingsItems}
|
||||
className={'absolute top-full left-full z-10'}
|
||||
></Popup>
|
||||
);
|
||||
};
|
@ -0,0 +1,37 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
export const useBoardToolbar = () => {
|
||||
const [showSettings, setShowSettings] = useState(false);
|
||||
const [showAllFields, setShowAllFields] = useState(false);
|
||||
const [showGroupFields, setShowGroupFields] = useState(false);
|
||||
|
||||
const onSettingsClick = () => {
|
||||
setShowSettings(!showSettings);
|
||||
};
|
||||
|
||||
const onFieldsClick = () => {
|
||||
setShowSettings(false);
|
||||
setShowAllFields(true);
|
||||
};
|
||||
|
||||
const onGroupClick = () => {
|
||||
setShowSettings(false);
|
||||
setShowGroupFields(true);
|
||||
};
|
||||
|
||||
const hidePopup = () => {
|
||||
setShowSettings(false);
|
||||
setShowAllFields(false);
|
||||
setShowGroupFields(false);
|
||||
};
|
||||
|
||||
return {
|
||||
showSettings,
|
||||
onSettingsClick,
|
||||
onFieldsClick,
|
||||
onGroupClick,
|
||||
hidePopup,
|
||||
showAllFields,
|
||||
showGroupFields,
|
||||
};
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
import { SettingsSvg } from '$app/components/_shared/svg/SettingsSvg';
|
||||
import { useBoardToolbar } from '$app/components/board/BoardToolbar.hooks';
|
||||
import { BoardSettingsPopup } from '$app/components/board/BoardSettingsPopup';
|
||||
import { BoardFieldsPopup } from '$app/components/board/BoardFieldsPopup';
|
||||
import { BoardGroupFieldsPopup } from '$app/components/board/BoardGroupFieldsPopup';
|
||||
|
||||
export const BoardToolbar = ({ title }: { title: string }) => {
|
||||
const { showSettings, showAllFields, showGroupFields, onSettingsClick, onFieldsClick, onGroupClick, hidePopup } =
|
||||
useBoardToolbar();
|
||||
|
||||
return (
|
||||
<div className={'relative flex items-center gap-2'}>
|
||||
<div className={'text-xl font-semibold'}>{title}</div>
|
||||
<button onClick={() => onSettingsClick()} className={'h-5 w-5'}>
|
||||
<SettingsSvg></SettingsSvg>
|
||||
</button>
|
||||
{showSettings && (
|
||||
<BoardSettingsPopup
|
||||
hidePopup={hidePopup}
|
||||
onFieldsClick={onFieldsClick}
|
||||
onGroupClick={onGroupClick}
|
||||
></BoardSettingsPopup>
|
||||
)}
|
||||
{showAllFields && <BoardFieldsPopup hidePopup={hidePopup}></BoardFieldsPopup>}
|
||||
{showGroupFields && <BoardGroupFieldsPopup hidePopup={hidePopup}></BoardGroupFieldsPopup>}
|
||||
</div>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user