From 69fb3dc113334f0c90d27a8e903079863698b7f5 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, 18 Jan 2025 22:01:50 +0500 Subject: [PATCH] feat: start component 'Paginator' --- src/App.vue | 6 +- src/common/constants/icons.ts | 2 +- src/common/interfaces/componentsProps.ts | 7 ++ src/components/Paginator/Paginator.stories.ts | 84 +++++++++++++++++++ src/components/Paginator/Paginator.vue | 55 ++++++++++++ src/components/Paginator/PaginatorItem.vue | 38 +++++++++ .../ProgressBar/ProgressBar.stories.ts | 2 +- src/icons/Mono/ArrowDoubleLeftShortIcon.vue | 64 ++++++++++++++ ...ortDownIcon.vue => ArrowDownShortIcon.vue} | 0 src/icons/Mono/ArrowLeftShortIcon.vue | 24 ++++++ 10 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 src/components/Paginator/Paginator.stories.ts create mode 100644 src/components/Paginator/Paginator.vue create mode 100644 src/components/Paginator/PaginatorItem.vue create mode 100644 src/icons/Mono/ArrowDoubleLeftShortIcon.vue rename src/icons/Mono/{ArrowShortDownIcon.vue => ArrowDownShortIcon.vue} (100%) create mode 100644 src/icons/Mono/ArrowLeftShortIcon.vue diff --git a/src/App.vue b/src/App.vue index fc3bf13..8ee3a49 100644 --- a/src/App.vue +++ b/src/App.vue @@ -108,9 +108,11 @@ import UserIcon from '@icons/Mono/UserIcon.vue'; import ArrowsVerticalIcon from '@icons/Mono/ArrowsVerticalIcon.vue'; import TriangleIcon from '@icons/Mono/TriangleIcon.vue'; import Playground from '@/Playground.vue'; -import ArrowShortDownIcon from '@icons/Mono/ArrowShortDownIcon.vue'; +import ArrowShortDownIcon from '@icons/Mono/ArrowDownShortIcon.vue'; import StarIcon from '@icons/Mono/StarIcon.vue'; import StarFilledIcon from '@icons/Mono/StarFilledIcon.vue'; +import ArrowLeftShortIcon from '@icons/Mono/ArrowLeftShortIcon.vue'; +import ArrowDoubleLeftShortIcon from '@icons/Mono/ArrowDoubleLeftShortIcon.vue'; const gentleIcons = { Age18Icon, @@ -122,6 +124,8 @@ const gentleIcons = { AnchorIcon, AnchorLinkIcon, ArchiveIcon, + ArrowLeftShortIcon, + ArrowDoubleLeftShortIcon, ArrowForwardIcon, ArrowLeftIcon, ArrowRightIcon, diff --git a/src/common/constants/icons.ts b/src/common/constants/icons.ts index fe781d0..9ae57d6 100644 --- a/src/common/constants/icons.ts +++ b/src/common/constants/icons.ts @@ -107,7 +107,7 @@ import SortHorizontalIcon from '@icons/Mono/SortHorizontalIcon.vue'; import SortDownIcon from '@icons/Mono/SortDownIcon.vue'; import SortUpIcon from '@icons/Mono/SortUpIcon.vue'; import SortVerticalIcon from '@icons/Mono/SortVerticalIcon.vue'; -import ArrowShortDownIcon from '@icons/Mono/ArrowShortDownIcon.vue'; +import ArrowShortDownIcon from '@icons/Mono/ArrowDownShortIcon.vue'; import SearchIcon from '@icons/Mono/SearchIcon.vue'; import StarIcon from '@icons/Mono/StarIcon.vue'; import StarFilledIcon from '@icons/Mono/StarFilledIcon.vue'; diff --git a/src/common/interfaces/componentsProps.ts b/src/common/interfaces/componentsProps.ts index 07b4d81..81547c6 100644 --- a/src/common/interfaces/componentsProps.ts +++ b/src/common/interfaces/componentsProps.ts @@ -56,6 +56,13 @@ export interface ITIProps { themeColor: string; } +export interface IPaginatorProps { + value?: number; + total?: number; + itemsPerPage?: number; + size?: TSize; +} + export interface IMDProps { items: IMDItemProps[]; size?: TSize; diff --git a/src/components/Paginator/Paginator.stories.ts b/src/components/Paginator/Paginator.stories.ts new file mode 100644 index 0000000..c3f7619 --- /dev/null +++ b/src/components/Paginator/Paginator.stories.ts @@ -0,0 +1,84 @@ +import type { Meta, StoryObj } from '@storybook/vue3'; + +import Paginator from './Paginator.vue'; + +const meta: Meta = { + title: 'Components/Paginator', + component: Paginator, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: 'A component to display data in paged format and provide navigation between pages.', + }, + }, + }, + argTypes: { + value: { control: 'number' }, + max: { control: 'number' }, + width: { control: 'text' }, + height: { control: 'text' }, + labelBefore: { control: 'text' }, + labelAfter: { control: 'text' }, + showLabel: { control: 'boolean' }, + noBorder: { control: 'boolean' }, + size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] }, + fontSize: { control: 'text' }, + colorGaps: { control: 'object' }, + colorInactiveGaps: { control: 'object' }, + darknessTheme: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'] }, + darknessInactiveTheme: { + control: 'select', + options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'], + }, + theme: { + control: 'select', + options: [ + 'white', + 'blue', + 'sky', + 'cyan', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + inactiveTheme: { + control: 'select', + options: [ + 'white', + 'blue', + 'sky', + 'cyan', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + }, + args: {}, +} satisfies Meta<typeof Paginator>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Simple: Story = { + args: {}, +}; diff --git a/src/components/Paginator/Paginator.vue b/src/components/Paginator/Paginator.vue new file mode 100644 index 0000000..f4f9093 --- /dev/null +++ b/src/components/Paginator/Paginator.vue @@ -0,0 +1,55 @@ +<script setup lang="ts"> +import ArrowDoubleLeftShortIcon from '@icons/Mono/ArrowDoubleLeftShortIcon.vue'; +import ArrowLeftShortIcon from '@icons/Mono/ArrowLeftShortIcon.vue'; +import type { IPaginatorProps } from '@interfaces/componentsProps'; +import PaginatorItem from '@components/Paginator/PaginatorItem.vue'; +import { computed, ref } from 'vue'; + +const props = withDefaults(defineProps<IPaginatorProps>(), { + total: 10, + size: 'normal', + theme: 'black', + darknessTheme: '500', +}); + +const current = ref<number | undefined>(props.value); + +const items = computed(() => { + if (!current.value) return [1, 2, 3, 4, 5]; + const start = Math.floor(current.value / 5); + return [start + 1, start + 2, start + 3, start + 4, start + 5]; +}); +const iconSize = computed(() => { + const size = props.size; + if (size === 'normal') return '20'; + if (size === 'large') return '25'; + if (size === 'huge') return '30'; + return '15'; +}); +const itemSize = computed(() => `${+iconSize.value * 1.5}px`); +</script> + +<template> + <section class="container"> + <PaginatorItem class="paginatorItem"> + <ArrowDoubleLeftShortIcon :size="iconSize" /> + </PaginatorItem> + <PaginatorItem class="paginatorItem"> + <ArrowLeftShortIcon :size="iconSize" /> + </PaginatorItem> + <PaginatorItem v-for="item of items" :key="item" class="paginatorItem"> + {{ item }} + </PaginatorItem> + </section> +</template> + +<style scoped> +.container { + display: flex; + gap: 5px; +} +.paginatorItem { + width: v-bind(itemSize); + height: v-bind(itemSize); +} +</style> diff --git a/src/components/Paginator/PaginatorItem.vue b/src/components/Paginator/PaginatorItem.vue new file mode 100644 index 0000000..048735e --- /dev/null +++ b/src/components/Paginator/PaginatorItem.vue @@ -0,0 +1,38 @@ +<script setup lang="ts"></script> + +<template> + <div class="item"> + <div class="bg"></div> + <slot /> + </div> +</template> + +<style> +.item { + position: relative; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; +} +.item:hover > .bg { + opacity: 1; +} +.item:active > .bg { + opacity: 1; + background-color: rgba(0, 0, 0, 0.2) !important; +} +.bg { + width: 100%; + height: 100%; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 2; + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.1); + opacity: 0; + transition: all 0.15s ease; +} +</style> diff --git a/src/components/ProgressBar/ProgressBar.stories.ts b/src/components/ProgressBar/ProgressBar.stories.ts index 27e2b24..285c1c3 100644 --- a/src/components/ProgressBar/ProgressBar.stories.ts +++ b/src/components/ProgressBar/ProgressBar.stories.ts @@ -9,7 +9,7 @@ const meta: Meta = { parameters: { docs: { description: { - component: 'A component that is used as a ProgressBar.', + component: 'A process status indicator.', }, }, }, diff --git a/src/icons/Mono/ArrowDoubleLeftShortIcon.vue b/src/icons/Mono/ArrowDoubleLeftShortIcon.vue new file mode 100644 index 0000000..a4dc9ed --- /dev/null +++ b/src/icons/Mono/ArrowDoubleLeftShortIcon.vue @@ -0,0 +1,64 @@ +<script setup lang="ts"> +interface Props { + color?: string; + size?: string | number; +} +defineProps<Props>(); +</script> + +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + :width="`${size ?? 40}px`" + :height="`${size ?? 40}px`" + viewBox="0 0 532.153 532.153" + xml:space="preserve" + > + <line + x1="155" + y1="-100" + x2="-50" + y2="100" + transform="matrix(1.066014 0 0 1.167066 83.13335 150)" + fill="none" + :stroke="color ?? '#000000'" + stroke-width="50" + stroke-linecap="round" + /> + <line + x1="-50" + y1="100" + x2="155" + y2="300" + transform="matrix(1.066014 0 0 1.167066 83.13335 150)" + fill="none" + :stroke="color ?? '#000000'" + stroke-width="50" + stroke-linecap="round" + /> + <line + x1="335" + y1="-100" + x2="110" + y2="100" + transform="matrix(1.066014 0 0 1.167066 83.13335 150)" + fill="none" + :stroke="color ?? '#000000'" + stroke-width="50" + stroke-linecap="round" + /> + <line + x1="110" + y1="100" + x2="335" + y2="300" + transform="matrix(1.066014 0 0 1.167066 83.13335 150)" + fill="none" + :stroke="color ?? '#000000'" + stroke-width="50" + stroke-linecap="round" + /> + </svg> +</template> + +<style scoped></style> diff --git a/src/icons/Mono/ArrowShortDownIcon.vue b/src/icons/Mono/ArrowDownShortIcon.vue similarity index 100% rename from src/icons/Mono/ArrowShortDownIcon.vue rename to src/icons/Mono/ArrowDownShortIcon.vue diff --git a/src/icons/Mono/ArrowLeftShortIcon.vue b/src/icons/Mono/ArrowLeftShortIcon.vue new file mode 100644 index 0000000..8c2f7b9 --- /dev/null +++ b/src/icons/Mono/ArrowLeftShortIcon.vue @@ -0,0 +1,24 @@ +<script setup lang="ts"> +interface Props { + color?: string; + size?: string | number; +} +defineProps<Props>(); +</script> + +<template> + <svg :width="`${size ?? 40}px`" :height="`${size ?? 40}px`" viewBox="-4.5 0 20 20" xmlns="http://www.w3.org/2000/svg"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g transform="translate(-345.000000, -6679.000000)" :fill="color ?? '#000000'"> + <g id="icons" transform="translate(56.000000, 160.000000)"> + <path + d="M299.633777,6519.29231 L299.633777,6519.29231 C299.228878,6518.90256 298.573377,6518.90256 298.169513,6519.29231 L289.606572,6527.55587 C288.797809,6528.33636 288.797809,6529.60253 289.606572,6530.38301 L298.231646,6538.70754 C298.632403,6539.09329 299.27962,6539.09828 299.685554,6538.71753 L299.685554,6538.71753 C300.100809,6538.32879 300.104951,6537.68821 299.696945,6537.29347 L291.802968,6529.67648 C291.398069,6529.28574 291.398069,6528.65315 291.802968,6528.26241 L299.633777,6520.70538 C300.038676,6520.31563 300.038676,6519.68305 299.633777,6519.29231" + id="arrow_left-[#335]" + ></path> + </g> + </g> + </g> + </svg> +</template> + +<style scoped></style> -- GitLab