ui-ux-consultant-cli 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/assets/ui-ux-consultant/SKILL.md +844 -0
  2. package/assets/ui-ux-consultant/references/accessibility.md +175 -0
  3. package/assets/ui-ux-consultant/references/alt-libraries.md +90 -0
  4. package/assets/ui-ux-consultant/references/animations.md +448 -0
  5. package/assets/ui-ux-consultant/references/catalog/colors.md +91 -0
  6. package/assets/ui-ux-consultant/references/catalog/fonts.md +363 -0
  7. package/assets/ui-ux-consultant/references/catalog/products.md +340 -0
  8. package/assets/ui-ux-consultant/references/catalog/styles.md +165 -0
  9. package/assets/ui-ux-consultant/references/components.md +1116 -0
  10. package/assets/ui-ux-consultant/references/patterns.md +600 -0
  11. package/assets/ui-ux-consultant/references/performance.md +198 -0
  12. package/assets/ui-ux-consultant/references/stacks/astro.md +382 -0
  13. package/assets/ui-ux-consultant/references/stacks/flutter.md +308 -0
  14. package/assets/ui-ux-consultant/references/stacks/html-tailwind.md +415 -0
  15. package/assets/ui-ux-consultant/references/stacks/jetpack-compose.md +333 -0
  16. package/assets/ui-ux-consultant/references/stacks/laravel.md +521 -0
  17. package/assets/ui-ux-consultant/references/stacks/nextjs.md +275 -0
  18. package/assets/ui-ux-consultant/references/stacks/nuxt-ui.md +384 -0
  19. package/assets/ui-ux-consultant/references/stacks/nuxtjs.md +264 -0
  20. package/assets/ui-ux-consultant/references/stacks/react-native.md +346 -0
  21. package/assets/ui-ux-consultant/references/stacks/react.md +268 -0
  22. package/assets/ui-ux-consultant/references/stacks/shadcn.md +485 -0
  23. package/assets/ui-ux-consultant/references/stacks/svelte.md +429 -0
  24. package/assets/ui-ux-consultant/references/stacks/swiftui.md +336 -0
  25. package/assets/ui-ux-consultant/references/stacks/threejs.md +366 -0
  26. package/assets/ui-ux-consultant/references/stacks/vue.md +272 -0
  27. package/assets/ui-ux-consultant/references/theming.md +701 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +130 -0
  30. package/package.json +51 -0
