@codihaus/claude-skills 1.6.6 → 1.6.7

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.
@@ -1,577 +0,0 @@
1
- # Frontend Fundamentals
2
-
3
- The principles and patterns that create excellent user experiences.
4
-
5
- ## Core Mindset
6
-
7
- **"I am the communicator with humans. I must be clear, responsive, and consistent."**
8
-
9
- The frontend is the interface between humans and the system. It:
10
- - Communicates what's happening
11
- - Responds instantly (or appears to)
12
- - Behaves consistently
13
- - Works for everyone
14
-
15
- ---
16
-
17
- ## The Principles
18
-
19
- Principles are the fundamental laws. Patterns are solutions derived from them.
20
-
21
- ### 1. Always Communicate
22
-
23
- **Law**: The user should NEVER wonder what's happening.
24
-
25
- **Why**: Uncertainty creates anxiety. Users abandon apps that feel "broken" or "stuck."
26
-
27
- **Patterns derived**:
28
-
29
- | Pattern | What it Communicates |
30
- |---------|---------------------|
31
- | Loading State | "I'm working on it" |
32
- | Error State | "Something went wrong, here's what" |
33
- | Empty State | "Nothing here yet, here's why" |
34
- | Success Feedback | "Done! Here's the result" |
35
- | Progress Indicator | "X% complete" |
36
- | Skeleton UI | "Content is coming, here's the shape" |
37
-
38
- **Recognition signals**:
39
- - Blank screen while loading
40
- - Click button, nothing visible happens
41
- - Error occurs, user sees nothing
42
- - Form submits, no confirmation
43
- - List might be empty, just shows nothing
44
-
45
- **State matrix for EVERY data-fetching component**:
46
- ```
47
- STATE WHAT USER SEES
48
- ─────────────────────────────────────
49
- idle Initial state, maybe CTA
50
- loading Spinner, skeleton, or shimmer
51
- success The actual content
52
- empty Helpful message + action
53
- error What went wrong + retry option
54
- ```
55
-
56
- **Structure example**:
57
- ```vue
58
- <!-- BAD: No communication -->
59
- <template>
60
- <div v-for="item in items">{{ item.name }}</div>
61
- </template>
62
-
63
- <!-- GOOD: Always communicating -->
64
- <template>
65
- <!-- Loading: Show skeleton -->
66
- <div v-if="pending">
67
- <Skeleton v-for="i in 3" :key="i" />
68
- </div>
69
-
70
- <!-- Error: Explain and offer action -->
71
- <div v-else-if="error">
72
- <ErrorMessage :error="error" />
73
- <Button @click="refresh">Try Again</Button>
74
- </div>
75
-
76
- <!-- Empty: Guide the user -->
77
- <div v-else-if="items.length === 0">
78
- <EmptyState
79
- title="No items yet"
80
- description="Create your first item to get started"
81
- action="Create Item"
82
- @action="openCreateModal"
83
- />
84
- </div>
85
-
86
- <!-- Success: Show content -->
87
- <div v-else>
88
- <Item v-for="item in items" :key="item.id" :item="item" />
89
- </div>
90
- </template>
91
- ```
92
-
93
- ---
94
-
95
- ### 2. Feel Instant
96
-
97
- **Law**: Perception matters more than reality. Make it FEEL fast.
98
-
99
- **Why**: Users perceive 100ms as instant. After 1s they notice delay. After 3s they leave.
100
-
101
- **Patterns derived**:
102
-
103
- | Pattern | How it Feels Faster |
104
- |---------|---------------------|
105
- | Optimistic UI | Show result before server confirms |
106
- | Skeleton Loading | Show shape, brain fills in details |
107
- | Lazy Loading | Load what's visible first |
108
- | Prefetching | Load before user needs it |
109
- | Debouncing | Don't overwork on rapid input |
110
- | Code Splitting | Smaller initial bundle |
111
- | Instant Navigation | Client-side routing |
112
-
113
- **Recognition signals**:
114
- - User clicks, waits, then sees change
115
- - Full page reload on navigation
116
- - Large bundle size, slow initial load
117
- - Images load all at once, page jumps
118
- - Search triggers on every keystroke
119
-
120
- **Optimistic UI example**:
121
- ```javascript
122
- // BAD: Wait for server
123
- async function toggleLike(post) {
124
- const result = await api.likePost(post.id) // User waits 500ms
125
- post.liked = result.liked
126
- post.likeCount = result.likeCount
127
- }
128
-
129
- // GOOD: Optimistic update
130
- async function toggleLike(post) {
131
- // Immediately update UI (feels instant)
132
- const previousState = { liked: post.liked, count: post.likeCount }
133
- post.liked = !post.liked
134
- post.likeCount += post.liked ? 1 : -1
135
-
136
- try {
137
- await api.likePost(post.id)
138
- } catch (error) {
139
- // Rollback if server fails
140
- post.liked = previousState.liked
141
- post.likeCount = previousState.count
142
- toast.error('Could not update like')
143
- }
144
- }
145
- ```
146
-
147
- **Loading priority**:
148
- ```
149
- 1. Critical content (above fold) → Load immediately
150
- 2. Interactive elements → Load immediately
151
- 3. Below-fold content → Lazy load on scroll
152
- 4. Images → Lazy load + placeholder
153
- 5. Analytics, tracking → Load after page ready
154
- 6. Non-essential features → Load on interaction
155
- ```
156
-
157
- ---
158
-
159
- ### 3. Stay Consistent
160
-
161
- **Law**: Same action should always produce same result. Match existing patterns.
162
-
163
- **Why**: Consistency builds trust. Inconsistency confuses and frustrates.
164
-
165
- **Patterns derived**:
166
-
167
- | Pattern | What it Standardizes |
168
- |---------|---------------------|
169
- | Design System | Visual appearance |
170
- | Component Library | UI behavior |
171
- | Naming Conventions | Code readability |
172
- | Layout Templates | Page structure |
173
- | Form Patterns | Input behavior |
174
- | Navigation Patterns | Movement through app |
175
-
176
- **Recognition signals**:
177
- - Buttons look different on different pages
178
- - Same action has different animations
179
- - Forms behave differently
180
- - Different naming styles in codebase
181
- - New code doesn't match existing patterns
182
-
183
- **Consistency checklist**:
184
- ```
185
- Before writing new code, check existing codebase for:
186
-
187
- NAMING:
188
- □ How are components named? (PascalCase, kebab-case?)
189
- □ How are files named? (index.vue, ComponentName.vue?)
190
- □ How are props named? (isOpen, open, opened?)
191
- □ How are events named? (onClose, handleClose, close?)
192
- □ How are functions named? (getData, fetchData, loadData?)
193
-
194
- STRUCTURE:
195
- □ Where do components live? (components/, shared/?)
196
- □ How is state managed? (Pinia, composables, local?)
197
- □ How are forms handled? (controlled, libraries?)
198
- □ How is API data fetched? (useFetch, custom hooks?)
199
-
200
- STYLE:
201
- □ What CSS approach? (Tailwind, modules, styled?)
202
- □ What design tokens exist? (colors, spacing, shadows?)
203
- □ How are responsive breakpoints handled?
204
-
205
- BEHAVIOR:
206
- □ How do modals open/close?
207
- □ How is form validation shown?
208
- □ How are notifications displayed?
209
- □ How do lists handle empty/loading states?
210
- ```
211
-
212
- **Match existing pattern example**:
213
- ```javascript
214
- // EXISTING CODE uses this pattern:
215
- const { data: users, pending, error } = await useFetch('/api/users')
216
-
217
- // NEW CODE should match:
218
- // GOOD - matches existing
219
- const { data: products, pending, error } = await useFetch('/api/products')
220
-
221
- // BAD - different pattern
222
- const products = ref([])
223
- const loading = ref(true)
224
- onMounted(async () => {
225
- loading.value = true
226
- products.value = await fetch('/api/products').then(r => r.json())
227
- loading.value = false
228
- })
229
- ```
230
-
231
- ---
232
-
233
- ### 4. Work for Everyone
234
-
235
- **Law**: The interface must work for all users, not just ideal conditions.
236
-
237
- **Why**: Users have disabilities, slow connections, old devices, different languages.
238
-
239
- **Patterns derived**:
240
-
241
- | Pattern | Who it Helps |
242
- |---------|-------------|
243
- | Semantic HTML | Screen readers, SEO |
244
- | Keyboard Navigation | Motor disabilities, power users |
245
- | Color Contrast | Visual impairments |
246
- | Responsive Design | Mobile users |
247
- | Offline Support | Poor connections |
248
- | Error Recovery | All users |
249
- | Internationalization | Non-English speakers |
250
-
251
- **Recognition signals**:
252
- - Can't use with keyboard only
253
- - No alt text on images
254
- - Low color contrast
255
- - Breaks on mobile
256
- - Crashes on slow connection
257
- - No error recovery
258
-
259
- **Accessibility minimum**:
260
- ```html
261
- <!-- Semantic HTML first -->
262
- <nav> not <div class="nav">
263
- <button> not <div onclick>
264
- <main> not <div class="main">
265
- <h1>, <h2>, <h3> in order
266
-
267
- <!-- Images -->
268
- <img src="..." alt="Description of what image shows" />
269
- <img src="decorative.png" alt="" /> <!-- Empty alt for decorative -->
270
-
271
- <!-- Interactive elements -->
272
- <button aria-label="Close dialog">×</button>
273
- <input aria-describedby="help-text" />
274
- <div id="help-text">Password must be 8+ characters</div>
275
-
276
- <!-- Focus management -->
277
- <!-- When modal opens: focus first element -->
278
- <!-- When modal closes: focus trigger element -->
279
-
280
- <!-- Keyboard -->
281
- <!-- All interactive elements reachable via Tab -->
282
- <!-- Enter/Space activates buttons -->
283
- <!-- Escape closes modals/dropdowns -->
284
- ```
285
-
286
- **Responsive approach**:
287
- ```
288
- MOBILE FIRST:
289
- 1. Design for smallest screen first
290
- 2. Add complexity for larger screens
291
- 3. Test at: 320px, 768px, 1024px, 1440px
292
-
293
- CSS ORDER:
294
- .component {
295
- /* Mobile styles (default) */
296
- padding: 1rem;
297
- }
298
-
299
- @media (min-width: 768px) {
300
- /* Tablet and up */
301
- padding: 2rem;
302
- }
303
-
304
- @media (min-width: 1024px) {
305
- /* Desktop and up */
306
- padding: 3rem;
307
- }
308
- ```
309
-
310
- ---
311
-
312
- ### 5. Single Source of Truth
313
-
314
- **Law**: Each piece of state should live in ONE place.
315
-
316
- **Why**: Duplicate state gets out of sync. Bugs appear. Debugging is nightmare.
317
-
318
- **Patterns derived**:
319
-
320
- | Pattern | What it Centralizes |
321
- |---------|---------------------|
322
- | State Management (Pinia) | Global app state |
323
- | Composables | Shared logic |
324
- | Controlled Components | Form input values |
325
- | URL as State | Navigation/filter state |
326
- | Props Down, Events Up | Component communication |
327
-
328
- **Recognition signals**:
329
- - Same data stored in multiple places
330
- - Prop drilling through many levels
331
- - Components directly modifying parent state
332
- - State out of sync after actions
333
- - "Why isn't this updating?"
334
-
335
- **State location guide**:
336
- ```
337
- WHO NEEDS THIS STATE?
338
-
339
- ├─ Just this component → Local state (ref/reactive)
340
-
341
- ├─ Parent and children → Props down, events up
342
-
343
- ├─ Siblings → Lift state to common parent, or use composable
344
-
345
- ├─ Many unrelated components → Global store (Pinia)
346
-
347
- └─ Should survive refresh → URL params or localStorage
348
- ```
349
-
350
- **Example**:
351
- ```javascript
352
- // BAD: Duplicate state
353
- // In Parent:
354
- const selectedUser = ref(null)
355
-
356
- // In Child (duplicating):
357
- const selectedUser = ref(null) // Out of sync risk!
358
-
359
- // GOOD: Single source
360
- // In Parent:
361
- const selectedUser = ref(null)
362
-
363
- // In Child (receiving):
364
- const props = defineProps(['selectedUser'])
365
- const emit = defineEmits(['update:selectedUser'])
366
-
367
- // Or use store for global state:
368
- // store/user.js
369
- export const useUserStore = defineStore('user', () => {
370
- const selectedUser = ref(null)
371
- const selectUser = (user) => selectedUser.value = user
372
- return { selectedUser, selectUser }
373
- })
374
-
375
- // Any component:
376
- const userStore = useUserStore()
377
- userStore.selectUser(user)
378
- ```
379
-
380
- ---
381
-
382
- ### 6. Minimize Complexity
383
-
384
- **Law**: Simple is better than clever. Obvious is better than magical.
385
-
386
- **Why**: Others (and future you) must understand and modify this code.
387
-
388
- **Patterns derived**:
389
-
390
- | Pattern | How it Simplifies |
391
- |---------|-------------------|
392
- | Small Components | Each does one thing |
393
- | Composition | Combine simple pieces |
394
- | Explicit Props | Clear interface |
395
- | Flat State | Avoid deep nesting |
396
- | Co-location | Related code together |
397
-
398
- **Recognition signals**:
399
- - Component file > 300 lines
400
- - Props > 10 items
401
- - Deeply nested state (a.b.c.d.e)
402
- - "Magic" that's hard to trace
403
- - Heavy abstraction for simple tasks
404
-
405
- **Component size guide**:
406
- ```
407
- IDEAL COMPONENT:
408
- - One clear responsibility
409
- - < 200 lines (template + script)
410
- - < 10 props
411
- - Can describe in one sentence
412
-
413
- TOO BIG IF:
414
- - Multiple responsibilities
415
- - Lots of conditional rendering
416
- - Can't understand in 30 seconds
417
- - Needs comments to explain
418
-
419
- SPLIT INTO:
420
- - Container (data/logic) + Presenter (UI)
421
- - Multiple smaller components
422
- - Composable for shared logic
423
- ```
424
-
425
- **Composition over complexity**:
426
- ```vue
427
- <!-- BAD: One complex component -->
428
- <template>
429
- <div>
430
- <div v-if="mode === 'edit'">
431
- <!-- 100 lines of edit form -->
432
- </div>
433
- <div v-else-if="mode === 'view'">
434
- <!-- 100 lines of view display -->
435
- </div>
436
- <div v-else-if="mode === 'loading'">
437
- <!-- 50 lines of skeleton -->
438
- </div>
439
- </div>
440
- </template>
441
-
442
- <!-- GOOD: Composed simple components -->
443
- <template>
444
- <ProductSkeleton v-if="pending" />
445
- <ProductEditForm v-else-if="mode === 'edit'" :product="data" @save="save" />
446
- <ProductView v-else :product="data" @edit="startEdit" />
447
- </template>
448
- ```
449
-
450
- ---
451
-
452
- ## Pattern Decision Matrix
453
-
454
- Quick reference for choosing patterns:
455
-
456
- | Situation | Apply These Patterns |
457
- |-----------|---------------------|
458
- | Data from API | Loading + Error + Empty states |
459
- | User action → Server | Optimistic UI or Loading feedback |
460
- | Form with many fields | Form library + Validation schema |
461
- | Large list (100+ items) | Virtualization |
462
- | Heavy component rarely used | Lazy loading |
463
- | Multiple components need same data | State management (Pinia) |
464
- | Complex UI with many states | State machine |
465
- | Need to match existing code | Study patterns first, match exactly |
466
- | Reusable UI element | Extract to component |
467
- | Reusable logic | Extract to composable |
468
-
469
- ---
470
-
471
- ## Component Structure
472
-
473
- Standard component organization:
474
-
475
- ```vue
476
- <script setup lang="ts">
477
- // 1. Imports
478
- import { ref, computed, watch } from 'vue'
479
- import { useUserStore } from '@/stores/user'
480
- import ChildComponent from './ChildComponent.vue'
481
-
482
- // 2. Props & Emits
483
- const props = defineProps<{
484
- title: string
485
- items: Item[]
486
- }>()
487
-
488
- const emit = defineEmits<{
489
- select: [item: Item]
490
- close: []
491
- }>()
492
-
493
- // 3. Composables & Stores
494
- const userStore = useUserStore()
495
- const { data, pending, error } = await useFetch('/api/data')
496
-
497
- // 4. Local State
498
- const isOpen = ref(false)
499
- const searchQuery = ref('')
500
-
501
- // 5. Computed
502
- const filteredItems = computed(() =>
503
- props.items.filter(item =>
504
- item.name.includes(searchQuery.value)
505
- )
506
- )
507
-
508
- // 6. Methods
509
- function handleSelect(item: Item) {
510
- emit('select', item)
511
- }
512
-
513
- // 7. Lifecycle & Watchers
514
- watch(searchQuery, (newValue) => {
515
- // React to changes
516
- })
517
- </script>
518
-
519
- <template>
520
- <!-- Single root with clear structure -->
521
- </template>
522
-
523
- <style scoped>
524
- /* Component-specific styles */
525
- </style>
526
- ```
527
-
528
- ---
529
-
530
- ## UI States Template
531
-
532
- Every data component should handle:
533
-
534
- ```vue
535
- <script setup>
536
- const { data, pending, error, refresh } = await useFetch('/api/resource')
537
- </script>
538
-
539
- <template>
540
- <div class="resource-container">
541
- <!-- Loading -->
542
- <ResourceSkeleton v-if="pending" />
543
-
544
- <!-- Error -->
545
- <ErrorState
546
- v-else-if="error"
547
- :message="error.message"
548
- @retry="refresh"
549
- />
550
-
551
- <!-- Empty -->
552
- <EmptyState
553
- v-else-if="!data || data.length === 0"
554
- title="No resources found"
555
- description="Create your first resource to get started"
556
- >
557
- <Button @click="openCreate">Create Resource</Button>
558
- </EmptyState>
559
-
560
- <!-- Success -->
561
- <ResourceList v-else :items="data" />
562
- </div>
563
- </template>
564
- ```
565
-
566
- ---
567
-
568
- ## Checklist Before Implementation
569
-
570
- - [ ] Which principle applies to this feature?
571
- - [ ] Does this match existing code patterns?
572
- - [ ] What are all the UI states? (loading, error, empty, success)
573
- - [ ] How can this feel instant?
574
- - [ ] Can it be used with keyboard only?
575
- - [ ] Does it work on mobile?
576
- - [ ] Where should state live?
577
- - [ ] Is this component doing too much?