create-win-project 1.3.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.
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/ci/expo.yml +28 -0
- package/ci/laravel.yml +49 -0
- package/ci/nextjs.yml +29 -0
- package/ci/springboot.yml +33 -0
- package/ci/vite.yml +36 -0
- package/compatibility/profiles.json +237 -0
- package/docs/ARCHITECTURE.md +118 -0
- package/docs/CONTENT_MODEL.md +36 -0
- package/docs/DEPENDENCY_MAINTENANCE.md +31 -0
- package/index.js +431 -0
- package/lib/application-shapes.js +95 -0
- package/lib/banner.js +45 -0
- package/lib/catalog.js +343 -0
- package/lib/compatibility.js +116 -0
- package/lib/constants.js +3 -0
- package/lib/doctor.js +45 -0
- package/lib/files.js +158 -0
- package/lib/generator.js +366 -0
- package/lib/interview.js +77 -0
- package/lib/laravel-scaffold.js +3 -0
- package/lib/playbooks.js +172 -0
- package/lib/project-location.js +18 -0
- package/lib/scaffold.js +467 -0
- package/lib/stacks/context.js +27 -0
- package/lib/stacks/contract.js +142 -0
- package/lib/stacks/index.js +8 -0
- package/lib/stacks/laravel/architecture.js +27 -0
- package/lib/stacks/laravel/auth/oidc.js +13 -0
- package/lib/stacks/laravel/auth/public.js +28 -0
- package/lib/stacks/laravel/auth/sanctum.js +14 -0
- package/lib/stacks/laravel/auth/session.js +17 -0
- package/lib/stacks/laravel/composer.js +50 -0
- package/lib/stacks/laravel/generate.js +362 -0
- package/lib/stacks/laravel/index.js +18 -0
- package/lib/stacks/laravel/ui/blade.js +15 -0
- package/lib/stacks/laravel/ui/index.js +29 -0
- package/lib/stacks/laravel/ui/inertia-react.js +35 -0
- package/lib/stacks/laravel/ui/livewire.js +39 -0
- package/lib/stacks/laravel/ui/shared.js +14 -0
- package/lib/stacks/registry.js +42 -0
- package/lib/stacks/shared/contributions.js +25 -0
- package/lib/template.js +62 -0
- package/package.json +49 -0
- package/playbooks/INDEX.md +58 -0
- package/playbooks/capabilities/auth/oidc-resource-server.md +15 -0
- package/playbooks/capabilities/auth/spring-session.md +15 -0
- package/playbooks/capabilities/ci/github-actions.manifest.json +10 -0
- package/playbooks/capabilities/ci/github-actions.md +61 -0
- package/playbooks/capabilities/docker/docker.manifest.json +11 -0
- package/playbooks/capabilities/docker/overview.md +55 -0
- package/playbooks/capabilities/flyway/environments.md +5 -0
- package/playbooks/capabilities/flyway/flyway.manifest.json +12 -0
- package/playbooks/capabilities/flyway/migrations.md +7 -0
- package/playbooks/capabilities/flyway/testing.md +5 -0
- package/playbooks/capabilities/laravel/database.md +8 -0
- package/playbooks/capabilities/laravel/migrations.md +15 -0
- package/playbooks/capabilities/laravel/observability.md +8 -0
- package/playbooks/capabilities/laravel/oidc-resource-server.md +10 -0
- package/playbooks/capabilities/laravel/queues.md +8 -0
- package/playbooks/capabilities/laravel/sanctum-spa.md +8 -0
- package/playbooks/capabilities/laravel/scheduler.md +7 -0
- package/playbooks/capabilities/laravel/session-auth.md +8 -0
- package/playbooks/capabilities/laravel/storage-uploads.md +7 -0
- package/playbooks/capabilities/postgresql/architecture.md +5 -0
- package/playbooks/capabilities/postgresql/migrations.md +5 -0
- package/playbooks/capabilities/postgresql/postgresql.manifest.json +15 -0
- package/playbooks/capabilities/postgresql/schema-design.md +7 -0
- package/playbooks/capabilities/postgresql/security.md +5 -0
- package/playbooks/capabilities/postgresql/testing.md +5 -0
- package/playbooks/capabilities/prisma/architecture.md +5 -0
- package/playbooks/capabilities/prisma/migrations.md +11 -0
- package/playbooks/capabilities/prisma/prisma.manifest.json +14 -0
- package/playbooks/capabilities/prisma/runtime.md +5 -0
- package/playbooks/capabilities/prisma/schema.md +5 -0
- package/playbooks/capabilities/prisma/testing.md +5 -0
- package/playbooks/capabilities/supabase/architecture.md +5 -0
- package/playbooks/capabilities/supabase/authentication.md +5 -0
- package/playbooks/capabilities/supabase/expo.md +16 -0
- package/playbooks/capabilities/supabase/migrations.md +7 -0
- package/playbooks/capabilities/supabase/nextjs.md +24 -0
- package/playbooks/capabilities/supabase/rls.md +7 -0
- package/playbooks/capabilities/supabase/supabase.manifest.json +32 -0
- package/playbooks/capabilities/supabase/testing.md +5 -0
- package/playbooks/capabilities/supabase/vite.md +14 -0
- package/playbooks/concerns/axios.md +123 -0
- package/playbooks/concerns/next-safe-action.md +66 -0
- package/playbooks/concerns/next-themes.md +87 -0
- package/playbooks/concerns/nuqs.md +59 -0
- package/playbooks/concerns/t3-env.md +48 -0
- package/playbooks/concerns/tanstack-query.md +145 -0
- package/playbooks/concerns/zod.md +174 -0
- package/playbooks/concerns/zustand.md +93 -0
- package/playbooks/devops/makefile.manifest.json +10 -0
- package/playbooks/devops/makefile.md +556 -0
- package/playbooks/devops/pr-template.manifest.json +10 -0
- package/playbooks/devops/pr-template.md +106 -0
- package/playbooks/platform/laravel-ui/blade/architecture.md +5 -0
- package/playbooks/platform/laravel-ui/blade/runtime.md +5 -0
- package/playbooks/platform/laravel-ui/blade/security.md +5 -0
- package/playbooks/platform/laravel-ui/blade/structure.md +5 -0
- package/playbooks/platform/laravel-ui/blade/testing.md +5 -0
- package/playbooks/platform/laravel-ui/inertia-react/architecture.md +5 -0
- package/playbooks/platform/laravel-ui/inertia-react/runtime.md +5 -0
- package/playbooks/platform/laravel-ui/inertia-react/security.md +5 -0
- package/playbooks/platform/laravel-ui/inertia-react/structure.md +5 -0
- package/playbooks/platform/laravel-ui/inertia-react/testing.md +5 -0
- package/playbooks/platform/laravel-ui/livewire/architecture.md +5 -0
- package/playbooks/platform/laravel-ui/livewire/runtime.md +5 -0
- package/playbooks/platform/laravel-ui/livewire/security.md +5 -0
- package/playbooks/platform/laravel-ui/livewire/structure.md +5 -0
- package/playbooks/platform/laravel-ui/livewire/testing.md +5 -0
- package/playbooks/platform/mobile.manifest.json +17 -0
- package/playbooks/platform/mobile.md +15 -0
- package/playbooks/platform/web.manifest.json +17 -0
- package/playbooks/platform/web.md +17 -0
- package/playbooks/stack/expo/architecture.md +27 -0
- package/playbooks/stack/expo/runtime.md +14 -0
- package/playbooks/stack/expo/security.md +18 -0
- package/playbooks/stack/expo/structure.md +26 -0
- package/playbooks/stack/expo/testing.md +13 -0
- package/playbooks/stack/laravel/architecture.md +34 -0
- package/playbooks/stack/laravel/runtime.md +27 -0
- package/playbooks/stack/laravel/security.md +23 -0
- package/playbooks/stack/laravel/structure.md +29 -0
- package/playbooks/stack/laravel/testing.md +22 -0
- package/playbooks/stack/laravel-ui.manifest.json +42 -0
- package/playbooks/stack/laravel.manifest.json +35 -0
- package/playbooks/stack/nextjs/architecture.md +62 -0
- package/playbooks/stack/nextjs/runtime.md +31 -0
- package/playbooks/stack/nextjs/security.md +32 -0
- package/playbooks/stack/nextjs/structure.md +50 -0
- package/playbooks/stack/nextjs/testing.md +20 -0
- package/playbooks/stack/nextjs.manifest.json +49 -0
- package/playbooks/stack/no-frontend.manifest.json +25 -0
- package/playbooks/stack/none.manifest.json +21 -0
- package/playbooks/stack/react-native.manifest.json +49 -0
- package/playbooks/stack/react-vite/architecture.md +33 -0
- package/playbooks/stack/react-vite/runtime.md +13 -0
- package/playbooks/stack/react-vite/security.md +16 -0
- package/playbooks/stack/react-vite/structure.md +23 -0
- package/playbooks/stack/react-vite/testing.md +12 -0
- package/playbooks/stack/react-vite.manifest.json +46 -0
- package/playbooks/stack/springboot/architecture.md +40 -0
- package/playbooks/stack/springboot/runtime.md +28 -0
- package/playbooks/stack/springboot/security.md +28 -0
- package/playbooks/stack/springboot/structure.md +30 -0
- package/playbooks/stack/springboot/testing.md +22 -0
- package/playbooks/stack/springboot.manifest.json +38 -0
- package/playbooks/styling/css-modules-extensions.md +267 -0
- package/playbooks/styling/css-modules.manifest.json +11 -0
- package/playbooks/styling/native-styles.manifest.json +9 -0
- package/playbooks/styling/native-styles.md +29 -0
- package/playbooks/styling/tailwind-extensions.md +182 -0
- package/playbooks/styling/tailwind.manifest.json +11 -0
- package/playbooks/universal/accessibility.manifest.json +11 -0
- package/playbooks/universal/accessibility.md +45 -0
- package/playbooks/universal/coding-rules.manifest.json +12 -0
- package/playbooks/universal/coding-rules.md +281 -0
- package/playbooks/universal/error-handling.manifest.json +10 -0
- package/playbooks/universal/error-handling.md +21 -0
- package/playbooks/universal/git-conventions.manifest.json +10 -0
- package/playbooks/universal/git-conventions.md +186 -0
- package/playbooks/universal/observability.manifest.json +10 -0
- package/playbooks/universal/observability.md +29 -0
- package/playbooks/universal/security.manifest.json +11 -0
- package/playbooks/universal/security.md +30 -0
- package/playbooks/universal/typescript.manifest.json +11 -0
- package/playbooks/universal/typescript.md +272 -0
- package/scripts/compatibility-matrix.mjs +48 -0
- package/scripts/validate-content.mjs +76 -0
- package/scripts/verify-generated.mjs +153 -0
- package/templates/agents/nextjs.md +47 -0
- package/templates/agents/react-native.md +48 -0
- package/templates/agents/react-vite.md +48 -0
- package/templates/docker/compose/postgres.yml +29 -0
- package/templates/docker/compose/springboot.yml +69 -0
- package/templates/docker/compose/supabase.yml +18 -0
- package/templates/docker/compose-prod/springboot.yml +64 -0
- package/templates/docker/dockerfile/laravel-inertia.dev.dockerfile +21 -0
- package/templates/docker/dockerfile/laravel.dev.dockerfile +12 -0
- package/templates/docker/dockerfile/laravel.prod.dockerfile +13 -0
- package/templates/docker/dockerfile/nextjs.dev.dockerfile +6 -0
- package/templates/docker/dockerfile/nextjs.prod.dockerfile +18 -0
- package/templates/docker/dockerfile/springboot.dev.dockerfile +5 -0
- package/templates/docker/dockerfile/springboot.prod.dockerfile +10 -0
- package/templates/docker/dockerfile/vite.dev.dockerfile +6 -0
- package/templates/docker/dockerfile/vite.prod.dockerfile +12 -0
- package/templates/gitignore/base.gitignore +32 -0
- package/templates/gitignore/nextjs.gitignore +40 -0
- package/templates/gitignore/react-native.gitignore +43 -0
- package/templates/gitignore/react-vite.gitignore +39 -0
- package/templates/makefile/frontend.mk +31 -0
- package/templates/makefile/laravel.mk +47 -0
- package/templates/makefile/postgres.mk +40 -0
- package/templates/makefile/springboot.mk +125 -0
- package/templates/makefile/supabase.mk +42 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Styling: CSS Modules — Extensions
|
|
2
|
+
|
|
3
|
+
Extends your existing CSS Modules playbook with missing patterns.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Dark Mode with CSS Variables
|
|
8
|
+
```css
|
|
9
|
+
/* styles/tokens.css — single source of truth */
|
|
10
|
+
:root {
|
|
11
|
+
/* Colors */
|
|
12
|
+
--color-background: #ffffff;
|
|
13
|
+
--color-foreground: #0a0a0a;
|
|
14
|
+
--color-primary: #1a1a2e;
|
|
15
|
+
--color-primary-foreground: #f0f0f0;
|
|
16
|
+
--color-muted: #f5f5f5;
|
|
17
|
+
--color-muted-foreground: #737373;
|
|
18
|
+
--color-border: #e5e5e5;
|
|
19
|
+
--color-error: #dc2626;
|
|
20
|
+
--color-success: #16a34a;
|
|
21
|
+
|
|
22
|
+
/* Typography */
|
|
23
|
+
--font-size-sm: 0.875rem;
|
|
24
|
+
--font-size-base: 1rem;
|
|
25
|
+
--font-size-lg: 1.125rem;
|
|
26
|
+
--font-size-xl: 1.25rem;
|
|
27
|
+
--font-size-2xl: 1.5rem;
|
|
28
|
+
|
|
29
|
+
/* Spacing */
|
|
30
|
+
--space-1: 0.25rem;
|
|
31
|
+
--space-2: 0.5rem;
|
|
32
|
+
--space-3: 0.75rem;
|
|
33
|
+
--space-4: 1rem;
|
|
34
|
+
--space-6: 1.5rem;
|
|
35
|
+
--space-8: 2rem;
|
|
36
|
+
|
|
37
|
+
/* Radius */
|
|
38
|
+
--radius-sm: 0.25rem;
|
|
39
|
+
--radius-md: 0.375rem;
|
|
40
|
+
--radius-lg: 0.5rem;
|
|
41
|
+
|
|
42
|
+
/* Transitions */
|
|
43
|
+
--transition-fast: 100ms ease;
|
|
44
|
+
--transition-base: 200ms ease;
|
|
45
|
+
--transition-slow: 500ms ease;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
[data-theme="dark"] {
|
|
49
|
+
--color-background: #0a0a0a;
|
|
50
|
+
--color-foreground: #f0f0f0;
|
|
51
|
+
--color-primary: #e0e0f0;
|
|
52
|
+
--color-primary-foreground: #1a1a2e;
|
|
53
|
+
--color-muted: #1a1a1a;
|
|
54
|
+
--color-muted-foreground: #a3a3a3;
|
|
55
|
+
--color-border: #262626;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// app/providers.tsx — apply theme to root
|
|
61
|
+
import { useEffect, useState } from 'react'
|
|
62
|
+
|
|
63
|
+
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
64
|
+
const [theme, setTheme] = useState<'light' | 'dark'>('light')
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
document.documentElement.setAttribute('data-theme', theme)
|
|
68
|
+
}, [theme])
|
|
69
|
+
|
|
70
|
+
return <>{children}</>
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Component Pattern with Tokens
|
|
77
|
+
```css
|
|
78
|
+
/* components/ui/Button/Button.module.css */
|
|
79
|
+
.button {
|
|
80
|
+
display: inline-flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
justify-content: center;
|
|
83
|
+
padding: var(--space-2) var(--space-4);
|
|
84
|
+
font-size: var(--font-size-base);
|
|
85
|
+
border-radius: var(--radius-md);
|
|
86
|
+
transition: background-color var(--transition-base);
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.primary {
|
|
91
|
+
background-color: var(--color-primary);
|
|
92
|
+
color: var(--color-primary-foreground);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.primary:hover {
|
|
96
|
+
opacity: 0.9;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.ghost {
|
|
100
|
+
background-color: transparent;
|
|
101
|
+
color: var(--color-foreground);
|
|
102
|
+
border: 1px solid var(--color-border);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.ghost:hover {
|
|
106
|
+
background-color: var(--color-muted);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.disabled {
|
|
110
|
+
opacity: 0.5;
|
|
111
|
+
cursor: not-allowed;
|
|
112
|
+
pointer-events: none;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## clsx for Class Composition
|
|
119
|
+
```typescript
|
|
120
|
+
// Install: npm install clsx
|
|
121
|
+
import clsx from 'clsx'
|
|
122
|
+
import styles from './Button.module.css'
|
|
123
|
+
|
|
124
|
+
export function Button({ variant = 'primary', disabled, className }: ButtonProps) {
|
|
125
|
+
return (
|
|
126
|
+
<button
|
|
127
|
+
className={clsx(
|
|
128
|
+
styles.button,
|
|
129
|
+
styles[variant],
|
|
130
|
+
disabled && styles.disabled,
|
|
131
|
+
className // allow external class override
|
|
132
|
+
)}
|
|
133
|
+
disabled={disabled}
|
|
134
|
+
>
|
|
135
|
+
{children}
|
|
136
|
+
</button>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Responsive in Module File
|
|
144
|
+
```css
|
|
145
|
+
/* UserCard.module.css */
|
|
146
|
+
.card {
|
|
147
|
+
display: flex;
|
|
148
|
+
flex-direction: column;
|
|
149
|
+
padding: var(--space-4);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Responsive stays in the component's own module file */
|
|
153
|
+
@media (min-width: 768px) {
|
|
154
|
+
.card {
|
|
155
|
+
flex-direction: row;
|
|
156
|
+
padding: var(--space-6);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@media (min-width: 1024px) {
|
|
161
|
+
.card {
|
|
162
|
+
max-width: 800px;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Animation
|
|
170
|
+
```css
|
|
171
|
+
/* Define @keyframes in component module if component-specific */
|
|
172
|
+
/* Define in global.css if reused across components */
|
|
173
|
+
|
|
174
|
+
/* Component-specific */
|
|
175
|
+
@keyframes fadeIn {
|
|
176
|
+
from { opacity: 0; transform: translateY(-8px); }
|
|
177
|
+
to { opacity: 1; transform: translateY(0); }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.dropdown {
|
|
181
|
+
animation: fadeIn var(--transition-base);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Reused animation → globals.css */
|
|
185
|
+
@keyframes spin {
|
|
186
|
+
to { transform: rotate(360deg); }
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Never Mix Tailwind + CSS Modules on Same Element
|
|
193
|
+
```typescript
|
|
194
|
+
// ❌ mixing both on same element
|
|
195
|
+
<div className={clsx(styles.card, 'flex items-center')} />
|
|
196
|
+
|
|
197
|
+
// ✅ pick one strategy per project (defined at init)
|
|
198
|
+
// CSS Modules project → all styling via modules
|
|
199
|
+
<div className={styles.card} />
|
|
200
|
+
|
|
201
|
+
// Tailwind project → all styling via Tailwind
|
|
202
|
+
<div className="flex items-center gap-4 rounded-md" />
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Global Styles Structure
|
|
208
|
+
```
|
|
209
|
+
src/styles/
|
|
210
|
+
tokens.css → CSS variables (colors, space, type, radius)
|
|
211
|
+
globals.css → reset, base elements, @import tokens
|
|
212
|
+
animations.css → reusable @keyframes (optional)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
```css
|
|
216
|
+
/* globals.css */
|
|
217
|
+
@import './tokens.css';
|
|
218
|
+
|
|
219
|
+
*, *::before, *::after {
|
|
220
|
+
box-sizing: border-box;
|
|
221
|
+
margin: 0;
|
|
222
|
+
padding: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
body {
|
|
226
|
+
background-color: var(--color-background);
|
|
227
|
+
color: var(--color-foreground);
|
|
228
|
+
font-size: var(--font-size-base);
|
|
229
|
+
line-height: 1.5;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
a {
|
|
233
|
+
color: inherit;
|
|
234
|
+
text-decoration: none;
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Agent Quick Reference (Extended)
|
|
241
|
+
```
|
|
242
|
+
Dark mode?
|
|
243
|
+
→ [data-theme="dark"] on html element
|
|
244
|
+
→ CSS variables in tokens.css, overrides in [data-theme="dark"]
|
|
245
|
+
→ Toggle via data-theme attribute, not class swap
|
|
246
|
+
|
|
247
|
+
Conditional classes?
|
|
248
|
+
→ clsx(styles.base, condition && styles.variant)
|
|
249
|
+
→ Never string template literals
|
|
250
|
+
|
|
251
|
+
Responsive?
|
|
252
|
+
→ @media queries in component's own .module.css
|
|
253
|
+
→ Mobile styles first (no query), then @media (min-width: ...)
|
|
254
|
+
|
|
255
|
+
Animation?
|
|
256
|
+
→ Component-specific: @keyframes in component module
|
|
257
|
+
→ Reused: @keyframes in globals.css or animations.css
|
|
258
|
+
→ Duration: always use --transition-* tokens
|
|
259
|
+
|
|
260
|
+
New token needed?
|
|
261
|
+
→ Add to tokens.css under correct section
|
|
262
|
+
→ Never hardcode values in component modules
|
|
263
|
+
|
|
264
|
+
External class override allowed?
|
|
265
|
+
→ Accept className prop, pass to clsx as last arg
|
|
266
|
+
→ Allows parent to extend without modifying component
|
|
267
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "css-modules",
|
|
3
|
+
"kind": "styling",
|
|
4
|
+
"label": "CSS Modules",
|
|
5
|
+
"file": "styling/css-modules-extensions.md",
|
|
6
|
+
"required": false,
|
|
7
|
+
"folders": [],
|
|
8
|
+
"concerns": [
|
|
9
|
+
{ "id": "styling", "required": true, "sections": ["Dark Mode with CSS Variables", "Responsive in Module File"] }
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# React Native StyleSheet
|
|
2
|
+
|
|
3
|
+
## Default
|
|
4
|
+
|
|
5
|
+
Use React Native's built-in `StyleSheet` for the starter. It runs without a CSS compiler, Babel plugin, or platform-specific setup and keeps the generated Expo project immediately runnable.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { StyleSheet, Text, View } from 'react-native'
|
|
9
|
+
|
|
10
|
+
export function EmptyState() {
|
|
11
|
+
return (
|
|
12
|
+
<View style={styles.container}>
|
|
13
|
+
<Text style={styles.title}>Nothing here yet</Text>
|
|
14
|
+
</View>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const styles = StyleSheet.create({
|
|
19
|
+
container: { padding: 24 },
|
|
20
|
+
title: { fontSize: 20, fontWeight: '600' },
|
|
21
|
+
})
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Rules
|
|
25
|
+
|
|
26
|
+
- Keep styles next to a component until several components share the same design primitive.
|
|
27
|
+
- Use theme tokens for repeated colors, spacing, radius, and typography; do not create a global stylesheet of screen-specific rules.
|
|
28
|
+
- Test layout on Android, iOS, and web before assuming platform behavior is identical.
|
|
29
|
+
- Add NativeWind or another styling system only as an explicit project decision, including its complete Expo configuration and build verification.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Styling: Tailwind CSS — Extensions
|
|
2
|
+
|
|
3
|
+
Extends your existing tailwind playbook with missing patterns.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Optional cn() Utility for Conditional Classes
|
|
8
|
+
|
|
9
|
+
The starter does not install these packages. Add `clsx` and `tailwind-merge` before using this optional helper.
|
|
10
|
+
```typescript
|
|
11
|
+
// lib/utils.ts
|
|
12
|
+
import { clsx, type ClassValue } from 'clsx'
|
|
13
|
+
import { twMerge } from 'tailwind-merge'
|
|
14
|
+
|
|
15
|
+
export function cn(...inputs: ClassValue[]) {
|
|
16
|
+
return twMerge(clsx(inputs))
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// Usage — conditional classes
|
|
22
|
+
<div className={cn(
|
|
23
|
+
'base-class other-class',
|
|
24
|
+
isActive && 'active-class',
|
|
25
|
+
isDisabled && 'opacity-50 cursor-not-allowed',
|
|
26
|
+
variant === 'primary' ? 'bg-blue-500' : 'bg-gray-500'
|
|
27
|
+
)} />
|
|
28
|
+
|
|
29
|
+
// Never string concatenate
|
|
30
|
+
// ❌ `base ${isActive ? 'active' : ''}`
|
|
31
|
+
// ✅ cn('base', isActive && 'active')
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Optional shadcn/ui Integration
|
|
37
|
+
|
|
38
|
+
shadcn/ui is not part of the generated starter. If the project deliberately adopts it:
|
|
39
|
+
- Components live in `components/ui/` — you own the code
|
|
40
|
+
- Install via CLI: `npx shadcn@latest add [component]`
|
|
41
|
+
- Prefer wrapping generated primitives when adding application-specific behavior
|
|
42
|
+
- Use shadcn variants as-is or override in your wrapper
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// components/ui/button.tsx — generated by shadcn CLI, don't hand-write
|
|
46
|
+
// components/shared/SubmitButton.tsx — your wrapper that extends it
|
|
47
|
+
import { Button } from '@/components/ui/button'
|
|
48
|
+
|
|
49
|
+
export function SubmitButton({ isLoading, children }: SubmitButtonProps) {
|
|
50
|
+
return (
|
|
51
|
+
<Button type="submit" disabled={isLoading}>
|
|
52
|
+
{isLoading ? <Spinner /> : children}
|
|
53
|
+
</Button>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Dark Mode
|
|
61
|
+
```typescript
|
|
62
|
+
// tailwind.config.ts
|
|
63
|
+
export default {
|
|
64
|
+
darkMode: 'class', // controlled by next-themes or manual class toggle
|
|
65
|
+
content: ['./src/**/*.{ts,tsx}'],
|
|
66
|
+
theme: {
|
|
67
|
+
extend: {
|
|
68
|
+
colors: {
|
|
69
|
+
// semantic tokens — use these, not raw colors
|
|
70
|
+
background: 'hsl(var(--background))',
|
|
71
|
+
foreground: 'hsl(var(--foreground))',
|
|
72
|
+
primary: {
|
|
73
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
74
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
75
|
+
},
|
|
76
|
+
muted: {
|
|
77
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
78
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```css
|
|
87
|
+
/* globals.css */
|
|
88
|
+
@layer base {
|
|
89
|
+
:root {
|
|
90
|
+
--background: 0 0% 100%;
|
|
91
|
+
--foreground: 222.2 84% 4.9%;
|
|
92
|
+
--primary: 222.2 47.4% 11.2%;
|
|
93
|
+
--primary-foreground: 210 40% 98%;
|
|
94
|
+
--muted: 210 40% 96%;
|
|
95
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.dark {
|
|
99
|
+
--background: 222.2 84% 4.9%;
|
|
100
|
+
--foreground: 210 40% 98%;
|
|
101
|
+
--primary: 210 40% 98%;
|
|
102
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
103
|
+
--muted: 217.2 32.6% 17.5%;
|
|
104
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Responsive — Mobile First Always
|
|
112
|
+
```typescript
|
|
113
|
+
// ✅ mobile-first (correct)
|
|
114
|
+
<div className="flex-col sm:flex-row md:gap-8 lg:max-w-7xl" />
|
|
115
|
+
|
|
116
|
+
// ❌ never reverse-breakpoint
|
|
117
|
+
<div className="flex-row lg:flex-col" /> // only acceptable in specific override cases
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Animation Rules
|
|
123
|
+
```typescript
|
|
124
|
+
// ✅ use Tailwind transition classes
|
|
125
|
+
<button className="transition-colors duration-200 hover:bg-primary/90" />
|
|
126
|
+
|
|
127
|
+
// ✅ define durations in config — not arbitrary
|
|
128
|
+
// tailwind.config.ts
|
|
129
|
+
transitionDuration: {
|
|
130
|
+
DEFAULT: '200ms',
|
|
131
|
+
fast: '100ms',
|
|
132
|
+
slow: '500ms',
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ❌ arbitrary duration values
|
|
136
|
+
<div className="duration-[347ms]" /> // use config token instead
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Color Rules
|
|
142
|
+
```typescript
|
|
143
|
+
// ✅ use semantic tokens
|
|
144
|
+
<div className="bg-background text-foreground" />
|
|
145
|
+
<button className="bg-primary text-primary-foreground" />
|
|
146
|
+
|
|
147
|
+
// ❌ hardcoded color values
|
|
148
|
+
<div className="bg-[#1a1a2e]" />
|
|
149
|
+
<div className="text-[#f0f0f0]" />
|
|
150
|
+
|
|
151
|
+
// ❌ raw Tailwind colors for brand elements (grey-to-blue shifts on upgrade)
|
|
152
|
+
<div className="bg-blue-600" /> // use 'bg-primary' instead
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Agent Quick Reference (Extended)
|
|
158
|
+
```
|
|
159
|
+
Conditional classes?
|
|
160
|
+
→ cn() from lib/utils.ts always
|
|
161
|
+
→ Never string template literals for class composition
|
|
162
|
+
|
|
163
|
+
shadcn component needed?
|
|
164
|
+
→ npx shadcn@latest add [component-name]
|
|
165
|
+
→ Component lands in components/ui/
|
|
166
|
+
→ Wrap in components/shared/ if you add business logic
|
|
167
|
+
|
|
168
|
+
Dark mode colors?
|
|
169
|
+
→ Use CSS variable tokens in tailwind.config.ts
|
|
170
|
+
→ Define :root and .dark in globals.css
|
|
171
|
+
→ Apply via 'bg-background', 'text-foreground' classes
|
|
172
|
+
|
|
173
|
+
Responsive?
|
|
174
|
+
→ Mobile styles first (no prefix)
|
|
175
|
+
→ Tablet: sm: or md:
|
|
176
|
+
→ Desktop: lg: or xl:
|
|
177
|
+
|
|
178
|
+
Animation?
|
|
179
|
+
→ transition-[property] duration-[token] ease-[type]
|
|
180
|
+
→ Custom durations in tailwind.config.ts
|
|
181
|
+
→ No arbitrary duration values
|
|
182
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "accessibility-baseline",
|
|
3
|
+
"kind": "universal",
|
|
4
|
+
"label": "Accessibility Baseline",
|
|
5
|
+
"required": true,
|
|
6
|
+
"folders": [],
|
|
7
|
+
"concerns": [
|
|
8
|
+
{ "id": "accessibility", "required": true, "sections": ["Semantic Structure", "Keyboard and Focus", "Forms and Authentication", "Accessibility Testing"] }
|
|
9
|
+
]
|
|
10
|
+
}
|
|
11
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Accessibility Baseline
|
|
2
|
+
|
|
3
|
+
> Target WCAG 2.2 AA for web interfaces. Mobile interfaces follow the same perceivable, operable, understandable, and robust principles using platform accessibility APIs.
|
|
4
|
+
|
|
5
|
+
## Semantic Structure
|
|
6
|
+
|
|
7
|
+
- Use native elements and controls before recreating behavior with generic containers.
|
|
8
|
+
- Give each page one descriptive primary heading and a logical heading hierarchy.
|
|
9
|
+
- Every control has an accessible name. Every form field has a persistent label and associated error/help text.
|
|
10
|
+
- Images need meaningful alternative text or an explicit decorative treatment.
|
|
11
|
+
|
|
12
|
+
## Keyboard and Focus
|
|
13
|
+
|
|
14
|
+
- All interactive behavior works from the keyboard without a trap.
|
|
15
|
+
- Focus order follows visual and reading order.
|
|
16
|
+
- Dialogs move focus inside, contain it while open, close with Escape when appropriate, and restore focus to the trigger.
|
|
17
|
+
- Route changes, validation failures, and asynchronous updates move or announce focus only when it helps the user understand the change.
|
|
18
|
+
- Visible focus indicators must not be removed or obscured.
|
|
19
|
+
|
|
20
|
+
## Visual and Motion
|
|
21
|
+
|
|
22
|
+
- Do not use color alone to communicate state.
|
|
23
|
+
- Meet WCAG contrast requirements for text, controls, states, and focus indicators.
|
|
24
|
+
- Layout must support zoom, text resizing, narrow screens, and content reflow without hiding essential actions.
|
|
25
|
+
- Respect `prefers-reduced-motion`; avoid flashing and unnecessary autoplay.
|
|
26
|
+
- Touch targets must be large enough and not depend on precision dragging alone.
|
|
27
|
+
|
|
28
|
+
## Forms and Authentication
|
|
29
|
+
|
|
30
|
+
- Identify errors in text, associate them with fields, and preserve entered values after failed validation.
|
|
31
|
+
- Allow password managers and paste. Do not block autocomplete or require users to transcribe credentials unnecessarily.
|
|
32
|
+
- Provide accessible alternatives to cognitive-function authentication tests where required by WCAG 2.2.
|
|
33
|
+
- Loading and disabled states remain perceivable to assistive technology.
|
|
34
|
+
|
|
35
|
+
## Accessibility Testing
|
|
36
|
+
|
|
37
|
+
- Prefer role, label, and visible-name queries in component and end-to-end tests.
|
|
38
|
+
- Add automated axe checks for common violations, but do not treat automation as complete coverage.
|
|
39
|
+
- Manually test keyboard navigation, focus, zoom/reflow, reduced motion, and at least one screen reader for critical flows.
|
|
40
|
+
- Include authentication, errors, dialogs, navigation, and the core user journey in manual coverage.
|
|
41
|
+
|
|
42
|
+
## Primary Reference
|
|
43
|
+
|
|
44
|
+
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
|
|
45
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "coding-rules",
|
|
3
|
+
"kind": "universal",
|
|
4
|
+
"label": "Coding Rules",
|
|
5
|
+
"required": true,
|
|
6
|
+
"folders": [],
|
|
7
|
+
"devDeps": ["prettier"],
|
|
8
|
+
"concerns": [
|
|
9
|
+
{ "id": "naming", "required": true, "sections": ["Naming", "Functions", "Imports", "Constants"] },
|
|
10
|
+
{ "id": "no-debug", "required": true, "sections": ["No Debug Code in Commits", "One Thing Per File"] }
|
|
11
|
+
]
|
|
12
|
+
}
|