skills/vue/SKILL.md
Vue 3 Composition API 패턴 가이드를 실행합니다.
npx skillsauth add excatt/superclaude-plusplus vueInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Vue 3 Composition API 패턴 가이드를 실행합니다.
src/
├── main.ts
├── App.vue
├── components/
│ ├── common/
│ └── features/
├── composables/ # Composition 함수
│ ├── useAuth.ts
│ └── useFetch.ts
├── stores/ # Pinia 스토어
│ └── user.ts
├── views/ # 페이지 컴포넌트
├── router/
│ └── index.ts
├── types/
└── utils/
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
// Props 정의
const props = defineProps<{
title: string
count?: number
}>()
// Emits 정의
const emit = defineEmits<{
(e: 'update', value: number): void
(e: 'close'): void
}>()
// Reactive State
const count = ref(0)
const user = ref<User | null>(null)
// Computed
const doubleCount = computed(() => count.value * 2)
// Methods
function increment() {
count.value++
emit('update', count.value)
}
// Lifecycle
onMounted(async () => {
user.value = await fetchUser()
})
// Watch
watch(count, (newVal, oldVal) => {
console.log(`Count changed from ${oldVal} to ${newVal}`)
})
</script>
<template>
<div>
<h1>{{ props.title }}</h1>
<p>Count: {{ count }} (Double: {{ doubleCount }})</p>
<button @click="increment">Increment</button>
</div>
</template>
// composables/useFetch.ts
import { ref, shallowRef } from 'vue'
interface UseFetchOptions {
immediate?: boolean
}
export function useFetch<T>(url: string, options: UseFetchOptions = {}) {
const data = shallowRef<T | null>(null)
const error = ref<Error | null>(null)
const isLoading = ref(false)
async function execute() {
isLoading.value = true
error.value = null
try {
const response = await fetch(url)
if (!response.ok) throw new Error('Network error')
data.value = await response.json()
} catch (e) {
error.value = e as Error
} finally {
isLoading.value = false
}
}
if (options.immediate !== false) {
execute()
}
return { data, error, isLoading, execute }
}
// 사용
const { data: users, isLoading, execute: refetch } = useFetch<User[]>('/api/users')
// composables/useAuth.ts
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
const user = ref<User | null>(null)
const token = ref<string | null>(localStorage.getItem('token'))
export function useAuth() {
const router = useRouter()
const isAuthenticated = computed(() => !!token.value)
async function login(email: string, password: string) {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password }),
})
const data = await response.json()
token.value = data.token
user.value = data.user
localStorage.setItem('token', data.token)
router.push('/dashboard')
}
function logout() {
token.value = null
user.value = null
localStorage.removeItem('token')
router.push('/login')
}
return { user, token, isAuthenticated, login, logout }
}
// stores/user.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserStore = defineStore('user', () => {
// State
const users = ref<User[]>([])
const currentUser = ref<User | null>(null)
const isLoading = ref(false)
// Getters
const activeUsers = computed(() =>
users.value.filter(u => u.isActive)
)
const userCount = computed(() => users.value.length)
// Actions
async function fetchUsers() {
isLoading.value = true
try {
const response = await fetch('/api/users')
users.value = await response.json()
} finally {
isLoading.value = false
}
}
async function createUser(data: CreateUserDTO) {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(data),
})
const newUser = await response.json()
users.value.push(newUser)
return newUser
}
function setCurrentUser(user: User) {
currentUser.value = user
}
// Persist (with pinia-plugin-persistedstate)
return {
users,
currentUser,
isLoading,
activeUsers,
userCount,
fetchUsers,
createUser,
setCurrentUser,
}
}, {
persist: true,
})
// 사용
const userStore = useUserStore()
await userStore.fetchUsers()
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('@/views/Home.vue'),
},
{
path: '/users',
component: () => import('@/views/Users.vue'),
meta: { requiresAuth: true },
},
{
path: '/users/:id',
component: () => import('@/views/UserDetail.vue'),
props: true,
},
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/NotFound.vue'),
},
]
const router = createRouter({
history: createWebHistory(),
routes,
})
// Navigation Guard
router.beforeEach((to, from) => {
const { isAuthenticated } = useAuth()
if (to.meta.requiresAuth && !isAuthenticated.value) {
return { path: '/login', query: { redirect: to.fullPath } }
}
})
export default router
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'
import { watch } from 'vue'
const route = useRoute()
const router = useRouter()
// 파라미터 접근
const userId = computed(() => route.params.id as string)
// 쿼리 접근
const page = computed(() => Number(route.query.page) || 1)
// 라우트 변경 감지
watch(() => route.params.id, (newId) => {
fetchUser(newId)
})
// 프로그래매틱 네비게이션
function goToUser(id: string) {
router.push({ name: 'user', params: { id } })
}
</script>
<!-- components/CustomInput.vue -->
<script setup lang="ts">
const model = defineModel<string>()
</script>
<template>
<input v-model="model" />
</template>
<!-- 사용 -->
<CustomInput v-model="username" />
<!-- components/Card.vue -->
<script setup lang="ts">
defineSlots<{
default(): any
header?(): any
footer?(): any
}>()
</script>
<template>
<div class="card">
<div v-if="$slots.header" class="card-header">
<slot name="header" />
</div>
<div class="card-body">
<slot />
</div>
<div v-if="$slots.footer" class="card-footer">
<slot name="footer" />
</div>
</div>
</template>
// 부모 컴포넌트
import { provide, ref } from 'vue'
const theme = ref('dark')
provide('theme', theme)
// 자식 컴포넌트
import { inject } from 'vue'
const theme = inject<Ref<string>>('theme', ref('light'))
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod'
const schema = toTypedSchema(
z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Min 8 characters'),
})
)
const { handleSubmit, errors, defineField, isSubmitting } = useForm({
validationSchema: schema,
})
const [email, emailAttrs] = defineField('email')
const [password, passwordAttrs] = defineField('password')
const onSubmit = handleSubmit(async (values) => {
await login(values.email, values.password)
})
</script>
<template>
<form @submit="onSubmit">
<div>
<input v-model="email" v-bind="emailAttrs" type="email" />
<span v-if="errors.email">{{ errors.email }}</span>
</div>
<div>
<input v-model="password" v-bind="passwordAttrs" type="password" />
<span v-if="errors.password">{{ errors.password }}</span>
</div>
<button type="submit" :disabled="isSubmitting">Login</button>
</form>
</template>
<!-- 비동기 컴포넌트 -->
<script setup lang="ts">
const user = await fetchUser() // top-level await
</script>
<!-- 부모에서 Suspense 사용 -->
<template>
<Suspense>
<template #default>
<UserProfile />
</template>
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>
</template>
## Vue Implementation
### Components
| Component | Props | Emits |
|-----------|-------|-------|
| UserCard | user: User | select |
### Composables
| Hook | Returns | Usage |
|------|---------|-------|
| useAuth | user, login, logout | 인증 |
### Stores
| Store | State | Actions |
|-------|-------|---------|
| user | users[], isLoading | fetchUsers |
요청에 맞는 Vue 3 구현을 설계하세요.
testing
사용자 계획을 기존 도메인 모델에 대해 stress-test하는 인터뷰 세션. 용어를 날카롭게 다듬고, 결정이 굳어질 때마다 CONTEXT.md(도메인 어휘 사전)와 ADR을 인라인으로 갱신한다. 새 기능 요구사항 탐색은 `/brainstorm`을, 기존 도메인 모델·용어와의 정합성 점검은 이 스킬을 사용한다.
development
# Excel (XLSX) Spreadsheet Skill Claude Code supports comprehensive spreadsheet operations through the **xlsx** skill, enabling creation, editing, and analysis of Excel files (.xlsx, .xlsm, .csv, .tsv). ## Trigger - When user needs Excel spreadsheet creation or editing - Financial modeling or data analysis required - Spreadsheet formulas and calculations needed - Data import from CSV/TSV files ## Core Capabilities **Primary functions include:** - Creating new spreadsheets with formulas and f
tools
Generate structured implementation workflows from PRDs and feature requirements
development
실시간 통신 설계 가이드를 실행합니다.