88 lines
2.2 KiB
Vue
88 lines
2.2 KiB
Vue
<script setup lang="ts">
|
||
// 카운터 컴포넌트 props 정의
|
||
interface Props {
|
||
initialCount?: number
|
||
min?: number
|
||
max?: number
|
||
label?: string
|
||
}
|
||
|
||
const props = withDefaults(defineProps<Props>(), {
|
||
initialCount: 0,
|
||
min: 0,
|
||
max: 100,
|
||
label: '카운트',
|
||
})
|
||
|
||
const count = ref<number>(props.initialCount)
|
||
|
||
// 증가 (최대값 초과 방지)
|
||
function increment() {
|
||
if (count.value < props.max) {
|
||
count.value++
|
||
}
|
||
}
|
||
|
||
// 감소 (최소값 미만 방지)
|
||
function decrement() {
|
||
if (count.value > props.min) {
|
||
count.value--
|
||
}
|
||
}
|
||
|
||
// 초기화
|
||
function reset() {
|
||
count.value = props.initialCount
|
||
}
|
||
|
||
const isMin = computed(() => count.value <= props.min)
|
||
const isMax = computed(() => count.value >= props.max)
|
||
</script>
|
||
|
||
<template>
|
||
<div class="flex flex-col items-center gap-4 rounded-2xl border border-gray-200 bg-white p-6 shadow-sm sm:p-8">
|
||
<!-- 레이블 -->
|
||
<p class="text-sm font-medium text-gray-500">{{ props.label }}</p>
|
||
|
||
<!-- 카운트 표시 -->
|
||
<span class="text-5xl font-bold tabular-nums text-gray-800 sm:text-6xl">
|
||
{{ count }}
|
||
</span>
|
||
|
||
<!-- 버튼 영역 -->
|
||
<div class="flex items-center gap-3">
|
||
<!-- 감소 버튼 -->
|
||
<button
|
||
:disabled="isMin"
|
||
class="flex h-10 w-10 items-center justify-center rounded-full border border-gray-300 text-xl font-bold text-gray-600 transition hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40"
|
||
aria-label="감소"
|
||
@click="decrement"
|
||
>
|
||
−
|
||
</button>
|
||
|
||
<!-- 초기화 버튼 -->
|
||
<button
|
||
class="rounded-lg border border-gray-200 px-3 py-1.5 text-sm text-gray-500 transition hover:bg-gray-100"
|
||
aria-label="초기화"
|
||
@click="reset"
|
||
>
|
||
초기화
|
||
</button>
|
||
|
||
<!-- 증가 버튼 -->
|
||
<button
|
||
:disabled="isMax"
|
||
class="flex h-10 w-10 items-center justify-center rounded-full border border-gray-300 text-xl font-bold text-gray-600 transition hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40"
|
||
aria-label="증가"
|
||
@click="increment"
|
||
>
|
||
+
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 범위 표시 -->
|
||
<p class="text-xs text-gray-400">범위: {{ props.min }} ~ {{ props.max }}</p>
|
||
</div>
|
||
</template>
|