From b9db1e583cec4b0cc53a559e2e6da07959bdde64 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 9 Apr 2026 20:34:00 +0700 Subject: [PATCH 1/3] =?UTF-8?q?data-table:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F,=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D1=81=D1=8B,=20=D0=BE=D0=B1=D1=91=D1=80=D1=82?= =?UTF-8?q?=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data-table/data-table.component.ts | 94 +++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/data-table.ts | 28 + .../data-table/data-table.stories.ts | 569 ++++++++++++++++++ .../examples/data-table-default.component.ts | 38 ++ .../data-table-grid-lines.component.ts | 35 ++ .../data-table-pagination.component.ts | 44 ++ .../data-table-scroll-horizontal.component.ts | 37 ++ .../data-table-scroll-vertical.component.ts | 42 ++ .../data-table-selectable.component.ts | 42 ++ ...data-table-selection-checkbox.component.ts | 42 ++ .../data-table-selection-radio.component.ts | 42 ++ .../data-table-striped-rows.component.ts | 35 ++ 13 files changed, 1053 insertions(+) create mode 100644 src/lib/components/data-table/data-table.component.ts create mode 100644 src/prime-preset/tokens/components/data-table.ts create mode 100644 src/stories/components/data-table/data-table.stories.ts create mode 100644 src/stories/components/data-table/examples/data-table-default.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-grid-lines.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-pagination.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-selectable.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-selection-radio.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-striped-rows.component.ts diff --git a/src/lib/components/data-table/data-table.component.ts b/src/lib/components/data-table/data-table.component.ts new file mode 100644 index 0000000..798bf68 --- /dev/null +++ b/src/lib/components/data-table/data-table.component.ts @@ -0,0 +1,94 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { TableModule } from 'primeng/table'; +import { PrimeTemplate } from 'primeng/api'; + +export interface DataTableColumn { + field?: string; + header?: string; + sortable?: boolean; + style?: string; + headerStyle?: string; + selectionMode?: 'single' | 'multiple'; +} + +@Component({ + selector: 'data-table', + host: { style: 'display: block' }, + standalone: true, + imports: [TableModule, PrimeTemplate], + template: ` + + + + @for (col of columns; track $index) { + @if (col.selectionMode === 'single') { + + } @else if (col.selectionMode === 'multiple') { + + + + } @else if (col.sortable) { + + {{ col.header }} + + + } @else { + {{ col.header }} + } + } + + + + + + @for (col of columns; track $index) { + @if (col.selectionMode === 'single') { + + + + } @else if (col.selectionMode === 'multiple') { + + + + } @else { + {{ rowData[col.field] }} + } + } + + + + `, +}) +export class DataTableComponent { + @Input() value: any[] = []; + @Input() columns: DataTableColumn[] = []; + @Input() stripedRows = false; + @Input() showGridlines = false; + @Input() loading = false; + @Input() size: 'small' | 'large' | undefined = undefined; + @Input() scrollable = false; + @Input() scrollHeight = ''; + @Input() paginator = false; + @Input() rows = 5; + @Input() rowsPerPageOptions: number[] = [5, 10, 25]; + @Input() selectionMode: 'single' | 'multiple' | undefined = undefined; + @Input() selection: any = null; + @Output() selectionChange = new EventEmitter(); + @Input() dataKey = 'id'; +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 3962758..7fbaefa 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -4,6 +4,7 @@ import type { AuraBaseDesignTokens } from '@primeuix/themes/aura/base'; import tokens from './tokens/tokens.json'; import { buttonCss } from './tokens/components/button'; +import { dataTableCss } from './tokens/components/data-table'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], @@ -14,6 +15,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + datatable: { + ...(tokens.components.datatable as unknown as ComponentsDesignTokens['datatable']), + css: dataTableCss, + }, } as ComponentsDesignTokens, }; diff --git a/src/prime-preset/tokens/components/data-table.ts b/src/prime-preset/tokens/components/data-table.ts new file mode 100644 index 0000000..f770594 --- /dev/null +++ b/src/prime-preset/tokens/components/data-table.ts @@ -0,0 +1,28 @@ +export const dataTableCss = ({ dt }: { dt: (token: string) => string }): string => ` + .p-datatable .p-datatable-thead > tr > th { + font-weight: ${dt('datatable.columnTitle.fontWeight')}; + } + + .p-datatable .p-datatable-tfoot > tr > td { + font-weight: ${dt('datatable.columnFooter.fontWeight')}; + } + + .p-datatable .p-datatable-sort-icon { + width: ${dt('datatable.sortIcon.size')}; + height: ${dt('datatable.sortIcon.size')}; + } + + .p-datatable .p-datatable-loading-icon { + width: ${dt('datatable.loadingIcon.size')}; + height: ${dt('datatable.loadingIcon.size')}; + } + + .p-datatable .p-datatable-row-toggle-button { + width: ${dt('datatable.rowToggleButton.size')}; + height: ${dt('datatable.rowToggleButton.size')}; + } + + .p-datatable .p-datatable-sortable-column:not(.p-datatable-column-sorted):hover { + color: ${dt('datatable.headerCell.hoverColor')}; + } +`; diff --git a/src/stories/components/data-table/data-table.stories.ts b/src/stories/components/data-table/data-table.stories.ts new file mode 100644 index 0000000..6ea5f7f --- /dev/null +++ b/src/stories/components/data-table/data-table.stories.ts @@ -0,0 +1,569 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { DataTableComponent } from '../../../lib/components/data-table/data-table.component'; +import { DataTableDefaultComponent } from './examples/data-table-default.component'; +import { DataTableStripedRowsComponent } from './examples/data-table-striped-rows.component'; +import { DataTableSelectableComponent } from './examples/data-table-selectable.component'; +import { DataTableGridLinesComponent } from './examples/data-table-grid-lines.component'; +import { DataTablePaginationComponent } from './examples/data-table-pagination.component'; +import { DataTableSelectionRadioComponent } from './examples/data-table-selection-radio.component'; +import { DataTableSelectionCheckboxComponent } from './examples/data-table-selection-checkbox.component'; +import { DataTableScrollVerticalComponent } from './examples/data-table-scroll-vertical.component'; +import { DataTableScrollHorizontalComponent } from './examples/data-table-scroll-horizontal.component'; + +const meta: Meta = { + title: 'Components/Data/DataTable', + component: DataTableComponent, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: `Таблица данных с поддержкой сортировки, пагинации, выбора строк и прокрутки. + +\`\`\`typescript +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-datatable' }, + }, + argTypes: { + value: { + control: false, + description: 'Массив данных для отображения в таблице.', + table: { + category: 'Props', + type: { summary: 'any[]' }, + }, + }, + columns: { + control: false, + description: 'Определения столбцов таблицы.', + table: { + category: 'Props', + type: { summary: 'DataTableColumn[]' }, + }, + }, + stripedRows: { + control: 'boolean', + description: 'Чередование цвета строк.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + showGridlines: { + control: 'boolean', + description: 'Отображение сетки между ячейками.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + loading: { + control: 'boolean', + description: 'Отображает индикатор загрузки.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + size: { + control: 'select', + options: ['small', 'large', undefined], + description: 'Размер таблицы.', + table: { + category: 'Props', + defaultValue: { summary: 'undefined (normal)' }, + type: { summary: "'small' | 'large' | undefined" }, + }, + }, + scrollable: { + control: 'boolean', + description: 'Включает прокрутку таблицы.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + scrollHeight: { + control: 'text', + description: 'Высота области прокрутки (например "400px"). Работает только при scrollable=true.', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, + paginator: { + control: 'boolean', + description: 'Включает пагинацию.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + rows: { + control: 'number', + description: 'Количество строк на странице (при paginator=true).', + table: { + category: 'Props', + defaultValue: { summary: '5' }, + type: { summary: 'number' }, + }, + }, + selectionMode: { + control: 'select', + options: ['single', 'multiple', undefined], + description: 'Режим выбора строк.', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: "'single' | 'multiple' | undefined" }, + }, + }, + dataKey: { + control: 'text', + description: 'Поле объекта, используемое как уникальный идентификатор строки.', + table: { + category: 'Props', + defaultValue: { summary: "'id'" }, + type: { summary: 'string' }, + }, + }, + selectionChange: { + control: false, + description: 'Событие изменения выбранных строк.', + table: { + category: 'Events', + type: { summary: 'EventEmitter' }, + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'DataTable', + decorators: [moduleMetadata({ imports: [DataTableDefaultComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Базовая таблица отправлений с сортировкой по всем столбцам.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-default', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableDefaultComponent { + shipments = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + ]; + + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── StripedRows ─────────────────────────────────────────────────────────────── + +export const StripedRows: Story = { + name: 'StripedRows', + decorators: [moduleMetadata({ imports: [DataTableStripedRowsComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Чередование цвета строк для улучшения читаемости.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-striped-rows', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableStripedRowsComponent { + shipments = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + ]; + + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── Selectable ──────────────────────────────────────────────────────────────── + +export const Selectable: Story = { + name: 'Selectable', + decorators: [moduleMetadata({ imports: [DataTableSelectableComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Выбор строки кликом. Режим single — выбирается одна строка.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-selectable', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableSelectableComponent { + shipments = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + ]; + + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; + + selected: any = null; +} + `, + }, + }, + }, +}; + +// ── GridLines ───────────────────────────────────────────────────────────────── + +export const GridLines: Story = { + name: 'GridLines', + decorators: [moduleMetadata({ imports: [DataTableGridLinesComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Сетка между ячейками для наглядного разграничения данных.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-grid-lines', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableGridLinesComponent { + shipments = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + ]; + + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── Pagination ──────────────────────────────────────────────────────────────── + +export const Pagination: Story = { + name: 'Pagination', + decorators: [moduleMetadata({ imports: [DataTablePaginationComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Пагинация для больших наборов данных. Управление количеством строк на странице.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-pagination', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTablePaginationComponent { + shipments = [...]; // массив отправлений + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── SelectionRadio ──────────────────────────────────────────────────────────── + +export const SelectionRadio: Story = { + name: 'Row Selection: RadioButton', + decorators: [moduleMetadata({ imports: [DataTableSelectionRadioComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Выбор одной строки через радио-кнопку. Укажите selectionMode: "single" в первом столбце.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-selection-radio', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableSelectionRadioComponent { + shipments = [...]; // массив отправлений + columns: DataTableColumn[] = [ + { selectionMode: 'single' }, + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + ]; + selected: any = null; +} + `, + }, + }, + }, +}; + +// ── SelectionCheckbox ───────────────────────────────────────────────────────── + +export const SelectionCheckbox: Story = { + name: 'Row Selection: Checkbox', + decorators: [moduleMetadata({ imports: [DataTableSelectionCheckboxComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Множественный выбор строк через чекбоксы. Первый столбец с selectionMode: "multiple" добавляет чекбокс в заголовок.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-selection-checkbox', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableSelectionCheckboxComponent { + shipments = [...]; // массив отправлений + columns: DataTableColumn[] = [ + { selectionMode: 'multiple' }, + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + ]; + selected: any[] = []; +} + `, + }, + }, + }, +}; + +// ── ScrollVertical ──────────────────────────────────────────────────────────── + +export const ScrollVertical: Story = { + name: 'Scroll: Vertical', + decorators: [moduleMetadata({ imports: [DataTableScrollVerticalComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Вертикальная прокрутка с фиксированной высотой контейнера. Заголовок остаётся видимым.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-scroll-vertical', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableScrollVerticalComponent { + shipments = [...]; // большой массив отправлений + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── ScrollHorizontal ────────────────────────────────────────────────────────── + +export const ScrollHorizontal: Story = { + name: 'Scroll: Horizontal', + decorators: [moduleMetadata({ imports: [DataTableScrollHorizontalComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Горизонтальная прокрутка при большом количестве столбцов. Используйте style с min-width на столбцах.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-scroll-horizontal', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableScrollHorizontalComponent { + shipments = [...]; // массив отправлений + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true, style: 'min-width: 160px' }, + { field: 'sender', header: 'Отправитель', sortable: true, style: 'min-width: 160px' }, + { field: 'destination', header: 'Назначение', sortable: true, style: 'min-width: 160px' }, + { field: 'status', header: 'Статус', sortable: true, style: 'min-width: 140px' }, + { field: 'weight', header: 'Вес, кг', sortable: true, style: 'min-width: 120px' }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true, style: 'min-width: 140px' }, + { field: 'dimensions', header: 'Габариты', sortable: false, style: 'min-width: 160px' }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/data-table/examples/data-table-default.component.ts b/src/stories/components/data-table/examples/data-table-default.component.ts new file mode 100644 index 0000000..db4cdd0 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-default.component.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-default', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableDefaultComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-grid-lines.component.ts b/src/stories/components/data-table/examples/data-table-grid-lines.component.ts new file mode 100644 index 0000000..2aa5bed --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-grid-lines.component.ts @@ -0,0 +1,35 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-grid-lines', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableGridLinesComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-pagination.component.ts b/src/stories/components/data-table/examples/data-table-pagination.component.ts new file mode 100644 index 0000000..275670d --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-pagination.component.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-pagination', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTablePaginationComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts b/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts new file mode 100644 index 0000000..3c6962b --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts @@ -0,0 +1,37 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', sender: 'Иванов И.И.', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200, dimensions: '30×20×15 см' }, + { id: 2, trackNumber: 'ЦД-00123457', sender: 'Петров П.П.', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450, dimensions: '10×10×10 см' }, + { id: 3, trackNumber: 'ЦД-00123458', sender: 'Сидоров С.С.', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100, dimensions: '50×40×30 см' }, + { id: 4, trackNumber: 'ЦД-00123459', sender: 'Козлов К.К.', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750, dimensions: '20×15×10 см' }, + { id: 5, trackNumber: 'ЦД-00123460', sender: 'Новиков Н.Н.', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800, dimensions: '40×30×20 см' }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true, style: 'min-width: 160px' }, + { field: 'sender', header: 'Отправитель', sortable: true, style: 'min-width: 160px' }, + { field: 'destination', header: 'Назначение', sortable: true, style: 'min-width: 160px' }, + { field: 'status', header: 'Статус', sortable: true, style: 'min-width: 140px' }, + { field: 'weight', header: 'Вес, кг', sortable: true, style: 'min-width: 120px' }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true, style: 'min-width: 140px' }, + { field: 'dimensions', header: 'Габариты', sortable: false, style: 'min-width: 160px' }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-scroll-horizontal', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableScrollHorizontalComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts b/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts new file mode 100644 index 0000000..f819b9e --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const BASE_SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-scroll-vertical', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableScrollVerticalComponent { + shipments = [...BASE_SHIPMENTS, ...BASE_SHIPMENTS, ...BASE_SHIPMENTS]; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-selectable.component.ts b/src/stories/components/data-table/examples/data-table-selectable.component.ts new file mode 100644 index 0000000..2b9eb35 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-selectable.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-selectable', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableSelectableComponent { + shipments = SHIPMENTS; + columns = COLUMNS; + selected: any = null; +} diff --git a/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts b/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts new file mode 100644 index 0000000..ea9120e --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { selectionMode: 'multiple' }, + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-selection-checkbox', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableSelectionCheckboxComponent { + shipments = SHIPMENTS; + columns = COLUMNS; + selected: any[] = []; +} diff --git a/src/stories/components/data-table/examples/data-table-selection-radio.component.ts b/src/stories/components/data-table/examples/data-table-selection-radio.component.ts new file mode 100644 index 0000000..fe6c411 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-selection-radio.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { selectionMode: 'single' }, + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-selection-radio', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableSelectionRadioComponent { + shipments = SHIPMENTS; + columns = COLUMNS; + selected: any = null; +} diff --git a/src/stories/components/data-table/examples/data-table-striped-rows.component.ts b/src/stories/components/data-table/examples/data-table-striped-rows.component.ts new file mode 100644 index 0000000..e86ca8d --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-striped-rows.component.ts @@ -0,0 +1,35 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-striped-rows', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableStripedRowsComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} From cf0045f068e3306fc5f2d92435ff7734d20710d0 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 13 Apr 2026 19:04:19 +0700 Subject: [PATCH 2/3] =?UTF-8?q?sortable=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=B2=D0=BD=D1=83=D1=82=D1=80=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D0=B8=D0=BC=20=D1=83=D1=81=D0=BB=D0=BE=D0=B2=D0=B8=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/data-table/data-table.component.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/components/data-table/data-table.component.ts b/src/lib/components/data-table/data-table.component.ts index 798bf68..75d3d3b 100644 --- a/src/lib/components/data-table/data-table.component.ts +++ b/src/lib/components/data-table/data-table.component.ts @@ -43,13 +43,13 @@ export interface DataTableColumn { - } @else if (col.sortable) { - + } @else { + {{ col.header }} - + @if (col.sortable) { + + } - } @else { - {{ col.header }} } } From 6927c6299677926d3a5a65dc61bc00013ca61849 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 13 Apr 2026 19:18:23 +0700 Subject: [PATCH 3/3] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D1=82=D0=B0=20=D0=BF=D1=80=D0=B8=20=D0=BD=D0=B0?= =?UTF-8?q?=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B8=D0=B8=20=D0=B2=20headerCel?= =?UTF-8?q?l?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/data-table.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/data-table.ts b/src/prime-preset/tokens/components/data-table.ts index f770594..d5d0960 100644 --- a/src/prime-preset/tokens/components/data-table.ts +++ b/src/prime-preset/tokens/components/data-table.ts @@ -23,6 +23,6 @@ export const dataTableCss = ({ dt }: { dt: (token: string) => string }): string } .p-datatable .p-datatable-sortable-column:not(.p-datatable-column-sorted):hover { - color: ${dt('datatable.headerCell.hoverColor')}; + color: ${dt('text.hoverColor')}; } `;