|
<script setup lang="ts"> |
|
import { LifebuoyIcon } from "@heroicons/vue/24/outline" |
|
import { FunctionalComponent } from "vue" |
|
import type { IconName } from "~/components/Icon.vue" |
|
|
|
const props = withDefaults(defineProps<{ |
|
type?: "button" | "submit" | "reset" |
|
variant?: "primary" | "secondary" | "tertiary" |
|
size?: "sm" | "md" | "lg" |
|
icon?: IconName | FunctionalComponent |
|
rightIcon?: IconName | FunctionalComponent |
|
loading?: boolean |
|
disabled?: boolean |
|
}>(), { |
|
type: "button", |
|
variant: "primary", |
|
size: "md", |
|
icon: undefined, |
|
rightIcon: undefined, |
|
loading: false, |
|
disabled: false, |
|
}) |
|
|
|
const variantClasses = computed(() => ({ |
|
primary: { |
|
button: "bg-indigo-500 text-white hover:bg-indigo-600 active:bg-indigo-700", |
|
icon: "text-white", |
|
}, |
|
secondary: { |
|
button: "bg-gray-100 text-gray-800 hover:bg-gray-200 active:bg-gray-300", |
|
icon: "text-gray-800", |
|
}, |
|
tertiary: { |
|
button: "bg-transparent text-gray-800 hover:bg-gray-100 active:bg-gray-200", |
|
icon: "text-gray-800", |
|
}, |
|
}[props.variant])) |
|
|
|
const sizeClasses = computed(() => ({ |
|
sm: { |
|
button: "h-8 px-3 gap-1 text-sm", |
|
icon: "h-3 w-3", |
|
text: "translate-y-[-0.5px]", |
|
}, |
|
md: { |
|
button: "h-10 px-4 gap-1.5", |
|
icon: "h-3.5 w-3.5", |
|
text: "translate-y-[-1px]", |
|
}, |
|
lg: { |
|
button: "h-12 px-5 gap-2 text-lg", |
|
icon: "h-4 w-4", |
|
text: "", |
|
}, |
|
}[props.size])) |
|
</script> |
|
|
|
<template> |
|
<button |
|
:class="[ |
|
'flex items-center justify-center font-medium rounded-md whitespace-nowrap', |
|
variantClasses.button, |
|
sizeClasses.button, |
|
]" |
|
> |
|
<component |
|
:is="icon" |
|
v-if="icon" |
|
:class="['text-gray-800', variantClasses.icon, sizeClasses.icon]" |
|
/> |
|
|
|
<span :class="sizeClasses.text"> |
|
<slot /> |
|
</span> |
|
|
|
<component |
|
:is="loading ? LifebuoyIcon : rightIcon" |
|
v-if="rightIcon || loading" |
|
:class="[ |
|
'text-gray-800', |
|
variantClasses.icon, |
|
sizeClasses.icon, |
|
loading && 'animate-spin', |
|
]" |
|
/> |
|
</button> |
|
</template> |