Files
web-temp/layers/components/atoms/Button/index.vue
2025-09-24 21:20:41 +09:00

91 lines
2.3 KiB
Vue

<script setup lang="ts">
import type { GameDataKeyCodeCodes } from '#layers/types/api/gameData'
interface ButtonProps {
backgroundColor?: string
textColor?: string
icon?: string
disabled?: boolean
backgroundImage?: string
}
const props = withDefaults(defineProps<ButtonProps>(), {
backgroundColor: 'var(--primary)',
textColor: 'var(--alternative-02)',
icon: '',
disabled: false,
})
// 색상 코드 키 목록 key_code_codes
const PARSED_KEY_CODE_CODES_KEYS: (keyof GameDataKeyCodeCodes)[] = [
'primary',
'text-primary',
'text-secondary',
'alternative-01',
'alternative-02',
]
// 색상 값을 CSS 변수로 변환하는 헬퍼 함수
const getColorValue = (color: string) =>
PARSED_KEY_CODE_CODES_KEYS.includes(color as keyof GameDataKeyCodeCodes)
? `var(--${color})`
: color
const buttonClasses = computed(() => [
'btn-base group relative inline-flex items-center justify-center font-medium border border-gray-600/30 overflow-hidden',
props.disabled ? 'cursor-default' : 'cursor-pointer',
])
const buttonStyles = computed(() => {
const styles: Record<string, string> = {
backgroundColor: getColorValue(props.backgroundColor),
color: getColorValue(props.textColor),
}
if (props.backgroundImage) {
styles.backgroundImage = `url(${props.backgroundImage})`
styles.backgroundSize = 'contain'
styles.backgroundPosition = 'center'
styles.backgroundRepeat = 'no-repeat'
}
return styles
})
const overlayClasses = computed(() => [
'absolute inset-0 -m-px transition-opacity duration-200',
props.disabled
? 'opacity-20 z-10'
: 'bg-white opacity-0 group-hover:opacity-20',
])
const overlayDisabledStyles = computed(
() =>
props.disabled && {
backgroundColor: props.textColor,
}
)
const contentDisabledStyles = computed(() => props.disabled && { opacity: 0.2 })
</script>
<template>
<button
:class="buttonClasses"
:style="buttonStyles"
:disabled="props.disabled"
>
<!-- 호버 효과 / Disabled 오버레이 -->
<span :class="overlayClasses" :style="overlayDisabledStyles" />
<!-- 버튼 내용 -->
<span
class="relative flex items-center gap-2"
:style="contentDisabledStyles"
>
<slot />
<span v-if="props.icon" class="flex-shrink-0" v-html="props.icon" />
</span>
</button>
</template>