diff --git a/src/common/interfaces/componentsProp.ts b/src/common/interfaces/componentsProp.ts index 7cda8e53ca9c1642a2b2ddf7329c0db51625ca0e..7d1f60b02188c7e6a4806bdee6e1ba8729f56d40 100644 --- a/src/common/interfaces/componentsProp.ts +++ b/src/common/interfaces/componentsProp.ts @@ -58,9 +58,11 @@ export interface IMDItemProps { export interface ISelectOption { value: string; label?: string; + group?: string; iconLeft?: TIcons; iconRight?: TIcons; - iconColor?: TThemeColor; + iconLeftColor?: TThemeColor; + iconRightColor?: TThemeColor; color?: TThemeColor; darknessColor?: TDarkness; background?: TThemeColor; @@ -68,10 +70,12 @@ export interface ISelectOption { } export interface ISelectGroup { - title: string; + name: string; + titleColor?: TThemeColor; iconLeft?: TIcons; iconRight?: TIcons; - items: string[]; + iconLeftColor?: TThemeColor; + iconRightColor?: TThemeColor; } export interface ISBOption { diff --git a/src/common/interfaces/componentsProps.ts b/src/common/interfaces/componentsProps.ts index b0195bc89f70505903be06af139f586e65fbc528..fd964d6d268593071b8ae6d3c1d0a9646a8566af 100644 --- a/src/common/interfaces/componentsProps.ts +++ b/src/common/interfaces/componentsProps.ts @@ -134,8 +134,11 @@ export interface ISelectProps { name?: string; theme?: TThemeColor; background?: TThemeColor; + placeholderColor?: TThemeColor; + openIconColor?: TThemeColor; darknessTheme?: TDarkness; darknessBackground?: TDarkness; + darknessOpenIcon?: TDarkness; disabled?: boolean; } diff --git a/src/stories/components/MenuDial/MenuDial.stories.ts b/src/stories/components/MenuDial/MenuDial.stories.ts index ba5314da02b9733cb9e4900f2887f55061124591..4da386bd179245a0a78e47caf732f872ddda7d17 100644 --- a/src/stories/components/MenuDial/MenuDial.stories.ts +++ b/src/stories/components/MenuDial/MenuDial.stories.ts @@ -102,7 +102,7 @@ export const Full: Story = { }, }; -export const Down: Story = { +export const Vertical: Story = { args: { items: [ { @@ -125,7 +125,7 @@ export const Down: Story = { }, }; -export const Huge: Story = { +export const Full2: Story = { args: { items: [ { diff --git a/src/stories/components/Select/Select.stories.ts b/src/stories/components/Select/Select.stories.ts index de89784a49f17b204faf01ededecd6e9119ee37e..2412f303135ed4ddf23c4bc20c1158c6bee8820c 100644 --- a/src/stories/components/Select/Select.stories.ts +++ b/src/stories/components/Select/Select.stories.ts @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from '@storybook/vue3'; import Select from './Select.vue'; +import { iconsSet } from '@/common/constants/icons'; const meta: Meta = { title: 'Components/Select', @@ -18,9 +19,11 @@ const meta: Meta = { disabled: { control: 'boolean' }, placeholder: { control: 'text' }, name: { control: 'text' }, + openIcon: { control: 'select', options: Object.keys(iconsSet) }, size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] }, 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'] }, + darknessOpenIcon: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'] }, theme: { control: 'select', options: [ @@ -61,6 +64,46 @@ const meta: Meta = { 'black', ], }, + openIconColor: { + control: 'select', + options: [ + 'white', + 'blue', + 'sky', + 'cyan', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, + placeholderColor: { + control: 'select', + options: [ + 'white', + 'blue', + 'sky', + 'cyan', + 'teal', + 'green', + 'yellow', + 'orange', + 'pink', + 'fuchsia', + 'purple', + 'indigo', + 'rose', + 'red', + 'black', + ], + }, }, } satisfies Meta<typeof Select>; @@ -95,7 +138,7 @@ export const Full: Story = { }, { value: 'Second', - iconColor: 'red', + iconRightColor: 'red', iconRight: 'Age18', }, { @@ -112,5 +155,6 @@ export const Full: Story = { background: 'sky', darknessTheme: '700', darknessBackground: '200', + openIconColor: 'sky', }, }; diff --git a/src/stories/components/Select/Select.vue b/src/stories/components/Select/Select.vue index 93df67fc010693190e947e056bf017dbe40e181e..44ce926df2fc67f29a0821c99b6e6d24a4404e5c 100644 --- a/src/stories/components/Select/Select.vue +++ b/src/stories/components/Select/Select.vue @@ -4,6 +4,7 @@ import { computed, ref } from 'vue'; import { convertThemeToColor } from '@helpers/common'; import { iconsSet } from '@/common/constants/icons'; import type { TThemeColor } from '@interfaces/common'; +import SelectItem from '@stories/components/Select/SelectItem.vue'; const props = withDefaults(defineProps<ISelectProps>(), { size: 'normal', @@ -11,22 +12,20 @@ const props = withDefaults(defineProps<ISelectProps>(), { theme: 'black', darknessTheme: '700', darknessBackground: '200', + darknessOpenIcon: '700', name: 'select', placeholder: 'Nothing selected', openIcon: 'ArrowShortDown', }); const selected = defineModel('value'); -// watch(, () => {}); const isOpen = ref<boolean>(false); const selectedOption = computed(() => props.options.find((option) => option.value === selected.value)); -const textColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme)); +const textColor = computed(() => (props.disabled ? '#62708c' : convertThemeToColor(props.theme, props.darknessTheme))); const backgroundColor = computed(() => convertThemeToColor( props.background ?? (props.theme === 'white' ? 'black' : props.theme === 'black' ? 'white' : props.theme), - (!props.background && props.theme === 'black') || (props.background === 'white' && props.theme === 'black') - ? '500' - : props.darknessBackground, + (!props.background && props.theme === 'black') || props.background === 'white' ? '500' : props.darknessBackground, ), ); const fontSize = computed(() => { @@ -36,6 +35,13 @@ const fontSize = computed(() => { if (size === 'huge') return '24px'; return '12px'; }); +const padding = computed(() => { + const size = props.size; + if (size === 'normal') return '6px'; + if (size === 'large') return '10px'; + if (size === 'huge') return '14px'; + return '4px'; +}); const pickOption = (value: string) => { selected.value = value; @@ -54,38 +60,31 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string | </option> </select> <div class="list" :style="`background-color: ${backgroundColor}`"> - <button @click.prevent="isOpen = !isOpen" class="button" :style="`width: ${width}`"> - <span + <button + @click.prevent="!disabled ? (isOpen = !isOpen) : ''" + :class="[ + 'button', + { + disabled: disabled, + }, + ]" + :style="`width: ${width}`" + > + <SelectItem class="selected" - :style="`color: ${selected ? calcOptionColor(selectedOption?.color, selectedOption?.darknessColor, textColor) : '#62708c'}; font-weight: 600`" + :style="`color: ${selected ? calcOptionColor(selectedOption?.color, selectedOption?.darknessColor, textColor) : placeholderColor ? convertThemeToColor(placeholderColor, '700') : '#62708c'}; font-weight: 600`" + :option="selectedOption" + :fontSize="fontSize" + :textColor="textColor" > <slot :name="`icon-left-${selectedOption?.value}`"></slot> - <component - v-if="selectedOption?.iconLeft" - :is="iconsSet[selectedOption?.iconLeft]" - :size="fontSize.slice(0, -2)" - :color=" - calcOptionColor( - selectedOption.iconColor ?? selectedOption?.color, - selectedOption?.darknessColor, - textColor, - ) - " /><span>{{ selected ?? placeholder }}</span> - <component - v-if="selectedOption?.iconRight" - :is="iconsSet[selectedOption?.iconRight]" - :size="fontSize.slice(0, -2)" - :color=" - calcOptionColor( - selectedOption.iconColor ?? selectedOption?.color, - selectedOption?.darknessColor, - textColor, - ) - " /><slot :name="`icon-right-${selectedOption?.value}`"></slot></span - ><component + <span :style="`font-size: ${fontSize}`">{{ selected ?? placeholder }}</span> + <slot :name="`icon-right-${selectedOption?.value}`"></slot> + </SelectItem> + <component :is="iconsSet[openIcon]" :size="fontSize.slice(0, -2)" - color="#62708c" + :color="openIconColor ? convertThemeToColor(openIconColor, darknessOpenIcon) : '#62708c'" :style="`width: ${fontSize}`" /> </button> @@ -98,7 +97,7 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string | ]" > <div style="overflow: hidden"> - <p + <SelectItem @click.prevent="pickOption(option.value)" v-for="option of options" :key="option.value" @@ -111,22 +110,14 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string | ]" :style="`color: ${calcOptionColor(option.color, option.darknessColor, textColor)}; background-color: ${calcOptionColor(option.background, option.darknessBackground, backgroundColor)}`" + :option="option" + :fontSize="fontSize" + :textColor="textColor" > <slot :name="`icon-left-${option.value}`"></slot> - <component - v-if="option.iconLeft" - :is="iconsSet[option.iconLeft]" - :size="fontSize.slice(0, -2)" - :color="calcOptionColor(option.iconColor ?? option.color, option.darknessColor, textColor)" - /><span>{{ option.label ?? option.value }}</span - ><component - v-if="option.iconRight" - :is="iconsSet[option.iconRight]" - :size="fontSize.slice(0, -2)" - :color="calcOptionColor(option.iconColor ?? option.color, option.darknessColor, textColor)" - /> + <span :style="`font-size: ${fontSize}`">{{ option.label ?? option.value }}</span> <slot :name="`icon-right-${option.value}`"></slot> - </p> + </SelectItem> </div> </div> </div> @@ -146,7 +137,7 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string | } .button { display: flex; - padding: 7px; + padding: v-bind(padding); justify-content: space-between; gap: 10px; } @@ -176,7 +167,7 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string | display: flex; align-items: center; gap: 5px; - padding: 7px; + padding: v-bind(padding); } .option:hover { filter: brightness(90%); @@ -193,36 +184,9 @@ const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string | border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; } +.disabled { + cursor: auto; + background-color: #e1e7f1 !important; + border-radius: 4px; +} </style> -<!--.list {--> -<!--position: relative;--> -<!--width: max-content;--> -<!--border: 1px solid v-bind(textColor);--> -<!--border-radius: 5px 5px 0 0;--> -<!--cursor: pointer;--> -<!--}--> -<!--.button {--> -<!--display: flex;--> -<!--padding: 7px;--> -<!--justify-content: space-between;--> -<!--gap: 10px;--> -<!--}--> -<!--.selected {--> -<!--display: flex;--> -<!--gap: 5px;--> -<!--}--> -<!--.options {--> -<!--position: absolute;--> -<!--top: 100%;--> -<!--width: 100%;--> -<!--border: 1px solid v-bind(textColor);--> -<!--border-top: none;--> -<!--border-bottom-left-radius: 5px;--> -<!--border-bottom-right-radius: 5px;--> -<!--display: grid;--> -<!--grid-template-rows: 0fr;--> -<!--opacity: 0;--> -<!--transition:--> -<!--all 0.2s ease-in-out,--> -<!--opacity 0.1s ease-in-out;--> -<!--}--> diff --git a/src/stories/components/Select/SelectItem.vue b/src/stories/components/Select/SelectItem.vue new file mode 100644 index 0000000000000000000000000000000000000000..5ed46435ce84dbd97179436e4e5653169a9aeab7 --- /dev/null +++ b/src/stories/components/Select/SelectItem.vue @@ -0,0 +1,36 @@ +<script setup lang="ts"> +import { iconsSet } from '@/common/constants/icons'; +import type { ISelectOption } from '@interfaces/componentsProp'; +import type { TThemeColor } from '@interfaces/common'; +import { convertThemeToColor } from '@helpers/common'; +interface IProps { + option: ISelectOption | undefined; + fontSize: string; + textColor: string; +} +defineProps<IProps>(); +const calcOptionColor = (color: TThemeColor | undefined, darknessColor: string | undefined, defaultColor: string) => + color ? convertThemeToColor(color, darknessColor ?? '500') : defaultColor; +</script> + +<template> + <span> + <slot :name="`icon-left-${option?.value}`"></slot> + <component + v-if="option?.iconLeft" + :is="iconsSet[option?.iconLeft]" + :size="fontSize.slice(0, -2)" + :color="calcOptionColor(option?.iconLeftColor ?? option?.color, option?.darknessColor, textColor)" + /> + <slot /> + <component + v-if="option?.iconRight" + :is="iconsSet[option?.iconRight]" + :size="fontSize.slice(0, -2)" + :color="calcOptionColor(option?.iconRightColor ?? option?.color, option?.darknessColor, textColor)" + /> + <slot :name="`icon-right-${option?.value}`"></slot> + </span> +</template> + +<style scoped></style>