Skip to content
Snippets Groups Projects
SelectButton.vue 4.72 KiB
Newer Older
<script setup lang="ts">
import { computed } from 'vue';
import type { ISBProps } from '@interfaces/componentsProps';
import { convertThemeToColor } from '@helpers/common';
const props = withDefaults(defineProps<ISBProps>(), {
  activeBackgroundColor: 'sky',
  darknessActiveBackgroundColor: 500,
  darknessBorder: 500,
const emit = defineEmits(['onClick']);
const value = defineModel<never>('value');
const themeColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme));
const textColor = computed(() => {
  if (props.theme === 'white' || (props.darknessTheme <= 600 && props.theme !== 'black'))
    return '#000000';
  return '#ffffff';
});
const activeBackgroundColorComputed = computed(() =>
  props.activeBackgroundColor
    ? convertThemeToColor(props.activeBackgroundColor, props.darknessActiveBackgroundColor)
    : '',
);
const borderColor = computed(() =>
  !props.border ? '' : convertThemeToColor(props.border, props.darknessBorder),
);
const textSize = computed(() => {
  switch (props.size) {
    case 'small':
      return '12px';
    case 'large':
      return '20px';
});
const buttonPadding = computed(() => {
  switch (props.size) {
    case 'small':
      return '0.5rem 0.375rem';
    case 'large':
      return '1.2rem 0.8rem';
});
const buttonHeight = computed(() => {
  switch (props.size) {
    case 'small':
      return '24px';
    case 'large':
      return '68px';
});
</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',
        },
          value = (item.value as never) ?? item.label;
        :style="`background-color: ${activeBackgroundColorComputed && ((value && value === item.value) || value === item.label) ? activeBackgroundColorComputed : (convertThemeToColor(item.backgroundColor, item.darknessBackgroundColor ?? 500) ?? themeColor)}`"
        :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,
          },
        :style="`color: ${(item.value && value === item.value) || value === item.label ? (convertThemeToColor(item.activeColor, item.darknessActiveColor ?? 500) ?? textColor) : (convertThemeToColor(item.color, item.darknessColor ?? 500) ?? textColor)}; font-size: ${textSize}`"
            italic: item.textStyle === 'italic',
          },
        >{{ item.label ?? index }}</span
            'order-1': item.iconPosition === 'left' || item.iconPosition === 'top',
          },
      >
        <slot :name="`${index + 1}Icon`" />
  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;
}