R: Refactor table usage

This commit is contained in:
Ivan 2025-03-05 00:57:03 +03:00
parent 28c84d90ba
commit b9e5331d91
6 changed files with 133 additions and 131 deletions

View File

@ -7,11 +7,12 @@ import { HelpTopic } from '../models/helpTopic';
export function HelpRSLang() {
const windowSize = useWindowSize();
const isSmall = windowSize.isSmall;
const videoHeight = (() => {
const viewH = windowSize.height ?? 0;
const viewW = windowSize.width ?? 0;
const availableWidth = viewW - (windowSize.isSmall ? 35 : 310);
const availableWidth = viewW - (isSmall ? 35 : 310);
return Math.min(1080, Math.max(viewH - 450, 300), Math.floor((availableWidth * 9) / 16));
})();

View File

@ -1,43 +1,48 @@
'use client';
import { useLayoutEffect, useState } from 'react';
import { useIntl } from 'react-intl';
import clsx from 'clsx';
import { urls, useConceptNavigation } from '@/app';
import { useLabelUser } from '@/features/users';
import { FlexColumn } from '@/components/Container';
import { MiniButton, TextURL } from '@/components/Control';
import { createColumnHelper, DataTable, type IConditionalStyle, type VisibilityState } from '@/components/DataTable';
import { IconFolderTree } from '@/components/Icons';
import { TextURL } from '@/components/Control';
import { DataTable, type IConditionalStyle, type VisibilityState } from '@/components/DataTable';
import { useWindowSize } from '@/hooks/useWindowSize';
import { useFitHeight } from '@/stores/appLayout';
import { usePreferencesStore } from '@/stores/preferences';
import { APP_COLORS } from '@/styling/colors';
import { type ILibraryItem, LibraryItemType } from '../../backend/types';
import { BadgeLocation } from '../../components/BadgeLocation';
import { useLibrarySearchStore } from '../../stores/librarySearch';
import { useLibraryColumns } from './useLibraryColumns';
interface TableLibraryItemsProps {
items: ILibraryItem[];
}
const columnHelper = createColumnHelper<ILibraryItem>();
export function TableLibraryItems({ items }: TableLibraryItemsProps) {
const router = useConceptNavigation();
const intl = useIntl();
const getUserLabel = useLabelUser();
const { isSmall } = useWindowSize();
const folderMode = useLibrarySearchStore(state => state.folderMode);
const toggleFolderMode = useLibrarySearchStore(state => state.toggleFolderMode);
const resetFilter = useLibrarySearchStore(state => state.resetFilter);
const itemsPerPage = usePreferencesStore(state => state.libraryPagination);
const setItemsPerPage = usePreferencesStore(state => state.setLibraryPagination);
const columns = useLibraryColumns();
const columnVisibility: VisibilityState = { owner: !isSmall };
const conditionalRowStyles: IConditionalStyle<ILibraryItem>[] = [
{
when: (item: ILibraryItem) => item.item_type === LibraryItemType.OSS,
style: {
color: APP_COLORS.fgGreen
}
}
];
const tableHeight = useFitHeight('2.2rem');
function handleOpenItem(item: ILibraryItem, event: React.MouseEvent<Element>) {
const selection = window.getSelection();
if (!!selection && selection.toString().length > 0) {
@ -50,108 +55,6 @@ export function TableLibraryItems({ items }: TableLibraryItemsProps) {
}
}
const windowSize = useWindowSize();
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
useLayoutEffect(() => {
setColumnVisibility({
owner: !windowSize.isSmall
});
}, [windowSize]);
function handleToggleFolder(event: React.MouseEvent<Element>) {
event.preventDefault();
event.stopPropagation();
toggleFolderMode();
}
const columns = [
...(folderMode
? []
: [
columnHelper.accessor('location', {
id: 'location',
header: () => (
<MiniButton
noPadding
noHover
className='pl-2 max-h-[1rem] translate-y-[-0.125rem]'
onClick={handleToggleFolder}
titleHtml='Переключение в режим Проводник'
icon={<IconFolderTree size='1.25rem' className='clr-text-controls' />}
/>
),
size: 50,
minSize: 50,
maxSize: 50,
enableSorting: true,
cell: props => <BadgeLocation location={props.getValue()} />,
sortingFn: 'text'
})
]),
columnHelper.accessor('alias', {
id: 'alias',
header: 'Шифр',
size: 150,
minSize: 80,
maxSize: 150,
enableSorting: true,
cell: props => <div className='min-w-[5rem]'>{props.getValue()}</div>,
sortingFn: 'text'
}),
columnHelper.accessor('title', {
id: 'title',
header: 'Название',
size: 1200,
minSize: 200,
maxSize: 1200,
enableSorting: true,
sortingFn: 'text'
}),
columnHelper.accessor(item => item.owner ?? 0, {
id: 'owner',
header: 'Владелец',
size: 400,
minSize: 100,
maxSize: 400,
cell: props => getUserLabel(props.getValue()),
enableSorting: true,
sortingFn: 'text'
}),
columnHelper.accessor('time_update', {
id: 'time_update',
header: windowSize.isSmall ? 'Дата' : 'Обновлена',
cell: props => (
<div className='whitespace-nowrap'>
{new Date(props.getValue()).toLocaleString(intl.locale, {
year: '2-digit',
month: '2-digit',
day: '2-digit',
...(!windowSize.isSmall && {
hour: '2-digit',
minute: '2-digit'
})
})}
</div>
),
enableSorting: true,
sortingFn: 'datetime',
sortDescFirst: true
})
];
const tableHeight = useFitHeight('2.2rem');
const conditionalRowStyles: IConditionalStyle<ILibraryItem>[] = [
{
when: (item: ILibraryItem) => item.item_type === LibraryItemType.OSS,
style: {
color: APP_COLORS.fgGreen
}
}
];
return (
<DataTable
id='library_data'

View File

@ -26,7 +26,7 @@ interface ViewSideLocationProps {
export function ViewSideLocation({ isVisible, onRenameLocation }: ViewSideLocationProps) {
const { user, isAnonymous } = useAuthSuspense();
const { items } = useLibrary();
const windowSize = useWindowSize();
const { isSmall } = useWindowSize();
const location = useLibrarySearchStore(state => state.location);
const setLocation = useLibrarySearchStore(state => state.setLocation);
@ -68,7 +68,7 @@ export function ViewSideLocation({ isVisible, onRenameLocation }: ViewSideLocati
transitionProperty: 'width, min-width, opacity',
transitionDuration: `${PARAMETER.moveDuration}ms`,
transitionTimingFunction: 'ease-out',
minWidth: isVisible ? (windowSize.isSmall ? '10rem' : '15rem') : '0',
minWidth: isVisible ? (isSmall ? '10rem' : '15rem') : '0',
width: isVisible ? '100%' : '0',
opacity: isVisible ? 1 : 0
}}

View File

@ -0,0 +1,104 @@
import { useIntl } from 'react-intl';
import { useLabelUser } from '@/features/users';
import { MiniButton } from '@/components/Control';
import { createColumnHelper } from '@/components/DataTable';
import { IconFolderTree } from '@/components/Icons';
import { useWindowSize } from '@/hooks/useWindowSize';
import { type ILibraryItem } from '../../backend/types';
import { BadgeLocation } from '../../components/BadgeLocation';
import { useLibrarySearchStore } from '../../stores/librarySearch';
const columnHelper = createColumnHelper<ILibraryItem>();
export function useLibraryColumns() {
const { isSmall } = useWindowSize();
const intl = useIntl();
const getUserLabel = useLabelUser();
const folderMode = useLibrarySearchStore(state => state.folderMode);
const toggleFolderMode = useLibrarySearchStore(state => state.toggleFolderMode);
function handleToggleFolder(event: React.MouseEvent<Element>) {
event.preventDefault();
event.stopPropagation();
toggleFolderMode();
}
return [
...(folderMode
? []
: [
columnHelper.accessor('location', {
id: 'location',
header: () => (
<MiniButton
noPadding
noHover
className='pl-2 max-h-[1rem] translate-y-[-0.125rem]'
onClick={handleToggleFolder}
titleHtml='Переключение в режим Проводник'
icon={<IconFolderTree size='1.25rem' className='clr-text-controls' />}
/>
),
size: 50,
minSize: 50,
maxSize: 50,
enableSorting: true,
cell: props => <BadgeLocation location={props.getValue()} />,
sortingFn: 'text'
})
]),
columnHelper.accessor('alias', {
id: 'alias',
header: 'Шифр',
size: 150,
minSize: 80,
maxSize: 150,
enableSorting: true,
cell: props => <div className='min-w-[5rem]'>{props.getValue()}</div>,
sortingFn: 'text'
}),
columnHelper.accessor('title', {
id: 'title',
header: 'Название',
size: 1200,
minSize: 200,
maxSize: 1200,
enableSorting: true,
sortingFn: 'text'
}),
columnHelper.accessor(item => item.owner ?? 0, {
id: 'owner',
header: 'Владелец',
size: 400,
minSize: 100,
maxSize: 400,
cell: props => getUserLabel(props.getValue()),
enableSorting: true,
sortingFn: 'text'
}),
columnHelper.accessor('time_update', {
id: 'time_update',
header: isSmall ? 'Дата' : 'Обновлена',
cell: props => (
<div className='whitespace-nowrap'>
{new Date(props.getValue()).toLocaleString(intl.locale, {
year: '2-digit',
month: '2-digit',
day: '2-digit',
...(!isSmall && {
hour: '2-digit',
minute: '2-digit'
})
})}
</div>
),
enableSorting: true,
sortingFn: 'datetime',
sortDescFirst: true
})
];
}

View File

@ -1,6 +1,5 @@
'use client';
import { useLayoutEffect, useState } from 'react';
import clsx from 'clsx';
import { TextURL } from '@/components/Control';
@ -49,16 +48,6 @@ export function TableRSList({
}: TableRSListProps) {
const windowSize = useWindowSize();
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
useLayoutEffect(() => {
setColumnVisibility({
type: (windowSize.width ?? 0) >= COLUMN_TYPE_HIDE_THRESHOLD,
convention: (windowSize.width ?? 0) >= COLUMN_CONVENTION_HIDE_THRESHOLD,
definition: (windowSize.width ?? 0) >= COLUMN_DEFINITION_HIDE_THRESHOLD
});
}, [windowSize]);
function handleRowClicked(cst: IConstituenta, event: React.MouseEvent<Element>) {
if (event.altKey) {
event.preventDefault();
@ -127,6 +116,12 @@ export function TableRSList({
})
];
const columnVisibility: VisibilityState = {
type: (windowSize.width ?? 0) >= COLUMN_TYPE_HIDE_THRESHOLD,
convention: (windowSize.width ?? 0) >= COLUMN_CONVENTION_HIDE_THRESHOLD,
definition: (windowSize.width ?? 0) >= COLUMN_DEFINITION_HIDE_THRESHOLD
};
return (
<DataTable
dense
@ -140,7 +135,6 @@ export function TableRSList({
onRowClicked={handleRowClicked}
enableHiding
columnVisibility={columnVisibility}
onColumnVisibilityChange={setColumnVisibility}
enableRowSelection={enableSelection}
rowSelection={selected}
onRowSelectionChange={setSelected}

View File

@ -21,7 +21,7 @@ interface ViewHiddenProps {
}
export function ViewHidden({ items }: ViewHiddenProps) {
const windowSize = useWindowSize();
const { isSmall } = useWindowSize();
const coloring = useTermGraphStore(state => state.coloring);
const { navigateCst, setFocus, schema, selected, toggleSelect } = useRSEdit();
@ -29,7 +29,7 @@ export function ViewHidden({ items }: ViewHiddenProps) {
const isFolded = useTermGraphStore(state => state.foldHidden);
const toggleFolded = useTermGraphStore(state => state.toggleFoldHidden);
const setActiveCst = useCstTooltipStore(state => state.setActiveCst);
const hiddenHeight = useFitHeight(windowSize.isSmall ? '10.4rem + 2px' : '12.5rem + 2px');
const hiddenHeight = useFitHeight(isSmall ? '10.4rem + 2px' : '12.5rem + 2px');
function handleClick(event: React.MouseEvent<Element>, cstID: number) {
event.preventDefault();