@@ -0,0 +1,429 @@
1
+ # Svelte 5 + SvelteKit — UI/UX Reference
2
+
3
+ ## When to Read
4
+ Use this file when building UI with Svelte 5 (runes API) or SvelteKit. Covers reactivity, props, bindings, stores, transitions, routing, and form actions.
5
+
6
+ ---
7
+
8
+ ## Recommended Libraries
9
+
10
+ | Library | Best for | Install |
11
+ |---|---|---|
12
+ | Shadcn-svelte | Copy-paste components | `npx shadcn-svelte@latest init` |
13
+ | Skeleton UI | Tailwind component system | `npm install @skeletonlabs/skeleton` |
14
+ | Melt UI | Headless accessible primitives | `npm install @melt-ui/svelte` |
15
+ | Paneforge | Resizable pane layouts | `npm install paneforge` |
16
+ | Superforms | SvelteKit form handling | `npm install sveltekit-superforms` |
17
+ | Floating UI | Tooltips, popovers, dropdowns | `npm install @floating-ui/dom` |
18
+ | Motion One | Animations | `npm install motion` |
19
+
20
+ ---
21
+
22
+ ## Style Recommendations
23
+
24
+ - **Consumer / lifestyle apps:** Skeleton UI + Aurora UI aesthetic
25
+ - **Minimal SaaS:** Shadcn-svelte + Flat Design
26
+ - **Custom design system:** Tailwind utilities directly, no component lib
27
+ - **Documentation:** Minimalism, dark mode first
28
+ - **Marketing / landing:** Motion-Driven + subtle gradients
29
+
30
+ ---
31
+
32
+ ## Svelte 5 Runes — Core Patterns
33
+
34
+ ### Reactive State
35
+
36
+ ```svelte
37
+ <script lang="ts">
38
+ // $state — reactive primitive (replaces let with reactivity)
39
+ let count = $state(0);
40
+ let items = $state<string[]>([]);
41
+ let user = $state({ name: 'Alice', age: 30 });
42
+
43
+ // $derived — computed value (replaces $: reactive statements)
44
+ let doubled = $derived(count * 2);
45
+ let total = $derived(items.length);
46
+ let greeting = $derived(`Hello, ${user.name}`);
47
+
48
+ // $effect — side effect after render (replaces onMount + reactive blocks)
49
+ $effect(() => {
50
+ document.title = `Count: ${count}`;
51
+ return () => { document.title = 'App'; }; // cleanup on destroy
52
+ });
53
+ </script>
54
+ ```
55
+
56
+ ### Props
57
+
58
+ ```svelte
59
+ <script lang="ts">
60
+ // Destructure $props() for typed props
61
+ let {
62
+ name,
63
+ count = 0, // default value
64
+ onchange,
65
+ class: className = '', // rename reserved words
66
+ ...rest // pass-through props
67
+ }: {
68
+ name: string;
69
+ count?: number;
70
+ onchange: (v: string) => void;
71
+ class?: string;
72
+ } = $props();
73
+ </script>
74
+ ```
75
+
76
+ ### Bindings
77
+
78
+ ```svelte
79
+ <script lang="ts">
80
+ let value = $state('');
81
+ let checked = $state(false);
82
+ let selected = $state('option-a');
83
+ let el = $state<HTMLDivElement>(); // bind:this
84
+ </script>
85
+
86
+ <input bind:value />
87
+ <input type="checkbox" bind:checked />
88
+ <select bind:value={selected}>
89
+ <option value="option-a">A</option>
90
+ </select>
91
+ <div bind:this={el}>Reference</div>
92
+ ```
93
+
94
+ ### Two-Way Bindable Props (Svelte 5)
95
+
96
+ ```svelte
97
+ <!-- Child.svelte -->
98
+ <script lang="ts">
99
+ let { value = $bindable('') } = $props();
100
+ </script>
101
+ <input bind:value />
102
+
103
+ <!-- Parent.svelte -->
104
+ <Child bind:value={parentValue} />
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Top UX Patterns with Code
110
+
111
+ ### 1. Conditional Rendering with Transitions
112
+
113
+ ```svelte
114
+ <script lang="ts">
115
+ import { fade, fly, slide, scale } from 'svelte/transition';
116
+ import { quintOut } from 'svelte/easing';
117
+ let visible = $state(true);
118
+ let items = $state(['a', 'b', 'c']);
119
+ </script>
120
+
121
+ {#if visible}
122
+ <div transition:fade={{ duration: 200 }}>Fades in/out</div>
123
+ <div in:fly={{ y: -20, duration: 300 }} out:fade={{ duration: 150 }}>
124
+ Flies in, fades out
125
+ </div>
126
+ {/if}
127
+
128
+ <!-- List animations -->
129
+ {#each items as item (item)}
130
+ <div animate:flip={{ duration: 200 }} transition:slide>
131
+ {item}
132
+ </div>
133
+ {/each}
134
+ ```
135
+
136
+ ### 2. Async Data with Loading States
137
+
138
+ ```svelte
139
+ <script lang="ts">
140
+ async function fetchUser(id: string) {
141
+ const res = await fetch(`/api/users/${id}`);
142
+ if (!res.ok) throw new Error('Not found');
143
+ return res.json();
144
+ }
145
+
146
+ let userPromise = $state(fetchUser('1'));
147
+ </script>
148
+
149
+ {#await userPromise}
150
+ <div class="skeleton h-8 w-48 rounded" />
151
+ {:then user}
152
+ <h2>{user.name}</h2>
153
+ {:catch error}
154
+ <p class="text-red-500">{error.message}</p>
155
+ {/await}
156
+ ```
157
+
158
+ ### 3. Reusable Modal Pattern
159
+
160
+ ```svelte
161
+ <!-- Modal.svelte -->
162
+ <script lang="ts">
163
+ let { open = $bindable(false), title, children } = $props();
164
+
165
+ function handleKeydown(e: KeyboardEvent) {
166
+ if (e.key === 'Escape') open = false;
167
+ }
168
+ </script>
169
+
170
+ <svelte:window on:keydown={handleKeydown} />
171
+
172
+ {#if open}
173
+ <div class="fixed inset-0 z-50 flex items-center justify-center">
174
+ <button class="absolute inset-0 bg-black/50" onclick={() => open = false} />
175
+ <div class="relative z-10 bg-white rounded-xl p-6 shadow-xl max-w-md w-full"
176
+ role="dialog" aria-modal="true" aria-labelledby="modal-title">
177
+ <h2 id="modal-title" class="text-lg font-semibold">{title}</h2>
178
+ {@render children?.()}
179
+ </div>
180
+ </div>
181
+ {/if}
182
+ ```
183
+
184
+ ### 4. Form Validation
185
+
186
+ ```svelte
187
+ <script lang="ts">
188
+ import { superForm } from 'sveltekit-superforms';
189
+ import { zod } from 'sveltekit-superforms/adapters';
190
+ import { z } from 'zod';
191
+
192
+ const schema = z.object({
193
+ email: z.string().email(),
194
+ name: z.string().min(2),
195
+ });
196
+
197
+ const { form, errors, enhance } = superForm(data.form, {
198
+ validators: zod(schema),
199
+ });
200
+ </script>
201
+
202
+ <form method="POST" use:enhance>
203
+ <label>
204
+ Email
205
+ <input bind:value={$form.email} name="email" type="email" />
206
+ {#if $errors.email}<span class="text-red-500">{$errors.email}</span>{/if}
207
+ </label>
208
+ <button type="submit">Submit</button>
209
+ </form>
210
+ ```
211
+
212
+ ### 5. Context API (Component Tree State)
213
+
214
+ ```typescript
215
+ // context.ts
216
+ import { setContext, getContext } from 'svelte';
217
+
218
+ const THEME_KEY = Symbol('theme');
219
+
220
+ export function setTheme(theme: 'light' | 'dark') {
221
+ setContext(THEME_KEY, { theme: $state(theme) });
222
+ }
223
+
224
+ export function getTheme() {
225
+ return getContext<{ theme: 'light' | 'dark' }>(THEME_KEY);
226
+ }
227
+ ```
228
+
229
+ ### 6. Stores (Svelte 4 / cross-component interop)
230
+
231
+ ```typescript
232
+ // stores/cart.ts
233
+ import { writable, derived, get } from 'svelte/store';
234
+
235
+ interface CartItem { id: string; qty: number; price: number; }
236
+
237
+ const items = writable<CartItem[]>([]);
238
+ const total = derived(items, $items =>
239
+ $items.reduce((sum, i) => sum + i.qty * i.price, 0)
240
+ );
241
+
242
+ function add(item: CartItem) {
243
+ items.update(current => {
244
+ const existing = current.find(i => i.id === item.id);
245
+ if (existing) return current.map(i => i.id === item.id ? { ...i, qty: i.qty + 1 } : i);
246
+ return [...current, item];
247
+ });
248
+ }
249
+
250
+ export const cart = { subscribe: items.subscribe, total, add };
251
+ ```
252
+
253
+ ```svelte
254
+ <!-- Auto-subscribes and unsubscribes with $ prefix -->
255
+ <p>Items: {$cart.length}</p>
256
+ <p>Total: ${$cart.total}</p>
257
+ ```
258
+
259
+ ---
260
+
261
+ ## SvelteKit Routing
262
+
263
+ ```
264
+ src/routes/
265
+ +page.svelte # route component
266
+ +layout.svelte # wraps all child routes
267
+ +page.server.ts # server-only load + actions
268
+ +layout.server.ts # server-only layout load
269
+ +server.ts # API endpoint (GET/POST/etc.)
270
+ [slug]/ # dynamic segment
271
+ (group)/ # route group (no URL segment)
272
+ [[optional]]/ # optional segment
273
+ ```
274
+
275
+ ### Data Loading
276
+
277
+ ```typescript
278
+ // +page.server.ts — runs server-side only
279
+ import type { PageServerLoad } from './$types';
280
+
281
+ export const load: PageServerLoad = async ({ params, fetch, locals, cookies }) => {
282
+ const user = await db.user.findUnique({ where: { id: params.id } });
283
+ if (!user) error(404, 'User not found');
284
+ return { user };
285
+ };
286
+ ```
287
+
288
+ ```svelte
289
+ <!-- +page.svelte — typed data from load() -->
290
+ <script lang="ts">
291
+ import type { PageData } from './$types';
292
+ let { data }: { data: PageData } = $props();
293
+ </script>
294
+ <h1>{data.user.name}</h1>
295
+ ```
296
+
297
+ ### Form Actions
298
+
299
+ ```typescript
300
+ // +page.server.ts
301
+ import type { Actions } from './$types';
302
+ import { fail, redirect } from '@sveltejs/kit';
303
+
304
+ export const actions: Actions = {
305
+ create: async ({ request, locals }) => {
306
+ const data = await request.formData();
307
+ const title = data.get('title') as string;
308
+
309
+ if (!title) return fail(400, { error: 'Title required' });
310
+
311
+ await db.post.create({ data: { title, userId: locals.user.id } });
312
+ redirect(303, '/posts');
313
+ },
314
+ delete: async ({ request }) => {
315
+ const data = await request.formData();
316
+ await db.post.delete({ where: { id: data.get('id') as string } });
317
+ },
318
+ };
319
+ ```
320
+
321
+ ```svelte
322
+ <!-- +page.svelte -->
323
+ <script lang="ts">
324
+ import { enhance } from '$app/forms';
325
+ let { form } = $props(); // ActionData from failed actions
326
+ </script>
327
+
328
+ <form method="POST" action="?/create" use:enhance>
329
+ <input name="title" required />
330
+ {#if form?.error}<p class="text-red-500">{form.error}</p>{/if}
331
+ <button type="submit">Create</button>
332
+ </form>
333
+ ```
334
+
335
+ ### API Routes
336
+
337
+ ```typescript
338
+ // src/routes/api/users/+server.ts
339
+ import type { RequestHandler } from './$types';
340
+ import { json } from '@sveltejs/kit';
341
+
342
+ export const GET: RequestHandler = async ({ url }) => {
343
+ const users = await db.user.findMany();
344
+ return json(users);
345
+ };
346
+
347
+ export const POST: RequestHandler = async ({ request }) => {
348
+ const body = await request.json();
349
+ const user = await db.user.create({ data: body });
350
+ return json(user, { status: 201 });
351
+ };
352
+ ```
353
+
354
+ ---
355
+
356
+ ## Best Practices by Category
357
+
358
+ ### Reactivity
359
+ - Use `$state` for all mutable values in Svelte 5
360
+ - Use `$derived` for computed values — never `$effect` for derivations
361
+ - `$effect` is for side effects only (logging, DOM manipulation, subscriptions)
362
+ - Always return cleanup from `$effect` when subscribing to events
363
+ - Prefer `$state` arrays/objects — they are deeply reactive via proxies
364
+
365
+ ### Component Design
366
+ - Keep components under 150 lines; extract sub-components early
367
+ - Use `$props()` destructuring with TypeScript types always
368
+ - Use `$bindable()` sparingly — only for true two-way binding needs
369
+ - Prefer composition with `{@render children?.()}` over slots where possible
370
+ - Co-locate component logic in `<script>` not in separate stores
371
+
372
+ ### Accessibility
373
+ - Always use semantic HTML: `<button>`, `<nav>`, `<main>`, `<article>`
374
+ - Add `role` and `aria-*` to custom interactive elements
375
+ - Ensure keyboard navigation: `on:keydown` handlers for custom widgets
376
+ - Use `transition:` instead of display toggling for screen reader compat
377
+ - Test with `svelte-check` — it catches a11y issues at compile time
378
+
379
+ ### SvelteKit Specifics
380
+ - Use `+page.server.ts` for data that should never reach the client
381
+ - Prefer form actions over fetch for mutations (progressive enhancement)
382
+ - Use `locals` in `hooks.server.ts` for auth/session data
383
+ - `$app/navigation`: `goto()`, `invalidate()`, `preloadData()` for SPA feel
384
+ - Enable `prerender = true` on static pages for performance
385
+
386
+ ### Styling
387
+ - Scoped styles in `<style>` block are local by default
388
+ - Use `:global()` sparingly for third-party component overrides
389
+ - Tailwind + shadcn-svelte is the recommended production pairing
390
+ - CSS custom properties work well with Svelte's scoped styles
391
+
392
+ ---
393
+
394
+ ## Common Anti-Patterns
395
+
396
+ 1. **Mutating arrays without reassignment (Svelte 4)** — `items.push(x)` doesn't trigger reactivity in Svelte 4; use `items = [...items, x]`. In Svelte 5, `$state` arrays are proxy-wrapped and reactive to mutations.
397
+
398
+ 2. **Using `$effect` for derived values** — `$effect` runs asynchronously after render. Use `$derived` for synchronous computed state.
399
+
400
+ 3. **`export let` without defaults (Svelte 4)** — props may arrive as `undefined`. Always provide defaults or use TypeScript optional types.
401
+
402
+ 4. **Missing `{#key}` when reusing components with different data** — without a key, Svelte reuses the DOM node and the component won't re-initialize. Use `{#key item.id}<Component />{/key}`.
403
+
404
+ 5. **DOM manipulation in `onMount` when a binding suffices** — use `bind:this`, `bind:value`, `bind:clientWidth` instead of querySelector.
405
+
406
+ 6. **Fetching in `+page.svelte` instead of `+page.server.ts`** — client-side fetch loses SSR, caching, and auth context benefits.
407
+
408
+ 7. **`client:*` directives on every component (Astro crossover)** — in SvelteKit, all components are server-rendered by default; no directives needed.
409
+
410
+ 8. **Large inline event handlers** — extract to named functions for readability and testability.
411
+
412
+ 9. **Not using `use:enhance`** on forms — without it, SvelteKit forms do full page reloads and lose progressive enhancement.
413
+
414
+ 10. **Reactive store values without `$` prefix in templates** — `{count}` renders the store object, not its value; use `{$count}`.
415
+
416
+ ---
417
+
418
+ ## Performance Checklist
419
+
420
+ - [ ] Use `{#key item.id}` when component identity matters across data changes
421
+ - [ ] `svelte:options immutable={true}` for components receiving large immutable objects
422
+ - [ ] Lazy-load heavy routes: `import('./HeavyComponent.svelte')` with dynamic import
423
+ - [ ] Use built-in `svelte/transition` instead of JS animation libraries where possible
424
+ - [ ] `$derived` not `$effect` for computed values (avoids async render cycle)
425
+ - [ ] `loading="lazy"` on below-fold images
426
+ - [ ] SvelteKit prerendering: `export const prerender = true` for static pages
427
+ - [ ] `invalidate()` instead of full `goto()` for partial data refresh
428
+ - [ ] Avoid reactive statements that trigger on every keystroke without debounce
429
+ - [ ] Profile with Svelte DevTools — check for unnecessary re-renders