From 080c686a7aabf85acdf25d5015fd8478dcc2392f 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?= Date: Tue, 21 Jan 2025 18:06:41 +0500 Subject: [PATCH] feat: 'Paginator' in process --- src/common/interfaces/componentsProps.ts | 5 +- src/components/Paginator/Paginator.stories.ts | 4 +- src/components/Paginator/Paginator.vue | 77 +++++++++++++------ src/components/Paginator/PaginatorItem.vue | 20 ++++- 4 files changed, 75 insertions(+), 31 deletions(-) diff --git a/src/common/interfaces/componentsProps.ts b/src/common/interfaces/componentsProps.ts index 843197d..689ac68 100644 --- a/src/common/interfaces/componentsProps.ts +++ b/src/common/interfaces/componentsProps.ts @@ -57,7 +57,6 @@ export interface ITIProps { } export interface IPaginatorProps { - value?: number; total?: number; itemsPerPage?: number; itemsPerPageOptions?: number[]; @@ -163,16 +162,16 @@ export interface ISelectProps { placeholder?: string; openIcon?: TIcon; size?: TSize; + fontSize?: string; name?: string; theme?: TThemeColor; - background?: TThemeColor; placeholderColor?: TThemeColor; openIconColor?: TThemeColor; darknessTheme?: TDarkness; - darknessBackground?: TDarkness; darknessOpenIcon?: TDarkness; filtered?: boolean; disabled?: boolean; + noHighlight?: boolean; } export interface ISBProps { diff --git a/src/components/Paginator/Paginator.stories.ts b/src/components/Paginator/Paginator.stories.ts index e4ff882..159dbde 100644 --- a/src/components/Paginator/Paginator.stories.ts +++ b/src/components/Paginator/Paginator.stories.ts @@ -14,7 +14,6 @@ const meta: Meta = { }, }, argTypes: { - value: { control: 'number' }, total: { control: 'number' }, itemsPerPage: { control: 'number' }, itemsPerPageOptions: { control: 'object' }, @@ -56,5 +55,8 @@ export const Simple: Story = { export const Full: Story = { args: { itemsPerPageOptions: ['10', '20', '30'], + total: 50, + size: 'large', + theme: 'black', }, }; diff --git a/src/components/Paginator/Paginator.vue b/src/components/Paginator/Paginator.vue index 68ad21b..1080535 100644 --- a/src/components/Paginator/Paginator.vue +++ b/src/components/Paginator/Paginator.vue @@ -5,14 +5,15 @@ import ArrowLeftShortIcon from '@icons/Mono/ArrowLeftShortIcon.vue'; import ArrowRightShortIcon from '@icons/Mono/ArrowRightShortIcon.vue'; import type { IPaginatorProps } from '@interfaces/componentsProps'; import PaginatorItem from '@components/Paginator/PaginatorItem.vue'; -import { computed, ref, type Ref } from 'vue'; +import { computed, ref, type Ref, watch } from 'vue'; import Select from '@components/Select/Select.vue'; import type { ISelectOption } from '@interfaces/componentsProp'; +import { convertThemeToColor, convertThemeToTextColor } from '@helpers/common'; const props = withDefaults(defineProps(), { total: 10, size: 'normal', - theme: 'black', + theme: 'white', darknessTheme: '500', itemsPerPage: 1, }); @@ -21,46 +22,56 @@ const current = defineModel({ default: 1, }) as Ref; -const perPage = ref(props.itemsPerPage); +const perPage = ref(props.itemsPerPageOptions?.[0] ?? props.itemsPerPage); -const itemsLength = computed(() => Math.floor(props.total / perPage.value)); +const itemsLength = computed(() => Math.ceil(props.total / perPage.value)); +const initArray = computed(() => Array.from({ length: itemsLength.value }, (_, i) => i + 1)); const selectOptions = computed(() => !props.itemsPerPageOptions ? [{ value: '1' }] : props.itemsPerPageOptions.map((item) => ({ value: String(item) })), ) as unknown as ISelectOption[]; const isStartDisabled = computed(() => current.value === 1); const isEndDisabled = computed(() => current.value === itemsLength.value); const items = computed(() => { - if (!current.value) return [1, 2, 3, 4, 5]; - const center = current.value; const length = itemsLength.value; - if (center - 2 < 2) return [1, 2, 3, 4, 5]; - if (center + 2 > length) return [length - 5, length - 4, length - 3, length - 1, length]; - return [center - 2, center - 1, center, center + 1, center + 2]; + const itemsPerView = Math.min(length, 5); + const cur = current.value; + if (cur - 2 < 2) return initArray.value.slice(0, itemsPerView + 1); + if (cur + 2 > length) return initArray.value.slice(-itemsPerView); + if (itemsPerView === 5) return [cur - 2, cur - 1, cur, cur + 1, cur + 2]; + return initArray.value; }); const iconSize = computed(() => { const size = props.size; if (size === 'normal') return '10'; - if (size === 'large') return '25'; - if (size === 'huge') return '30'; - return '15'; + if (size === 'large') return '15'; + if (size === 'huge') return '18'; + return '7'; }); const fontSize = computed(() => { + if (props.fontSize) return props.fontSize; const size = props.size; if (size === 'normal') return '16px'; if (size === 'large') return '26px'; if (size === 'huge') return '32px'; - return '36px'; + return '12px'; }); const itemSize = computed(() => `${+iconSize.value * 2.5}px`); +const color = computed(() => convertThemeToColor(props.theme, props.darknessTheme)); +const textColor = computed(() => convertThemeToTextColor(props.theme, props.darknessTheme)); + +watch(perPage, (cur, prev) => { + if (cur > prev) current.value = Math.ceil((current.value * prev) / cur); + else current.value = Math.ceil((prev * (current.value - 1) + +cur) / cur); +});