Files
FileCodeBoxFronted2026/src/components/common/BaseButton.vue
T
2026-06-05 13:23:23 +08:00

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>