CommonButton.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <!-- Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { computed } from 'vue'
  4. import { startCase } from 'lodash-es'
  5. import type { ButtonSize, ButtonType, ButtonVariant } from './types.ts'
  6. interface Props {
  7. variant?: ButtonVariant
  8. type?: ButtonType
  9. disabled?: boolean
  10. block?: boolean
  11. form?: string
  12. size?: ButtonSize
  13. prefixIcon?: string
  14. icon?: string
  15. suffixIcon?: string
  16. }
  17. const props = withDefaults(defineProps<Props>(), {
  18. variant: 'secondary',
  19. type: 'button',
  20. size: 'small',
  21. })
  22. const variantClasses = computed(() => {
  23. switch (props.variant) {
  24. case 'primary':
  25. return ['btn-primary', 'bg-blue-800', 'hover:bg-blue-800', 'text-white']
  26. case 'tertiary':
  27. return [
  28. 'btn-neutral',
  29. 'bg-green-200',
  30. 'hover:bg-green-200',
  31. 'dark:bg-gray-600',
  32. 'dark:hover:bg-gray-600',
  33. 'text-gray-300',
  34. 'dark:text-neutral-400',
  35. ]
  36. case 'submit':
  37. return [
  38. 'btn-accent',
  39. 'bg-yellow-300',
  40. 'hover:bg-yellow-300',
  41. 'text-black',
  42. ]
  43. case 'danger':
  44. return [
  45. 'btn-error',
  46. 'bg-pink-100',
  47. 'hover:bg-pink-100',
  48. 'dark:bg-red-900',
  49. 'dark:hover:bg-red-900',
  50. 'text-red-500',
  51. ]
  52. case 'secondary':
  53. default:
  54. return [
  55. 'btn-secondary',
  56. 'bg-transparent',
  57. 'hover:bg-transparent',
  58. 'text-blue-800',
  59. ]
  60. }
  61. })
  62. const sizeClasses = computed(() => {
  63. switch (props.size) {
  64. case 'large':
  65. return ['btn-lg', 'text-base']
  66. case 'medium':
  67. return ['btn-md', 'text-sm']
  68. case 'small':
  69. default:
  70. return ['btn-sm', 'text-xs']
  71. }
  72. })
  73. const paddingClasses = computed(() => {
  74. if (props.icon) return ['p-1']
  75. switch (props.size) {
  76. case 'large':
  77. return ['px-4', 'py-2.5']
  78. case 'medium':
  79. return ['px-3', 'py-2']
  80. case 'small':
  81. default:
  82. return ['px-2.5', 'py-1.5']
  83. }
  84. })
  85. const disabledClasses = computed(() => {
  86. if (!props.disabled) return []
  87. return [
  88. '!bg-green-100',
  89. 'dark:!bg-gray-400',
  90. 'text-stone-200',
  91. 'dark:text-neutral-500',
  92. ]
  93. })
  94. const borderRadiusClass = computed(() => {
  95. switch (props.size) {
  96. case 'large':
  97. if (props.icon) return 'rounded-lg'
  98. return 'rounded-xl'
  99. case 'medium':
  100. return 'rounded-lg'
  101. case 'small':
  102. default:
  103. return 'rounded-md'
  104. }
  105. })
  106. const iconSizeClass = computed(() => {
  107. switch (props.size) {
  108. case 'large':
  109. return 'small'
  110. case 'medium':
  111. return 'tiny'
  112. case 'small':
  113. default:
  114. return 'xs'
  115. }
  116. })
  117. </script>
  118. <template>
  119. <button
  120. class="btn h-min min-h-min border-0 shadow-none font-normal flex-nowrap gap-x-2.5 hover:outline hover:outline-1 hover:outline-offset-1 hover:outline-blue-600 dark:hover:outline-blue-900 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-blue-800"
  121. :class="[
  122. ...variantClasses,
  123. ...sizeClasses,
  124. ...paddingClasses,
  125. ...disabledClasses,
  126. borderRadiusClass,
  127. {
  128. 'btn-block': block,
  129. },
  130. ]"
  131. :type="type"
  132. :form="form"
  133. :disabled="disabled"
  134. >
  135. <CommonIcon
  136. v-if="prefixIcon"
  137. class="shrink-0"
  138. decorative
  139. :size="iconSizeClass"
  140. :name="prefixIcon"
  141. />
  142. <CommonIcon
  143. v-if="icon"
  144. class="shrink-0"
  145. decorative
  146. :size="iconSizeClass"
  147. :name="icon"
  148. />
  149. <span v-else class="truncate">
  150. <slot>{{ $t(startCase(variant)) }}</slot>
  151. </span>
  152. <CommonIcon
  153. v-if="suffixIcon"
  154. class="shrink-0"
  155. decorative
  156. :size="iconSizeClass"
  157. :name="suffixIcon"
  158. />
  159. </button>
  160. </template>