Commit 080c686a authored by Дмитрий Малюгин's avatar Дмитрий Малюгин 🕓
Browse files

feat: 'Paginator' in process

parent 301c7a42
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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 {
+3 −1
Original line number Diff line number Diff line
@@ -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',
  },
};
+54 −23
Original line number Diff line number Diff line
@@ -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<IPaginatorProps>(), {
  total: 10,
  size: 'normal',
  theme: 'black',
  theme: 'white',
  darknessTheme: '500',
  itemsPerPage: 1,
});
@@ -21,46 +22,56 @@ const current = defineModel({
  default: 1,
}) as Ref<number>;

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);
});
</script>

<template>
  <section class="container">
    <PaginatorItem @click="current = 1" :disable="isStartDisabled" class="paginatorItem">
      <ArrowDoubleLeftShortIcon :color="isStartDisabled ? '#aaa' : 'black'" :size="iconSize" />
    <PaginatorItem @click="current = 1" :color="color" :disable="isStartDisabled" class="paginatorItem">
      <ArrowDoubleLeftShortIcon :color="isStartDisabled ? '#aaa' : textColor" :size="iconSize" />
    </PaginatorItem>
    <PaginatorItem @click="current--" :disable="isStartDisabled" class="paginatorItem">
      <ArrowLeftShortIcon :color="isStartDisabled ? '#aaa' : 'black'" :size="iconSize" />
    <PaginatorItem @click="current--" :color="color" :disable="isStartDisabled" class="paginatorItem">
      <ArrowLeftShortIcon :color="isStartDisabled ? '#aaa' : textColor" :size="iconSize" />
    </PaginatorItem>
    <PaginatorItem
      v-for="item of items"
@@ -71,20 +82,40 @@ const itemSize = computed(() => `${+iconSize.value * 2.5}px`);
    >
      <span class="digital">{{ item }}</span>
    </PaginatorItem>
    <PaginatorItem @click="isEndDisabled ? '' : current++" :disable="isEndDisabled" class="paginatorItem">
      <ArrowRightShortIcon :color="isEndDisabled ? '#aaa' : 'black'" :size="iconSize" />
    <PaginatorItem
      @click="isEndDisabled ? '' : current++"
      :color="color"
      :disable="isEndDisabled"
      class="paginatorItem"
    >
      <ArrowRightShortIcon :color="isEndDisabled ? '#aaa' : textColor" :size="iconSize" />
    </PaginatorItem>
    <PaginatorItem @click="isEndDisabled ? '' : (current = total)" :disable="isEndDisabled" class="paginatorItem">
      <ArrowDoubleRightShortIcon :color="isEndDisabled ? '#aaa' : 'black'" :size="iconSize" />
    <PaginatorItem
      @click="isEndDisabled ? '' : (current = itemsLength)"
      :color="color"
      :disable="isEndDisabled"
      class="paginatorItem"
    >
      <ArrowDoubleRightShortIcon :color="isEndDisabled ? '#aaa' : textColor" :size="iconSize" />
    </PaginatorItem>
    <Select v-if="itemsPerPageOptions" v-model="perPage" :options="selectOptions"></Select>
    <Select
      v-if="itemsPerPageOptions"
      v-model="perPage"
      :theme="theme"
      :size="size"
      width="max-width"
      no-highlight
      :font-size="fontSize"
      :options="selectOptions"
    ></Select>
  </section>
</template>

<style scoped>
.container {
  display: flex;
  gap: 5px;
  gap: calc(v-bind(fontSize) * 0.25);
  align-items: center;
}
.paginatorItem {
  width: v-bind(itemSize);
+16 −4
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
defineProps<{
  active?: boolean;
  disable?: boolean;
  color?: string;
}>();
</script>

@@ -36,12 +37,23 @@ defineProps<{
  cursor: pointer;
  line-height: 1.2;
}
.item::before {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  top: 0;
  left: 0;
  z-index: -1;
  background-color: v-bind(color);
}
.item:hover > .bg {
  opacity: 1;
}
.item:active > .bg {
  opacity: 1;
  background-color: rgba(0, 0, 0, 0.2);
  opacity: 0.2;
  background-color: black;
}
.bg {
  width: 120%;
@@ -51,9 +63,9 @@ defineProps<{
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 10px;
  z-index: -1;
  z-index: -2;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.1);
  background-color: transparent;
  opacity: 0;
  transition: all 0.2s ease;
}