mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Add snap to table scrolls
This commit is contained in:
parent
ff48364536
commit
91c5993b10
|
@ -94,7 +94,7 @@ function ConstituentaMultiPicker({ id, schema, prefixID, rows, selected, setSele
|
||||||
noFooter
|
noFooter
|
||||||
rows={rows}
|
rows={rows}
|
||||||
contentHeight='1.3rem'
|
contentHeight='1.3rem'
|
||||||
className={clsx('overflow-y-auto', 'border', 'text-sm', 'select-none')}
|
className={clsx('cc-scroll-y', 'border', 'text-sm', 'select-none')}
|
||||||
data={schema?.items ?? []}
|
data={schema?.items ?? []}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
headPosition='0rem'
|
headPosition='0rem'
|
||||||
|
|
|
@ -101,7 +101,7 @@ function ConstituentaPicker({
|
||||||
dense
|
dense
|
||||||
noHeader
|
noHeader
|
||||||
noFooter
|
noFooter
|
||||||
className='overflow-y-auto text-sm select-none'
|
className='text-sm select-none cc-scroll-y'
|
||||||
data={filteredData}
|
data={filteredData}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
|
|
|
@ -98,7 +98,7 @@ function SchemaPicker({ id, initialFilter = '', rows = 4, value, onSelectValue }
|
||||||
dense
|
dense
|
||||||
noHeader
|
noHeader
|
||||||
noFooter
|
noFooter
|
||||||
className='overflow-y-auto text-sm select-none'
|
className='text-sm select-none cc-scroll-y'
|
||||||
data={items}
|
data={items}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
|
|
|
@ -155,6 +155,7 @@ function DataTable<TData extends RowData>({
|
||||||
<TableBody
|
<TableBody
|
||||||
table={tableImpl}
|
table={tableImpl}
|
||||||
dense={dense}
|
dense={dense}
|
||||||
|
noHeader={noHeader}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
enableRowSelection={enableRowSelection}
|
enableRowSelection={enableRowSelection}
|
||||||
lastSelected={lastSelected}
|
lastSelected={lastSelected}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Cell, flexRender, Row, Table } from '@tanstack/react-table';
|
import { Cell, flexRender, Row, Table } from '@tanstack/react-table';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { CProps } from '@/components/props';
|
import { CProps } from '@/components/props';
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ import SelectRow from './SelectRow';
|
||||||
interface TableBodyProps<TData> {
|
interface TableBodyProps<TData> {
|
||||||
table: Table<TData>;
|
table: Table<TData>;
|
||||||
dense?: boolean;
|
dense?: boolean;
|
||||||
|
noHeader?: boolean;
|
||||||
enableRowSelection?: boolean;
|
enableRowSelection?: boolean;
|
||||||
conditionalRowStyles?: IConditionalStyle<TData>[];
|
conditionalRowStyles?: IConditionalStyle<TData>[];
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ interface TableBodyProps<TData> {
|
||||||
function TableBody<TData>({
|
function TableBody<TData>({
|
||||||
table,
|
table,
|
||||||
dense,
|
dense,
|
||||||
|
noHeader,
|
||||||
enableRowSelection,
|
enableRowSelection,
|
||||||
conditionalRowStyles,
|
conditionalRowStyles,
|
||||||
lastSelected,
|
lastSelected,
|
||||||
|
@ -67,14 +70,16 @@ function TableBody<TData>({
|
||||||
{table.getRowModel().rows.map((row: Row<TData>, index) => (
|
{table.getRowModel().rows.map((row: Row<TData>, index) => (
|
||||||
<tr
|
<tr
|
||||||
key={row.id}
|
key={row.id}
|
||||||
className={
|
className={clsx(
|
||||||
|
'cc-table-row',
|
||||||
|
!noHeader && 'scroll-mt-[calc(2px+2rem)]',
|
||||||
row.getIsSelected()
|
row.getIsSelected()
|
||||||
? 'clr-selected clr-hover'
|
? 'clr-selected clr-hover'
|
||||||
: index % 2 === 0
|
: index % 2 === 0
|
||||||
? 'clr-controls clr-hover'
|
? 'clr-controls clr-hover'
|
||||||
: 'clr-app clr-hover'
|
: 'clr-app clr-hover'
|
||||||
}
|
)}
|
||||||
style={conditionalRowStyles && getRowStyles(row)}
|
style={{ ...(conditionalRowStyles ? getRowStyles(row) : []) }}
|
||||||
>
|
>
|
||||||
{enableRowSelection ? (
|
{enableRowSelection ? (
|
||||||
<td key={`select-${row.id}`} className='pl-3 pr-1 align-middle border-y'>
|
<td key={`select-${row.id}`} className='pl-3 pr-1 align-middle border-y'>
|
||||||
|
|
|
@ -152,7 +152,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
noHeader
|
noHeader
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'max-h-[5.8rem] min-h-[5.8rem]', // prettier: split lines
|
'max-h-[5.8rem] min-h-[5.8rem]', // prettier: split lines
|
||||||
'overflow-y-auto',
|
'cc-scroll-y',
|
||||||
'text-sm',
|
'text-sm',
|
||||||
'border',
|
'border',
|
||||||
'select-none'
|
'select-none'
|
||||||
|
|
|
@ -92,10 +92,10 @@ function VersionsTable({ processing, items, onDelete, selected, onSelect }: Vers
|
||||||
<DataTable
|
<DataTable
|
||||||
dense
|
dense
|
||||||
noFooter
|
noFooter
|
||||||
className={clsx('mb-2', 'max-h-[17.4rem] min-h-[17.4rem]', 'border', 'overflow-y-auto')}
|
headPosition='0'
|
||||||
|
className={clsx('mb-2', 'max-h-[17.4rem] min-h-[17.4rem]', 'border', 'cc-scroll-y')}
|
||||||
data={items}
|
data={items}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
headPosition='0'
|
|
||||||
onRowClicked={rowData => onSelect(rowData.id)}
|
onRowClicked={rowData => onSelect(rowData.id)}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -37,7 +37,6 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
|
||||||
() => [
|
() => [
|
||||||
columnHelper.accessor('text', {
|
columnHelper.accessor('text', {
|
||||||
id: 'text',
|
id: 'text',
|
||||||
header: 'Текст',
|
|
||||||
size: 350,
|
size: 350,
|
||||||
minSize: 500,
|
minSize: 500,
|
||||||
maxSize: 500,
|
maxSize: 500,
|
||||||
|
@ -45,7 +44,6 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('grams', {
|
columnHelper.accessor('grams', {
|
||||||
id: 'grams',
|
id: 'grams',
|
||||||
header: 'Граммемы',
|
|
||||||
maxSize: 150,
|
maxSize: 150,
|
||||||
cell: props => <WordFormBadge keyPrefix={props.cell.id} form={props.row.original} />
|
cell: props => <WordFormBadge keyPrefix={props.cell.id} form={props.row.original} />
|
||||||
}),
|
}),
|
||||||
|
@ -74,7 +72,8 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
|
||||||
<DataTable
|
<DataTable
|
||||||
dense
|
dense
|
||||||
noFooter
|
noFooter
|
||||||
className={clsx('mb-2', 'max-h-[17.4rem] min-h-[17.4rem]', 'border', 'text-sm', 'overflow-y-auto')}
|
noHeader
|
||||||
|
className={clsx('mb-2', 'max-h-[17.4rem] min-h-[17.4rem]', 'border', 'text-sm', 'cc-scroll-y')}
|
||||||
data={forms}
|
data={forms}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
headPosition='0'
|
headPosition='0'
|
||||||
|
|
|
@ -7,7 +7,6 @@ import DataLoader from '@/components/wrap/DataLoader';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useLibrary } from '@/context/LibraryContext';
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
|
||||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||||
import useQueryStrings from '@/hooks/useQueryStrings';
|
import useQueryStrings from '@/hooks/useQueryStrings';
|
||||||
import { ILibraryItem } from '@/models/library';
|
import { ILibraryItem } from '@/models/library';
|
||||||
|
@ -26,7 +25,6 @@ function LibraryPage() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
const library = useLibrary();
|
const library = useLibrary();
|
||||||
const { setShowScroll } = useConceptOptions();
|
|
||||||
|
|
||||||
const [filter, setFilter] = useState<ILibraryFilter>({});
|
const [filter, setFilter] = useState<ILibraryFilter>({});
|
||||||
const [items, setItems] = useState<ILibraryItem[]>([]);
|
const [items, setItems] = useState<ILibraryItem[]>([]);
|
||||||
|
@ -47,11 +45,6 @@ function LibraryPage() {
|
||||||
setFilter(filterFromStrategy(queryFilter));
|
setFilter(filterFromStrategy(queryFilter));
|
||||||
}, [user, router, setQuery, setFilter, setStrategy, strategy, queryFilter]);
|
}, [user, router, setQuery, setFilter, setStrategy, strategy, queryFilter]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
setShowScroll(true);
|
|
||||||
return () => setShowScroll(false);
|
|
||||||
}, [setShowScroll]);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
setItems(library.applyFilter(filter));
|
setItems(library.applyFilter(filter));
|
||||||
}, [library, filter, filter.query]);
|
}, [library, filter, filter.query]);
|
||||||
|
|
|
@ -11,6 +11,7 @@ import DataTable, { createColumnHelper, VisibilityState } from '@/components/ui/
|
||||||
import FlexColumn from '@/components/ui/FlexColumn';
|
import FlexColumn from '@/components/ui/FlexColumn';
|
||||||
import TextURL from '@/components/ui/TextURL';
|
import TextURL from '@/components/ui/TextURL';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import { useUsers } from '@/context/UsersContext';
|
import { useUsers } from '@/context/UsersContext';
|
||||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||||
import useWindowSize from '@/hooks/useWindowSize';
|
import useWindowSize from '@/hooks/useWindowSize';
|
||||||
|
@ -31,6 +32,7 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { getUserLabel } = useUsers();
|
const { getUserLabel } = useUsers();
|
||||||
|
const { calculateHeight } = useConceptOptions();
|
||||||
const [itemsPerPage, setItemsPerPage] = useLocalStorage<number>(storage.libraryPagination, 50);
|
const [itemsPerPage, setItemsPerPage] = useLocalStorage<number>(storage.libraryPagination, 50);
|
||||||
|
|
||||||
function handleOpenItem(item: ILibraryItem, event: CProps.EventMouse) {
|
function handleOpenItem(item: ILibraryItem, event: CProps.EventMouse) {
|
||||||
|
@ -109,6 +111,8 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) {
|
||||||
[intl, getUserLabel, windowSize]
|
[intl, getUserLabel, windowSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const tableHeight = useMemo(() => calculateHeight('2.2rem'), [calculateHeight]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className='sticky top-[2.3rem]'>
|
<div className='sticky top-[2.3rem]'>
|
||||||
|
@ -127,8 +131,9 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) {
|
||||||
id='library_data'
|
id='library_data'
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={items}
|
data={items}
|
||||||
headPosition='2.2rem'
|
headPosition='0'
|
||||||
className='text-xs sm:text-sm'
|
className='text-xs sm:text-sm cc-scroll-y'
|
||||||
|
style={{ maxHeight: tableHeight }}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
||||||
<p>Список схем пуст</p>
|
<p>Список схем пуст</p>
|
||||||
|
|
|
@ -121,7 +121,7 @@ function RSTable({ items, maxHeight, enableSelection, selected, setSelected, onE
|
||||||
<DataTable
|
<DataTable
|
||||||
dense
|
dense
|
||||||
noFooter
|
noFooter
|
||||||
className={clsx('min-h-[16rem]', 'overflow-y-auto', 'text-sm', 'select-none')}
|
className={clsx('min-h-[16rem]', 'cc-scroll-y', 'text-sm', 'select-none')}
|
||||||
style={{ maxHeight: maxHeight }}
|
style={{ maxHeight: maxHeight }}
|
||||||
data={items ?? []}
|
data={items ?? []}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
|
|
@ -129,7 +129,7 @@ function ConstituentsTable({ items, activeID, onOpenEdit, maxHeight, denseThresh
|
||||||
<DataTable
|
<DataTable
|
||||||
dense
|
dense
|
||||||
noFooter
|
noFooter
|
||||||
className='overflow-y-auto text-sm select-none overscroll-none'
|
className='text-sm select-none cc-scroll-y overscroll-none'
|
||||||
style={{ maxHeight: maxHeight }}
|
style={{ maxHeight: maxHeight }}
|
||||||
data={items}
|
data={items}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
|
|
@ -65,7 +65,7 @@ function ViewSubscriptions({ items }: ViewSubscriptionsProps) {
|
||||||
<DataTable
|
<DataTable
|
||||||
dense
|
dense
|
||||||
noFooter
|
noFooter
|
||||||
className='max-h-[23.8rem] overflow-y-auto text-sm border'
|
className='max-h-[23.8rem] cc-scroll-y text-sm border'
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={items}
|
data={items}
|
||||||
headPosition='0'
|
headPosition='0'
|
||||||
|
|
|
@ -216,6 +216,16 @@
|
||||||
@apply flex gap-1;
|
@apply flex gap-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cc-table-row {
|
||||||
|
scroll-snap-align: start;
|
||||||
|
scroll-snap-stop: always;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cc-scroll-y {
|
||||||
|
overflow-y: auto;
|
||||||
|
scroll-snap-type: y mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
.cc-blur {
|
.cc-blur {
|
||||||
backdrop-filter: blur(3px);
|
backdrop-filter: blur(3px);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user