feat: 공통 컴포넌트·인증·Riverpod 기초 골격 추가

- frontend: BaseButton 공통 컴포넌트, auth.store(세션 인증)·useAuth(로그인 흐름),
  라우터 가드를 auth.store 와 연동
- flutter: dio_provider(인터셉터 적용 Dio DI), features/user 수직 슬라이스
  (model·repository·provider) 예제

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 13:58:01 +09:00
parent 6306160dda
commit b35ddfc9c3
6 changed files with 174 additions and 3 deletions
+76
View File
@@ -0,0 +1,76 @@
<script setup lang="ts">
// 공통 버튼 컴포넌트 — 모든 재사용 컴포넌트의 기준 패턴
// (타입 지정 Props/Emits, scoped 스타일, rem 단위, 기본 접근성 속성)
// 사용 예: <BaseButton label="저장" variant="primary" @click="onSave" />
// Props 정의
interface Props {
// 버튼 라벨 (접근성 aria-label 로도 사용)
label: string
// 시각 변형
variant?: 'primary' | 'secondary'
// 비활성화 여부
disabled?: boolean
// 네이티브 button type
type?: 'button' | 'submit'
}
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
disabled: false,
type: 'button',
})
// Emits 정의
interface Emits {
// 클릭 이벤트
(e: 'click', event: MouseEvent): void
}
const emit = defineEmits<Emits>()
// 클릭 핸들러 — 비활성화 상태에서는 이벤트를 전파하지 않음
function handleClick(event: MouseEvent) {
if (props.disabled) return
emit('click', event)
}
</script>
<template>
<button
:type="type"
:class="['base-button', `base-button--${variant}`]"
:disabled="disabled"
:aria-label="label"
:aria-disabled="disabled"
@click="handleClick"
>
{{ label }}
</button>
</template>
<style scoped>
/* 모든 치수는 rem 기준 (16px = 1rem) */
.base-button {
padding: 0.5rem 1rem;
font-size: 1rem;
border: none;
border-radius: 0.375rem;
cursor: pointer;
}
.base-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.base-button--primary {
background-color: #4f46e5;
color: #ffffff;
}
.base-button--secondary {
background-color: #e5e7eb;
color: #111827;
}
</style>