diff --git a/src/Playground.vue b/src/Playground.vue index 9caebc0acb64cd3e936cbb62f294dcbd685f802e..ce15ff7f94fef6a8fc1d5033ca335403996b0571 100644 --- a/src/Playground.vue +++ b/src/Playground.vue @@ -14,6 +14,7 @@ import Table from '@stories/components/Table/Table.vue'; import { ref } from 'vue'; import type { ISBOption, ISliderOptions, ITableColumn } from '@interfaces/componentsProp'; import Checkbox from '@stories/components/Checkbox/Checkbox.vue'; +import Tag from '@stories/components/Tag/Tag.vue'; const visibleDrawer = ref(false); const sliderOptions: ISliderOptions[] = [ @@ -184,6 +185,10 @@ const activeCheckbox = ref(); <template> <h2 class="title gradient-text">Playground</h2> + <Tag theme="sky"> + <template #icon-right><TrashIcon color="#3333aa" size="18" /></template> + <template #icon-left><TrashIcon color="sky" size="18" /></template> + </Tag> {{ activeCheckbox }} <Checkbox v-model:active="activeCheckbox" size="small" /> <Checkbox v-model:active="activeCheckbox" /> diff --git a/src/common/interfaces/componentsProps.ts b/src/common/interfaces/componentsProps.ts index 443f8b24a990e6062e68f72002d2420532adb65a..7d32e0b29af41ac294fc307dc02960e74a01bdc6 100644 --- a/src/common/interfaces/componentsProps.ts +++ b/src/common/interfaces/componentsProps.ts @@ -157,6 +157,20 @@ export interface ITSProps { disabled?: boolean; } +export interface ITagProps { + value?: string; + size?: TSize; + rounded?: boolean; + iconLeft?: TIcons; + iconRight?: TIcons; + theme?: TThemeColor; + background?: TThemeColor; + border?: TThemeColor; + darknessTheme?: TDarkness; + darknessBackground?: TDarkness; + darknessBorder?: TDarkness; +} + export interface ICheckboxProps { label?: string; labelPos?: TPosition; @@ -171,7 +185,7 @@ export interface ICheckboxProps { darknessTheme?: TDarkness; darknessActiveTheme?: TDarkness; darknessTextColor?: TDarkness; - darknessBorderColor?: TDarkness; + darknessBorder?: TDarkness; } export interface IDividerProps { diff --git a/src/stories/components/Checkbox/Checkbox.stories.ts b/src/stories/components/Checkbox/Checkbox.stories.ts index d0124e2ea704386ed3f4b9c1cd8f068d9b5d4864..9bdc8ac40bfcd94ca1ed81a050b53659c1f236bc 100644 --- a/src/stories/components/Checkbox/Checkbox.stories.ts +++ b/src/stories/components/Checkbox/Checkbox.stories.ts @@ -30,7 +30,7 @@ const meta: Meta = { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'], }, - darknessBorderColor: { + darknessBorder: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'], }, diff --git a/src/stories/components/Checkbox/Checkbox.vue b/src/stories/components/Checkbox/Checkbox.vue index 80eb924e7ef649aabfbf6771c7bc9fe17de3d90e..d4572c1c4819c03fe1b2e8ac800db6846098db34 100644 --- a/src/stories/components/Checkbox/Checkbox.vue +++ b/src/stories/components/Checkbox/Checkbox.vue @@ -16,7 +16,7 @@ const props = withDefaults(defineProps<ICheckboxProps>(), { darknessTheme: '500', darknessActiveTheme: '500', darknessTextColor: '500', - darknessBorderColor: '500', + darknessBorder: '500', }); const active = defineModel('active'); // watch(, () => {}); @@ -27,11 +27,7 @@ const iconColor = computed(() => ); const color = computed(() => convertThemeToColor(props.textColor, props.darknessTextColor)); const borderColor = computed(() => - props.invalid - ? 'red' - : props.disabled - ? '#62708c' - : convertThemeToColor(props.borderColor, props.darknessBorderColor), + props.invalid ? 'red' : props.disabled ? '#62708c' : convertThemeToColor(props.borderColor, props.darknessBorder), ); const elSize = computed(() => { const size = props.size; diff --git a/src/stories/components/Tag/Tag.stories.ts b/src/stories/components/Tag/Tag.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..91c23aa548bdff8e11c480b2289f42b3d5c6be53 --- /dev/null +++ b/src/stories/components/Tag/Tag.stories.ts @@ -0,0 +1,147 @@ +import type { Meta, StoryObj } from '@storybook/vue3'; + +import Tag from './Tag.vue'; +import { iconsSet } from '@/common/constants/icons'; + +const meta: Meta = { + title: 'Components/Tag', + component: Tag, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: 'A component is used to categorize content. Can be used with icon.', + }, + }, + }, + argTypes: { + value: { control: 'text' }, + rounded: { control: 'boolean' }, + size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] }, + iconLeft: { control: 'select', options: Object.keys(iconsSet) }, + iconRight: { control: 'select', options: Object.keys(iconsSet) }, + darknessTheme: { + control: 'select', + options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'], + }, + darknessBackground: { + control: 'select', + options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'], + }, + darknessBorder: { + 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', + ], + }, + background: { + control: 'select', + options: [ + 'white', + 'blue', + 'sky', + 'cyan', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + border: { + control: 'select', + options: [ + 'white', + 'blue', + 'sky', + 'cyan', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + }, + args: {}, +} satisfies Meta<typeof Tag>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Simple: Story = { + args: { + active: true, + }, +}; + +export const Small: Story = { + args: { + size: 'small', + theme: 'red', + value: 'Dangerous', + iconRight: 'Age18Icon', + }, +}; + +export const Normal_rounded: Story = { + args: { + size: 'normal', + theme: 'green', + value: 'Be calm', + rounded: true, + }, +}; + +export const Large: Story = { + args: { + size: 'large', + theme: 'sky', + value: 'Ice cream', + iconLeft: 'CoinsIcon', + }, +}; + +export const Huge: Story = { + args: { + size: 'huge', + theme: 'indigo', + value: 'Unique', + iconLeft: 'BallFootballIcon', + iconRight: 'ArrowForwardIcon', + darknessBackground: '300', + darknessBorder: '500', + border: 'indigo', + }, +}; diff --git a/src/stories/components/Tag/Tag.vue b/src/stories/components/Tag/Tag.vue new file mode 100644 index 0000000000000000000000000000000000000000..d7d083973ca29524e1d2c11a0b105d8b57ed1c25 --- /dev/null +++ b/src/stories/components/Tag/Tag.vue @@ -0,0 +1,65 @@ +<script setup lang="ts"> +import type { ITagProps } from '@interfaces/componentsProps'; +import { computed } from 'vue'; +import { convertThemeToColor } from '@helpers/common'; +import { iconsSet } from '@/common/constants/icons'; + +const props = withDefaults(defineProps<ITagProps>(), { + value: 'Tag', + size: 'normal', + theme: 'black', + darknessTheme: '700', + darknessBackground: '200', + darknessBorder: '500', +}); +const textColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme)); +const backgroundColor = computed(() => + convertThemeToColor( + props.background ?? (props.theme === 'white' ? 'black' : props.theme === 'black' ? 'white' : props.theme), + props.darknessBackground, + ), +); +const borderColor = computed(() => (props.border ? convertThemeToColor(props.border, props.darknessBorder) : '')); +const fontSize = computed(() => { + const size = props.size; + if (size === 'normal') return '16px'; + if (size === 'large') return '20px'; + if (size === 'huge') return '24px'; + return '12px'; +}); +const padding = computed(() => { + const size = props.size; + if (size === 'normal') return '5px 11px'; + if (size === 'large') return '6px 13px'; + if (size === 'huge') return '7px 16px'; + return '3px 7px'; +}); +</script> + +<template> + <div + class="container" + :style="`border-radius: ${rounded ? fontSize : `calc(${fontSize} / 2)`}; gap: calc(${fontSize} / 2.5); border: ${['normal', 'small'].includes(size) ? '1px' : '2px'} solid ${borderColor}`" + > + <slot name="icon-left"></slot> + <component v-show="iconLeft" :is="iconsSet[iconLeft ?? 0]" :color="textColor" :size="fontSize.slice(0, -2)" /> + <span class="text">{{ value }}</span> + <component v-show="iconRight" :is="iconsSet[iconRight ?? 0]" :color="textColor" :size="fontSize.slice(0, -2)" /> + <slot name="icon-right"></slot> + </div> +</template> + +<style scoped> +.container { + display: flex; + width: max-content; + padding: v-bind(padding); + align-items: center; + background-color: v-bind(backgroundColor); +} +.text { + font-weight: bold; + font-size: v-bind(fontSize); + color: v-bind(textColor); +} +</style>