ui-ux-master 1.2.1 → 1.5.0

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.
@@ -0,0 +1,636 @@
1
+ # Tech Stack Guidelines
2
+
3
+ Load this file when the user specifies a frontend framework or tech stack. Apply the stack-specific rules on top of the design system tokens and component specs. Each section covers: component patterns, styling approach, accessibility patterns, and common pitfalls to avoid.
4
+
5
+ Default stack when none specified: **HTML + Tailwind CSS**.
6
+
7
+ ---
8
+
9
+ ## Stack Index
10
+
11
+ | # | Stack | Trigger words |
12
+ |---|-------|--------------|
13
+ | 1 | HTML + Tailwind CSS | "tailwind", "html", "vanilla", no stack specified |
14
+ | 2 | React + Tailwind | "react", "vite + react", "create react app" |
15
+ | 3 | Next.js | "next", "next.js", "nextjs", "app router", "pages router" |
16
+ | 4 | Vue 3 | "vue", "vue 3", "composition api" |
17
+ | 5 | Nuxt.js | "nuxt", "nuxt.js", "nuxt 3" |
18
+ | 6 | Angular | "angular", "ng" |
19
+ | 7 | Svelte / SvelteKit | "svelte", "sveltekit" |
20
+ | 8 | Astro | "astro" |
21
+ | 9 | Remix | "remix" |
22
+ | 10 | SolidJS | "solid", "solidjs" |
23
+ | 11 | React Native | "react native", "rn", "expo mobile" |
24
+ | 12 | Flutter | "flutter", "dart" |
25
+ | 13 | SwiftUI | "swiftui", "ios", "swift" |
26
+ | 14 | shadcn/ui | "shadcn", "shadcn/ui", "radix" |
27
+ | 15 | Jetpack Compose | "jetpack", "compose", "android" |
28
+ | 16 | Laravel (Blade + Tailwind) | "laravel", "blade", "php" |
29
+
30
+ ---
31
+
32
+ ## 1 — HTML + Tailwind CSS
33
+
34
+ **Use for:** Static sites, landing pages, simple web apps, when user doesn't specify a framework.
35
+
36
+ ### Component Pattern
37
+ ```html
38
+ <!-- Button — Primary -->
39
+ <button
40
+ class="bg-indigo-600 hover:bg-indigo-700 active:bg-indigo-800
41
+ text-white font-medium px-5 py-2.5 rounded-lg
42
+ transition-colors duration-150
43
+ focus:outline-none focus:ring-2 focus:ring-indigo-400 focus:ring-offset-2
44
+ disabled:opacity-50 disabled:cursor-not-allowed"
45
+ type="button">
46
+ Get Started
47
+ </button>
48
+
49
+ <!-- Card -->
50
+ <div class="bg-white border border-neutral-200 rounded-xl p-6 shadow-sm hover:shadow-md transition-shadow">
51
+ <h3 class="text-lg font-semibold text-neutral-900">Card Title</h3>
52
+ <p class="mt-2 text-sm text-neutral-600">Card description text here.</p>
53
+ </div>
54
+
55
+ <!-- Input with label -->
56
+ <div class="space-y-1.5">
57
+ <label for="email" class="block text-sm font-medium text-neutral-700">Email</label>
58
+ <input
59
+ id="email" type="email" name="email"
60
+ class="w-full px-3.5 py-2.5 rounded-lg border border-neutral-300
61
+ text-sm text-neutral-900 placeholder:text-neutral-400
62
+ focus:outline-none focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400
63
+ disabled:bg-neutral-100 disabled:text-neutral-400"
64
+ placeholder="you@example.com" />
65
+ </div>
66
+ ```
67
+
68
+ ### Rules
69
+ - Always use semantic HTML: `<button>` not `<div onclick>`. `<nav>`, `<main>`, `<section>`, `<article>` for structure.
70
+ - Never use Tailwind arbitrary value interpolation: `bg-[${color}]` is a runtime error — use full class names.
71
+ - CSS variables for brand tokens: define in `:root`, reference in Tailwind config via `extend.colors`.
72
+ - `prefers-reduced-motion`: wrap all transitions in `motion-safe:` variant or check via JS.
73
+ - Dark mode: use `dark:` prefix classes. Enable in `tailwind.config.js` with `darkMode: 'class'`.
74
+
75
+ ### Common AI Mistakes to Avoid
76
+ - `text-shadow-*` — Tailwind has no text-shadow utility by default (needs plugin).
77
+ - `h-screen` on mobile — causes layout shift with dynamic viewport height. Use `min-h-dvh` instead.
78
+ - `target="_blank"` without `rel="noopener noreferrer"` — security vulnerability.
79
+ - `hover:` states without matching `focus-visible:` states — breaks keyboard navigation.
80
+ - Interpolated class names: `bg-${color}-500` — Tailwind purges these and they won't work.
81
+
82
+ ---
83
+
84
+ ## 2 — React + Tailwind CSS
85
+
86
+ **Use for:** SPAs, interactive dashboards, component-heavy applications.
87
+
88
+ ### Component Pattern
89
+ ```tsx
90
+ // Button component
91
+ interface ButtonProps {
92
+ variant?: 'primary' | 'secondary' | 'ghost';
93
+ size?: 'sm' | 'md' | 'lg';
94
+ disabled?: boolean;
95
+ onClick?: () => void;
96
+ children: React.ReactNode;
97
+ 'aria-label'?: string;
98
+ }
99
+
100
+ const Button = ({ variant = 'primary', size = 'md', disabled, onClick, children, 'aria-label': ariaLabel }: ButtonProps) => {
101
+ const base = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed';
102
+ const variants = {
103
+ primary: 'bg-indigo-600 hover:bg-indigo-700 text-white focus:ring-indigo-400',
104
+ secondary: 'bg-white hover:bg-neutral-50 text-neutral-900 border border-neutral-300 focus:ring-neutral-400',
105
+ ghost: 'hover:bg-neutral-100 text-neutral-700 focus:ring-neutral-400',
106
+ };
107
+ const sizes = {
108
+ sm: 'px-3 py-1.5 text-sm',
109
+ md: 'px-5 py-2.5 text-sm',
110
+ lg: 'px-6 py-3 text-base',
111
+ };
112
+ return (
113
+ <button
114
+ className={`${base} ${variants[variant]} ${sizes[size]}`}
115
+ disabled={disabled}
116
+ onClick={onClick}
117
+ aria-label={ariaLabel}
118
+ type="button">
119
+ {children}
120
+ </button>
121
+ );
122
+ };
123
+ ```
124
+
125
+ ### Rules
126
+ - Use `clsx` or `cn()` (from shadcn) for conditional class merging — not template literals.
127
+ - All form inputs must have associated `<label>` (via `htmlFor`) or `aria-label`.
128
+ - Client state with `useState`/`useReducer`. Never fetch in render — use `useEffect` or React Query.
129
+ - List items always need `key` prop with stable IDs — not array index for dynamic lists.
130
+ - Accessible modals: use `role="dialog"`, `aria-modal="true"`, trap focus, close on Escape.
131
+
132
+ ### Common AI Mistakes
133
+ - Missing `key` prop on list items (causes React reconciliation bugs).
134
+ - `useEffect` with missing dependencies (stale closures).
135
+ - Mutating state directly: `state.items.push(x)` — always return new objects/arrays.
136
+ - `onClick` on non-interactive elements without `role` and `tabIndex`.
137
+ - Not handling loading and error states in async components.
138
+
139
+ ---
140
+
141
+ ## 3 — Next.js (App Router)
142
+
143
+ **Use for:** Production web apps, SEO-important pages, full-stack React applications.
144
+
145
+ ### Component Pattern
146
+ ```tsx
147
+ // app/components/ui/card.tsx — Server Component (default)
148
+ import { cn } from '@/lib/utils';
149
+
150
+ interface CardProps {
151
+ className?: string;
152
+ children: React.ReactNode;
153
+ }
154
+
155
+ export function Card({ className, children }: CardProps) {
156
+ return (
157
+ <div className={cn('bg-white border border-neutral-200 rounded-xl p-6 shadow-sm', className)}>
158
+ {children}
159
+ </div>
160
+ );
161
+ }
162
+
163
+ // Use 'use client' only when needed
164
+ 'use client';
165
+ import { useState } from 'react';
166
+ export function Counter() {
167
+ const [count, setCount] = useState(0);
168
+ return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
169
+ }
170
+ ```
171
+
172
+ ### Rules
173
+ - Default to **Server Components** — add `'use client'` only for interactivity, browser APIs, hooks.
174
+ - Use `<Image>` from `next/image` for all images — automatic optimization, lazy loading, `alt` required.
175
+ - Use `<Link>` from `next/link` for all internal navigation — never `<a href>` for same-domain.
176
+ - Metadata: export `metadata` object from each page for SEO — never set `<title>` in JSX directly.
177
+ - Route groups `(group)/` for layout sharing without URL segments.
178
+ - Loading UI: `loading.tsx` at each route level for streaming suspense.
179
+ - Error boundaries: `error.tsx` at each route level.
180
+
181
+ ### Common AI Mistakes
182
+ - Mixing Server and Client component patterns (e.g., using `useState` in a Server Component).
183
+ - Forgetting `alt` on `<Image>` — required prop.
184
+ - Using `getServerSideProps` (Pages Router API) in App Router — doesn't exist.
185
+ - Not wrapping `useSearchParams()` in `<Suspense>`.
186
+ - Fetching the same data multiple times instead of using `fetch` with Next.js caching.
187
+
188
+ ---
189
+
190
+ ## 4 — Vue 3 (Composition API)
191
+
192
+ **Use for:** Progressive web apps, teams coming from Vue 2, component-heavy applications.
193
+
194
+ ### Component Pattern
195
+ ```vue
196
+ <template>
197
+ <button
198
+ :class="[baseClasses, variantClasses[variant], sizeClasses[size]]"
199
+ :disabled="disabled"
200
+ type="button"
201
+ @click="$emit('click')">
202
+ <slot />
203
+ </button>
204
+ </template>
205
+
206
+ <script setup lang="ts">
207
+ interface Props {
208
+ variant?: 'primary' | 'secondary' | 'ghost'
209
+ size?: 'sm' | 'md' | 'lg'
210
+ disabled?: boolean
211
+ }
212
+ const props = withDefaults(defineProps<Props>(), {
213
+ variant: 'primary',
214
+ size: 'md',
215
+ disabled: false,
216
+ })
217
+ defineEmits(['click'])
218
+
219
+ const baseClasses = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed'
220
+ const variantClasses = {
221
+ primary: 'bg-indigo-600 hover:bg-indigo-700 text-white focus:ring-indigo-400',
222
+ secondary: 'border border-neutral-300 hover:bg-neutral-50 text-neutral-900 focus:ring-neutral-400',
223
+ ghost: 'hover:bg-neutral-100 text-neutral-700 focus:ring-neutral-400',
224
+ }
225
+ const sizeClasses = { sm: 'px-3 py-1.5 text-sm', md: 'px-5 py-2.5 text-sm', lg: 'px-6 py-3 text-base' }
226
+ </script>
227
+ ```
228
+
229
+ ### Rules
230
+ - `<script setup>` syntax (Composition API) — not Options API for new code.
231
+ - `defineProps` with TypeScript generics for type-safe props.
232
+ - `v-for` always requires `:key` with stable, unique value.
233
+ - Use `computed()` for derived state, not methods that run on every render.
234
+ - `v-model` for two-way binding on form inputs.
235
+ - Avoid `v-html` — XSS risk. Use `DOMPurify` if unavoidable.
236
+
237
+ ### Common AI Mistakes
238
+ - Using Options API (`data()`, `methods:`) when Composition API is available.
239
+ - Missing `:key` on `v-for`.
240
+ - Accessing DOM directly with `document.querySelector` — use `ref` instead.
241
+ - Mutating props directly — always emit events.
242
+
243
+ ---
244
+
245
+ ## 5 — Nuxt.js 3
246
+
247
+ **Use for:** SSR/SSG sites, SEO-heavy applications, Vue-based full-stack.
248
+
249
+ ### Rules
250
+ - `<NuxtLink>` for all internal navigation (not `<a>`).
251
+ - `<NuxtImg>` for images (requires `@nuxt/image` module).
252
+ - `useFetch()` / `useAsyncData()` for data fetching — not raw `fetch()` in setup.
253
+ - `useHead()` or `<Head>` component for meta tags on each page.
254
+ - Auto-imports: components, composables, and utils in their respective directories are auto-imported.
255
+ - `server/api/` for API routes (Nitro server).
256
+
257
+ ### Common AI Mistakes
258
+ - Using Vue Router's `useRouter` instead of Nuxt's `useRouter` / `navigateTo`.
259
+ - Forgetting that Nuxt auto-imports — don't manually import components from `~/components/`.
260
+ - Using `<head>` directly in template — use `<Head>` component or `useHead()`.
261
+
262
+ ---
263
+
264
+ ## 6 — Angular
265
+
266
+ **Use for:** Enterprise applications, teams with Java/C# backgrounds, large-scale SPAs.
267
+
268
+ ### Component Pattern
269
+ ```typescript
270
+ // button.component.ts
271
+ import { Component, Input, Output, EventEmitter } from '@angular/core';
272
+ import { CommonModule } from '@angular/common';
273
+
274
+ @Component({
275
+ selector: 'app-button',
276
+ standalone: true,
277
+ imports: [CommonModule],
278
+ template: `
279
+ <button
280
+ [class]="buttonClasses"
281
+ [disabled]="disabled"
282
+ (click)="clicked.emit()"
283
+ type="button">
284
+ <ng-content></ng-content>
285
+ </button>
286
+ `
287
+ })
288
+ export class ButtonComponent {
289
+ @Input() variant: 'primary' | 'secondary' | 'ghost' = 'primary';
290
+ @Input() disabled = false;
291
+ @Output() clicked = new EventEmitter<void>();
292
+
293
+ get buttonClasses(): string {
294
+ const base = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed';
295
+ const variants: Record<string, string> = {
296
+ primary: 'bg-indigo-600 hover:bg-indigo-700 text-white focus:ring-indigo-400',
297
+ secondary: 'border border-neutral-300 hover:bg-neutral-50 text-neutral-900',
298
+ ghost: 'hover:bg-neutral-100 text-neutral-700',
299
+ };
300
+ return `${base} ${variants[this.variant]} px-5 py-2.5 text-sm`;
301
+ }
302
+ }
303
+ ```
304
+
305
+ ### Rules
306
+ - Use standalone components (Angular 14+) — not `NgModule` for new code.
307
+ - `OnPush` change detection for performance-sensitive components.
308
+ - Use Angular's `HttpClient` not `fetch` — interceptors, error handling, type safety.
309
+ - Template-driven forms for simple; Reactive forms (`FormBuilder`) for complex.
310
+ - Use `AsyncPipe` in templates for observables — auto-unsubscribes.
311
+ - Accessibility: use CDK A11y (`FocusTrap`, `LiveAnnouncer`) for complex interactive patterns.
312
+
313
+ ---
314
+
315
+ ## 7 — Svelte / SvelteKit
316
+
317
+ **Use for:** Performance-critical sites, smaller bundle requirements, modern full-stack.
318
+
319
+ ### Component Pattern
320
+ ```svelte
321
+ <script lang="ts">
322
+ export let variant: 'primary' | 'secondary' | 'ghost' = 'primary';
323
+ export let disabled = false;
324
+ import { createEventDispatcher } from 'svelte';
325
+ const dispatch = createEventDispatcher();
326
+ </script>
327
+
328
+ <button
329
+ class={`inline-flex items-center justify-center font-medium rounded-lg transition-colors
330
+ focus:outline-none focus:ring-2 focus:ring-offset-2
331
+ disabled:opacity-50 disabled:cursor-not-allowed
332
+ ${variant === 'primary' ? 'bg-indigo-600 hover:bg-indigo-700 text-white focus:ring-indigo-400 px-5 py-2.5' : ''}
333
+ ${variant === 'secondary' ? 'border border-neutral-300 hover:bg-neutral-50 text-neutral-900 px-5 py-2.5' : ''}
334
+ ${variant === 'ghost' ? 'hover:bg-neutral-100 text-neutral-700 px-5 py-2.5' : ''}`}
335
+ {disabled}
336
+ on:click={() => dispatch('click')}
337
+ type="button">
338
+ <slot />
339
+ </button>
340
+ ```
341
+
342
+ ### Rules
343
+ - Reactive declarations with `$:` for derived values.
344
+ - `bind:` for two-way binding on form elements.
345
+ - Svelte transitions (`fade`, `slide`, `fly`) — always check `prefers-reduced-motion`.
346
+ - SvelteKit: use `load()` in `+page.ts` / `+page.server.ts` for data. Never fetch in component mount.
347
+ - Named slots for flexible component composition.
348
+
349
+ ---
350
+
351
+ ## 8 — Astro
352
+
353
+ **Use for:** Content sites, blogs, marketing pages, multi-framework islands.
354
+
355
+ ### Rules
356
+ - Default to **zero JavaScript** — add `client:` directive only for interactive islands.
357
+ - `client:load` — hydrates immediately. `client:visible` — hydrates when in viewport. `client:idle` — hydrates when browser is idle.
358
+ - Use `<Image>` from `astro:assets` for optimized images.
359
+ - Content Collections for type-safe markdown/MDX content.
360
+ - `Astro.props` for component props, typed with `Props` interface.
361
+ - Can mix React, Vue, Svelte components — use the right tool for each island.
362
+
363
+ ### Common AI Mistakes
364
+ - Adding `client:load` to every component — defeats Astro's performance benefit.
365
+ - Not using Content Collections for blog/docs content.
366
+ - Using React hooks in `.astro` files — not supported.
367
+
368
+ ---
369
+
370
+ ## 9 — Remix
371
+
372
+ **Use for:** Full-stack React apps, progressive enhancement, form-heavy applications.
373
+
374
+ ### Rules
375
+ - `loader()` for all data fetching — runs server-side, type-safe with `LoaderFunctionArgs`.
376
+ - `action()` for all mutations — replaces `fetch POST` from components.
377
+ - Forms submit to `action()` — works without JavaScript (progressive enhancement).
378
+ - `useLoaderData()` to consume loader data in components.
379
+ - Error boundaries: `ErrorBoundary` export on each route.
380
+ - Nested routes compose layouts automatically.
381
+ - Use `<Form>` from `@remix-run/react` not `<form>` for enhanced forms.
382
+
383
+ ---
384
+
385
+ ## 10 — SolidJS
386
+
387
+ **Use for:** High-performance SPAs, fine-grained reactivity needs.
388
+
389
+ ### Rules
390
+ - Reactive primitives: `createSignal`, `createMemo`, `createEffect`.
391
+ - No virtual DOM — updates are surgical. Don't think in "re-renders".
392
+ - `<For>` component instead of `.map()` for lists (fine-grained updates).
393
+ - `<Show>` instead of ternary for conditional rendering.
394
+ - `createStore` for complex nested state.
395
+ - Solid's JSX is different from React's — no `key` prop needed on `<For>`.
396
+
397
+ ---
398
+
399
+ ## 11 — React Native (Expo)
400
+
401
+ **Use for:** Cross-platform iOS + Android apps.
402
+
403
+ ### Component Pattern
404
+ ```tsx
405
+ import { TouchableOpacity, Text, StyleSheet } from 'react-native';
406
+
407
+ interface ButtonProps {
408
+ title: string;
409
+ onPress: () => void;
410
+ variant?: 'primary' | 'secondary';
411
+ disabled?: boolean;
412
+ accessibilityLabel?: string;
413
+ }
414
+
415
+ export function Button({ title, onPress, variant = 'primary', disabled, accessibilityLabel }: ButtonProps) {
416
+ return (
417
+ <TouchableOpacity
418
+ style={[styles.base, styles[variant], disabled && styles.disabled]}
419
+ onPress={onPress}
420
+ disabled={disabled}
421
+ accessible={true}
422
+ accessibilityRole="button"
423
+ accessibilityLabel={accessibilityLabel ?? title}
424
+ accessibilityState={{ disabled }}>
425
+ <Text style={[styles.text, variant === 'secondary' && styles.textSecondary]}>{title}</Text>
426
+ </TouchableOpacity>
427
+ );
428
+ }
429
+
430
+ const styles = StyleSheet.create({
431
+ base: { paddingHorizontal: 20, paddingVertical: 12, borderRadius: 8, alignItems: 'center', minHeight: 44 },
432
+ primary: { backgroundColor: '#4361EE' },
433
+ secondary: { backgroundColor: 'transparent', borderWidth: 1, borderColor: '#D1D5DB' },
434
+ disabled: { opacity: 0.5 },
435
+ text: { color: '#FFFFFF', fontSize: 15, fontWeight: '600' },
436
+ textSecondary: { color: '#111827' },
437
+ });
438
+ ```
439
+
440
+ ### Rules
441
+ - Minimum touch target: **44×44pt** (Apple HIG) — use `minHeight: 44, minWidth: 44`.
442
+ - Always provide `accessibilityLabel` and `accessibilityRole` on interactive elements.
443
+ - `TouchableOpacity` over `Pressable` for simpler cases; `Pressable` for complex press states.
444
+ - Use `StyleSheet.create()` — not inline objects (performance).
445
+ - `ScrollView` for short lists; `FlatList`/`FlashList` for long dynamic lists.
446
+ - `KeyboardAvoidingView` for forms.
447
+ - Safe area: use `useSafeAreaInsets()` or `SafeAreaView` — never hardcode status bar height.
448
+
449
+ ### Common AI Mistakes
450
+ - Using CSS selectors/classes (not supported in RN).
451
+ - `<div>`, `<span>`, `<img>` — use `<View>`, `<Text>`, `<Image>`.
452
+ - Not handling keyboard avoid on form screens.
453
+ - Touch targets smaller than 44pt.
454
+ - Missing `accessibilityRole` on interactive elements.
455
+
456
+ ---
457
+
458
+ ## 12 — Flutter
459
+
460
+ **Use for:** Cross-platform iOS + Android + web apps with native performance.
461
+
462
+ ### Component Pattern
463
+ ```dart
464
+ // Primary button widget
465
+ class AppButton extends StatelessWidget {
466
+ final String label;
467
+ final VoidCallback? onPressed;
468
+ final ButtonVariant variant;
469
+
470
+ const AppButton({
471
+ super.key,
472
+ required this.label,
473
+ this.onPressed,
474
+ this.variant = ButtonVariant.primary,
475
+ });
476
+
477
+ @override
478
+ Widget build(BuildContext context) {
479
+ final theme = Theme.of(context);
480
+ return SizedBox(
481
+ height: 48,
482
+ child: ElevatedButton(
483
+ onPressed: onPressed,
484
+ style: ElevatedButton.styleFrom(
485
+ backgroundColor: variant == ButtonVariant.primary
486
+ ? theme.colorScheme.primary
487
+ : Colors.transparent,
488
+ foregroundColor: variant == ButtonVariant.primary
489
+ ? theme.colorScheme.onPrimary
490
+ : theme.colorScheme.primary,
491
+ side: variant == ButtonVariant.secondary
492
+ ? BorderSide(color: theme.colorScheme.outline)
493
+ : null,
494
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
495
+ padding: const EdgeInsets.symmetric(horizontal: 20),
496
+ ),
497
+ child: Text(label, style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 15)),
498
+ ),
499
+ );
500
+ }
501
+ }
502
+ enum ButtonVariant { primary, secondary }
503
+ ```
504
+
505
+ ### Rules
506
+ - Use `ThemeData` with `ColorScheme.fromSeed()` for consistent theming.
507
+ - `Material 3` (`useMaterial3: true`) for modern design language.
508
+ - Minimum touch target: 48×48dp — use `SizedBox` or `ConstrainedBox` to enforce.
509
+ - `Semantics` widget for custom accessibility labels.
510
+ - `const` constructors wherever possible — reduces rebuilds.
511
+ - `ListView.builder` for long lists — not `ListView` with `children:`.
512
+
513
+ ---
514
+
515
+ ## 13 — SwiftUI
516
+
517
+ **Use for:** Native iOS, macOS, tvOS, watchOS, visionOS applications.
518
+
519
+ ### Component Pattern
520
+ ```swift
521
+ struct PrimaryButton: View {
522
+ let title: String
523
+ let action: () -> Void
524
+ var isDisabled: Bool = false
525
+
526
+ var body: some View {
527
+ Button(action: action) {
528
+ Text(title)
529
+ .font(.system(size: 15, weight: .semibold))
530
+ .foregroundColor(.white)
531
+ .frame(maxWidth: .infinity)
532
+ .padding(.vertical, 12)
533
+ .padding(.horizontal, 20)
534
+ }
535
+ .background(Color.accentColor)
536
+ .cornerRadius(8)
537
+ .disabled(isDisabled)
538
+ .opacity(isDisabled ? 0.5 : 1.0)
539
+ .accessibilityLabel(title)
540
+ }
541
+ }
542
+ ```
543
+
544
+ ### Rules
545
+ - Use `@State`, `@Binding`, `@StateObject`, `@ObservedObject`, `@EnvironmentObject` correctly.
546
+ - Follow Apple HIG: min 44×44pt touch target, Dynamic Type support required.
547
+ - `accessibilityLabel` and `accessibilityHint` on interactive elements.
548
+ - `@ViewBuilder` for conditional view composition.
549
+ - `SF Symbols` for icons — consistent with system UI.
550
+ - Support `preferredColorScheme` — do not hard-code light/dark colors.
551
+
552
+ ---
553
+
554
+ ## 14 — shadcn/ui (React + Radix)
555
+
556
+ **Use for:** React/Next.js apps requiring a pre-built accessible component library.
557
+
558
+ ### Rules
559
+ - Install components with `npx shadcn-ui@latest add [component]` — they're copied to your project and owned by you.
560
+ - Customize via `tailwind.config.ts` theme extension and `globals.css` CSS variables.
561
+ - Base primitives come from Radix UI — keyboard navigation and ARIA already handled.
562
+ - Use `cn()` utility from `lib/utils.ts` for class merging.
563
+ - Override styles via `className` prop — never modify `components/ui/` files directly.
564
+
565
+ ### CSS Variable Pattern (globals.css)
566
+ ```css
567
+ @layer base {
568
+ :root {
569
+ --background: 0 0% 100%;
570
+ --foreground: 222.2 84% 4.9%;
571
+ --primary: 222.2 47.4% 11.2%;
572
+ --primary-foreground: 210 40% 98%;
573
+ --ring: 222.2 84% 4.9%;
574
+ --radius: 0.5rem;
575
+ }
576
+ .dark {
577
+ --background: 222.2 84% 4.9%;
578
+ --foreground: 210 40% 98%;
579
+ }
580
+ }
581
+ ```
582
+
583
+ ### Common AI Mistakes
584
+ - Editing `components/ui/` files — defeats the copy-owned model.
585
+ - Using HSL shorthand wrong for shadcn variables (they're space-separated, not comma-separated).
586
+ - Not running `npx shadcn-ui init` first.
587
+
588
+ ---
589
+
590
+ ## 15 — Jetpack Compose (Android)
591
+
592
+ **Use for:** Native Android applications.
593
+
594
+ ### Rules
595
+ - Stateless composables where possible — pass state down, events up.
596
+ - `remember {}` for local state, `rememberSaveable {}` for state that survives recomposition.
597
+ - `LazyColumn` / `LazyRow` for scrollable lists — not `Column` with map.
598
+ - Material 3 (`androidx.compose.material3`): `MaterialTheme.colorScheme`, `MaterialTheme.typography`.
599
+ - Minimum touch target: 48×48dp — `Modifier.sizeIn(minWidth = 48.dp, minHeight = 48.dp)`.
600
+ - `Modifier.semantics` for custom accessibility.
601
+ - Avoid side effects in composable functions — use `LaunchedEffect`, `SideEffect`, `DisposableEffect`.
602
+
603
+ ---
604
+
605
+ ## 16 — Laravel (Blade + Tailwind)
606
+
607
+ **Use for:** PHP-based web apps, traditional server-rendered with Tailwind.
608
+
609
+ ### Rules
610
+ - Use Blade components (`<x-button>`, `<x-card>`) for reusable UI.
611
+ - `{{ $variable }}` for escaped output (XSS safe). `{!! $html !!}` only for trusted HTML.
612
+ - CSRF: `@csrf` in every POST form — required.
613
+ - Livewire for reactive components without writing JavaScript.
614
+ - Alpine.js for lightweight interactivity in Blade.
615
+ - Vite for asset bundling (`vite.config.js` + `@vite()` directive).
616
+ - `route()` helper for all URL generation — never hardcode paths.
617
+
618
+ ---
619
+
620
+ ## Universal Rules (All Stacks)
621
+
622
+ Regardless of stack, always apply:
623
+
624
+ ```
625
+ UNIVERSAL CHECKLIST
626
+ [ ] Semantic HTML structure (nav, main, section, article, aside, footer)
627
+ [ ] All images have meaningful alt text
628
+ [ ] All interactive elements reachable by keyboard (Tab order)
629
+ [ ] Focus states visible and not removed with outline: none
630
+ [ ] ARIA labels on icon-only buttons and custom interactive widgets
631
+ [ ] prefers-reduced-motion: wrap all CSS/JS animations
632
+ [ ] Color not the only differentiator for any meaning
633
+ [ ] Min touch target 44×44px (web) / 44pt (iOS) / 48dp (Android)
634
+ [ ] Error messages identify the field + state the recovery action
635
+ [ ] Loading states shown for async operations > 300ms
636
+ ```