update ListConfigMenu to work with new lists

This commit is contained in:
jeffvli
2025-10-09 14:26:52 -07:00
parent 943b26dfea
commit 1172152018
4 changed files with 847 additions and 183 deletions
@@ -0,0 +1,200 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { ListConfigTable } from '/@/renderer/features/shared/components/list-config-menu';
import {
DataGridProps,
DataListProps,
useSettingsStore,
useSettingsStoreActions,
} from '/@/renderer/store';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Badge } from '/@/shared/components/badge/badge';
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
import { Group } from '/@/shared/components/group/group';
import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control';
import { Slider } from '/@/shared/components/slider/slider';
import { ItemListKey, ListPaginationType } from '/@/shared/types/types';
type GridConfigProps = {
extraOptions?: {
component: React.ReactNode;
id: string;
label: string;
}[];
listKey: ItemListKey;
};
export const GridConfig = ({ extraOptions, listKey }: GridConfigProps) => {
const { t } = useTranslation();
const list = useSettingsStore((state) => state.lists[listKey]) as DataListProps;
const grid = useSettingsStore((state) => state.lists[listKey].grid) as DataGridProps;
const { setList } = useSettingsStoreActions();
const options = useMemo(() => {
return [
{
component: (
<SegmentedControl
data={[
{
label: t('table.config.general.pagination_infinite', {
postProcess: 'sentenceCase',
}),
value: ListPaginationType.INFINITE,
},
{
label: t('table.config.general.pagination_paginate', {
postProcess: 'sentenceCase',
}),
value: ListPaginationType.PAGINATED,
},
]}
onChange={(value) =>
setList(listKey, {
...list,
pagination: value as ListPaginationType,
})
}
size="sm"
value={list.pagination}
w="100%"
/>
),
id: 'pagination',
label: t('table.config.general.pagination', { postProcess: 'sentenceCase' }),
size: 'sm',
},
{
component: (
<Slider
defaultValue={list.itemsPerPage}
marks={[
{ value: 25 },
{ value: 50 },
{ value: 100 },
{ value: 150 },
{ value: 200 },
{ value: 250 },
{ value: 300 },
{ value: 400 },
{ value: 500 },
]}
max={500}
min={25}
onChangeEnd={(value) => setList(listKey, { ...list, itemsPerPage: value })}
restrictToMarks
w="100%"
/>
),
id: 'itemsPerPage',
label: (
<Group>
{t('table.config.general.pagination_itemsPerPage', {
postProcess: 'sentenceCase',
})}
<Badge>{list.itemsPerPage}</Badge>
</Group>
),
},
{
component: (
<Group gap="xs" grow w="100%">
<ActionIcon
disabled={grid.itemGap === 'xl'}
icon="arrowUp"
iconProps={{ size: 'lg' }}
onClick={() => {
if (grid.itemGap === 'xl') return;
if (grid.itemGap === 'lg') {
return setList(listKey, { grid: { itemGap: 'xl' } });
}
if (grid.itemGap === 'md') {
return setList(listKey, { grid: { itemGap: 'lg' } });
}
if (grid.itemGap === 'sm') {
return setList(listKey, { grid: { itemGap: 'md' } });
}
return setList(listKey, { grid: { itemGap: 'sm' } });
}}
size="xs"
/>
<ActionIcon
disabled={grid.itemGap === 'xs'}
icon="arrowDown"
iconProps={{ size: 'lg' }}
onClick={() => {
if (grid.itemGap === 'xs') return;
if (grid.itemGap === 'sm') {
return setList(listKey, { grid: { itemGap: 'xs' } });
}
if (grid.itemGap === 'md') {
return setList(listKey, { grid: { itemGap: 'sm' } });
}
if (grid.itemGap === 'lg') {
return setList(listKey, { grid: { itemGap: 'md' } });
}
return setList(listKey, { grid: { itemGap: 'lg' } });
}}
size="xs"
/>
</Group>
),
id: 'itemGap',
label: (
<Group>
{t('table.config.general.gap', { postProcess: 'sentenceCase' })}
<Badge>{grid.itemGap}</Badge>
</Group>
),
},
{
component: (
<Slider
defaultValue={grid.itemsPerRow}
max={20}
min={2}
onChangeEnd={(value) => setList(listKey, { grid: { itemsPerRow: value } })}
w="100%"
/>
),
id: 'itemsPerRow',
label: (
<Group justify="space-between" w="100%" wrap="nowrap">
<Group>
{t('table.config.general.itemsPerRow', { postProcess: 'sentenceCase' })}
<Badge>{grid.itemsPerRow}</Badge>
</Group>
<Checkbox
checked={grid.itemsPerRowEnabled}
label={t('common.enable', { postProcess: 'titleCase' })}
onChange={(e) =>
setList(listKey, {
grid: { itemsPerRowEnabled: e.target.checked },
})
}
size="xs"
/>
</Group>
),
},
...(extraOptions || []),
];
}, [list, t, grid, extraOptions, setList, listKey]);
return (
<>
<ListConfigTable options={options} />
</>
);
};
@@ -1,91 +1,128 @@
import { useTranslation } from 'react-i18next';
import { ReactNode } from 'react';
import i18n from '/@/i18n/i18n';
import { GridConfig } from '/@/renderer/features/shared/components/grid-config';
import { SettingsButton } from '/@/renderer/features/shared/components/settings-button';
import { CheckboxSelect } from '/@/shared/components/checkbox-select/checkbox-select';
import { TableConfig } from '/@/renderer/features/shared/components/table-config';
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store';
import { Group } from '/@/shared/components/group/group';
import { Icon } from '/@/shared/components/icon/icon';
import { Popover } from '/@/shared/components/popover/popover';
import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control';
import { Slider } from '/@/shared/components/slider/slider';
import { Stack } from '/@/shared/components/stack/stack';
import { Switch } from '/@/shared/components/switch/switch';
import { Table } from '/@/shared/components/table/table';
import { ListDisplayType } from '/@/shared/types/types';
import { ItemListKey, ListDisplayType } from '/@/shared/types/types';
const DISPLAY_TYPES = [
{
label: (
<Stack align="center" p="sm">
<Group align="center" justify="center" p="sm">
<Icon icon="layoutTable" size="lg" />
{i18n.t('table.config.view.table', { postProcess: 'sentenceCase' }) as string}
</Stack>
</Group>
),
value: ListDisplayType.TABLE,
},
{
label: (
<Stack align="center" p="sm">
<Group align="center" justify="center" p="sm">
<Icon icon="layoutGrid" size="lg" />
{i18n.t('table.config.view.card', { postProcess: 'sentenceCase' }) as string}
</Stack>
{i18n.t('table.config.view.grid', { postProcess: 'sentenceCase' }) as string}
</Group>
),
value: ListDisplayType.GRID,
},
{
disabled: true,
label: (
<Stack align="center" p="sm">
<Icon icon="layoutList" size="lg" />
{i18n.t('table.config.view.list', { postProcess: 'sentenceCase' }) as string}
</Stack>
),
value: ListDisplayType.LIST,
},
// {
// disabled: true,
// label: (
// <Stack align="center" p="sm">
// <Icon icon="layoutList" size="lg" />
// {i18n.t('table.config.view.list', { postProcess: 'sentenceCase' }) as string}
// </Stack>
// ),
// value: ListDisplayType.LIST,
// },
];
export const ListConfigBooleanControl = ({
onChange,
value,
}: {
onChange: (value: boolean) => void;
value: boolean;
}) => {
return (
<SegmentedControl
data={[
{
label: i18n.t('common.enable', {
postProcess: 'sentenceCase',
}) as string,
value: 'true',
},
{
label: i18n.t('common.disable', {
postProcess: 'sentenceCase',
}) as string,
value: 'false',
},
]}
onChange={(value) => onChange(value === 'true' ? true : false)}
size="sm"
value={value ? 'true' : 'false'}
w="100%"
/>
);
};
interface ListConfigMenuProps {
autoFitColumns?: boolean;
disabledViewTypes?: ListDisplayType[];
displayType: ListDisplayType;
itemGap?: number;
itemSize?: number;
onChangeAutoFitColumns?: (autoFitColumns: boolean) => void;
onChangeDisplayType?: (displayType: ListDisplayType) => void;
onChangeItemGap?: (itemGap: number) => void;
onChangeItemSize?: (itemSize: number) => void;
onChangeTableColumns?: (tableColumns: string[]) => void;
tableColumns?: string[];
tableColumnsData?: { label: string; value: string }[];
listKey: ItemListKey;
tableColumnsData: { label: string; value: string }[];
}
export const ListConfigMenu = (props: ListConfigMenuProps) => {
const displayType = useSettingsStore((state) => state.lists[props.listKey].display);
const { setList } = useSettingsStoreActions();
return (
<Popover position="bottom-end" width={300}>
<Popover position="bottom-end" trapFocus width={640}>
<Popover.Target>
<SettingsButton />
</Popover.Target>
<Popover.Dropdown p="md">
<Stack>
<SegmentedControl
data={DISPLAY_TYPES.map((type) => ({
...type,
disabled: props.disabledViewTypes?.includes(type.value),
}))}
onChange={(value) => props.onChangeDisplayType?.(value as ListDisplayType)}
value={props.displayType}
w="100%"
withItemsBorders={false}
/>
<Config {...props} />
</Stack>
<Popover.Dropdown>
<ScrollArea
allowDragScroll
scrollX
style={{ height: 'auto', maxHeight: '70dvh', padding: '1rem' }}
>
<Stack>
<SegmentedControl
data={DISPLAY_TYPES.map((type) => ({
...type,
}))}
fullWidth
onChange={(value) => {
setList(props.listKey, {
display: value as ListDisplayType,
});
}}
value={displayType}
withItemsBorders={false}
/>
<Config displayType={displayType} {...props} />
</Stack>
</ScrollArea>
</Popover.Dropdown>
</Popover>
);
};
const Config = (props: ListConfigMenuProps) => {
switch (props.displayType) {
const Config = ({
displayType,
...props
}: ListConfigMenuProps & { displayType: ListDisplayType }) => {
switch (displayType) {
case ListDisplayType.GRID:
return <GridConfig {...props} />;
@@ -97,141 +134,28 @@ const Config = (props: ListConfigMenuProps) => {
}
};
type TableConfigProps = Pick<
ListConfigMenuProps,
| 'autoFitColumns'
| 'itemSize'
| 'onChangeAutoFitColumns'
| 'onChangeItemSize'
| 'onChangeTableColumns'
| 'tableColumns'
| 'tableColumnsData'
>;
const TableConfig = ({
autoFitColumns,
itemSize,
onChangeAutoFitColumns,
onChangeItemSize,
onChangeTableColumns,
tableColumns,
tableColumnsData,
}: TableConfigProps) => {
const { t } = useTranslation();
if (
!tableColumnsData ||
!onChangeTableColumns ||
!tableColumns ||
!onChangeItemSize ||
autoFitColumns === undefined ||
!onChangeAutoFitColumns ||
itemSize === undefined
) {
console.error('TableConfig: Missing required props', {
itemSize,
onChangeItemSize,
onChangeTableColumns,
tableColumns,
tableColumnsData,
});
return null;
}
export const ListConfigTable = ({
options,
}: {
options: { component: ReactNode; id: string; label: ReactNode | string }[];
}) => {
return (
<>
<Table variant="vertical" withColumnBorders withRowBorders withTableBorder>
<Table.Tbody>
<Table.Tr>
<Table.Th>
{t('table.config.general.size', {
postProcess: 'sentenceCase',
})}
</Table.Th>
<Table.Td>
<Slider
defaultValue={itemSize}
max={100}
min={30}
onChangeEnd={onChangeItemSize}
/>
</Table.Td>
<Table
style={{ borderRadius: '1rem' }}
styles={{ th: { backgroundColor: 'initial', padding: 'var(--theme-spacing-md) 0' } }}
variant="vertical"
withColumnBorders={false}
withRowBorders={false}
withTableBorder={false}
>
<Table.Tbody>
{options.map((option) => (
<Table.Tr key={option.id}>
<Table.Th w="50%">{option.label}</Table.Th>
<Table.Td>{option.component}</Table.Td>
</Table.Tr>
<Table.Tr>
<Table.Th w="50%">
{t('table.config.general.autoFitColumns', {
postProcess: 'sentenceCase',
})}
</Table.Th>
<Table.Td style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Switch
defaultChecked={autoFitColumns}
onChange={(e) => onChangeAutoFitColumns?.(e.target.checked)}
size="xs"
/>
</Table.Td>
</Table.Tr>
</Table.Tbody>
</Table>
<ScrollArea allowDragScroll style={{ maxHeight: '200px' }}>
<CheckboxSelect
data={tableColumnsData}
onChange={onChangeTableColumns}
value={tableColumns}
/>
</ScrollArea>
</>
);
};
type GridConfigProps = Pick<
ListConfigMenuProps,
'itemGap' | 'itemSize' | 'onChangeItemGap' | 'onChangeItemSize'
>;
const GridConfig = ({ itemSize, onChangeItemGap, onChangeItemSize }: GridConfigProps) => {
const { t } = useTranslation();
if (!onChangeItemGap || !onChangeItemSize || !itemSize) {
return null;
}
return (
<>
<Table variant="vertical" withColumnBorders withRowBorders withTableBorder>
<Table.Tbody>
<Table.Tr>
<Table.Th w="50%">
{t('table.config.general.gap', {
postProcess: 'sentenceCase',
})}
</Table.Th>
<Table.Td>
<Slider
defaultValue={itemSize}
max={30}
min={0}
onChangeEnd={onChangeItemGap}
/>
</Table.Td>
</Table.Tr>
<Table.Tr>
<Table.Th w="50%">
{t('table.config.general.size', {
postProcess: 'sentenceCase',
})}
</Table.Th>
<Table.Td>
<Slider
defaultValue={itemSize}
max={300}
min={135}
onChangeEnd={onChangeItemSize}
/>
</Table.Td>
</Table.Tr>
</Table.Tbody>
</Table>
</>
))}
</Table.Tbody>
</Table>
);
};
@@ -0,0 +1,18 @@
.group {
overflow: hidden;
border: 1px solid var(--theme-colors-border);
border-radius: var(--theme-radius-md);
}
.number-input {
width: 140px;
}
.item {
display: flex;
flex-wrap: nowrap;
gap: var(--theme-spacing-md);
align-items: center;
justify-content: space-between;
width: 100%;
}
@@ -0,0 +1,522 @@
import clsx from 'clsx';
import { motion } from 'motion/react';
import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import styles from './table-config.module.css';
import { ItemTableListColumnConfig } from '/@/renderer/components/item-list/types';
import {
ListConfigBooleanControl,
ListConfigTable,
} from '/@/renderer/features/shared/components/list-config-menu';
import { DataListProps, useSettingsStore, useSettingsStoreActions } from '/@/renderer/store';
import { ActionIcon, ActionIconGroup } from '/@/shared/components/action-icon/action-icon';
import { Badge } from '/@/shared/components/badge/badge';
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
import { Group } from '/@/shared/components/group/group';
import { NumberInput } from '/@/shared/components/number-input/number-input';
import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control';
import { Slider } from '/@/shared/components/slider/slider';
import { Stack } from '/@/shared/components/stack/stack';
import { Tooltip } from '/@/shared/components/tooltip/tooltip';
import { ItemListKey, ListPaginationType } from '/@/shared/types/types';
interface TableConfigProps {
extraOptions?: {
component: React.ReactNode;
id: string;
label: string;
}[];
listKey: ItemListKey;
tableColumnsData: { label: string; value: string }[];
}
export const TableConfig = ({ extraOptions, listKey, tableColumnsData }: TableConfigProps) => {
const { t } = useTranslation();
const list = useSettingsStore((state) => state.lists[listKey]) as DataListProps;
const { setList } = useSettingsStoreActions();
const options = useMemo(() => {
return [
{
component: (
<SegmentedControl
data={[
{
label: t('table.config.general.pagination_infinite', {
postProcess: 'sentenceCase',
}),
value: 'infinite',
},
{
label: t('table.config.general.pagination_paginate', {
postProcess: 'sentenceCase',
}),
value: 'paginate',
},
]}
onChange={(value) =>
setList(listKey, { pagination: value as ListPaginationType })
}
size="sm"
value={list.pagination}
w="100%"
/>
),
id: 'pagination',
label: t('table.config.general.pagination', { postProcess: 'sentenceCase' }),
size: 'sm',
},
{
component: (
<Slider
defaultValue={list.itemsPerPage}
marks={[
{ value: 25 },
{ value: 50 },
{ value: 100 },
{ value: 150 },
{ value: 200 },
{ value: 250 },
{ value: 300 },
{ value: 400 },
{ value: 500 },
]}
max={500}
min={25}
onChangeEnd={(value) => setList(listKey, { itemsPerPage: value })}
restrictToMarks
w="100%"
/>
),
id: 'itemsPerPage',
label: (
<Group>
{t('table.config.general.pagination_itemsPerPage', {
postProcess: 'sentenceCase',
})}
<Badge>{list.itemsPerPage}</Badge>
</Group>
),
},
{
component: (
<SegmentedControl
data={[
{
label: t('table.config.general.size_compact', {
postProcess: 'titleCase',
}),
value: 'compact',
},
{
label: t('table.config.general.size_default', {
postProcess: 'titleCase',
}),
value: 'default',
},
{
label: t('table.config.general.size_large', {
postProcess: 'titleCase',
}),
value: 'large',
},
]}
onChange={(value) =>
setList(listKey, {
table: { size: value as 'compact' | 'default' },
})
}
size="sm"
value={list.table.size}
w="100%"
/>
),
id: 'size',
label: t('table.config.general.size', {
postProcess: 'titleCase',
}),
},
{
component: (
<ListConfigBooleanControl
onChange={(e) =>
setList(listKey, { table: { enableRowHoverHighlight: e } })
}
value={list.table.enableRowHoverHighlight}
/>
),
id: 'enableRowHoverHighlight',
label: t('table.config.general.rowHoverHighlight', {
postProcess: 'sentenceCase',
}),
},
{
component: (
<ListConfigBooleanControl
onChange={(e) =>
setList(listKey, { table: { enableAlternateRowColors: e } })
}
value={list.table.enableAlternateRowColors}
/>
),
id: 'enableAlternateRowColors',
label: t('table.config.general.alternateRowColors', {
postProcess: 'sentenceCase',
}),
},
{
component: (
<ListConfigBooleanControl
onChange={(e) =>
setList(listKey, { table: { enableHorizontalBorders: e } })
}
value={list.table.enableHorizontalBorders}
/>
),
id: 'enableHorizontalBorders',
label: t('table.config.general.horizontalBorders', {
postProcess: 'sentenceCase',
}),
},
{
component: (
<ListConfigBooleanControl
onChange={(e) => setList(listKey, { table: { enableVerticalBorders: e } })}
value={list.table.enableVerticalBorders}
/>
),
id: 'enableVerticalBorders',
label: t('table.config.general.verticalBorders', {
postProcess: 'sentenceCase',
}),
},
...(extraOptions || []),
];
}, [extraOptions, listKey, setList, t, list]);
return (
<>
<ListConfigTable options={options} />
<TableColumnConfig
data={tableColumnsData}
listKey={listKey}
onChange={(columns) =>
setList(listKey, { ...list, table: { ...list.table, columns } })
}
value={list.table.columns}
/>
</>
);
};
const TableColumnConfig = ({
data,
listKey,
onChange,
value,
}: {
data: { label: string; value: string }[];
listKey: ItemListKey;
onChange: (value: ItemTableListColumnConfig[]) => void;
value: ItemTableListColumnConfig[];
}) => {
const { t } = useTranslation();
const labelMap = useMemo(() => {
return data.reduce(
(acc, item) => {
acc[item.value] = item.label;
return acc;
},
{} as Record<string, string>,
);
}, [data]);
const handleChangeEnabled = useCallback(
(item: ItemTableListColumnConfig, checked: boolean) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
const newValues = [...value];
newValues[index] = { ...newValues[index], isEnabled: checked };
onChange(newValues);
},
[listKey, onChange],
);
const handleMoveUp = useCallback(
(item: ItemTableListColumnConfig) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
if (index === 0) return;
const newValues = [...value];
[newValues[index], newValues[index - 1]] = [newValues[index - 1], newValues[index]];
onChange(newValues);
},
[listKey, onChange],
);
const handleMoveDown = useCallback(
(item: ItemTableListColumnConfig) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
if (index === value.length - 1) return;
const newValues = [...value];
[newValues[index], newValues[index + 1]] = [newValues[index + 1], newValues[index]];
onChange(newValues);
},
[listKey, onChange],
);
const handlePinToLeft = useCallback(
(item: ItemTableListColumnConfig) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
const newValues = [...value];
const isPinned = newValues[index].pinned;
const isPinnedLeft = isPinned === 'left';
if (isPinnedLeft) {
newValues[index] = { ...newValues[index], pinned: null };
} else {
newValues[index] = { ...newValues[index], pinned: 'left' };
}
onChange(newValues);
},
[listKey, onChange],
);
const handlePinToRight = useCallback(
(item: ItemTableListColumnConfig) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
const newValues = [...value];
const isPinned = newValues[index].pinned;
const isPinnedRight = isPinned === 'right';
if (isPinnedRight) {
newValues[index] = { ...newValues[index], pinned: null };
} else {
newValues[index] = { ...newValues[index], pinned: 'right' };
}
onChange(newValues);
},
[listKey, onChange],
);
const handleAlignLeft = useCallback(
(item: ItemTableListColumnConfig) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
const newValues = [...value];
newValues[index] = { ...newValues[index], align: 'start' };
onChange(newValues);
},
[listKey, onChange],
);
const handleAlignCenter = useCallback(
(item: ItemTableListColumnConfig) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
const newValues = [...value];
newValues[index] = { ...newValues[index], align: 'center' };
onChange(newValues);
},
[listKey, onChange],
);
const handleAlignRight = useCallback(
(item: ItemTableListColumnConfig) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
const newValues = [...value];
newValues[index] = { ...newValues[index], align: 'end' };
onChange(newValues);
},
[listKey, onChange],
);
const handleAutoSize = useCallback(
(item: ItemTableListColumnConfig, checked: boolean) => {
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
const newValues = [...value];
newValues[index] = { ...newValues[index], autoSize: checked };
onChange(newValues);
},
[listKey, onChange],
);
const handleRowWidth = useCallback(
(item: ItemTableListColumnConfig, number: number | string) => {
if (typeof number !== 'number') {
number = 0;
}
if (number < 0) {
number = 0;
}
if (number > 2000) {
number = 2000;
}
const value = useSettingsStore.getState().lists[listKey].table.columns;
const index = value.findIndex((v) => v.id === item.id);
const newValues = [...value];
newValues[index] = { ...newValues[index], width: number };
onChange(newValues);
},
[listKey, onChange],
);
return (
<Stack gap="xs">
{value.map((item) => (
<motion.div className={styles.item} key={item.id} layout>
<Group wrap="nowrap">
<Checkbox
checked={item.isEnabled}
id={item.id}
label={labelMap[item.id]}
onChange={(e) => handleChangeEnabled(item, e.currentTarget.checked)}
size="sm"
/>
</Group>
<Group wrap="nowrap">
<ActionIconGroup className={styles.group}>
<ActionIcon
icon="arrowUp"
iconProps={{ size: 'md' }}
onClick={() => handleMoveUp(item)}
size="xs"
tooltip={{
label: t('table.config.general.moveUp', {
postProcess: 'sentenceCase',
}),
}}
variant="subtle"
/>
<ActionIcon
icon="arrowDown"
iconProps={{ size: 'md' }}
onClick={() => handleMoveDown(item)}
size="xs"
tooltip={{
label: t('table.config.general.moveDown', {
postProcess: 'sentenceCase',
}),
}}
variant="subtle"
/>
</ActionIconGroup>
<ActionIconGroup className={styles.group}>
<ActionIcon
icon="arrowLeftToLine"
iconProps={{ size: 'md' }}
onClick={() => handlePinToLeft(item)}
size="xs"
tooltip={{
label: t('table.config.general.pinToLeft', {
postProcess: 'sentenceCase',
}),
}}
variant={item.pinned === 'left' ? 'filled' : 'subtle'}
/>
<ActionIcon
icon="arrowRightToLine"
iconProps={{ size: 'md' }}
onClick={() => handlePinToRight(item)}
size="xs"
tooltip={{
label: t('table.config.general.pinToRight', {
postProcess: 'sentenceCase',
}),
}}
variant={item.pinned === 'right' ? 'filled' : 'subtle'}
/>
</ActionIconGroup>
<ActionIconGroup className={styles.group}>
<ActionIcon
icon="alignLeft"
iconProps={{ size: 'md' }}
onClick={() => handleAlignLeft(item)}
size="xs"
tooltip={{
label: t('table.config.general.alignLeft', {
postProcess: 'sentenceCase',
}),
}}
variant={item.align === 'start' ? 'filled' : 'subtle'}
/>
<ActionIcon
icon="alignCenter"
iconProps={{ size: 'md' }}
onClick={() => handleAlignCenter(item)}
size="xs"
tooltip={{
label: t('table.config.general.alignCenter', {
postProcess: 'sentenceCase',
}),
}}
variant={item.align === 'center' ? 'filled' : 'subtle'}
/>
<ActionIcon
icon="alignRight"
iconProps={{ size: 'md' }}
onClick={() => handleAlignRight(item)}
size="xs"
tooltip={{
label: t('table.config.general.alignRight', {
postProcess: 'sentenceCase',
}),
}}
variant={item.align === 'end' ? 'filled' : 'subtle'}
/>
</ActionIconGroup>
<NumberInput
className={clsx(styles.group, styles.numberInput)}
hideControls={false}
leftSection={
<>
{item.pinned === null && (
<Tooltip
label={t('table.config.general.autosize', {
postProcess: 'sentenceCase',
})}
>
<Checkbox
checked={item.autoSize}
disabled={item.pinned !== null}
id={item.id}
onChange={(e) =>
handleAutoSize(item, e.currentTarget.checked)
}
size="xs"
/>
</Tooltip>
)}
</>
}
max={2000}
min={0}
onChange={(value) => handleRowWidth(item, value)}
size="xs"
step={10}
value={item.width}
variant="subtle"
/>
</Group>
</motion.div>
))}
</Stack>
);
};