From 7e6482055b1a44fb9c4d790faba3fd991a2c5c5d 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: Thu, 12 Dec 2024 18:14:22 +0500 Subject: [PATCH] feat: finished - Button, ToggleButton, ToggleSwitch --- README.md | 2 + index.html | 2 +- public/favicon.ico | Bin 4286 -> 0 bytes src/App.vue | 22 ++- src/assets/main.css | 1 - src/common/constants/icons.ts | 136 ++++++++--------- src/common/interfaces/components.ts | 9 ++ .../components/Button/Button.stories.ts | 108 ++++++++++++++ src/stories/components/Button/Button.vue | 58 ++++---- .../components/Divider/Divider.stories.ts | 7 + src/stories/components/Divider/divider.css | 0 .../components/Drawer/Drawer.stories.ts | 17 ++- src/stories/components/Drawer/Drawer.vue | 1 + .../ToggleButton/ToggleButton.stories.ts | 118 +++++++++++++++ .../components/ToggleButton/ToggleButton.vue | 137 +++++++++--------- .../ToggleSwitch/ToggleSwitch.stories.ts | 11 +- .../components/ToggleSwitch/ToggleSwitch.vue | 57 ++++---- .../components/TreeList/TreeList.stories.ts | 88 +++++++++++ src/stories/components/TreeList/TreeList.vue | 122 +++++++++------- src/stories/icons/Mono/TriangleIcon.vue | 26 ++++ tsconfig.app.json | 2 +- 21 files changed, 671 insertions(+), 253 deletions(-) delete mode 100644 public/favicon.ico create mode 100644 src/common/interfaces/components.ts create mode 100644 src/stories/components/Button/Button.stories.ts delete mode 100644 src/stories/components/Divider/divider.css create mode 100644 src/stories/components/ToggleButton/ToggleButton.stories.ts create mode 100644 src/stories/components/TreeList/TreeList.stories.ts create mode 100644 src/stories/icons/Mono/TriangleIcon.vue diff --git a/README.md b/README.md index 5b1dc0d..08054c7 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ - TreeList; - Drawer; - Button; +- ToggleButton; +- ToggleSwitch; - Divider; ### ÐаÑтройка Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ diff --git a/index.html b/index.html index 7f488bd..0ab5bb4 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ <html lang=""> <head> <meta charset="UTF-8"> - <link rel="icon" href="/favicon.ico"> + <link rel="icon" href="/storybook.ico"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>UI Storybook</title> </head> diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index df36fcfb72584e00488330b560ebcf34a41c64c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kev<ISBgE$F{SFy+(=9Z)f)De0Se}ZDZW}Z3B zElCeVrw;K0Fdl_Cg=gZOFXXc3pL)Q05CAuT+XucQ<8g~3dteP~|7s7c6QYP;fy;mF zMN;>tV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?<QnEgvj4i?s}Yk=qA2z`-^*<eK3c)MS4JOdbsTQEOa0) z0NWqlna2rzs>5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7<X*Er!BfRbvU93$DH%#v6dRt^6HBxz1xBNHx=$&_Gv<&J}Ljk zJN<Fzx(`Oe@KgQ0F$<14=XV#WK`o#6Ku>z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{T<?%b6i9IjI)Ls)S{-*mq<@~R{?$}ZKjf;^k75i_}(2MXt}^SEBVg7AI@28 zo_uPg2V)_e-`2Ois=PYoe%9u*n9({PFR)OnHJPi{dNx>Kx<YG`4QQ>D#iCLfl2<BD h7L=-;Q>vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S diff --git a/src/App.vue b/src/App.vue index c946895..498670c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -103,6 +103,9 @@ import TableIcon from '@stories/icons/Mono/TableIcon.vue'; import TrashIcon from '@stories/icons/Mono/TrashIcon.vue'; import UserIcon from '@stories/icons/Mono/UserIcon.vue'; import ArrowsVerticalIcon from '@stories/icons/Mono/ArrowsVerticalIcon.vue'; +import ToggleButton from '@stories/components/ToggleButton/ToggleButton.vue'; +import ToggleSwitch from '@stories/components/ToggleSwitch/ToggleSwitch.vue'; +import TriangleIcon from '@stories/icons/Mono/TriangleIcon.vue'; const gentleIcons = [ Age18Icon, @@ -206,12 +209,29 @@ const gentleIcons = [ SettingsIcon, TableIcon, TrashIcon, + TriangleIcon, UserIcon, ]; const visibleDrawer = ref(true); +const options = [ + { + label: 'First', + textStyle: 'bold', + iconPosition: 'top', + }, + { + label: 'Second', + }, +]; </script> <template> + <ToggleButton :options="options" size="large"> + <template #1Icon> + <TrashIcon /> + </template> + </ToggleButton> + <ToggleSwitch /> <Drawer v-model:visible="visibleDrawer" theme="sky" closeIcon="CropIcon"> <template #header>Ðто - Drawer</template> <p> @@ -286,7 +306,7 @@ const visibleDrawer = ref(true); .testButton { position: absolute; right: 50px; - bottom: 50px; + top: 50px; background-color: red; color: white; padding: 10px; diff --git a/src/assets/main.css b/src/assets/main.css index f5f937c..940084e 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -171,7 +171,6 @@ body { *::before, *::after { box-sizing: border-box; - user-select: none; font-weight: 500; } diff --git a/src/common/constants/icons.ts b/src/common/constants/icons.ts index 3762015..892a811 100644 --- a/src/common/constants/icons.ts +++ b/src/common/constants/icons.ts @@ -35,73 +35,74 @@ import ChartPieIcon from '@stories/icons/Mono/ChartPieIcon.vue'; import ChatIcon from '@stories/icons/Mono/ChatIcon.vue'; import CrossCircleIcon from '@stories/icons/Mono/CrossCircleIcon.vue'; import CropIcon from '@stories/icons/Mono/CropIcon.vue'; -import ChatWritingIcon from '@stories/icons/Mono/ChatWritingIcon.vue' -import CheckmarkIcon from '@stories/icons/Mono/CheckmarkIcon.vue' -import ChemistryFlaskIcon from '@stories/icons/Mono/ChemistryFlaskIcon.vue' -import CodeIcon from '@stories/icons/Mono/CodeIcon.vue' -import CoinsIcon from '@stories/icons/Mono/CoinsIcon.vue' -import ColorPaletteIcon from '@stories/icons/Mono/ColorPaletteIcon.vue' -import CompassIcon from '@stories/icons/Mono/CompassIcon.vue' -import ConstructionWorkerIcon from '@stories/icons/Mono/ConstructionWorkerIcon.vue' -import ContactsIcon from '@stories/icons/Mono/ContactsIcon.vue' -import CrossIcon from '@stories/icons/Mono/CrossIcon.vue' -import CubeIcon from '@stories/icons/Mono/CubeIcon.vue' -import CupIcon from '@stories/icons/Mono/CupIcon.vue' -import CursorIcon from '@stories/icons/Mono/CursorIcon.vue' -import DiamondIcon from '@stories/icons/Mono/DiamondIcon.vue' -import DiaryIcon from '@stories/icons/Mono/DiaryIcon.vue' -import DiceIcon from '@stories/icons/Mono/DiceIcon.vue' -import DigIcon from '@stories/icons/Mono/DigIcon.vue' -import DislikeIcon from '@stories/icons/Mono/DislikeIcon.vue' -import DisplayIcon from '@stories/icons/Mono/DisplayIcon.vue' -import DocumentIcon from '@stories/icons/Mono/DocumentIcon.vue' -import DocumentAddIcon from '@stories/icons/Mono/DocumentAddIcon.vue' -import DocumentDeleteIcon from '@stories/icons/Mono/DocumentDeleteIcon.vue' -import DocumentEditIcon from '@stories/icons/Mono/DocumentEditIcon.vue' -import DollarIcon from '@stories/icons/Mono/DollarIcon.vue' -import DotsHorizontalIcon from '@stories/icons/Mono/DotsHorizontalIcon.vue' -import DotsVerticalIcon from '@stories/icons/Mono/DotsVerticalIcon.vue' -import DownloadIcon from '@stories/icons/Mono/DownloadIcon.vue' -import DropIcon from '@stories/icons/Mono/DropIcon.vue' -import DumbbelIcon from '@stories/icons/Mono/DumbbelIcon.vue' -import EarthIcon from '@stories/icons/Mono/EarthIcon.vue' -import EditIcon from '@stories/icons/Mono/EditIcon.vue' -import EncyclopediaIcon from '@stories/icons/Mono/EncyclopediaIcon.vue' -import ExitIcon from '@stories/icons/Mono/ExitIcon.vue' -import EyeIcon from '@stories/icons/Mono/EyeIcon.vue' -import FeedbackIcon from '@stories/icons/Mono/FeedbackIcon.vue' -import FilterIcon from '@stories/icons/Mono/FilterIcon.vue' -import FingerprintIcon from '@stories/icons/Mono/FingerprintIcon.vue' -import FireIcon from '@stories/icons/Mono/FireIcon.vue' -import FlagIcon from '@stories/icons/Mono/FlagIcon.vue' -import FlashIcon from '@stories/icons/Mono/FlashIcon.vue' -import FlashlightIcon from '@stories/icons/Mono/FlashlightIcon.vue' -import FolderLockIcon from '@stories/icons/Mono/FolderLockIcon.vue' -import FrameIcon from '@stories/icons/Mono/FrameIcon.vue' -import FullScreenIcon from '@stories/icons/Mono/FullScreenIcon.vue' -import GameControllerIcon from '@stories/icons/Mono/GameControllerIcon.vue' -import GiftIcon from '@stories/icons/Mono/GiftIcon.vue' -import GlassesIcon from '@stories/icons/Mono/GlassesIcon.vue' -import HamburgerIcon from '@stories/icons/Mono/HamburgerIcon.vue' -import HandIcon from '@stories/icons/Mono/HandIcon.vue' -import HomeIcon from '@stories/icons/Mono/HomeIcon.vue' -import ImageIcon from '@stories/icons/Mono/ImageIcon.vue' -import ImageEditIcon from '@stories/icons/Mono/ImageEditIcon.vue' -import LineIcon from '@stories/icons/Mono/LineIcon.vue' -import LineDashedIcon from '@stories/icons/Mono/LineDashedIcon.vue' -import LineDottedIcon from '@stories/icons/Mono/LineDottedIcon.vue' -import LineDiagonalIcon from '@stories/icons/Mono/LineDiagonalIcon.vue' -import MoveIcon from '@stories/icons/Mono/MoveIcon.vue' -import ParagraphIcon from '@stories/icons/Mono/ParagraphIcon.vue' -import PhoneHandsetIcon from '@stories/icons/Mono/PhoneHandsetIcon.vue' -import PlusCircleIcon from '@stories/icons/Mono/PlusCircleIcon.vue' -import PlusIcon from '@stories/icons/Mono/PlusIcon.vue' -import PointerIcon from '@stories/icons/Mono/PointerIcon.vue' -import SaveIcon from '@stories/icons/Mono/SaveIcon.vue' -import SettingsIcon from '@stories/icons/Mono/SettingsIcon.vue' -import TableIcon from '@stories/icons/Mono/TableIcon.vue' -import TrashIcon from '@stories/icons/Mono/TrashIcon.vue' -import UserIcon from '@stories/icons/Mono/UserIcon.vue' +import ChatWritingIcon from '@stories/icons/Mono/ChatWritingIcon.vue'; +import CheckmarkIcon from '@stories/icons/Mono/CheckmarkIcon.vue'; +import ChemistryFlaskIcon from '@stories/icons/Mono/ChemistryFlaskIcon.vue'; +import CodeIcon from '@stories/icons/Mono/CodeIcon.vue'; +import CoinsIcon from '@stories/icons/Mono/CoinsIcon.vue'; +import ColorPaletteIcon from '@stories/icons/Mono/ColorPaletteIcon.vue'; +import CompassIcon from '@stories/icons/Mono/CompassIcon.vue'; +import ConstructionWorkerIcon from '@stories/icons/Mono/ConstructionWorkerIcon.vue'; +import ContactsIcon from '@stories/icons/Mono/ContactsIcon.vue'; +import CrossIcon from '@stories/icons/Mono/CrossIcon.vue'; +import CubeIcon from '@stories/icons/Mono/CubeIcon.vue'; +import CupIcon from '@stories/icons/Mono/CupIcon.vue'; +import CursorIcon from '@stories/icons/Mono/CursorIcon.vue'; +import DiamondIcon from '@stories/icons/Mono/DiamondIcon.vue'; +import DiaryIcon from '@stories/icons/Mono/DiaryIcon.vue'; +import DiceIcon from '@stories/icons/Mono/DiceIcon.vue'; +import DigIcon from '@stories/icons/Mono/DigIcon.vue'; +import DislikeIcon from '@stories/icons/Mono/DislikeIcon.vue'; +import DisplayIcon from '@stories/icons/Mono/DisplayIcon.vue'; +import DocumentIcon from '@stories/icons/Mono/DocumentIcon.vue'; +import DocumentAddIcon from '@stories/icons/Mono/DocumentAddIcon.vue'; +import DocumentDeleteIcon from '@stories/icons/Mono/DocumentDeleteIcon.vue'; +import DocumentEditIcon from '@stories/icons/Mono/DocumentEditIcon.vue'; +import DollarIcon from '@stories/icons/Mono/DollarIcon.vue'; +import DotsHorizontalIcon from '@stories/icons/Mono/DotsHorizontalIcon.vue'; +import DotsVerticalIcon from '@stories/icons/Mono/DotsVerticalIcon.vue'; +import DownloadIcon from '@stories/icons/Mono/DownloadIcon.vue'; +import DropIcon from '@stories/icons/Mono/DropIcon.vue'; +import DumbbelIcon from '@stories/icons/Mono/DumbbelIcon.vue'; +import EarthIcon from '@stories/icons/Mono/EarthIcon.vue'; +import EditIcon from '@stories/icons/Mono/EditIcon.vue'; +import EncyclopediaIcon from '@stories/icons/Mono/EncyclopediaIcon.vue'; +import ExitIcon from '@stories/icons/Mono/ExitIcon.vue'; +import EyeIcon from '@stories/icons/Mono/EyeIcon.vue'; +import FeedbackIcon from '@stories/icons/Mono/FeedbackIcon.vue'; +import FilterIcon from '@stories/icons/Mono/FilterIcon.vue'; +import FingerprintIcon from '@stories/icons/Mono/FingerprintIcon.vue'; +import FireIcon from '@stories/icons/Mono/FireIcon.vue'; +import FlagIcon from '@stories/icons/Mono/FlagIcon.vue'; +import FlashIcon from '@stories/icons/Mono/FlashIcon.vue'; +import FlashlightIcon from '@stories/icons/Mono/FlashlightIcon.vue'; +import FolderLockIcon from '@stories/icons/Mono/FolderLockIcon.vue'; +import FrameIcon from '@stories/icons/Mono/FrameIcon.vue'; +import FullScreenIcon from '@stories/icons/Mono/FullScreenIcon.vue'; +import GameControllerIcon from '@stories/icons/Mono/GameControllerIcon.vue'; +import GiftIcon from '@stories/icons/Mono/GiftIcon.vue'; +import GlassesIcon from '@stories/icons/Mono/GlassesIcon.vue'; +import HamburgerIcon from '@stories/icons/Mono/HamburgerIcon.vue'; +import HandIcon from '@stories/icons/Mono/HandIcon.vue'; +import HomeIcon from '@stories/icons/Mono/HomeIcon.vue'; +import ImageIcon from '@stories/icons/Mono/ImageIcon.vue'; +import ImageEditIcon from '@stories/icons/Mono/ImageEditIcon.vue'; +import LineIcon from '@stories/icons/Mono/LineIcon.vue'; +import LineDashedIcon from '@stories/icons/Mono/LineDashedIcon.vue'; +import LineDottedIcon from '@stories/icons/Mono/LineDottedIcon.vue'; +import LineDiagonalIcon from '@stories/icons/Mono/LineDiagonalIcon.vue'; +import MoveIcon from '@stories/icons/Mono/MoveIcon.vue'; +import ParagraphIcon from '@stories/icons/Mono/ParagraphIcon.vue'; +import PhoneHandsetIcon from '@stories/icons/Mono/PhoneHandsetIcon.vue'; +import PlusCircleIcon from '@stories/icons/Mono/PlusCircleIcon.vue'; +import PlusIcon from '@stories/icons/Mono/PlusIcon.vue'; +import PointerIcon from '@stories/icons/Mono/PointerIcon.vue'; +import SaveIcon from '@stories/icons/Mono/SaveIcon.vue'; +import SettingsIcon from '@stories/icons/Mono/SettingsIcon.vue'; +import TableIcon from '@stories/icons/Mono/TableIcon.vue'; +import TrashIcon from '@stories/icons/Mono/TrashIcon.vue'; +import UserIcon from '@stories/icons/Mono/UserIcon.vue'; +import TriangleIcon from '@stories/icons/Mono/TriangleIcon.vue'; export const iconsSet: Record<string, Component> = { Age18Icon: Age18Icon, @@ -205,5 +206,6 @@ export const iconsSet: Record<string, Component> = { SettingsIcon: SettingsIcon, TableIcon: TableIcon, TrashIcon: TrashIcon, + TriangleIcon: TriangleIcon, UserIcon: UserIcon, }; diff --git a/src/common/interfaces/components.ts b/src/common/interfaces/components.ts new file mode 100644 index 0000000..8f276af --- /dev/null +++ b/src/common/interfaces/components.ts @@ -0,0 +1,9 @@ +export interface ITreeItem { + label: string; + link?: string; + color?: string; + iconBefore?: string; + iconAfter?: string; + iconColor?: string; + children?: ITreeItem[]; +} diff --git a/src/stories/components/Button/Button.stories.ts b/src/stories/components/Button/Button.stories.ts new file mode 100644 index 0000000..9d64adc --- /dev/null +++ b/src/stories/components/Button/Button.stories.ts @@ -0,0 +1,108 @@ +import type { Meta, StoryObj } from '@storybook/vue3'; + +import Button from './Button.vue'; + +const meta: Meta = { + title: 'Components/Button', + component: Button, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: 'A component that is used to select a value from a list using a button.', + }, + }, + }, + argTypes: { + label: { control: 'text' }, + size: { control: 'select', options: ['small', 'medium', 'large', 'huge'] }, + textStyle: { control: 'select', options: ['bold', 'italic'] }, + iconPos: { control: 'select', options: ['left', 'top', 'right', 'bottom'] }, + width: { control: 'text' }, + theme: { + control: 'select', + options: [ + 'white', + 'slate', + 'blue', + 'sky', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + textColor: { + control: 'select', + options: [ + 'white', + 'slate', + 'blue', + 'sky', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + border: { + control: 'select', + options: [ + 'white', + 'slate', + 'blue', + 'sky', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + }, + args: { + // primary: false, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + }, +} satisfies Meta<typeof Button>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Primary: Story = { + args: {}, +}; + +export const LargeFull: Story = { + args: { + label: 'Press me!', + size: 'large', + textStyle: 'bold', + iconPos: 'left', + width: '200', + theme: 'sky', + textColor: 'white', + border: 'black', + }, +}; diff --git a/src/stories/components/Button/Button.vue b/src/stories/components/Button/Button.vue index 807a9dc..63b95ba 100644 --- a/src/stories/components/Button/Button.vue +++ b/src/stories/components/Button/Button.vue @@ -1,28 +1,30 @@ <script setup lang="ts"> import { computed } from 'vue'; -import { convertThemeToColorBlackDefault, convertThemeToColorWhiteDefault } from './helpers/index'; -import type { TThemeColor } from './interfaces/index'; +import type { TThemeColor } from '@interfaces/common'; +import { convert500ThemeToColor } from '@helpers/colors'; -interface Props { - label?: string; - iconPos?: 'left' | 'top' | 'right' | 'bottom'; - textStyle?: 'bold' | 'italic'; - border?: TThemeColor; - size?: 'small' | 'medium' | 'large' | 'extraLarge'; - textColor?: TThemeColor; - theme?: TThemeColor; - width?: string | number; -} -const props = withDefaults(defineProps<Props>(), { - iconPos: 'left' -}); -const themeColor = computed(() => convertThemeToColorWhiteDefault(props.theme)); -const textColor = computed(() => convertThemeToColorBlackDefault(props.textColor)); -const borderColor = computed(() => - props.border ? convertThemeToColorBlackDefault(props.border) : '' +const props = withDefaults( + defineProps<{ + label?: string; + size?: 'small' | 'medium' | 'large' | 'extraLarge'; + textStyle?: 'bold' | 'italic'; + iconPos?: 'left' | 'top' | 'right' | 'bottom'; + width?: string | number; + theme?: TThemeColor; + textColor?: TThemeColor; + border?: TThemeColor; + }>(), + { + size: 'medium', + theme: 'white', + textColor: 'black', + iconPos: 'left', + }, ); +const themeColor = computed(() => convert500ThemeToColor(props.theme)); +const textColor = computed(() => convert500ThemeToColor(props.textColor)); +const borderColor = computed(() => (props.border ? convert500ThemeToColor(props.border) : '')); const textSize = computed(() => { - if (!props?.size || props.size === 'medium') return '16px'; switch (props.size) { case 'small': return '12px'; @@ -31,9 +33,9 @@ const textSize = computed(() => { case 'extraLarge': return '24px'; } + return '16px'; }); const buttonPadding = computed(() => { - if (!props?.size || props.size === 'medium') return '0.75rem 0.5rem'; switch (props.size) { case 'small': return '0.5rem 0.375rem'; @@ -42,6 +44,7 @@ const buttonPadding = computed(() => { case 'extraLarge': return '1.8rem 1.2rem'; } + return '0.75rem 0.5rem'; }); const width = computed(() => (props.width ? `${props.width}px` : 'max-content')); </script> @@ -52,8 +55,8 @@ const width = computed(() => (props.width ? `${props.width}px` : 'max-content')) 'button', { 'flex-column': iconPos === 'top' || iconPos === 'bottom', - border: borderColor - } + border: borderColor, + }, ]" :style="`padding: ${buttonPadding}; width: ${width}`" > @@ -64,17 +67,18 @@ const width = computed(() => (props.width ? `${props.width}px` : 'max-content')) 'text', { bold: textStyle === 'bold', - italic: textStyle === 'italic' - } + italic: textStyle === 'italic', + }, ]" >{{ label ?? 'Button' }}</span > <span + v-if="$slots.default" :class="[ 'icon', { - 'order-1': iconPos === 'left' || iconPos === 'top' - } + 'order-1': iconPos === 'left' || iconPos === 'top', + }, ]" > <slot /> diff --git a/src/stories/components/Divider/Divider.stories.ts b/src/stories/components/Divider/Divider.stories.ts index aa8f212..86b93fd 100644 --- a/src/stories/components/Divider/Divider.stories.ts +++ b/src/stories/components/Divider/Divider.stories.ts @@ -6,6 +6,13 @@ const meta: Meta = { title: 'Components/Divider', component: Divider, tags: ['autodocs'], + parameters: { + docs: { + description: { + component: 'A component that is used to separate content.', + }, + }, + }, argTypes: { height: { control: 'number' }, type: { control: 'select', options: ['solid', 'dashed', 'dotted'] }, diff --git a/src/stories/components/Divider/divider.css b/src/stories/components/Divider/divider.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/stories/components/Drawer/Drawer.stories.ts b/src/stories/components/Drawer/Drawer.stories.ts index 458c58e..f29ee2c 100644 --- a/src/stories/components/Drawer/Drawer.stories.ts +++ b/src/stories/components/Drawer/Drawer.stories.ts @@ -2,11 +2,19 @@ import type { Meta, StoryObj } from '@storybook/vue3'; import Drawer from './Drawer.vue'; import { iconsSet } from '@/common/constants/icons'; +import { fn } from '@storybook/test'; const meta: Meta = { title: 'Components/Drawer', component: Drawer, tags: ['autodocs'], + parameters: { + docs: { + description: { + component: 'A component that displayed as an overlay. Can be used as a sidebar or tooltip.', + }, + }, + }, argTypes: { visible: { control: 'boolean' }, position: { control: 'select', options: ['left', 'right', 'top', 'bottom'] }, @@ -43,7 +51,7 @@ const meta: Meta = { args: { // primary: false, // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args - // onClick: fn(), + onClose: fn(), }, } satisfies Meta<typeof Drawer>; @@ -66,12 +74,13 @@ export const BlackFull: Story = { closeIcon: 'CrossIcon', header: 'Drawer', footer: 'The end.', - isHeaderDivider: true, - isFooterDivider: true, + headerDivider: true, + footerDivider: true, default: ' Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto dicta dolorum eaque explicabo illo. Beatae et eveniet itaque libero sint. Atque blanditiis consequuntur dolorum explicabo, facilis iste nulla numquam provident.', - isModal: true, + modal: false, + dismissible: false, }, }; diff --git a/src/stories/components/Drawer/Drawer.vue b/src/stories/components/Drawer/Drawer.vue index 6f5d31c..bddd900 100644 --- a/src/stories/components/Drawer/Drawer.vue +++ b/src/stories/components/Drawer/Drawer.vue @@ -155,6 +155,7 @@ const drawerWidth = computed(() => { font-size: 32px; width: calc(100% - 30px); margin-bottom: 10px; + min-height: 37px; height: 37px; overflow: auto; } diff --git a/src/stories/components/ToggleButton/ToggleButton.stories.ts b/src/stories/components/ToggleButton/ToggleButton.stories.ts new file mode 100644 index 0000000..64c15f2 --- /dev/null +++ b/src/stories/components/ToggleButton/ToggleButton.stories.ts @@ -0,0 +1,118 @@ +import type { Meta, StoryObj } from '@storybook/vue3'; + +import ToggleButton from './ToggleButton.vue'; +import { fn } from '@storybook/test'; + +const meta: Meta = { + title: 'Components/ToggleButton', + component: ToggleButton, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: 'A component that is used to select a value from a list using a button.', + }, + }, + }, + argTypes: { + options: { + control: 'array', + }, + size: { control: 'select', options: ['small', 'medium', 'large', 'huge'] }, + rounded: { control: 'boolean' }, + activeBgColor: { + control: 'select', + options: [ + 'white', + 'slate', + 'blue', + 'sky', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + border: { + control: 'select', + options: [ + 'white', + 'slate', + 'blue', + 'sky', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + disabled: { control: 'boolean' }, + }, + args: { + // primary: false, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + onClick: fn(), + }, +} satisfies Meta<typeof ToggleButton>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Primary: Story = { + args: { + options: [ + { + label: 'First', + }, + { + label: 'Second', + }, + ], + + rounded: false, + disabled: false, + }, +}; + +export const LargeFull: Story = { + args: { + options: [ + { + label: 'First', + color: 'white', + backgroundColor: 'black', + }, + { + label: 'Second', + activeColor: 'blue', + backgroundColor: 'yellow', + }, + { + label: 'Third', + activeColor: 'green', + backgroundColor: 'purple', + }, + ], + + border: 'sky', + activeBgColor: 'red', + rounded: true, + disabled: false, + size: 'large', + }, +}; diff --git a/src/stories/components/ToggleButton/ToggleButton.vue b/src/stories/components/ToggleButton/ToggleButton.vue index 14a0f36..4367a1c 100644 --- a/src/stories/components/ToggleButton/ToggleButton.vue +++ b/src/stories/components/ToggleButton/ToggleButton.vue @@ -1,81 +1,71 @@ <script setup lang="ts"> import { computed } from 'vue'; -import { convertThemeToColorBlackDefault, convertThemeToColorWhiteDefault } from './helpers/index'; -import { useVModel } from '@vueuse/core'; -type TTheme = - | 'white' - | 'slate' - | 'blue' - | 'sky' - | 'teal' - | 'lime' - | 'green' - | 'yellow' - | 'orange' - | 'pink' - | 'fuchsia' - | 'purple' - | 'indigo' - | 'rose' - | 'red' - | 'black'; -interface Props { - value: any; - options: { - label: string; - value?: any; - textColor?: TTheme; - backgroundColor?: TTheme; - isLabelHidden?: boolean; - iconPos?: string; - textStyle?: 'bold' | 'italic'; - }[]; - border?: TTheme; - size?: 'small' | 'medium' | 'large' | 'extraLarge'; - theme?: TTheme; - rounded?: any; -} -const props = defineProps<Props>(); -const emit = defineEmits(['update:value']); -const value = useVModel(props, 'value', emit); -const activeBGColor = computed(() => - props.theme ? convertThemeToColorBlackDefault(props.theme) : '' +import type { TThemeColor } from '@interfaces/common'; +import { convert500ThemeToColor } from '@helpers/colors'; + +const props = withDefaults( + defineProps<{ + options: { + label: string; + value?: never; + color?: TThemeColor; + activeColor?: TThemeColor; + backgroundColor?: TThemeColor; + isLabelHidden?: boolean; + iconPosition?: 'left' | 'right' | 'top' | 'bottom'; + textStyle?: 'bold' | 'italic'; + }[]; + size?: 'small' | 'medium' | 'large' | 'huge'; + rounded?: boolean; + activeBgColor?: TThemeColor; + border?: TThemeColor; + disabled?: boolean; + }>(), + { + size: 'medium', + border: 'black', + activeBgColor: 'sky', + }, ); -const borderColor = computed(() => - props.border ? convertThemeToColorBlackDefault(props.border) : '' +const emit = defineEmits(['onClick']); +const value = defineModel<boolean>('value'); + +const activeBgColor = computed(() => + props.activeBgColor ? convert500ThemeToColor(props.activeBgColor) : '', ); +const borderColor = computed(() => (props.border ? convert500ThemeToColor(props.border) : '')); const textSize = computed(() => { - if (!props?.size || props.size === 'medium') return '16px'; switch (props.size) { case 'small': return '12px'; case 'large': return '20px'; - case 'extraLarge': + case 'huge': return '24px'; } + return '16px'; }); const buttonPadding = computed(() => { - if (!props?.size || props.size === 'medium') return '0.75rem 0.5rem'; switch (props.size) { case 'small': return '0.5rem 0.375rem'; case 'large': return '1.2rem 0.8rem'; - case 'extraLarge': + case 'huge': return '1.8rem 1.2rem'; } + return '0.75rem 0.5rem'; }); const buttonHeight = computed(() => { - if (!props?.size || props.size === 'medium') return '40px'; switch (props.size) { case 'small': return '24px'; case 'large': return '68px'; - case 'extraLarge': + case 'huge': return '114px'; } + return '40px'; }); </script> @@ -85,8 +75,9 @@ const buttonHeight = computed(() => { 'buttonGroup', { 'rounded-full': props.rounded, - border: borderColor - } + border: borderColor, + disabled: disabled, + }, ]" > <button @@ -95,53 +86,60 @@ const buttonHeight = computed(() => { :class="[ 'button', { - 'flex-column': item.iconPos === 'top' || item.iconPos === 'bottom' - } + 'flex-column': item.iconPosition === 'top' || item.iconPosition === 'bottom', + }, ]" :style="`padding: ${buttonPadding}`" - @click.prevent="value = item?.value ?? item.label" + @click.prevent=" + () => { + value = item?.value ?? item.label; + emit('onClick', value); + } + " > <span - :style="`background-color: ${activeBGColor && (value === item.value || value === item.label) ? activeBGColor : convertThemeToColorWhiteDefault(item.backgroundColor)}`" + :style="`background-color: ${activeBgColor && (value === item.value || value === item.label) ? activeBgColor : convert500ThemeToColor(item.backgroundColor ?? 'white')}`" :class="[ 'background', { 'rounded-left': index === 0, 'rounded-left-full': index === 0 && props.rounded, 'rounded-right': index === options.length - 1, - 'rounded-right-full': index === options.length - 1 && props.rounded - } + 'rounded-right-full': index === options.length - 1 && props.rounded, + }, ]" ></span> <span v-if="!item.isLabelHidden" - :style="`color: ${convertThemeToColorBlackDefault(item.textColor)}; font-size: ${textSize}`" + :style="`color: ${value === item.value || value === item.label ? item.activeColor : convert500ThemeToColor(item.color ?? 'black')}; font-size: ${textSize}`" :class="[ 'text', { bold: item.textStyle === 'bold', - italic: item.textStyle === 'italic' - } + italic: item.textStyle === 'italic', + }, ]" - >{{ item.label ?? 'Button' }}</span + >{{ item.label ?? index }}</span > - <slot + <div :class="[ 'icon', { - 'order-1': item.iconPos === 'left' || item.iconPos === 'top' - } + 'order-1': item.iconPosition === 'left' || item.iconPosition === 'top', + }, ]" - :name="`${index + 1}Icon`" - /> + > + <slot :name="`${index + 1}Icon`" /> + </div> </button> </div> </template> <style scoped> .buttonGroup { + width: max-content; display: flex; - border-radius: 0.5rem; + border-radius: 0.75rem; position: relative; } .button { @@ -198,4 +196,11 @@ const buttonHeight = computed(() => { .rounded-full { border-radius: v-bind(buttonHeight); } +.disabled { + pointer-events: none; + background-color: #e1e7f1; +} +.disabled * { + color: #62708c !important; +} </style> diff --git a/src/stories/components/ToggleSwitch/ToggleSwitch.stories.ts b/src/stories/components/ToggleSwitch/ToggleSwitch.stories.ts index bd37919..4083f33 100644 --- a/src/stories/components/ToggleSwitch/ToggleSwitch.stories.ts +++ b/src/stories/components/ToggleSwitch/ToggleSwitch.stories.ts @@ -6,7 +6,15 @@ const meta: Meta = { title: 'Components/ToggleSwitch', component: ToggleSwitch, tags: ['autodocs'], + parameters: { + docs: { + description: { + component: 'A component that is used to select a boolean value.', + }, + }, + }, argTypes: { + active: { control: 'boolean' }, size: { control: 'select', options: ['small', 'medium', 'large', 'huge'] }, negativeTheme: { control: 'select', @@ -49,11 +57,11 @@ const meta: Meta = { ], }, darkNegative: { control: 'boolean' }, + disabled: { control: 'boolean' }, }, args: { // primary: false, // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args - // onClick: fn(), }, } satisfies Meta<typeof ToggleSwitch>; @@ -64,6 +72,7 @@ type Story = StoryObj<typeof meta>; export const Primary: Story = { args: { darkNegative: true, + active: false, }, }; diff --git a/src/stories/components/ToggleSwitch/ToggleSwitch.vue b/src/stories/components/ToggleSwitch/ToggleSwitch.vue index 38e6483..c91b9bc 100644 --- a/src/stories/components/ToggleSwitch/ToggleSwitch.vue +++ b/src/stories/components/ToggleSwitch/ToggleSwitch.vue @@ -9,6 +9,7 @@ const props = withDefaults( theme?: TThemeColorNoWhite; negativeTheme?: TThemeColor; darkNegative?: boolean; + disabled?: boolean; }>(), { size: 'medium', @@ -28,32 +29,32 @@ const inactiveColor = computed(() => const sizes = computed(() => { if (!props?.size) { return { - containerWidth: 45, - containerHeight: 27, - padding: 4, - borderRadius: 14, - circleSize: 19, - transformXCircle: 18, + containerWidth: 37, + containerHeight: 21, + padding: 3, + borderRadius: 11, + circleSize: 15, + transformXCircle: 16, }; } switch (props.size) { case 'small': return { - containerWidth: 35, - containerHeight: 21, + containerWidth: 28, + containerHeight: 16, padding: 3, - borderRadius: 11, - circleSize: 15, - transformXCircle: 14, + borderRadius: 8, + circleSize: 10, + transformXCircle: 12, }; case 'large': return { - containerWidth: 55, - containerHeight: 33, + containerWidth: 45, + containerHeight: 27, padding: 4, - borderRadius: 17, - circleSize: 25, - transformXCircle: 22, + borderRadius: 14, + circleSize: 19, + transformXCircle: 18, }; case 'huge': return { @@ -66,33 +67,33 @@ const sizes = computed(() => { }; } return { - containerWidth: 45, - containerHeight: 27, - padding: 4, - borderRadius: 14, - circleSize: 19, - transformXCircle: 18, + containerWidth: 37, + containerHeight: 21, + padding: 3, + borderRadius: 11, + circleSize: 15, + transformXCircle: 16, }; }); </script> <template> <button - :style="`width: ${sizes.containerWidth}px; min-height: ${sizes.containerHeight}px; border-radius: ${sizes.borderRadius}px; padding: ${sizes.padding}px;`" + :style="`width: ${sizes.containerWidth}px; min-height: ${sizes.containerHeight}px; border-radius: ${sizes.borderRadius}px; padding: ${sizes.padding}px; cursor: ${disabled ? 'auto' : 'pointer'}`" class="switcher" - @click.prevent="active = !active" + @click.prevent="!disabled && (active = !active)" > <span - :style="`background-color: ${themeColor}; border-radius: ${sizes.borderRadius}px;`" + :style="`background-color: ${disabled ? '#e1e7f1 !important' : themeColor}; border-radius: ${sizes.borderRadius}px;`" :class="[ 'activeBackground', { - inactiveBackground: !active, + inactiveBackground: !active && !disabled, }, ]" ></span> <span - :style="`width: ${sizes.circleSize}px; height: ${sizes.circleSize}px; transform: translateX(${active ? sizes.transformXCircle : 0}px);`" + :style="`width: ${sizes.circleSize}px; height: ${sizes.circleSize}px; transform: translateX(${active ? sizes.transformXCircle : 0}px); background-color: ${disabled ? '#62708c' : 'white'}`" class="switcherCircle" ></span> </button> @@ -101,7 +102,6 @@ const sizes = computed(() => { <style scoped> .switcher { position: relative; - cursor: pointer; } .activeBackground { display: block; @@ -121,7 +121,6 @@ const sizes = computed(() => { } .switcherCircle { display: block; - background-color: white; border-radius: 50%; transition: transform 0.2s ease-in-out; } diff --git a/src/stories/components/TreeList/TreeList.stories.ts b/src/stories/components/TreeList/TreeList.stories.ts new file mode 100644 index 0000000..9a0d9e4 --- /dev/null +++ b/src/stories/components/TreeList/TreeList.stories.ts @@ -0,0 +1,88 @@ +import type { Meta, StoryObj } from '@storybook/vue3'; + +import TreeList from './TreeList.vue'; + +const meta: Meta = { + title: 'Components/TreeList', + component: TreeList, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: 'A component that is used to select a value from a list using a TreeList.', + }, + }, + }, + argTypes: { + items: { control: 'array' }, + maxWidth: { control: 'number' }, + expand: { control: 'boolean' }, + disabled: { control: 'boolean' }, + theme: { + control: 'select', + options: [ + 'white', + 'slate', + 'blue', + 'sky', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + }, + args: { + // primary: false, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + }, +} satisfies Meta<typeof TreeList>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Primary: Story = { + args: { + items: [ + { + label: 'First', + children: [ + { + label: '1-1', + children: [ + { + label: '1-1-1', + }, + { + label: '1-1-2', + }, + ], + }, + { + label: '1-2', + }, + ], + }, + { + label: 'Second', + children: [ + { + label: '2-1', + }, + ], + }, + ], + }, +}; + +export const Full: Story = { + args: {}, +}; diff --git a/src/stories/components/TreeList/TreeList.vue b/src/stories/components/TreeList/TreeList.vue index 3a4ce92..bc6f912 100644 --- a/src/stories/components/TreeList/TreeList.vue +++ b/src/stories/components/TreeList/TreeList.vue @@ -1,24 +1,28 @@ <script setup lang="ts"> -import { computed, ref } from 'vue'; -import { convertThemeToColorWhiteDefault, icons } from './helpers/index'; -import type { ITreeItem, TThemeColor } from './interfaces/index'; -import TriangleOpenIcon from '@/shared/ui/icons/TriangleOpenIcon.vue'; +import { computed, ref, watch } from 'vue'; +import type { ITreeItem } from '@interfaces/components'; +import type { TThemeColor } from '@interfaces/common'; +import { iconsSet } from '@/common/constants/icons'; +import { convert500ThemeToColor } from '@helpers/colors'; +import TriangleIcon from '@stories/icons/Mono/TriangleIcon.vue'; -interface Props { - items?: ITreeItem[]; - maxWidth?: number; - expand?: boolean; - theme?: TThemeColor; - disabled?: boolean; - onClick?: (link?: string) => void | never | typeof link; -} -const props = withDefaults(defineProps<Props>(), { - maxWidth: 300, - disabled: false, - onClick: () => null -}); +const props = withDefaults( + defineProps<{ + items?: ITreeItem[]; + maxWidth?: number; + expand?: boolean; + theme?: TThemeColor; + disabled?: boolean; + }>(), + { + theme: 'white', + maxWidth: 300, + disabled: false, + }, +); +const emit = defineEmits(['onClick']); const items = computed(() => props.items); -const themeColor = computed(() => convertThemeToColorWhiteDefault(props.theme)); +const themeColor = computed(() => convert500ThemeToColor(props.theme)); const textColor = computed(() => { if (!props.theme) return '#000000'; if (props.theme === 'white') return '#000000'; @@ -28,22 +32,22 @@ const textColor = computed(() => { const state = ref([]); const setInitialState = () => { if (!props?.items) return; - for (let item of props.items) { + for (const item of props.items) { state.value.push({ isOpen: props?.expand, - label: item.label + label: item.label, }); if (item.children) { - for (let child of item.children) { + for (const child of item.children) { state.value.push({ isOpen: props?.expand, - label: child.label + label: child.label, }); if (child.children) { - for (let grandChild of child.children) { + for (const grandChild of child.children) { state.value.push({ isOpen: props?.expand, - label: grandChild.label + label: grandChild.label, }); } } @@ -57,8 +61,8 @@ watch( if (items.value) setInitialState(); }, { - immediate: true - } + immediate: true, + }, ); const toggleIsOpen = (item) => state.value.map((itemState) => { @@ -74,41 +78,45 @@ const toggleIsOpen = (item) => :class="[ 'item', { - openContent: state.find((itemState) => itemState.label === item.label && itemState.isOpen) - } + openContent: state.find( + (itemState) => itemState.label === item.label && itemState.isOpen, + ), + }, ]" > <section :class="[ 'textContainer', { - pointer: !disabled && item.children - } + pointer: !disabled && item.children, + }, ]" > - <TriangleOpenIcon + <TriangleIcon v-if="item.children && !disabled" :class="[ 'openButton', { openButtonOpened: state.find( - (itemState) => itemState.label === item.label && itemState.isOpen - ) - } + (itemState) => itemState.label === item.label && itemState.isOpen, + ), + }, ]" :color="textColor" size="15" @click.prevent="toggleIsOpen(item)" /> <component - :is="icons[item.iconBefore]" + :is="iconsSet[item.iconBefore]" v-if="item.iconBefore" :color="item.iconColor" size="20" /> - <a :href="item.link" class="label" @click.prevent="onClick(item.link)">{{ item.label }}</a> + <a :href="item.link" class="label" @click.prevent="emit('onClick', item.link)">{{ + item.label + }}</a> <component - :is="icons[item.iconAfter]" + :is="iconsSet[item.iconAfter]" v-if="item.iconAfter" :color="item.iconColor" size="20" @@ -123,44 +131,44 @@ const toggleIsOpen = (item) => { pl50: !child.children, openContent: state.find( - (itemState) => itemState.label === child.label && itemState.isOpen - ) - } + (itemState) => itemState.label === child.label && itemState.isOpen, + ), + }, ]" > <section :class="[ 'textContainer', { - pointer: !disabled && child.children - } + pointer: !disabled && child.children, + }, ]" > - <TriangleOpenIcon + <TriangleIcon v-if="child.children && !disabled" :class="[ 'openButton', { openButtonOpened: state.find( - (itemState) => itemState.label === child.label && itemState.isOpen - ) - } + (itemState) => itemState.label === child.label && itemState.isOpen, + ), + }, ]" :color="textColor" size="15" @click.prevent="toggleIsOpen(child)" /> <component - :is="icons[child.iconBefore]" + :is="iconsSet[child.iconBefore]" v-if="child.iconBefore" :color="child.iconColor" size="20" /> - <a :href="child.link" class="label" @click.prevent="onClick(child.link)">{{ + <a :href="child.link" class="label" @click.prevent="emit('onClick', item.link)">{{ child.label }}</a> <component - :is="icons[child.iconAfter]" + :is="iconsSet[child.iconAfter]" v-if="child.iconAfter" :color="child.iconColor" size="20" @@ -175,23 +183,27 @@ const toggleIsOpen = (item) => { pl50: !grandChild.children, openContent: state.find( - (itemState) => itemState.label === grandChild.label && itemState.isOpen - ) - } + (itemState) => itemState.label === grandChild.label && itemState.isOpen, + ), + }, ]" > <div class="textContainer"> <component - :is="icons[grandChild.iconBefore]" + :is="iconsSet[grandChild.iconBefore]" v-if="grandChild.iconBefore" :color="grandChild.iconColor" size="20" /> - <p :href="grandChild.link" class="label" @click.prevent="onClick(grandChild.link)"> + <p + :href="grandChild.link" + class="label" + @click.prevent="emit('onClick', item.link)" + > {{ grandChild.label }} </p> <component - :is="icons[grandChild.iconAfter]" + :is="iconsSet[grandChild.iconAfter]" v-if="grandChild.iconAfter" :color="grandChild.iconColor" size="20" diff --git a/src/stories/icons/Mono/TriangleIcon.vue b/src/stories/icons/Mono/TriangleIcon.vue new file mode 100644 index 0000000..3f89a51 --- /dev/null +++ b/src/stories/icons/Mono/TriangleIcon.vue @@ -0,0 +1,26 @@ +<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="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M12.0001 5.94363L4.76627 18H19.2339L12.0001 5.94363ZM10.7138 4.20006C11.2964 3.22905 12.7037 3.22905 13.2863 4.20006L21.4032 17.7282C22.0031 18.728 21.2829 20 20.117 20H3.88318C2.71724 20 1.99706 18.728 2.59694 17.7282L10.7138 4.20006Z" + :fill="color ?? '#000000'" + /> + </svg> +</template> + +<style scoped></style> diff --git a/tsconfig.app.json b/tsconfig.app.json index 86f1f01..b5c26be 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -1,6 +1,6 @@ { "extends": "@vue/tsconfig/tsconfig.dom.json", - "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "App.vue"], "exclude": ["src/**/__tests__/*"], "compilerOptions": { "composite": true, -- GitLab