-
Дмитрий Малюгин authoredДмитрий Малюгин authored
SelectButton.vue 4.15 KiB
<script setup lang="ts">
import { computed } from 'vue';
import { convert500ThemeToColor } from '@helpers/colors';
import type { ISBProps } from '@interfaces/componentsProps';
const props = withDefaults(defineProps<ISBProps>(), {
size: 'medium',
border: 'black',
activeBackgroundColor: 'sky',
});
const emit = defineEmits(['onClick']);
const value = defineModel<never>('value');
const activeBackgroundColorComputed = computed(() =>
props.activeBackgroundColor ? convert500ThemeToColor(props.activeBackgroundColor) : '',
);
const borderColor = computed(() => (props.border ? convert500ThemeToColor(props.border) : ''));
const textSize = computed(() => {
switch (props.size) {
case 'small':
return '12px';
case 'large':
return '20px';
case 'huge':
return '24px';
}
return '16px';
});
const buttonPadding = computed(() => {
switch (props.size) {
case 'small':
return '0.5rem 0.375rem';
case 'large':
return '1.2rem 0.8rem';
case 'huge':
return '1.8rem 1.2rem';
}
return '0.75rem 0.5rem';
});
const buttonHeight = computed(() => {
switch (props.size) {
case 'small':
return '24px';
case 'large':
return '68px';
case 'huge':
return '114px';
}
return '40px';
});
</script>
<template>
<div
:class="[
'buttonGroup',
{
'rounded-full': props.rounded,
border: borderColor,
disabled: disabled,
},
]"
>
<button
v-for="(item, index) of options"
:key="item.label"
:class="[
'button',
{
'flex-column': item.iconPosition === 'top' || item.iconPosition === 'bottom',
},
]"
:style="`padding: ${buttonPadding}`"
@click.prevent="
() => {
value = (item.value as never) ?? item.label;
emit('onClick', value);
}
"
>
<span
:style="`background-color: ${activeBackgroundColorComputed && ((value && value === item.value) || value === item.label) ? activeBackgroundColorComputed : 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,
},
]"
></span>
<span
v-if="!item.isLabelHidden"
: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',
},
]"
>{{ item.label ?? index }}</span
>
<div
:class="[
'icon',
{
'order-1': item.iconPosition === 'left' || item.iconPosition === 'top',
},
]"
>
<slot :name="`${index + 1}Icon`" />
</div>
</button>
</div>
</template>
<style scoped>
.buttonGroup {
width: max-content;
display: flex;
border-radius: 0.75rem;
position: relative;
}
.button {
position: relative;
display: flex;
gap: 8px;
align-items: center;
user-select: none;
}
.button:hover .background {
filter: brightness(90%);
}
.button:active .background {
filter: brightness(75%);
}
.background {
width: 100%;
height: 100%;
position: absolute;
z-index: -2;
top: 0;
left: 0;
transition: filter 0.2s ease-in-out;
}
.icon {
display: flex;
align-items: center;
justify-content: center;
}
.order-1 {
order: -1;
}
.border {
border: 2px solid v-bind(borderColor);
}
.rounded-left {
border-radius: 0.5rem 0 0 0.5rem;
}
.rounded-left-full {
border-radius: v-bind(buttonHeight) 0 0 v-bind(buttonHeight);
}
.rounded-right {
border-radius: 0 0.5rem 0.5rem 0;
}
.rounded-right-full {
border-radius: 0 v-bind(buttonHeight) v-bind(buttonHeight) 0;
}
.rounded-full {
border-radius: v-bind(buttonHeight);
}
.disabled {
pointer-events: none;
background-color: #e1e7f1;
}
.disabled * {
color: #62708c !important;
}
</style>