mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
add modularity to the ListConfigMenu
This commit is contained in:
@@ -46,9 +46,20 @@ type GridConfigProps = {
|
|||||||
}[];
|
}[];
|
||||||
gridRowsData: { label: string; value: string }[];
|
gridRowsData: { label: string; value: string }[];
|
||||||
listKey: ItemListKey;
|
listKey: ItemListKey;
|
||||||
|
optionsConfig?: {
|
||||||
|
[key: string]: {
|
||||||
|
disabled?: boolean;
|
||||||
|
hidden?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GridConfig = ({ extraOptions, gridRowsData, listKey }: GridConfigProps) => {
|
export const GridConfig = ({
|
||||||
|
extraOptions,
|
||||||
|
gridRowsData,
|
||||||
|
listKey,
|
||||||
|
optionsConfig,
|
||||||
|
}: GridConfigProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const list = useSettingsStore((state) => state.lists[listKey]) as ItemListSettings;
|
const list = useSettingsStore((state) => state.lists[listKey]) as ItemListSettings;
|
||||||
@@ -56,7 +67,7 @@ export const GridConfig = ({ extraOptions, gridRowsData, listKey }: GridConfigPr
|
|||||||
const { setList } = useSettingsStoreActions();
|
const { setList } = useSettingsStoreActions();
|
||||||
|
|
||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
return [
|
const allOptions = [
|
||||||
{
|
{
|
||||||
component: (
|
component: (
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
@@ -214,7 +225,24 @@ export const GridConfig = ({ extraOptions, gridRowsData, listKey }: GridConfigPr
|
|||||||
|
|
||||||
...(extraOptions || []),
|
...(extraOptions || []),
|
||||||
];
|
];
|
||||||
}, [list, t, grid, extraOptions, setList, listKey]);
|
|
||||||
|
// Filter and apply config (hidden/disabled)
|
||||||
|
return allOptions
|
||||||
|
.map((option) => {
|
||||||
|
const config = optionsConfig?.[option.id];
|
||||||
|
if (config?.hidden) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...option,
|
||||||
|
disabled: config?.disabled || false,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(
|
||||||
|
(option): option is typeof allOptions[0] & { disabled?: boolean } =>
|
||||||
|
option !== null,
|
||||||
|
);
|
||||||
|
}, [list, t, grid, extraOptions, optionsConfig, setList, listKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import i18n from '/@/i18n/i18n';
|
import i18n from '/@/i18n/i18n';
|
||||||
@@ -77,8 +77,30 @@ export const ListConfigBooleanControl = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface ListConfigMenuDisplayTypeConfig {
|
||||||
|
disabled?: boolean;
|
||||||
|
hidden?: boolean;
|
||||||
|
value: ListDisplayType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListConfigMenuOptionConfig {
|
||||||
|
disabled?: boolean;
|
||||||
|
hidden?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListConfigMenuOptionsConfig {
|
||||||
|
grid?: {
|
||||||
|
[key: string]: ListConfigMenuOptionConfig;
|
||||||
|
};
|
||||||
|
table?: {
|
||||||
|
[key: string]: ListConfigMenuOptionConfig;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface ListConfigMenuProps {
|
interface ListConfigMenuProps {
|
||||||
|
displayTypes?: ListConfigMenuDisplayTypeConfig[];
|
||||||
listKey: ItemListKey;
|
listKey: ItemListKey;
|
||||||
|
optionsConfig?: ListConfigMenuOptionsConfig;
|
||||||
tableColumnsData: { label: string; value: string }[];
|
tableColumnsData: { label: string; value: string }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +112,29 @@ export const ListConfigMenu = (props: ListConfigMenuProps) => {
|
|||||||
const { setList } = useSettingsStoreActions();
|
const { setList } = useSettingsStoreActions();
|
||||||
const [isOpen, handlers] = useDisclosure(false);
|
const [isOpen, handlers] = useDisclosure(false);
|
||||||
|
|
||||||
|
// Filter display types based on config
|
||||||
|
const availableDisplayTypes = useMemo(() => {
|
||||||
|
if (!props.displayTypes) {
|
||||||
|
return DISPLAY_TYPES;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtered = DISPLAY_TYPES.map((type) => {
|
||||||
|
const config = props.displayTypes?.find((c) => c.value === type.value);
|
||||||
|
if (config?.hidden) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const result: (typeof DISPLAY_TYPES)[0] & { disabled?: boolean } = {
|
||||||
|
...type,
|
||||||
|
};
|
||||||
|
if (config?.disabled) {
|
||||||
|
result.disabled = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}).filter((type): type is NonNullable<typeof type> => type !== null);
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}, [props.displayTypes]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsButton onClick={handlers.toggle} />
|
<SettingsButton onClick={handlers.toggle} />
|
||||||
@@ -101,9 +146,7 @@ export const ListConfigMenu = (props: ListConfigMenuProps) => {
|
|||||||
>
|
>
|
||||||
<Stack>
|
<Stack>
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
data={DISPLAY_TYPES.map((type) => ({
|
data={availableDisplayTypes}
|
||||||
...type,
|
|
||||||
}))}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setList(props.listKey, {
|
setList(props.listKey, {
|
||||||
@@ -122,15 +165,28 @@ export const ListConfigMenu = (props: ListConfigMenuProps) => {
|
|||||||
|
|
||||||
const Config = ({
|
const Config = ({
|
||||||
displayType,
|
displayType,
|
||||||
|
optionsConfig,
|
||||||
tableColumnsData,
|
tableColumnsData,
|
||||||
...props
|
...props
|
||||||
}: ListConfigMenuProps & { displayType: ListDisplayType }) => {
|
}: ListConfigMenuProps & { displayType: ListDisplayType }) => {
|
||||||
switch (displayType) {
|
switch (displayType) {
|
||||||
case ListDisplayType.GRID:
|
case ListDisplayType.GRID:
|
||||||
return <GridConfig {...props} gridRowsData={tableColumnsData} />;
|
return (
|
||||||
|
<GridConfig
|
||||||
|
{...props}
|
||||||
|
gridRowsData={tableColumnsData}
|
||||||
|
optionsConfig={optionsConfig?.grid}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
case ListDisplayType.TABLE:
|
case ListDisplayType.TABLE:
|
||||||
return <TableConfig {...props} tableColumnsData={tableColumnsData} />;
|
return (
|
||||||
|
<TableConfig
|
||||||
|
{...props}
|
||||||
|
optionsConfig={optionsConfig?.table}
|
||||||
|
tableColumnsData={tableColumnsData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview';
|
import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview';
|
||||||
import { useDebouncedState } from '@mantine/hooks';
|
import { useDebouncedState } from '@mantine/hooks';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import Fuse from 'fuse.js';
|
import Fuse, { type FuseResultMatch } from 'fuse.js';
|
||||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@@ -45,17 +45,28 @@ interface TableConfigProps {
|
|||||||
label: string;
|
label: string;
|
||||||
}[];
|
}[];
|
||||||
listKey: ItemListKey;
|
listKey: ItemListKey;
|
||||||
|
optionsConfig?: {
|
||||||
|
[key: string]: {
|
||||||
|
disabled?: boolean;
|
||||||
|
hidden?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
tableColumnsData: { label: string; value: string }[];
|
tableColumnsData: { label: string; value: string }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TableConfig = ({ extraOptions, listKey, tableColumnsData }: TableConfigProps) => {
|
export const TableConfig = ({
|
||||||
|
extraOptions,
|
||||||
|
listKey,
|
||||||
|
optionsConfig,
|
||||||
|
tableColumnsData,
|
||||||
|
}: TableConfigProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const list = useSettingsStore((state) => state.lists[listKey]) as ItemListSettings;
|
const list = useSettingsStore((state) => state.lists[listKey]) as ItemListSettings;
|
||||||
const { setList } = useSettingsStoreActions();
|
const { setList } = useSettingsStoreActions();
|
||||||
|
|
||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
return [
|
const allOptions = [
|
||||||
{
|
{
|
||||||
component: (
|
component: (
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
@@ -222,7 +233,18 @@ export const TableConfig = ({ extraOptions, listKey, tableColumnsData }: TableCo
|
|||||||
|
|
||||||
...(extraOptions || []),
|
...(extraOptions || []),
|
||||||
];
|
];
|
||||||
}, [extraOptions, listKey, setList, t, list]);
|
|
||||||
|
// Filter and apply config (hidden/disabled)
|
||||||
|
return allOptions
|
||||||
|
.map((option) => {
|
||||||
|
const config = optionsConfig?.[option.id];
|
||||||
|
if (config?.hidden) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return option;
|
||||||
|
})
|
||||||
|
.filter((option): option is NonNullable<typeof option> => option !== null);
|
||||||
|
}, [extraOptions, listKey, optionsConfig, setList, t, list]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -497,14 +519,18 @@ const TableColumnConfig = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const DragHandle = ({ dragHandleRef }: { dragHandleRef: React.RefObject<HTMLButtonElement> }) => {
|
const DragHandle = ({
|
||||||
|
dragHandleRef,
|
||||||
|
}: {
|
||||||
|
dragHandleRef: React.RefObject<HTMLButtonElement | null>;
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
icon="dragVertical"
|
icon="dragVertical"
|
||||||
iconProps={{
|
iconProps={{
|
||||||
size: 'md',
|
size: 'md',
|
||||||
}}
|
}}
|
||||||
ref={dragHandleRef}
|
ref={dragHandleRef as React.RefObject<HTMLButtonElement>}
|
||||||
size="xs"
|
size="xs"
|
||||||
style={{ cursor: 'grab' }}
|
style={{ cursor: 'grab' }}
|
||||||
variant="default"
|
variant="default"
|
||||||
@@ -542,7 +568,7 @@ const TableColumnItem = memo(
|
|||||||
handleRowWidth: (item: ItemTableListColumnConfig, number: number | string) => void;
|
handleRowWidth: (item: ItemTableListColumnConfig, number: number | string) => void;
|
||||||
item: ItemTableListColumnConfig;
|
item: ItemTableListColumnConfig;
|
||||||
label: string;
|
label: string;
|
||||||
matches: null | readonly Fuse.FuseResultMatch[];
|
matches: null | readonly FuseResultMatch[];
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user