Loading src/common/interfaces/componentsProps.ts +1 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ export interface ITableProps { data: ITableItem[][]; multipleSort?: boolean; gap?: string; size?: TSize; showAllLines?: boolean; stripedRows?: boolean; center?: boolean; Loading src/stories/components/Table/Table.stories.ts +9 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ const meta: Meta = { data: { control: 'text' }, fontSize: { control: 'text' }, gap: { control: 'text' }, size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] }, showAllLines: { control: 'boolean' }, stripedRows: { control: 'boolean' }, center: { control: 'boolean' }, Loading Loading @@ -125,12 +126,14 @@ export const Full: Story = { name: 'Name', type: 'text', sortable: true, initSort: 'none', }, { name: 'Age', type: 'number', sortable: true, filterable: true, initSort: 'down', }, { name: 'Hobbies', Loading @@ -138,12 +141,15 @@ export const Full: Story = { padding: '30px', filterable: true, sortable: true, initSort: 'none', }, { name: 'Country', type: 'text', initSort: 'none', }, ], data: [ [ { Loading Loading @@ -216,12 +222,14 @@ export const Full: Story = { }, ], ], fontSize: '20px', fontSize: '24px', showAllLines: true, border: 'fuchsia', theme: 'black', stripedRows: true, darknessTextColor: '500', center: true, size: 'large', }, }; src/stories/components/Table/Table.vue +7 −3 Original line number Diff line number Diff line Loading @@ -3,10 +3,11 @@ import type { ITableProps } from '@interfaces/componentsProps'; import { computed, ref, watch } from 'vue'; import { convertThemeToColor, convertThemeToSecondaryColor, convertThemeToTextColor } from '@helpers/common'; import type { ITableItem } from '@interfaces/componentsProp'; import { calcGap, calcRows } from '@stories/components/Table/helpers'; import { calcAdditionalHeight, calcGap, calcRows } from '@stories/components/Table/helpers'; import TableHeader from '@stories/components/Table/TableHeader.vue'; const props = withDefaults(defineProps<ITableProps>(), { size: 'normal', theme: 'white', darknessTheme: '500', fontSize: '16px', Loading @@ -23,6 +24,7 @@ const isRegisterSensitive = ref<boolean>(false); watch(props.columns, () => (columns.value = props.columns)); const initGap = computed(() => calcGap(props.gap, props.fontSize)); const additionalHeightFromSize = computed(() => calcAdditionalHeight(props.size, props.fontSize)); const themeColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme)); const color = computed(() => props.textColor Loading @@ -44,7 +46,8 @@ const rows = computed<ITableItem[][]>(() => data.value!, sortStateActive.value, props.multipleSort, props.columns[sortStateActive.value[0] ?? 0].type, columnToFilter.value, props.columns[columnToFilter.value ?? 0].type, filterValue.value, isRegisterSensitive.value, ), Loading Loading @@ -95,6 +98,7 @@ const cancelFilter = () => { :sortState="sortState" :columnToFilter="columnToFilter" :initGap="initGap" :additionalHeightFromSize="additionalHeightFromSize" :theme="theme" :themeColor="themeColor" :secondaryColor="secondaryColor" Loading @@ -116,7 +120,7 @@ const cancelFilter = () => { }" v-for="item of row" :key="item.value" :style="`padding: calc(${initGap} / 2) ${initGap}; text-align: ${center ? 'center' : 'start'}`" :style="`padding: calc(${initGap} / 2 + ${additionalHeightFromSize}) ${initGap}; text-align: ${center ? 'center' : 'start'}`" > {{ item.value }} </td> Loading src/stories/components/Table/TableHeader.vue +4 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ interface Props { sortState: string[]; columnToFilter: number; initGap: string; additionalHeightFromSize: string; theme: TThemeColor; themeColor: string; secondaryColor: string; Loading Loading @@ -54,7 +55,7 @@ const isColumnTypeText = computed(() => props.columns[props.columnToFilter].type }" v-for="(column, index) of columns" :key="column.name" :style="`padding: calc(${initGap} / 2) ${initGap}`" :style="`padding: calc(${initGap} / 2 + ${additionalHeightFromSize}) ${initGap}`" > <div :style="`justify-content: ${center ? 'center' : 'start'}; gap: ${center ? '0' : initGap}; padding: ${calcColumnPadding(column, center, initGap)}`" Loading @@ -67,7 +68,7 @@ const isColumnTypeText = computed(() => props.columns[props.columnToFilter].type <button v-if="column.sortable" @click.prevent="emit('changeColumnSortMode', index)" style="min-width: 20px; min-height: 20px" :style="`min-width: ${fontSize}; min-height: ${fontSize}; max-height: ${fontSize}`" > <SortVerticalIcon v-show="sortState[index] === 'none'" :color="color" :size="iconSize" /> <SortDownIcon v-show="sortState[index] === 'down'" :color="color" :size="iconSize" /> Loading @@ -77,7 +78,7 @@ const isColumnTypeText = computed(() => props.columns[props.columnToFilter].type v-if="column.filterable" @pointerdown="emit('setFilter', index)" :id="`filter${index}`" style="position: relative" :style="`position: relative; width: ${fontSize}; max-height: ${fontSize}`" > <FilterIcon :color="color" :size="iconSize" /> </button> Loading src/stories/components/Table/helpers.ts +17 −3 Original line number Diff line number Diff line import type { ITableColumn, ITableItem, TTableColumnType } from '@interfaces/componentsProp'; import type { TSize } from '@interfaces/common'; export const calcRows = ( initRows: ITableItem[][], sortStateActive: [number, string] | [], multipleSort: boolean, columnToFilter: number, columnToFilterType: TTableColumnType, filterValue: string, isRegisterSensitive: boolean, ) => { // ['up', 'down', ...] let rows = [...initRows]; const sortIndex = sortStateActive[0]; if (filterValue && sortIndex) { if (filterValue) { rows = rows.filter((row) => { const item = isRegisterSensitive ? row[sortIndex].value : row[sortIndex].value.toLowerCase(); const item = isRegisterSensitive ? row[columnToFilter].value : row[columnToFilter].value.toLowerCase(); return item.startsWith(isRegisterSensitive ? filterValue : filterValue.toLowerCase()); }); } Loading @@ -41,6 +42,7 @@ export const calcRows = ( } else { const index = sortStateActive[0]; const value = sortStateActive[1]; console.log('index, value, columnToFilterType:', index, value, columnToFilterType); if (columnToFilterType === 'number') return rows.sort((a, b) => value === 'down' ? +a[index].value - +b[index].value : +b[index].value - +a[index].value, Loading @@ -59,5 +61,17 @@ export const calcGap = (gap: string, fontSize: string) => ? '10px' : '15px'); export const calcAdditionalHeight = (size: TSize, fontSize: string) => { if (size === 'normal') return '0px'; const isTwoLetters = isFinite(+fontSize.at(-3)!); const value = isTwoLetters ? fontSize.slice(0, -2) : fontSize.slice(0, -3); const unit = isTwoLetters ? fontSize.slice(-2) : fontSize.slice(-3); if (size === 'large') return +value / 2 + unit; if (size === 'huge') return value + unit; return -+value / 4 + unit; }; export const calcColumnPadding = (column: ITableColumn, center: boolean, gap: string) => center ? `0px calc(${gap} / 2 + ${column.padding ?? '0px'} / 2)` : `0 ${column.padding ?? '0px'} 0 0`; Loading
src/common/interfaces/componentsProps.ts +1 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ export interface ITableProps { data: ITableItem[][]; multipleSort?: boolean; gap?: string; size?: TSize; showAllLines?: boolean; stripedRows?: boolean; center?: boolean; Loading
src/stories/components/Table/Table.stories.ts +9 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ const meta: Meta = { data: { control: 'text' }, fontSize: { control: 'text' }, gap: { control: 'text' }, size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] }, showAllLines: { control: 'boolean' }, stripedRows: { control: 'boolean' }, center: { control: 'boolean' }, Loading Loading @@ -125,12 +126,14 @@ export const Full: Story = { name: 'Name', type: 'text', sortable: true, initSort: 'none', }, { name: 'Age', type: 'number', sortable: true, filterable: true, initSort: 'down', }, { name: 'Hobbies', Loading @@ -138,12 +141,15 @@ export const Full: Story = { padding: '30px', filterable: true, sortable: true, initSort: 'none', }, { name: 'Country', type: 'text', initSort: 'none', }, ], data: [ [ { Loading Loading @@ -216,12 +222,14 @@ export const Full: Story = { }, ], ], fontSize: '20px', fontSize: '24px', showAllLines: true, border: 'fuchsia', theme: 'black', stripedRows: true, darknessTextColor: '500', center: true, size: 'large', }, };
src/stories/components/Table/Table.vue +7 −3 Original line number Diff line number Diff line Loading @@ -3,10 +3,11 @@ import type { ITableProps } from '@interfaces/componentsProps'; import { computed, ref, watch } from 'vue'; import { convertThemeToColor, convertThemeToSecondaryColor, convertThemeToTextColor } from '@helpers/common'; import type { ITableItem } from '@interfaces/componentsProp'; import { calcGap, calcRows } from '@stories/components/Table/helpers'; import { calcAdditionalHeight, calcGap, calcRows } from '@stories/components/Table/helpers'; import TableHeader from '@stories/components/Table/TableHeader.vue'; const props = withDefaults(defineProps<ITableProps>(), { size: 'normal', theme: 'white', darknessTheme: '500', fontSize: '16px', Loading @@ -23,6 +24,7 @@ const isRegisterSensitive = ref<boolean>(false); watch(props.columns, () => (columns.value = props.columns)); const initGap = computed(() => calcGap(props.gap, props.fontSize)); const additionalHeightFromSize = computed(() => calcAdditionalHeight(props.size, props.fontSize)); const themeColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme)); const color = computed(() => props.textColor Loading @@ -44,7 +46,8 @@ const rows = computed<ITableItem[][]>(() => data.value!, sortStateActive.value, props.multipleSort, props.columns[sortStateActive.value[0] ?? 0].type, columnToFilter.value, props.columns[columnToFilter.value ?? 0].type, filterValue.value, isRegisterSensitive.value, ), Loading Loading @@ -95,6 +98,7 @@ const cancelFilter = () => { :sortState="sortState" :columnToFilter="columnToFilter" :initGap="initGap" :additionalHeightFromSize="additionalHeightFromSize" :theme="theme" :themeColor="themeColor" :secondaryColor="secondaryColor" Loading @@ -116,7 +120,7 @@ const cancelFilter = () => { }" v-for="item of row" :key="item.value" :style="`padding: calc(${initGap} / 2) ${initGap}; text-align: ${center ? 'center' : 'start'}`" :style="`padding: calc(${initGap} / 2 + ${additionalHeightFromSize}) ${initGap}; text-align: ${center ? 'center' : 'start'}`" > {{ item.value }} </td> Loading
src/stories/components/Table/TableHeader.vue +4 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ interface Props { sortState: string[]; columnToFilter: number; initGap: string; additionalHeightFromSize: string; theme: TThemeColor; themeColor: string; secondaryColor: string; Loading Loading @@ -54,7 +55,7 @@ const isColumnTypeText = computed(() => props.columns[props.columnToFilter].type }" v-for="(column, index) of columns" :key="column.name" :style="`padding: calc(${initGap} / 2) ${initGap}`" :style="`padding: calc(${initGap} / 2 + ${additionalHeightFromSize}) ${initGap}`" > <div :style="`justify-content: ${center ? 'center' : 'start'}; gap: ${center ? '0' : initGap}; padding: ${calcColumnPadding(column, center, initGap)}`" Loading @@ -67,7 +68,7 @@ const isColumnTypeText = computed(() => props.columns[props.columnToFilter].type <button v-if="column.sortable" @click.prevent="emit('changeColumnSortMode', index)" style="min-width: 20px; min-height: 20px" :style="`min-width: ${fontSize}; min-height: ${fontSize}; max-height: ${fontSize}`" > <SortVerticalIcon v-show="sortState[index] === 'none'" :color="color" :size="iconSize" /> <SortDownIcon v-show="sortState[index] === 'down'" :color="color" :size="iconSize" /> Loading @@ -77,7 +78,7 @@ const isColumnTypeText = computed(() => props.columns[props.columnToFilter].type v-if="column.filterable" @pointerdown="emit('setFilter', index)" :id="`filter${index}`" style="position: relative" :style="`position: relative; width: ${fontSize}; max-height: ${fontSize}`" > <FilterIcon :color="color" :size="iconSize" /> </button> Loading
src/stories/components/Table/helpers.ts +17 −3 Original line number Diff line number Diff line import type { ITableColumn, ITableItem, TTableColumnType } from '@interfaces/componentsProp'; import type { TSize } from '@interfaces/common'; export const calcRows = ( initRows: ITableItem[][], sortStateActive: [number, string] | [], multipleSort: boolean, columnToFilter: number, columnToFilterType: TTableColumnType, filterValue: string, isRegisterSensitive: boolean, ) => { // ['up', 'down', ...] let rows = [...initRows]; const sortIndex = sortStateActive[0]; if (filterValue && sortIndex) { if (filterValue) { rows = rows.filter((row) => { const item = isRegisterSensitive ? row[sortIndex].value : row[sortIndex].value.toLowerCase(); const item = isRegisterSensitive ? row[columnToFilter].value : row[columnToFilter].value.toLowerCase(); return item.startsWith(isRegisterSensitive ? filterValue : filterValue.toLowerCase()); }); } Loading @@ -41,6 +42,7 @@ export const calcRows = ( } else { const index = sortStateActive[0]; const value = sortStateActive[1]; console.log('index, value, columnToFilterType:', index, value, columnToFilterType); if (columnToFilterType === 'number') return rows.sort((a, b) => value === 'down' ? +a[index].value - +b[index].value : +b[index].value - +a[index].value, Loading @@ -59,5 +61,17 @@ export const calcGap = (gap: string, fontSize: string) => ? '10px' : '15px'); export const calcAdditionalHeight = (size: TSize, fontSize: string) => { if (size === 'normal') return '0px'; const isTwoLetters = isFinite(+fontSize.at(-3)!); const value = isTwoLetters ? fontSize.slice(0, -2) : fontSize.slice(0, -3); const unit = isTwoLetters ? fontSize.slice(-2) : fontSize.slice(-3); if (size === 'large') return +value / 2 + unit; if (size === 'huge') return value + unit; return -+value / 4 + unit; }; export const calcColumnPadding = (column: ITableColumn, center: boolean, gap: string) => center ? `0px calc(${gap} / 2 + ${column.padding ?? '0px'} / 2)` : `0 ${column.padding ?? '0px'} 0 0`;