Button.vue 2.91 KB
<template>
  <button
    :type="type"
    :class="[baseClasses, variantClass, sizeClass, roundedClass, block ? buttonBlock : '', className]"
    :disabled="disabled"
    @click="$emit('click', $event)"
  >
    <span v-if="leftIcon" class="mr-2">
      <slot name="leftIcon">
        {{ leftIcon }}
      </slot>
    </span>
    <slot></slot>
    <span v-if="rightIcon" class="ml-2">
      <slot name="rightIcon">
        {{ rightIcon }}
      </slot>
    </span>
  </button>
</template>

<script>
import { computed } from 'vue'

const buttonVariants = {
  primary: 'bg-gradient-to-r from-green-500 to-blue-500 hover:from-green-600 hover:to-blue-600 text-white border-transparent',
  secondary: 'bg-white hover:bg-gray-50 text-gray-700 border-gray-300',
  success: 'bg-green-600 hover:bg-green-700 text-white border-transparent',
  danger: 'bg-red-600 hover:bg-red-700 text-white border-transparent',
  warning: 'bg-yellow-500 hover:bg-yellow-600 text-white border-transparent',
  info: 'bg-blue-500 hover:bg-blue-600 text-white border-transparent',
  ghost: 'bg-transparent hover:bg-gray-100 text-gray-700 hover:text-gray-900 border-transparent'
}

const buttonSizes = {
  xs: 'px-2 py-1 text-xs',
  sm: 'px-2 py-1 text-sm',
  md: 'px-4 py-2',
  lg: 'px-6 py-3 text-lg',
  xl: 'px-8 py-4 text-xl'
}

const buttonRounded = {
  none: 'rounded-none',
  sm: 'rounded-sm',
  md: 'rounded-md',
  lg: 'rounded-lg',
  full: 'rounded-full'
}

const buttonBlock = 'w-full flex justify-center'

const baseClasses = 'flex items-center justify-center font-medium border shadow-sm transition duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 disabled:cursor-not-allowed'

export default {
  props: {
    variant: {
      type: String,
      default: 'primary',
      validator: (value) => Object.keys(buttonVariants).includes(value)
    },
    size: {
      type: String,
      default: 'md',
      validator: (value) => Object.keys(buttonSizes).includes(value)
    },
    rounded: {
      type: String,
      default: 'md',
      validator: (value) => Object.keys(buttonRounded).includes(value)
    },
    block: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    className: {
      type: String,
      default: ''
    },
    leftIcon: {
      type: [String, Object],
      default: null
    },
    rightIcon: {
      type: [String, Object],
      default: null
    },
    type: {
      type: String,
      default: 'button'
    }
  },
  emits: ['click'],
  setup(props) {
    const variantClass = computed(() => buttonVariants[props.variant] || buttonVariants.primary)
    const sizeClass = computed(() => buttonSizes[props.size] || buttonSizes.md)
    const roundedClass = computed(() => buttonRounded[props.rounded] || buttonRounded.md)

    return {
      baseClasses,
      variantClass,
      sizeClass,
      roundedClass,
      buttonBlock
    }
  }
}
</script>