Skip to content
Snippets Groups Projects
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>