85 lines
2.7 KiB
Vue
85 lines
2.7 KiB
Vue
<template>
|
|
<button
|
|
:type="type"
|
|
:disabled="disabled || loading"
|
|
@click="$emit('click', $event)"
|
|
class="inline-flex items-center justify-center rounded-[30px] px-4 py-2 font-medium shadow-sm transition-all duration-200 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:shadow-sm"
|
|
:class="[
|
|
sizeClasses,
|
|
variantClasses,
|
|
loading ? 'cursor-wait' : '',
|
|
disabled ? 'pointer-events-none' : ''
|
|
]"
|
|
>
|
|
<slot name="icon" v-if="$slots.icon && !loading"></slot>
|
|
<div v-if="loading" class="animate-spin rounded-full h-4 w-4 border-2 border-current border-t-transparent mr-2"></div>
|
|
<slot></slot>
|
|
</button>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useInjectedDarkMode } from '@/composables'
|
|
|
|
interface Props {
|
|
variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'outline'
|
|
size?: 'sm' | 'md' | 'lg'
|
|
type?: 'button' | 'submit' | 'reset'
|
|
disabled?: boolean
|
|
loading?: boolean
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
variant: 'primary',
|
|
size: 'md',
|
|
type: 'button',
|
|
disabled: false,
|
|
loading: false
|
|
})
|
|
|
|
defineEmits<{
|
|
click: [event: MouseEvent]
|
|
}>()
|
|
|
|
const isDarkMode = useInjectedDarkMode()
|
|
|
|
const sizeClasses = computed(() => {
|
|
const sizes = {
|
|
sm: 'px-3 py-1.5 text-sm',
|
|
md: 'px-4 py-2 text-sm',
|
|
lg: 'px-6 py-3 text-base'
|
|
}
|
|
return sizes[props.size]
|
|
})
|
|
|
|
const variantClasses = computed(() => {
|
|
const baseClasses = 'focus:ring-2 focus:ring-offset-2'
|
|
|
|
if (props.variant === 'primary') {
|
|
return `${baseClasses} bg-[#5f8796] text-white shadow-[#9fb8bf]/35 hover:bg-[#527887] focus:ring-[#8fb2bf]`
|
|
}
|
|
|
|
if (props.variant === 'secondary') {
|
|
return isDarkMode.value
|
|
? `${baseClasses} border border-[#40545c] bg-[#263941] text-[#d8e3e5] hover:border-[#7199a8] hover:bg-[#2d4751] focus:ring-[#7199a8]`
|
|
: `${baseClasses} border border-[#c8d8dc] bg-[#edf4f5] text-[#415d66] hover:border-[#9db6bd] hover:bg-[#e2ecee] focus:ring-[#8fb2bf]`
|
|
}
|
|
|
|
if (props.variant === 'danger') {
|
|
return `${baseClasses} bg-[#dc2626] text-white shadow-[#f87171]/35 hover:bg-[#b91c1c] focus:ring-[#ef4444]`
|
|
}
|
|
|
|
if (props.variant === 'success') {
|
|
return `${baseClasses} bg-[#6f9688] text-white shadow-[#aac4ba]/35 hover:bg-[#5f8377] focus:ring-[#92b3a7]`
|
|
}
|
|
|
|
if (props.variant === 'outline') {
|
|
return isDarkMode.value
|
|
? `${baseClasses} border border-[#40545c] text-[#d8e3e5] hover:border-[#7199a8] hover:bg-[#263941] focus:ring-[#7199a8]`
|
|
: `${baseClasses} border border-[#c8d8dc] text-[#415d66] hover:border-[#9db6bd] hover:bg-[#edf4f5] focus:ring-[#8fb2bf]`
|
|
}
|
|
|
|
return ''
|
|
})
|
|
</script>
|