123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
- <script setup lang="ts">
- import { startCase } from 'lodash-es'
- import { computed } from 'vue'
- import type { ButtonSize, ButtonType, ButtonVariant } from './types.ts'
- export interface Props {
- variant?: ButtonVariant
- type?: ButtonType
- disabled?: boolean
- block?: boolean
- form?: string
- size?: ButtonSize
- prefixIcon?: string
- icon?: string
- suffixIcon?: string
- }
- const props = withDefaults(defineProps<Props>(), {
- variant: 'secondary',
- type: 'button',
- size: 'small',
- })
- const variantClasses = computed(() => {
- switch (props.variant) {
- case 'primary':
- return ['bg-blue-800', 'hover:bg-blue-800', 'text-white']
- case 'tertiary':
- return [
- 'bg-green-200',
- 'hover:bg-green-200',
- 'dark:bg-gray-600',
- 'dark:hover:bg-gray-600',
- 'text-gray-300',
- 'dark:text-neutral-400',
- ]
- case 'submit':
- return ['bg-yellow-300', 'hover:bg-yellow-300', 'text-black']
- case 'danger':
- return [
- 'bg-pink-100',
- 'hover:bg-pink-100',
- 'dark:bg-red-900',
- 'dark:hover:bg-red-900',
- 'text-red-500',
- ]
- case 'remove':
- return [
- 'bg-red-400',
- 'hover:bg-red-400',
- 'dark:bg-red-600',
- 'dark:hover:bg-red-600',
- 'text-white',
- ]
- case 'subtle':
- return [
- 'bg-blue-600',
- 'dark:bg-blue-900',
- 'hover:bg-blue-600',
- 'dark:hover:bg-blue-900',
- 'text-black',
- 'dark:text-white',
- ]
- case 'neutral':
- return [
- 'bg-transparent',
- 'hover:bg-transparent',
- 'text-gray-100',
- 'dark:text-neutral-400',
- ]
- case 'none':
- return []
- case 'secondary':
- default:
- return ['-:bg-transparent', '-:hover:bg-transparent', 'text-blue-800']
- }
- })
- const sizeClasses = computed(() => {
- switch (props.size) {
- case 'large':
- return ['btn-lg', 'text-base']
- case 'medium':
- return ['btn-md', 'text-sm']
- case 'small':
- default:
- return ['btn-sm', 'text-xs']
- }
- })
- const paddingClasses = computed(() => {
- if (props.size === 'large' && props.icon) return ['p-2']
- if (props.icon) return ['p-1']
- switch (props.size) {
- case 'large':
- return ['px-4', 'py-2.5']
- case 'medium':
- return ['px-3', 'py-2']
- case 'small':
- default:
- return ['px-2.5', 'py-1.5']
- }
- })
- const disabledClasses = computed(() => {
- if (!props.disabled) return []
- return ['opacity-30', 'pointer-events-none']
- })
- const borderRadiusClass = computed(() => {
- switch (props.size) {
- case 'large':
- if (props.icon) return 'rounded-lg'
- return 'rounded-xl'
- case 'medium':
- return 'rounded-lg'
- case 'small':
- default:
- return 'rounded-md'
- }
- })
- const iconSizeClass = computed(() => {
- switch (props.size) {
- case 'large':
- return 'small'
- case 'medium':
- return 'tiny'
- case 'small':
- default:
- return 'xs'
- }
- })
- </script>
- <template>
- <button
- class="-:inline-flex -:focus:outline-none -:focus:outline-0 -:focus:outline-offset-0 -:border-0 h-min min-h-min flex-shrink-0 flex-nowrap items-center justify-center gap-x-1 font-normal shadow-none transition-transform duration-200 hover:outline hover:outline-1 hover:outline-offset-1 hover:outline-blue-600 focus:hover:outline focus:hover:outline-1 focus:hover:outline-offset-1 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-blue-800 focus:active:scale-[95%] focus:active:!outline-blue-800 dark:hover:outline-blue-900"
- :class="[
- ...variantClasses,
- ...sizeClasses,
- ...paddingClasses,
- ...disabledClasses,
- borderRadiusClass,
- {
- 'w-full': block,
- 'w-min': !block,
- },
- ]"
- :type="type"
- :form="form"
- :aria-disabled="disabled ? 'true' : undefined"
- >
- <slot name="label">
- <CommonIcon
- v-if="prefixIcon"
- class="pointer-events-none shrink-0"
- decorative
- :size="iconSizeClass"
- :name="prefixIcon"
- />
- <CommonIcon
- v-if="icon"
- class="pointer-events-none block shrink-0"
- decorative
- :size="iconSizeClass"
- :name="icon"
- />
- <span v-else class="truncate">
- <slot>{{ $t(startCase(variant)) }}</slot>
- </span>
- <CommonIcon
- v-if="suffixIcon"
- class="pointer-events-none shrink-0"
- decorative
- :size="iconSizeClass"
- :name="suffixIcon"
- />
- </slot>
- </button>
- </template>
|