library/specializations/web-development/skills/vue-development/SKILL.md
Vue 3 development with Composition API, reactivity system, component patterns, TypeScript integration, and best practices.
npx skillsauth add a5c-ai/babysitter vue-developmentInstall 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.
Expert assistance for building Vue 3 applications with Composition API and modern patterns.
Invoke this skill when you need to:
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | componentName | string | Yes | Component name (PascalCase) | | compositionApi | boolean | No | Use Composition API (default: true) | | typescript | boolean | No | Use TypeScript (default: true) | | scriptSetup | boolean | No | Use script setup (default: true) |
{
"componentName": "UserProfile",
"compositionApi": true,
"typescript": true,
"scriptSetup": true,
"features": ["props", "emits", "slots"]
}
<!-- components/UserProfile.vue -->
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
interface User {
id: string;
name: string;
email: string;
avatar: string;
}
// Props with defaults
const props = withDefaults(defineProps<{
user: User;
editable?: boolean;
}>(), {
editable: false,
});
// Emits with typing
const emit = defineEmits<{
update: [user: User];
delete: [id: string];
}>();
// Reactive state
const isEditing = ref(false);
const editedName = ref(props.user.name);
// Computed
const initials = computed(() => {
return props.user.name
.split(' ')
.map(n => n[0])
.join('')
.toUpperCase();
});
// Methods
function saveChanges() {
emit('update', { ...props.user, name: editedName.value });
isEditing.value = false;
}
// Lifecycle
onMounted(() => {
console.log('UserProfile mounted');
});
// Expose to parent
defineExpose({
resetForm: () => {
editedName.value = props.user.name;
isEditing.value = false;
},
});
</script>
<template>
<div class="user-profile">
<div class="avatar">
<img v-if="user.avatar" :src="user.avatar" :alt="user.name" />
<span v-else class="initials">{{ initials }}</span>
</div>
<div class="info">
<template v-if="isEditing">
<input v-model="editedName" @keyup.enter="saveChanges" />
<button @click="saveChanges">Save</button>
<button @click="isEditing = false">Cancel</button>
</template>
<template v-else>
<h2>{{ user.name }}</h2>
<p>{{ user.email }}</p>
<button v-if="editable" @click="isEditing = true">Edit</button>
</template>
</div>
<slot name="actions" :user="user" />
</div>
</template>
<style scoped>
.user-profile {
display: flex;
gap: 1rem;
padding: 1rem;
}
.avatar {
width: 64px;
height: 64px;
border-radius: 50%;
overflow: hidden;
}
.initials {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background: #e5e7eb;
font-weight: bold;
}
</style>
// composables/useUser.ts
import { ref, computed, readonly } from 'vue';
interface User {
id: string;
name: string;
email: string;
}
export function useUser(userId: string) {
const user = ref<User | null>(null);
const loading = ref(false);
const error = ref<Error | null>(null);
const isAuthenticated = computed(() => !!user.value);
async function fetchUser() {
loading.value = true;
error.value = null;
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error('Failed to fetch user');
user.value = await response.json();
} catch (e) {
error.value = e as Error;
} finally {
loading.value = false;
}
}
async function updateUser(data: Partial<User>) {
if (!user.value) return;
loading.value = true;
try {
const response = await fetch(`/api/users/${userId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
user.value = await response.json();
} catch (e) {
error.value = e as Error;
} finally {
loading.value = false;
}
}
return {
user: readonly(user),
loading: readonly(loading),
error: readonly(error),
isAuthenticated,
fetchUser,
updateUser,
};
}
// composables/useLocalStorage.ts
import { ref, watch } from 'vue';
export function useLocalStorage<T>(key: string, defaultValue: T) {
const stored = localStorage.getItem(key);
const data = ref<T>(stored ? JSON.parse(stored) : defaultValue);
watch(
data,
(newValue) => {
localStorage.setItem(key, JSON.stringify(newValue));
},
{ deep: true }
);
return data;
}
// context/theme.ts
import { provide, inject, ref, type Ref, type InjectionKey } from 'vue';
type Theme = 'light' | 'dark';
interface ThemeContext {
theme: Ref<Theme>;
toggleTheme: () => void;
}
const ThemeKey: InjectionKey<ThemeContext> = Symbol('theme');
export function provideTheme() {
const theme = ref<Theme>('light');
function toggleTheme() {
theme.value = theme.value === 'light' ? 'dark' : 'light';
}
provide(ThemeKey, { theme, toggleTheme });
return { theme, toggleTheme };
}
export function useTheme() {
const context = inject(ThemeKey);
if (!context) {
throw new Error('useTheme must be used within a theme provider');
}
return context;
}
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('@/layouts/DefaultLayout.vue'),
children: [
{
path: '',
name: 'home',
component: () => import('@/views/Home.vue'),
},
{
path: 'dashboard',
name: 'dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: { requiresAuth: true },
},
],
},
{
path: '/login',
name: 'login',
component: () => import('@/views/Login.vue'),
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
// Navigation guard
router.beforeEach((to, from, next) => {
const isAuthenticated = !!localStorage.getItem('token');
if (to.meta.requiresAuth && !isAuthenticated) {
next({ name: 'login', query: { redirect: to.fullPath } });
} else {
next();
}
});
export default router;
development
Model documentation skill for generating model cards following Google's model card framework.
development
MLflow integration skill for experiment tracking, model registry, and artifact management. Enables LLMs to log experiments, compare runs, manage model lifecycle, and retrieve artifacts through the MLflow API.
data-ai
LIME-based local explanation skill for individual predictions across tabular, text, and image data.
devops
Kubeflow Pipelines skill for ML workflow orchestration, component management, and Kubernetes-native ML.