From 2631a6b6bc3c0cb99536f115c2d1e4db68e17633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=9C=D0=B0?= =?UTF-8?q?=D0=BB=D1=8E=D0=B3=D0=B8=D0=BD?= <d.malygin@iqdev.digital> Date: Sat, 28 Dec 2024 15:27:49 +0500 Subject: [PATCH] feat: add sort for Table (only simple) --- src/common/interfaces/componentsProp.ts | 2 + src/common/interfaces/componentsProps.ts | 11 +-- src/stories/components/Table/Table.stories.ts | 15 ++++ src/stories/components/Table/Table.vue | 75 ++++++++++++++----- 4 files changed, 81 insertions(+), 22 deletions(-) diff --git a/src/common/interfaces/componentsProp.ts b/src/common/interfaces/componentsProp.ts index 7ada68d..269998a 100644 --- a/src/common/interfaces/componentsProp.ts +++ b/src/common/interfaces/componentsProp.ts @@ -6,6 +6,7 @@ export interface ITableColumn { editable?: boolean; filterable?: boolean; sortable?: boolean; + initSort?: 'up' | 'down' | 'none'; padding?: string; } @@ -16,6 +17,7 @@ export interface ITableItem { export type TTableColumnType = | 'checkbox' + | 'number' | 'text' | 'date' | 'tag' diff --git a/src/common/interfaces/componentsProps.ts b/src/common/interfaces/componentsProps.ts index 8f1d216..d85c97f 100644 --- a/src/common/interfaces/componentsProps.ts +++ b/src/common/interfaces/componentsProps.ts @@ -22,15 +22,16 @@ import type { export interface ITableProps { columns: ITableColumn[]; data: ITableItem[][]; - theme?: TThemeColor; - textColor?: TThemeColor; - darknessTheme?: TDarkness; - darknessTextColor?: TDarkness; + multipleSort?: boolean; gap?: string; - fontSize?: string; showAllLines?: boolean; stripedRows?: boolean; center?: boolean; + fontSize?: string; + theme?: TThemeColor; + textColor?: TThemeColor; + darknessTheme?: TDarkness; + darknessTextColor?: TDarkness; } export interface ITLProps { diff --git a/src/stories/components/Table/Table.stories.ts b/src/stories/components/Table/Table.stories.ts index 7d51e72..1bca7e8 100644 --- a/src/stories/components/Table/Table.stories.ts +++ b/src/stories/components/Table/Table.stories.ts @@ -21,6 +21,7 @@ const meta: Meta = { showAllLines: { control: 'boolean' }, stripedRows: { control: 'boolean' }, center: { control: 'boolean' }, + multipleSort: { control: 'boolean' }, darknessTheme: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'] }, darknessTextColor: { control: 'select', @@ -200,6 +201,20 @@ export const Full: Story = { value: 'Russia', }, ], + [ + { + value: 'КÑюша', + }, + { + value: '32', + }, + { + value: 'Backend', + }, + { + value: 'Russia', + }, + ], ], fontSize: '20px', diff --git a/src/stories/components/Table/Table.vue b/src/stories/components/Table/Table.vue index 825cf7c..2637655 100644 --- a/src/stories/components/Table/Table.vue +++ b/src/stories/components/Table/Table.vue @@ -1,6 +1,6 @@ <script setup lang="ts"> import type { ITableProps } from '@interfaces/componentsProps'; -import { computed, ref } from 'vue'; +import { computed, ref, watch } from 'vue'; import { convertThemeToColor, convertThemeToSecondaryColor, convertThemeToTextColor } from '@helpers/common'; import type { ITableItem } from '@interfaces/componentsProp'; import FilterIcon from '@stories/icons/Mono/FilterIcon.vue'; @@ -14,10 +14,10 @@ const props = withDefaults(defineProps<ITableProps>(), { darknessTheme: '500', fontSize: '16px', }); +const columns = ref(props.columns); +watch(props.columns, () => (columns.value = props.columns)); const gap = computed(() => props.gap); -// const emit = defineEmits(['']); -const data = defineModel('data') as ITableItem[][]; -// watch(, () => {}); +const data = defineModel<ITableItem[][]>('data'); const themeColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme)); const color = computed(() => props.textColor @@ -27,20 +27,57 @@ const color = computed(() => const secondaryColor = computed(() => convertThemeToSecondaryColor(props.theme, props.darknessTheme)); const darkCellColor = computed(() => convertThemeToSecondaryColor(props.theme, String(+props.darknessTheme + 300))); -const sortState = ref<string[]>( - (() => { - const columns = props.columns; - const result = []; - for (const column of columns) { - result.push(column.sortable ? 'none' : ''); - } - return result; - })(), -); +// ['', 'up', 'none', '', 'none', ...] +const sortState = computed<string[]>(() => { + const result = []; + for (const column of columns.value) { + result.push(column.sortable ? (column.initSort ?? 'none') : ''); + } + return result; +}); + +const sortStateActive = ref([]); +const rows = computed<ITableItem[][]>(() => { + // ['up', 'down', ...] + const rows = [...data.value]; + if (!sortStateActive.value.length) return rows; + + if (props.multipleSort) { + // let indexColumn = sortState.value.findIndex((state) => state && state !== 'none'); + // let lastColumnIndexSorted = indexColumn; + // console.log('indexColumn: ', indexColumn); + // for (const sortItem of sortStateActive.value) { + // rows.sort((a, b) => + // sortItem.split('$')[1] === 'down' + // ? a[indexColumn].value.localeCompare(b[indexColumn].value) + // : b[indexColumn].value.localeCompare(a[indexColumn].value), + // ); + // indexColumn = sortState.value.findIndex( + // (state, index) => state && state !== 'none' && index !== lastColumnIndexSorted, + // ); + // lastColumnIndexSorted = indexColumn; + // } + // return rows; + } else { + const index = sortStateActive.value[0]; + const value = sortStateActive.value[1]; + return rows.sort((a, b) => + value === 'down' ? a[index].value.localeCompare(b[index].value) : b[index].value.localeCompare(a[index].value), + ); + } +}); const changeColumnSortMode = (index: number) => { const cur = sortState.value[index]; - sortState.value[index] = cur === 'none' ? 'down' : cur === 'down' ? 'up' : 'none'; + const newValue = cur === 'none' ? 'down' : cur === 'down' ? 'up' : 'none'; + if (cur === 'up') { + sortStateActive.value = []; + } else { + sortStateActive.value[0] = index; + sortStateActive.value[1] = newValue; + } + if (!props.multipleSort) columns.value.forEach((column) => (column.initSort = 'none')); + columns.value[index].initSort = newValue; }; </script> @@ -76,7 +113,11 @@ const changeColumnSortMode = (index: number) => { <h3> {{ column.name }} </h3> - <button v-if="column.sortable" @click.prevent="changeColumnSortMode(index)"> + <button + v-if="column.sortable" + @click.prevent="changeColumnSortMode(index)" + style="min-width: 20px; min-height: 20px" + > <SortVerticalIcon v-show="sortState[index] === 'none'" :color="textColor" @@ -106,7 +147,7 @@ const changeColumnSortMode = (index: number) => { </tr> </thead> <tbody> - <tr v-for="(row, index) of data" :key="index"> + <tr v-for="(row, index) of rows" :key="index"> <td :class="{ leftBorder: showAllLines, -- GitLab