diff --git a/src/common/interfaces/componentsProp.ts b/src/common/interfaces/componentsProp.ts index 7ada68de9bbeaea1d0ffcedf2066ba614572e8f9..269998ab438077d4179cf6f5dd8ee98009bc379a 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 8f1d2168e530c41c72d17273cf8451a72877f9ae..d85c97fc0876f75859b4b33b3c2efab867c75690 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 7d51e729c49070083451a720d8333546f30a3121..1bca7e86a81b9bd110f558f07558e99ee70c7dfa 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 825cf7c4c21f40020ef6f2ce90e7263cf7e75c2d..2637655239d48d4e924157861b2765750acc9b57 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,