From f0715df343137ae3d7e7046d29d848581cc930b6 Mon Sep 17 00:00:00 2001
From: Ivan <8611739+IRBorisov@users.noreply.github.com>
Date: Wed, 16 Apr 2025 15:22:31 +0300
Subject: [PATCH] F: Improve color and animation styling
---
.vscode/extensions.json | 2 +-
README.md | 2 +-
.../src/app/navigation/navigation.tsx | 2 +-
.../src/components/data-table/data-table.tsx | 11 +-
.../src/components/data-table/index.tsx | 9 +-
.../data-table/pagination-tools.tsx | 31 ++---
.../data-table/select-pagination.tsx | 46 ++++++++
.../src/components/data-table/table-body.tsx | 101 +++++-----------
.../components/data-table/table-header.tsx | 1 +
.../src/components/data-table/table-row.tsx | 108 ++++++++++++++++++
.../components/data-table/use-data-table.ts | 5 +-
rsconcept/frontend/src/components/icons.tsx | 4 +-
rsconcept/frontend/src/components/loader.tsx | 10 +-
.../src/components/tabs/tab-label.tsx | 2 +-
.../features/help/components/badge-help.tsx | 2 +-
.../features/help/items/ui/help-rseditor.tsx | 4 +-
.../library/components/pick-schema.tsx | 3 +-
.../library/components/select-location.tsx | 2 +-
.../dlg-edit-versions/table-versions.tsx | 5 +-
.../library-page/table-library-items.tsx | 5 +-
.../rsform/components/badge-constituenta.tsx | 10 +-
.../rsform/components/pick-constituenta.tsx | 3 +-
.../rsform/components/pick-substitutions.tsx | 3 +-
.../rsform/components/refs-input/tooltip.ts | 12 +-
.../rsform/components/rs-input/tooltip.ts | 11 +-
.../rsform/components/wordform-button.tsx | 2 +-
.../dlg-cst-template/tab-arguments.tsx | 3 +-
.../dialogs/dlg-show-ast/dlg-show-ast.tsx | 2 +-
.../editor-rsexpression/status-bar.tsx | 2 +-
.../table-side-constituents.tsx | 13 +--
rsconcept/frontend/src/index.css | 24 +++-
rsconcept/frontend/src/styling/colors.ts | 1 -
rsconcept/frontend/src/styling/components.css | 10 +-
rsconcept/frontend/src/styling/constants.css | 46 +++++---
rsconcept/frontend/src/styling/overrides.css | 4 +
rsconcept/frontend/src/styling/utilities.css | 26 ++++-
36 files changed, 333 insertions(+), 194 deletions(-)
create mode 100644 rsconcept/frontend/src/components/data-table/select-pagination.tsx
create mode 100644 rsconcept/frontend/src/components/data-table/table-row.tsx
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 22ecb699..fd3c82ac 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -6,11 +6,11 @@
"fractalbrew.backticks",
"streetsidesoftware.code-spell-checker",
"streetsidesoftware.code-spell-checker-russian",
- "kamikillerto.vscode-colorize",
"batisteo.vscode-django",
"ms-azuretools.vscode-docker",
"dbaeumer.vscode-eslint",
"seyyedkhandon.firacode",
+ "nize.oklch-preview",
"ms-python.isort",
"ms-vscode.powershell",
"esbenp.prettier-vscode",
diff --git a/README.md b/README.md
index 9ec7e816..58887332 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,7 @@ This readme file is used mostly to document project dependencies and conventions
VS Code plugins
- ESLint
- - Colorize
+ - Oklch Color Preview
- Tailwind CSS IntelliSense
- Code Spell Checker (eng + rus)
- Backticks
diff --git a/rsconcept/frontend/src/app/navigation/navigation.tsx b/rsconcept/frontend/src/app/navigation/navigation.tsx
index 77d2bb11..7acb6a1d 100644
--- a/rsconcept/frontend/src/app/navigation/navigation.tsx
+++ b/rsconcept/frontend/src/app/navigation/navigation.tsx
@@ -34,7 +34,7 @@ export function Navigation() {
diff --git a/rsconcept/frontend/src/components/data-table/data-table.tsx b/rsconcept/frontend/src/components/data-table/data-table.tsx
index a26c84a2..5653905f 100644
--- a/rsconcept/frontend/src/components/data-table/data-table.tsx
+++ b/rsconcept/frontend/src/components/data-table/data-table.tsx
@@ -19,19 +19,10 @@ import { PaginationTools } from './pagination-tools';
import { TableBody } from './table-body';
import { TableFooter } from './table-footer';
import { TableHeader } from './table-header';
-import { useDataTable } from './use-data-table';
+import { type IConditionalStyle, useDataTable } from './use-data-table';
export { createColumnHelper, type RowSelectionState, type VisibilityState };
-/** Style to conditionally apply to rows. */
-export interface IConditionalStyle
{
- /** Callback to determine if the style should be applied. */
- when: (rowData: TData) => boolean;
-
- /** Style to apply. */
- style: React.CSSProperties;
-}
-
export interface DataTableProps
extends Styling,
Pick, 'data' | 'columns' | 'onRowSelectionChange' | 'onColumnVisibilityChange'> {
diff --git a/rsconcept/frontend/src/components/data-table/index.tsx b/rsconcept/frontend/src/components/data-table/index.tsx
index fc8bfb12..2e2d6fb0 100644
--- a/rsconcept/frontend/src/components/data-table/index.tsx
+++ b/rsconcept/frontend/src/components/data-table/index.tsx
@@ -1,7 +1,2 @@
-export {
- createColumnHelper,
- DataTable,
- type IConditionalStyle,
- type RowSelectionState,
- type VisibilityState
-} from './data-table';
+export { createColumnHelper, DataTable, type RowSelectionState, type VisibilityState } from './data-table';
+export { type IConditionalStyle } from './use-data-table';
diff --git a/rsconcept/frontend/src/components/data-table/pagination-tools.tsx b/rsconcept/frontend/src/components/data-table/pagination-tools.tsx
index 58593661..3f0ee03b 100644
--- a/rsconcept/frontend/src/components/data-table/pagination-tools.tsx
+++ b/rsconcept/frontend/src/components/data-table/pagination-tools.tsx
@@ -1,13 +1,12 @@
'use no memo';
'use client';
-import { useCallback } from 'react';
import { type Table } from '@tanstack/react-table';
-import { prefixes } from '@/utils/constants';
-
import { IconPageFirst, IconPageLast, IconPageLeft, IconPageRight } from '../icons';
+import { SelectPagination } from './select-pagination';
+
interface PaginationToolsProps {
id?: string;
table: Table;
@@ -21,15 +20,6 @@ export function PaginationTools({
onChangePaginationOption,
paginationOptions
}: PaginationToolsProps) {
- const handlePaginationOptionsChange = useCallback(
- (event: React.ChangeEvent) => {
- const perPage = Number(event.target.value);
- table.setPageSize(perPage);
- onChangePaginationOption?.(perPage);
- },
- [table, onChangePaginationOption]
- );
-
return (
@@ -93,19 +83,12 @@ export function PaginationTools({
-
+ table={table}
+ paginationOptions={paginationOptions}
+ onChange={onChangePaginationOption}
+ />
);
}
diff --git a/rsconcept/frontend/src/components/data-table/select-pagination.tsx b/rsconcept/frontend/src/components/data-table/select-pagination.tsx
new file mode 100644
index 00000000..a304f1a9
--- /dev/null
+++ b/rsconcept/frontend/src/components/data-table/select-pagination.tsx
@@ -0,0 +1,46 @@
+'use no memo';
+'use client';
+
+import { useCallback } from 'react';
+import { type Table } from '@tanstack/react-table';
+
+import { prefixes } from '@/utils/constants';
+
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../input/select';
+
+interface SelectPaginationProps {
+ id?: string;
+ table: Table;
+ paginationOptions: number[];
+ onChange?: (newValue: number) => void;
+}
+
+export function SelectPagination({ id, table, paginationOptions, onChange }: SelectPaginationProps) {
+ const handlePaginationOptionsChange = useCallback(
+ (newValue: string) => {
+ const perPage = Number(newValue);
+ table.setPageSize(perPage);
+ onChange?.(perPage);
+ },
+ [table, onChange]
+ );
+
+ return (
+
+ );
+}
diff --git a/rsconcept/frontend/src/components/data-table/table-body.tsx b/rsconcept/frontend/src/components/data-table/table-body.tsx
index 72f1e43a..14b7a2c9 100644
--- a/rsconcept/frontend/src/components/data-table/table-body.tsx
+++ b/rsconcept/frontend/src/components/data-table/table-body.tsx
@@ -1,11 +1,11 @@
'use no memo';
+'use client';
import { useCallback } from 'react';
-import { type Cell, flexRender, type Row, type Table } from '@tanstack/react-table';
-import clsx from 'clsx';
+import { type Row, type Table } from '@tanstack/react-table';
-import { SelectRow } from './select-row';
-import { type IConditionalStyle } from '.';
+import { TableRow } from './table-row';
+import { type IConditionalStyle } from './use-data-table';
interface TableBodyProps {
table: Table;
@@ -30,82 +30,43 @@ export function TableBody({
onRowClicked,
onRowDoubleClicked
}: TableBodyProps) {
- const handleRowClicked = useCallback(
- (target: Row, event: React.MouseEvent) => {
- onRowClicked?.(target.original, event);
- if (table.options.enableRowSelection && target.getCanSelect()) {
- if (event.shiftKey && !!lastSelected && lastSelected !== target.id) {
- const { rows, rowsById } = table.getRowModel();
- const lastIndex = rowsById[lastSelected].index;
- const currentIndex = target.index;
- const toggleRows = rows.slice(
- lastIndex > currentIndex ? currentIndex : lastIndex + 1,
- lastIndex > currentIndex ? lastIndex : currentIndex + 1
- );
- const newSelection: Record = {};
- toggleRows.forEach(row => {
- newSelection[row.id] = !target.getIsSelected();
- });
- table.setRowSelection(prev => ({ ...prev, ...newSelection }));
- onChangeLastSelected(null);
- } else {
- onChangeLastSelected(target.id);
- target.toggleSelected(!target.getIsSelected());
- }
- }
- },
- [table, lastSelected, onChangeLastSelected, onRowClicked]
+ const getRowStyles = useCallback(
+ (row: Row) =>
+ conditionalRowStyles
+ ?.filter(item => !!item.style && item.when(row.original))
+ ?.reduce((prev, item) => ({ ...prev, ...item.style }), {}),
+
+ [conditionalRowStyles]
);
- const getRowStyles = useCallback(
+ const getRowClasses = useCallback(
(row: Row) => {
- return {
- ...conditionalRowStyles!
- .filter(item => item.when(row.original))
- .reduce((prev, item) => ({ ...prev, ...item.style }), {})
- };
+ return conditionalRowStyles
+ ?.filter(item => !!item.className && item.when(row.original))
+ ?.reduce((prev, item) => {
+ prev.push(item.className!);
+ return prev;
+ }, [] as string[]);
},
[conditionalRowStyles]
);
return (
- {table.getRowModel().rows.map((row: Row, index) => (
- ) => (
+ handleRowClicked(row, event)}
- onDoubleClick={event => onRowDoubleClicked?.(row.original, event)}
- >
- {table.options.enableRowSelection ? (
-
-
- |
- ) : null}
- {row.getVisibleCells().map((cell: Cell) => (
-
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
- |
- ))}
-
+ table={table}
+ row={row}
+ className={getRowClasses(row)?.join(' ')}
+ style={conditionalRowStyles ? { ...getRowStyles(row) } : undefined}
+ noHeader={noHeader}
+ dense={dense}
+ lastSelected={lastSelected}
+ onChangeLastSelected={onChangeLastSelected}
+ onRowClicked={onRowClicked}
+ onRowDoubleClicked={onRowDoubleClicked}
+ />
))}
);
diff --git a/rsconcept/frontend/src/components/data-table/table-header.tsx b/rsconcept/frontend/src/components/data-table/table-header.tsx
index 1f7396e7..bfa4e7ce 100644
--- a/rsconcept/frontend/src/components/data-table/table-header.tsx
+++ b/rsconcept/frontend/src/components/data-table/table-header.tsx
@@ -1,4 +1,5 @@
'use no memo';
+'use client';
import { flexRender, type Header, type HeaderGroup, type Table } from '@tanstack/react-table';
import clsx from 'clsx';
diff --git a/rsconcept/frontend/src/components/data-table/table-row.tsx b/rsconcept/frontend/src/components/data-table/table-row.tsx
new file mode 100644
index 00000000..347b9dad
--- /dev/null
+++ b/rsconcept/frontend/src/components/data-table/table-row.tsx
@@ -0,0 +1,108 @@
+'use no memo';
+
+import { useCallback } from 'react';
+import { type Cell, flexRender, type Row, type Table } from '@tanstack/react-table';
+import clsx from 'clsx';
+
+import { cn } from '../utils';
+
+import { SelectRow } from './select-row';
+
+interface TableRowProps {
+ table: Table;
+ row: Row;
+
+ className?: string;
+ style?: React.CSSProperties;
+
+ noHeader?: boolean;
+ dense?: boolean;
+
+ lastSelected: string | null;
+ onChangeLastSelected: (newValue: string | null) => void;
+
+ onRowClicked?: (rowData: TData, event: React.MouseEvent) => void;
+ onRowDoubleClicked?: (rowData: TData, event: React.MouseEvent) => void;
+}
+
+export function TableRow({
+ table,
+ row,
+ className,
+ style,
+ noHeader,
+ dense,
+ lastSelected,
+ onChangeLastSelected,
+ onRowClicked,
+ onRowDoubleClicked
+}: TableRowProps) {
+ const hasBG = className?.includes('bg-') ?? false;
+
+ const handleRowClicked = useCallback(
+ (target: Row, event: React.MouseEvent) => {
+ onRowClicked?.(target.original, event);
+ if (table.options.enableRowSelection && target.getCanSelect()) {
+ if (event.shiftKey && !!lastSelected && lastSelected !== target.id) {
+ const { rows, rowsById } = table.getRowModel();
+ const lastIndex = rowsById[lastSelected].index;
+ const currentIndex = target.index;
+ const toggleRows = rows.slice(
+ lastIndex > currentIndex ? currentIndex : lastIndex + 1,
+ lastIndex > currentIndex ? lastIndex : currentIndex + 1
+ );
+ const newSelection: Record = {};
+ toggleRows.forEach(row => {
+ newSelection[row.id] = !target.getIsSelected();
+ });
+ table.setRowSelection(prev => ({ ...prev, ...newSelection }));
+ onChangeLastSelected(null);
+ } else {
+ onChangeLastSelected(target.id);
+ target.toggleSelected(!target.getIsSelected());
+ }
+ }
+ },
+ [table, lastSelected, onChangeLastSelected, onRowClicked]
+ );
+
+ return (
+ handleRowClicked(row, event)}
+ onDoubleClick={event => onRowDoubleClicked?.(row.original, event)}
+ >
+ {table.options.enableRowSelection ? (
+
+
+ |
+ ) : null}
+ {row.getVisibleCells().map((cell: Cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+ |
+ ))}
+
+ );
+}
diff --git a/rsconcept/frontend/src/components/data-table/use-data-table.ts b/rsconcept/frontend/src/components/data-table/use-data-table.ts
index de43a338..8d1cc0d5 100644
--- a/rsconcept/frontend/src/components/data-table/use-data-table.ts
+++ b/rsconcept/frontend/src/components/data-table/use-data-table.ts
@@ -21,7 +21,10 @@ export interface IConditionalStyle {
when: (rowData: TData) => boolean;
/** Style to apply. */
- style: React.CSSProperties;
+ style?: React.CSSProperties;
+
+ /** Classname to apply. */
+ className?: string;
}
interface UseDataTableProps
diff --git a/rsconcept/frontend/src/components/icons.tsx b/rsconcept/frontend/src/components/icons.tsx
index 16def543..f3375f6f 100644
--- a/rsconcept/frontend/src/components/icons.tsx
+++ b/rsconcept/frontend/src/components/icons.tsx
@@ -200,7 +200,7 @@ export function IconLogin(props: IconProps) {
export function CheckboxChecked() {
return (
-