Hwandji's picture
feat: initial HuggingFace Space deployment
4343907
raw
history blame
5.69 kB
<template>
<button
:class="buttonClasses"
:disabled="disabled || loading"
@click="handleClick"
:type="type"
>
<span v-if="loading" class="saap-button__spinner">
<svg class="animate-spin -ml-1 mr-3 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</span>
<span v-if="icon && !loading" :class="iconClasses">
<component :is="icon" />
</span>
<span class="saap-button__text">
<slot>{{ label }}</slot>
</span>
</button>
</template>
<script>
export default {
name: 'SaapButton',
props: {
variant: {
type: String,
default: 'primary',
validator: (value) => ['primary', 'secondary', 'tertiary', 'danger', 'success'].includes(value)
},
size: {
type: String,
default: 'md',
validator: (value) => ['sm', 'md', 'lg', 'xl'].includes(value)
},
disabled: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
icon: {
type: [String, Object],
default: null
},
iconPosition: {
type: String,
default: 'left',
validator: (value) => ['left', 'right'].includes(value)
},
label: {
type: String,
default: ''
},
type: {
type: String,
default: 'button',
validator: (value) => ['button', 'submit', 'reset'].includes(value)
},
fullWidth: {
type: Boolean,
default: false
}
},
emits: ['click'],
computed: {
buttonClasses() {
return [
'saap-button',
`saap-button--${this.variant}`,
`saap-button--${this.size}`,
{
'saap-button--disabled': this.disabled,
'saap-button--loading': this.loading,
'saap-button--full-width': this.fullWidth,
'saap-button--icon-right': this.icon && this.iconPosition === 'right'
}
];
},
iconClasses() {
return [
'saap-button__icon',
{
'saap-button__icon--right': this.iconPosition === 'right'
}
];
}
},
methods: {
handleClick(event) {
if (!this.disabled && !this.loading) {
this.$emit('click', event);
}
}
}
};
</script>
<style scoped>
/* SAAP Design System - Button Component */
.saap-button {
/* Base styles */
@apply inline-flex items-center justify-center;
@apply font-medium rounded-lg transition-all duration-200;
@apply focus:outline-none focus:ring-2 focus:ring-offset-2;
@apply disabled:opacity-50 disabled:cursor-not-allowed;
/* Typography from Design System */
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
line-height: 1.5;
}
/* Size Variants - 8pt Grid System */
.saap-button--sm {
@apply px-3 py-1.5 text-sm;
min-height: 32px; /* 4 * 8pt */
}
.saap-button--md {
@apply px-4 py-2 text-sm;
min-height: 40px; /* 5 * 8pt */
}
.saap-button--lg {
@apply px-6 py-3 text-base;
min-height: 48px; /* 6 * 8pt */
}
.saap-button--xl {
@apply px-8 py-4 text-lg;
min-height: 56px; /* 7 * 8pt */
}
/* Variant Styles - SAAP Design System Colors */
.saap-button--primary {
background-color: #2563EB; /* Primary Blue */
border: 1px solid #2563EB;
color: white;
}
.saap-button--primary:hover:not(:disabled) {
background-color: #1D4ED8;
border-color: #1D4ED8;
box-shadow: 0 4px 6px -1px rgba(37, 99, 235, 0.1);
}
.saap-button--primary:focus {
@apply ring-blue-500;
}
.saap-button--secondary {
background-color: #16A34A; /* Secondary Green */
border: 1px solid #16A34A;
color: white;
}
.saap-button--secondary:hover:not(:disabled) {
background-color: #15803D;
border-color: #15803D;
box-shadow: 0 4px 6px -1px rgba(22, 163, 74, 0.1);
}
.saap-button--secondary:focus {
@apply ring-green-500;
}
.saap-button--tertiary {
background-color: transparent;
border: 1px solid #D1D5DB;
color: #374151;
}
.saap-button--tertiary:hover:not(:disabled) {
background-color: #F9FAFB;
border-color: #9CA3AF;
}
.saap-button--tertiary:focus {
@apply ring-gray-500;
}
.saap-button--danger {
background-color: #DC2626;
border: 1px solid #DC2626;
color: white;
}
.saap-button--danger:hover:not(:disabled) {
background-color: #B91C1C;
border-color: #B91C1C;
}
.saap-button--danger:focus {
@apply ring-red-500;
}
.saap-button--success {
background-color: #16A34A;
border: 1px solid #16A34A;
color: white;
}
.saap-button--success:hover:not(:disabled) {
background-color: #15803D;
border-color: #15803D;
}
/* State Modifiers */
.saap-button--loading {
cursor: wait;
}
.saap-button--full-width {
@apply w-full;
}
/* Icon Styling */
.saap-button__icon {
@apply w-5 h-5 flex-shrink-0;
}
.saap-button__icon:not(.saap-button__icon--right) {
@apply mr-2;
}
.saap-button__icon--right {
@apply ml-2 order-2;
}
.saap-button--icon-right .saap-button__text {
@apply order-1;
}
/* Spinner */
.saap-button__spinner {
@apply flex items-center;
}
/* Accessibility */
@media (prefers-reduced-motion: reduce) {
.saap-button {
transition: none;
}
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.saap-button--tertiary {
background-color: transparent;
border-color: #4B5563;
color: #D1D5DB;
}
.saap-button--tertiary:hover:not(:disabled) {
background-color: #111827;
border-color: #6B7280;
}
}
</style>