@vadimcomanescu/nadicode-design-system 4.0.1 → 4.0.2
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/.agents/skills/seed/SKILL.md +34 -163
- package/.agents/skills/seed/references/animation.md +2 -2
- package/.agents/skills/seed/references/responsive.md +1 -1
- package/README.md +2 -2
- package/eslint-rules/nadicode/rules/no-has-svg-selector.js +1 -1
- package/package.json +1 -2
- package/scripts/ds-check.mjs +0 -10
- package/scripts/sync-seed-skill.mjs +0 -3
- package/.agents/skills/seed/contract.md +0 -110
- package/.agents/skills/seed/intent-map.md +0 -320
- package/.agents/skills/seed/recipes/agency-home.md +0 -311
- package/.agents/skills/seed/recipes/agents-chat.md +0 -305
- package/.agents/skills/seed/recipes/analytics.md +0 -253
- package/.agents/skills/seed/recipes/auth.md +0 -254
- package/.agents/skills/seed/recipes/blog-content.md +0 -307
- package/.agents/skills/seed/recipes/checkout.md +0 -311
- package/.agents/skills/seed/recipes/company-about.md +0 -276
- package/.agents/skills/seed/recipes/company-contact.md +0 -234
- package/.agents/skills/seed/recipes/crud-form.md +0 -233
- package/.agents/skills/seed/recipes/crud-list-detail.md +0 -230
- package/.agents/skills/seed/recipes/dashboard.md +0 -354
- package/.agents/skills/seed/recipes/digital-workers.md +0 -314
- package/.agents/skills/seed/recipes/error-pages.md +0 -199
- package/.agents/skills/seed/recipes/marketing-landing.md +0 -293
- package/.agents/skills/seed/recipes/marketing-shell.md +0 -156
- package/.agents/skills/seed/recipes/navigation-shell.md +0 -787
- package/.agents/skills/seed/recipes/onboarding.md +0 -258
- package/.agents/skills/seed/recipes/pricing.md +0 -271
- package/.agents/skills/seed/recipes/service-detail.md +0 -302
- package/.agents/skills/seed/recipes/settings.md +0 -252
- package/.agents/skills/seed/references/blocks.md +0 -128
- package/.agents/skills/seed/references/components.md +0 -287
- package/.agents/skills/seed/references/icons.md +0 -169
- package/.agents/skills/seed/references/nextjs.md +0 -49
- package/.agents/skills/seed/references/tokens.md +0 -88
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
# Recipe: Company Contact
|
|
2
|
-
|
|
3
|
-
Contact page with form, company information, and FAQ.
|
|
4
|
-
|
|
5
|
-
## Route Pattern
|
|
6
|
-
|
|
7
|
-
`/contact` or `/contatti`
|
|
8
|
-
|
|
9
|
-
## Shell
|
|
10
|
-
|
|
11
|
-
`marketing-shell` (HeaderBlock + FooterBlock)
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Layout Blueprint (Desktop)
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
+------------------------------------------------+
|
|
19
|
-
| HeaderBlock: Logo [Nav links] [CTA Button] |
|
|
20
|
-
+------------------------------------------------+
|
|
21
|
-
| |
|
|
22
|
-
| HEADING |
|
|
23
|
-
| "Get in Touch" |
|
|
24
|
-
| Subtitle |
|
|
25
|
-
| |
|
|
26
|
-
+------------------------------------------------+
|
|
27
|
-
| |
|
|
28
|
-
| CONTACT BLOCK (2-col) |
|
|
29
|
-
| +-------------------+ +------------------+ |
|
|
30
|
-
| | Contact form | | Company info | |
|
|
31
|
-
| | Name, Email, | | Address, phone, | |
|
|
32
|
-
| | Subject, Message | | email, map | |
|
|
33
|
-
| | [Submit] | | | |
|
|
34
|
-
| +-------------------+ +------------------+ |
|
|
35
|
-
| |
|
|
36
|
-
+------------------------------------------------+
|
|
37
|
-
| |
|
|
38
|
-
| INFO CARDS (3-col) |
|
|
39
|
-
| +----------+ +----------+ +----------+ |
|
|
40
|
-
| | Email | | Phone | | Office | |
|
|
41
|
-
| +----------+ +----------+ +----------+ |
|
|
42
|
-
| |
|
|
43
|
-
+------------------------------------------------+
|
|
44
|
-
| |
|
|
45
|
-
| FAQ (Accordion) |
|
|
46
|
-
| |
|
|
47
|
-
+------------------------------------------------+
|
|
48
|
-
| FooterBlock: columns + social + legal |
|
|
49
|
-
+------------------------------------------------+
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Section Sequence
|
|
55
|
-
|
|
56
|
-
### 1. Header
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
<HeaderBlock logo={<Logo />} links={navLinks} actions={<Button>Book a Call</Button>} />
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 2. Heading
|
|
63
|
-
|
|
64
|
-
```tsx
|
|
65
|
-
<section className="py-16 md:py-24">
|
|
66
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
|
67
|
-
<motion.div variants={heroStagger.container} initial="hidden" animate="visible">
|
|
68
|
-
<motion.h1 variants={heroStagger.child} className="text-4xl md:text-5xl font-bold tracking-tight">
|
|
69
|
-
Get in Touch
|
|
70
|
-
</motion.h1>
|
|
71
|
-
<motion.p variants={heroStagger.child} className="mt-4 text-lg text-text-secondary max-w-xl mx-auto">
|
|
72
|
-
Have a question or want to work together? We'd love to hear from you.
|
|
73
|
-
</motion.p>
|
|
74
|
-
</motion.div>
|
|
75
|
-
</div>
|
|
76
|
-
</section>
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 3. Contact Block
|
|
80
|
-
|
|
81
|
-
```tsx
|
|
82
|
-
<ScrollFadeIn>
|
|
83
|
-
<section className="pb-16 md:pb-24">
|
|
84
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
85
|
-
<ContactBlock
|
|
86
|
-
fields={contactFields}
|
|
87
|
-
companyInfo={companyInfo}
|
|
88
|
-
onSubmit={handleSubmit}
|
|
89
|
-
/>
|
|
90
|
-
</div>
|
|
91
|
-
</section>
|
|
92
|
-
</ScrollFadeIn>
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### 4. Info Cards
|
|
96
|
-
|
|
97
|
-
```tsx
|
|
98
|
-
<ScrollFadeIn>
|
|
99
|
-
<section className="py-16 md:py-24 bg-muted">
|
|
100
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
101
|
-
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
102
|
-
{contactChannels.map(channel => (
|
|
103
|
-
<Card key={channel.id} className="glass-panel p-6 text-center">
|
|
104
|
-
<channel.icon className="mx-auto mb-4 h-8 w-8 text-accent" />
|
|
105
|
-
<Heading level={4} size="title" >{channel.label}</Heading>
|
|
106
|
-
<Typography variant="body" className="mt-2 text-text-secondary">
|
|
107
|
-
{channel.value}
|
|
108
|
-
</Typography>
|
|
109
|
-
</Card>
|
|
110
|
-
))}
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
</section>
|
|
114
|
-
</ScrollFadeIn>
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### 5. FAQ
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
<ScrollFadeIn>
|
|
121
|
-
<section className="py-16 md:py-24">
|
|
122
|
-
<FAQBlock items={contactFaqItems} />
|
|
123
|
-
</section>
|
|
124
|
-
</ScrollFadeIn>
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### 6. Footer
|
|
128
|
-
|
|
129
|
-
```tsx
|
|
130
|
-
<FooterBlock columns={footerColumns} social={socialLinks} legal={legalLinks} />
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## Animation Storyboard
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
ANIMATION STORYBOARD
|
|
139
|
-
====================
|
|
140
|
-
BUDGET: 600ms (above-fold) | SPRING: dramatic (heading), snappy (rest) | REDUCED: opacity-only
|
|
141
|
-
|
|
142
|
-
T+0ms [nav] Header visible (instant)
|
|
143
|
-
T+100ms [headline] Page heading {fadeInUp, dramatic}
|
|
144
|
-
T+250ms [subtitle] Subtitle {fadeInUp, dramatic}
|
|
145
|
-
|
|
146
|
-
SCROLL-TRIGGERED (below fold):
|
|
147
|
-
[contact] ScrollFadeIn at 20% visible {fadeInUp, snappy}
|
|
148
|
-
[info-cards] ScrollFadeIn at 20% visible {fadeInUp, snappy, stagger 100ms}
|
|
149
|
-
[faq] ScrollFadeIn at 20% visible {fadeInUp, snappy}
|
|
150
|
-
|
|
151
|
-
REDUCED MOTION: All items visible immediately, opacity 0->1 in 10ms
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## Required Components
|
|
157
|
-
|
|
158
|
-
| Component | Import Path | Purpose |
|
|
159
|
-
|-----------|-------------|---------|
|
|
160
|
-
| `HeaderBlock` | `@vadimcomanescu/nadicode-design-system/catalog/components` via `seedComponents` | Site navigation |
|
|
161
|
-
| `FooterBlock` | `@vadimcomanescu/nadicode-design-system/catalog/components` via `seedComponents` | Site footer |
|
|
162
|
-
| `Button` | `@vadimcomanescu/nadicode-design-system/button` | CTAs and form submit |
|
|
163
|
-
| `ScrollFadeIn` | `@vadimcomanescu/nadicode-design-system/scroll-fade-in` | Below-fold animations |
|
|
164
|
-
| `ContactBlock` | `@vadimcomanescu/nadicode-design-system/catalog/components` via `seedComponents` | Contact form + company info |
|
|
165
|
-
|
|
166
|
-
### Allowed (optional)
|
|
167
|
-
|
|
168
|
-
`FAQBlock`, `Card`, `FeatureGridBlock`, `Badge`, `HeroBlock`, `HeroSectionBlock`, `CallToActionBlock`, `Typography`
|
|
169
|
-
|
|
170
|
-
### Forbidden
|
|
171
|
-
|
|
172
|
-
`Sidebar`, `DataTable`, `FormWizard`, `AgentTeamPanel`, `PricingBlock`, `SettingsLayout`, `ChatLayout`
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## Required States
|
|
177
|
-
|
|
178
|
-
| State | Trigger | Visual |
|
|
179
|
-
|-------|---------|--------|
|
|
180
|
-
| `default` | Page loaded | Form ready for input |
|
|
181
|
-
| `form-submitting` | Form submit | Button shows loading spinner, fields disabled |
|
|
182
|
-
| `form-success` | Submission succeeds | Success toast/message, form resets |
|
|
183
|
-
| `form-error` | Submission fails | Error toast/message, form retains values |
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## Responsive Contract
|
|
188
|
-
|
|
189
|
-
| Breakpoint | Heading | Contact Block | Info Cards | Content Width |
|
|
190
|
-
|------------|---------|---------------|------------|---------------|
|
|
191
|
-
| Mobile | text-center | Stacked (form above info) | 1 col | px-4 |
|
|
192
|
-
| `sm:` | text-center | Stacked (form above info) | 2 col | px-6, max-w-7xl |
|
|
193
|
-
| `lg:` | text-center | Side-by-side (form left, info right) | 3 col | px-8, max-w-7xl |
|
|
194
|
-
|
|
195
|
-
---
|
|
196
|
-
|
|
197
|
-
## Styling Rules
|
|
198
|
-
|
|
199
|
-
- Contact form container uses `glass-panel` for visual depth
|
|
200
|
-
- Info cards use `glass-panel` with centered icon layout
|
|
201
|
-
- Section backgrounds alternate: `bg-background` and `bg-muted`
|
|
202
|
-
- Form inputs use standard Seed Input/Textarea components
|
|
203
|
-
- Submit button uses `Button` with loading state
|
|
204
|
-
- No raw palette colors; semantic tokens only
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## Accessibility
|
|
209
|
-
|
|
210
|
-
- Page heading is `<h1>`, section headings are `<h2>`
|
|
211
|
-
- Form fields have visible stacked labels (no floating labels)
|
|
212
|
-
- Required fields marked with `aria-required="true"`
|
|
213
|
-
- Form errors announced via `aria-live="polite"` region
|
|
214
|
-
- Submit button disabled during submission with `aria-disabled`
|
|
215
|
-
- Skip-nav link to main content
|
|
216
|
-
- Mobile nav is keyboard accessible with focus trap
|
|
217
|
-
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
## Reference Implementations
|
|
221
|
-
|
|
222
|
-
- `src/components/blocks/ContactBlock.tsx`
|
|
223
|
-
- `src/components/blocks/FAQBlock.tsx`
|
|
224
|
-
|
|
225
|
-
---
|
|
226
|
-
|
|
227
|
-
## Verification
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
npx tsc --noEmit
|
|
231
|
-
npm run lint
|
|
232
|
-
npm run test
|
|
233
|
-
npx vitest run src/test/css-variable-usage.test.ts
|
|
234
|
-
```
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
# Recipe: CRUD Form
|
|
2
|
-
|
|
3
|
-
Create or edit entity pages with sectioned form groups and validation.
|
|
4
|
-
|
|
5
|
-
## Route Patterns
|
|
6
|
-
|
|
7
|
-
- `/[entity]/new` (create)
|
|
8
|
-
- `/[entity]/[id]/edit` (edit)
|
|
9
|
-
|
|
10
|
-
## Shell
|
|
11
|
-
|
|
12
|
-
`app-shell` (Sidebar + top bar + SearchCommand)
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Layout Blueprint (Desktop)
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
+--+---------------------------------------------+
|
|
20
|
-
| | Breadcrumb: Home > [Entity] > New |
|
|
21
|
-
|S | Page Title [Cancel] |
|
|
22
|
-
|I | |
|
|
23
|
-
|D | +------------------------------------------+ |
|
|
24
|
-
|E | | Section 1: Basic Information glass-panel|
|
|
25
|
-
|B | | +--------------------------------------+ | |
|
|
26
|
-
|A | | | Label | | |
|
|
27
|
-
|R | | | [Input] | | |
|
|
28
|
-
| | | | Label | | |
|
|
29
|
-
| | | | [Textarea] | | |
|
|
30
|
-
| | | +--------------------------------------+ | |
|
|
31
|
-
| | +------------------------------------------+ |
|
|
32
|
-
| | |
|
|
33
|
-
| | +------------------------------------------+ |
|
|
34
|
-
| | | Section 2: Configuration glass-panel| |
|
|
35
|
-
| | | [Select] [Switch] [Checkbox] | |
|
|
36
|
-
| | +------------------------------------------+ |
|
|
37
|
-
| | |
|
|
38
|
-
| | +------------------------------------------+ |
|
|
39
|
-
| | | Actions Row | |
|
|
40
|
-
| | | [Delete] [Cancel] [Save] | |
|
|
41
|
-
| | +------------------------------------------+ |
|
|
42
|
-
+--+---------------------------------------------+
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Section Sequence
|
|
48
|
-
|
|
49
|
-
### 1. Page Header
|
|
50
|
-
|
|
51
|
-
```tsx
|
|
52
|
-
<div className="flex items-center justify-between">
|
|
53
|
-
<div>
|
|
54
|
-
<Breadcrumb>...</Breadcrumb>
|
|
55
|
-
<Heading level={2} size="section" >{isEdit ? `Edit ${name}` : `New ${entityType}`}</Heading>
|
|
56
|
-
</div>
|
|
57
|
-
<Button variant="ghost" onClick={handleCancel}>Cancel</Button>
|
|
58
|
-
</div>
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 2. Form Sections (grouped in Cards)
|
|
62
|
-
|
|
63
|
-
```tsx
|
|
64
|
-
<Form {...form}>
|
|
65
|
-
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
|
66
|
-
{/* Section 1 */}
|
|
67
|
-
<Card className="glass-panel p-6">
|
|
68
|
-
<Heading level={4} size="title" className="mb-4">Basic Information</Heading>
|
|
69
|
-
<div className="space-y-4">
|
|
70
|
-
<FormField control={form.control} name="name" render={({ field }) => (
|
|
71
|
-
<FormItem>
|
|
72
|
-
<FormLabel>Name</FormLabel>
|
|
73
|
-
<FormControl><Input {...field} /></FormControl>
|
|
74
|
-
<FormMessage />
|
|
75
|
-
</FormItem>
|
|
76
|
-
)} />
|
|
77
|
-
<FormField control={form.control} name="description" render={({ field }) => (
|
|
78
|
-
<FormItem>
|
|
79
|
-
<FormLabel>Description</FormLabel>
|
|
80
|
-
<FormControl><Textarea {...field} /></FormControl>
|
|
81
|
-
<FormMessage />
|
|
82
|
-
</FormItem>
|
|
83
|
-
)} />
|
|
84
|
-
</div>
|
|
85
|
-
</Card>
|
|
86
|
-
|
|
87
|
-
{/* Section 2 */}
|
|
88
|
-
<Card className="glass-panel p-6">
|
|
89
|
-
<Heading level={4} size="title" className="mb-4">Configuration</Heading>
|
|
90
|
-
<div className="space-y-4">
|
|
91
|
-
{/* Select, Switch, Checkbox fields */}
|
|
92
|
-
</div>
|
|
93
|
-
</Card>
|
|
94
|
-
|
|
95
|
-
{/* Actions */}
|
|
96
|
-
<div className="flex items-center justify-between pt-4">
|
|
97
|
-
{isEdit && (
|
|
98
|
-
<AlertDialog>
|
|
99
|
-
<AlertDialogTrigger asChild>
|
|
100
|
-
<Button variant="destructive">Delete</Button>
|
|
101
|
-
</AlertDialogTrigger>
|
|
102
|
-
{/* Delete confirmation */}
|
|
103
|
-
</AlertDialog>
|
|
104
|
-
)}
|
|
105
|
-
<div className="flex items-center gap-3 ml-auto">
|
|
106
|
-
<Button variant="outline" onClick={handleCancel}>Cancel</Button>
|
|
107
|
-
<Button type="submit" disabled={!isDirty || isSubmitting}>
|
|
108
|
-
{isSubmitting ? <Spinner className="mr-2" /> : null}
|
|
109
|
-
{isEdit ? "Save Changes" : "Create"}
|
|
110
|
-
</Button>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
</form>
|
|
114
|
-
</Form>
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Animation Storyboard
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
ANIMATION STORYBOARD
|
|
123
|
-
====================
|
|
124
|
-
BUDGET: 400ms | SPRING: snappy | REDUCED: opacity-only
|
|
125
|
-
|
|
126
|
-
T+0ms [shell] Sidebar + top bar visible (instant)
|
|
127
|
-
T+50ms [header] Title + breadcrumb {fadeInUp, snappy}
|
|
128
|
-
T+130ms [section-1] First form section {fadeInUp, snappy}
|
|
129
|
-
T+230ms [section-2] Second form section {fadeInUp, snappy}
|
|
130
|
-
T+330ms [actions] Action buttons row {fadeIn, snappy}
|
|
131
|
-
|
|
132
|
-
REDUCED MOTION: All items visible immediately
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
## Required Components
|
|
138
|
-
|
|
139
|
-
| Component | Import Path | Purpose |
|
|
140
|
-
|-----------|-------------|---------|
|
|
141
|
-
| `Form` | `@vadimcomanescu/nadicode-design-system/form` | Form wrapper (react-hook-form) |
|
|
142
|
-
| `FormField` | `@vadimcomanescu/nadicode-design-system/form` | Field binding |
|
|
143
|
-
| `FormItem` | `@vadimcomanescu/nadicode-design-system/form` | Field container |
|
|
144
|
-
| `FormLabel` | `@vadimcomanescu/nadicode-design-system/form` | Stacked label (above input) |
|
|
145
|
-
| `FormControl` | `@vadimcomanescu/nadicode-design-system/form` | Control wrapper |
|
|
146
|
-
| `FormMessage` | `@vadimcomanescu/nadicode-design-system/form` | Validation error message |
|
|
147
|
-
| `Input` | `@vadimcomanescu/nadicode-design-system/input` | Text inputs |
|
|
148
|
-
| `Textarea` | `@vadimcomanescu/nadicode-design-system/textarea` | Long text |
|
|
149
|
-
| `Select` | `@vadimcomanescu/nadicode-design-system/select` | Dropdowns |
|
|
150
|
-
| `Switch` | `@vadimcomanescu/nadicode-design-system/switch` | Toggles |
|
|
151
|
-
| `Checkbox` | `@vadimcomanescu/nadicode-design-system/checkbox` | Boolean fields |
|
|
152
|
-
| `Button` | `@vadimcomanescu/nadicode-design-system/button` | Submit, cancel, delete |
|
|
153
|
-
| `Card` | `@vadimcomanescu/nadicode-design-system/card` | Section containers |
|
|
154
|
-
| `Typography` | `@vadimcomanescu/nadicode-design-system/typography` | Section headings |
|
|
155
|
-
| `Breadcrumb` | `@vadimcomanescu/nadicode-design-system/breadcrumb` | Navigation context |
|
|
156
|
-
| `AlertDialog` | `@vadimcomanescu/nadicode-design-system/alert-dialog` | Delete confirmation |
|
|
157
|
-
| `Alert` | `@vadimcomanescu/nadicode-design-system/alert` | Submission errors |
|
|
158
|
-
| `Spinner` | `@vadimcomanescu/nadicode-design-system/spinner` | Submit loading |
|
|
159
|
-
| `Skeleton` | `@vadimcomanescu/nadicode-design-system/skeleton` | Loading state (edit mode) |
|
|
160
|
-
|
|
161
|
-
### Allowed (optional)
|
|
162
|
-
|
|
163
|
-
`Field`, `Label`, `DatePicker`, `Combobox`, `TagInput`, `RadioGroup`, `Slider`, `FileUpload`, `InputOTP`, `NativeSelect`, `InputGroup`, `Tooltip`
|
|
164
|
-
|
|
165
|
-
### Forbidden
|
|
166
|
-
|
|
167
|
-
`DataTable`, `HeroBlock`, chart components, decorative effects, text effects, agentic components
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## Required States
|
|
172
|
-
|
|
173
|
-
| State | Trigger | Visual |
|
|
174
|
-
|-------|---------|--------|
|
|
175
|
-
| `loading` | Edit mode: fetching entity | Skeleton form sections |
|
|
176
|
-
| `pristine` | Form loaded, no changes | Submit button disabled |
|
|
177
|
-
| `dirty` | User modified a field | Submit button enabled, optional unsaved indicator |
|
|
178
|
-
| `submitting` | Form submitted | Submit button shows Spinner, form disabled |
|
|
179
|
-
| `validation-error` | Invalid fields | `FormMessage` below invalid fields (red text) |
|
|
180
|
-
| `submission-error` | Server error on submit | `Alert` variant="destructive" at top of form |
|
|
181
|
-
| `success` | Saved successfully | Toast "Saved" + redirect to list page |
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## Responsive Contract
|
|
186
|
-
|
|
187
|
-
| Breakpoint | Layout | Actions |
|
|
188
|
-
|------------|--------|---------|
|
|
189
|
-
| Mobile | Single column, cards full width | Stacked buttons, full width |
|
|
190
|
-
| `sm:` | Single column, max-w-2xl centered | Inline buttons, right-aligned |
|
|
191
|
-
| `lg:` | Single column within sidebar layout | Same as sm |
|
|
192
|
-
|
|
193
|
-
---
|
|
194
|
-
|
|
195
|
-
## Styling Rules
|
|
196
|
-
|
|
197
|
-
- Form sections: `glass-panel p-6`
|
|
198
|
-
- Labels: always stacked above inputs (never inline, never floating)
|
|
199
|
-
- Field spacing: `space-y-4` within sections
|
|
200
|
-
- Section spacing: `space-y-6`
|
|
201
|
-
- Required fields: visual asterisk on label
|
|
202
|
-
- Error text: `text-destructive text-sm`
|
|
203
|
-
- Delete button: `variant="destructive"`, left-aligned, separated from save/cancel
|
|
204
|
-
- Max form width: `max-w-2xl mx-auto` for readability
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## Accessibility
|
|
209
|
-
|
|
210
|
-
- All inputs have associated `<label>` via `FormLabel`
|
|
211
|
-
- Error messages linked via `aria-describedby`
|
|
212
|
-
- Required fields have `aria-required="true"`
|
|
213
|
-
- Delete uses `AlertDialog` with confirmation
|
|
214
|
-
- Tab order: fields top-to-bottom, then cancel, then save
|
|
215
|
-
- Form has `noValidate` (custom validation via react-hook-form)
|
|
216
|
-
|
|
217
|
-
---
|
|
218
|
-
|
|
219
|
-
## Reference Implementations
|
|
220
|
-
|
|
221
|
-
- `src/components/blocks/CreateBlock.tsx`
|
|
222
|
-
- `src/components/ui/Form.tsx` (form primitives)
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
|
|
226
|
-
## Verification
|
|
227
|
-
|
|
228
|
-
```bash
|
|
229
|
-
npx tsc --noEmit
|
|
230
|
-
npm run lint
|
|
231
|
-
npm run test
|
|
232
|
-
npx vitest run src/test/css-variable-usage.test.ts
|
|
233
|
-
```
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
# Recipe: CRUD List + Detail
|
|
2
|
-
|
|
3
|
-
Entity management page with search, filter, sort, and record inspection.
|
|
4
|
-
|
|
5
|
-
## Route Patterns
|
|
6
|
-
|
|
7
|
-
- `/[entity]` (list view)
|
|
8
|
-
- `/[entity]/[id]` (detail view, optional -- can use Dialog/Sheet instead)
|
|
9
|
-
|
|
10
|
-
## Shell
|
|
11
|
-
|
|
12
|
-
`app-shell` (Sidebar + top bar + SearchCommand)
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Layout Blueprint (Desktop)
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
+--+---------------------------------------------+
|
|
20
|
-
| | Breadcrumb: Home > [Entity] |
|
|
21
|
-
|S | Page Title [Search] [Filter] [+ New] |
|
|
22
|
-
|I | |
|
|
23
|
-
|D | +------------------------------------------+ |
|
|
24
|
-
|E | | DataTable | |
|
|
25
|
-
|B | | [ ] Name Status Date Actions| |
|
|
26
|
-
|A | | [ ] Record 1 Active Jan 1 ... | |
|
|
27
|
-
|R | | [ ] Record 2 Pending Jan 2 ... | |
|
|
28
|
-
| | | [ ] Record 3 Active Jan 3 ... | |
|
|
29
|
-
| | | ... | |
|
|
30
|
-
| | +------------------------------------------+ |
|
|
31
|
-
| | |
|
|
32
|
-
| | [< Prev] Page 1 of 10 [Next >] |
|
|
33
|
-
+--+---------------------------------------------+
|
|
34
|
-
|
|
35
|
-
Detail (Dialog/Sheet overlay):
|
|
36
|
-
+--+---------------------------------------------+
|
|
37
|
-
| | ...list in background... |
|
|
38
|
-
| | +---------------------------+ |
|
|
39
|
-
| | | Sheet/Dialog | |
|
|
40
|
-
| | | Entity Name | |
|
|
41
|
-
| | | Status: [Badge] | |
|
|
42
|
-
| | | | |
|
|
43
|
-
| | | Details section | |
|
|
44
|
-
| | | Related records section | |
|
|
45
|
-
| | | | |
|
|
46
|
-
| | | [Edit] [Archive] [Delete] | |
|
|
47
|
-
| | +---------------------------+ |
|
|
48
|
-
+--+---------------------------------------------+
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## Section Sequence
|
|
54
|
-
|
|
55
|
-
### 1. Page Header + Controls
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
59
|
-
<div>
|
|
60
|
-
<Breadcrumb>...</Breadcrumb>
|
|
61
|
-
<Heading level={2} size="section" >Entities</Heading>
|
|
62
|
-
</div>
|
|
63
|
-
<div className="flex items-center gap-3">
|
|
64
|
-
<Input placeholder="Search..." startIcon={<SearchIcon size={16} />} className="w-64" />
|
|
65
|
-
<Select>{/* Filter options */}</Select>
|
|
66
|
-
<Button><PlusIcon size={16} /> New Entity</Button>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### 2. Data Table
|
|
72
|
-
|
|
73
|
-
```tsx
|
|
74
|
-
<Card className="glass-panel">
|
|
75
|
-
<DataTable
|
|
76
|
-
columns={columns}
|
|
77
|
-
data={entities}
|
|
78
|
-
onRowClick={openDetail}
|
|
79
|
-
selectable
|
|
80
|
-
/>
|
|
81
|
-
</Card>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### 3. Pagination
|
|
85
|
-
|
|
86
|
-
```tsx
|
|
87
|
-
<div className="flex items-center justify-between mt-4">
|
|
88
|
-
<Typography variant="small" className="text-text-secondary">
|
|
89
|
-
Showing {start}-{end} of {total}
|
|
90
|
-
</Typography>
|
|
91
|
-
<Pagination current={page} total={totalPages} onPageChange={setPage} />
|
|
92
|
-
</div>
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### 4. Detail Panel (Sheet or Dialog)
|
|
96
|
-
|
|
97
|
-
```tsx
|
|
98
|
-
<Sheet open={!!selectedEntity} onOpenChange={closeDetail}>
|
|
99
|
-
<SheetContent className="sm:max-w-lg">
|
|
100
|
-
<SheetHeader>
|
|
101
|
-
<SheetTitle>{entity.name}</SheetTitle>
|
|
102
|
-
<Badge>{entity.status}</Badge>
|
|
103
|
-
</SheetHeader>
|
|
104
|
-
<div className="space-y-6 mt-6">
|
|
105
|
-
{/* Detail fields */}
|
|
106
|
-
{/* Related records */}
|
|
107
|
-
</div>
|
|
108
|
-
<SheetFooter>
|
|
109
|
-
<Button variant="outline">Edit</Button>
|
|
110
|
-
<AlertDialog>
|
|
111
|
-
<AlertDialogTrigger asChild>
|
|
112
|
-
<Button variant="destructive">Delete</Button>
|
|
113
|
-
</AlertDialogTrigger>
|
|
114
|
-
{/* Confirmation dialog */}
|
|
115
|
-
</AlertDialog>
|
|
116
|
-
</SheetFooter>
|
|
117
|
-
</SheetContent>
|
|
118
|
-
</Sheet>
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
## Animation Storyboard
|
|
124
|
-
|
|
125
|
-
```
|
|
126
|
-
ANIMATION STORYBOARD
|
|
127
|
-
====================
|
|
128
|
-
BUDGET: 400ms | SPRING: snappy | REDUCED: opacity-only
|
|
129
|
-
|
|
130
|
-
T+0ms [shell] Sidebar + top bar visible (instant)
|
|
131
|
-
T+50ms [header] Title + controls fade in {fadeInUp, snappy}
|
|
132
|
-
T+130ms [table] Table container fades in {fadeIn, snappy}
|
|
133
|
-
T+200ms [rows] Table rows stagger {blockStagger, 40ms, max 10}
|
|
134
|
-
T+400ms [pagination] Pagination fades in {fadeIn, snappy}
|
|
135
|
-
|
|
136
|
-
DETAIL PANEL:
|
|
137
|
-
T+0ms [overlay] Backdrop appears {fadeIn, 150ms}
|
|
138
|
-
T+0ms [sheet] Sheet slides in from right {slideInRight, gentle}
|
|
139
|
-
|
|
140
|
-
REDUCED MOTION: All items visible immediately
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Required Components
|
|
146
|
-
|
|
147
|
-
| Component | Import Path | Purpose |
|
|
148
|
-
|-----------|-------------|---------|
|
|
149
|
-
| `DataTable` | `@vadimcomanescu/nadicode-design-system/data-table` | Main data display |
|
|
150
|
-
| `Pagination` | `@vadimcomanescu/nadicode-design-system/pagination` | Page navigation |
|
|
151
|
-
| `Input` | `@vadimcomanescu/nadicode-design-system/input` | Search field |
|
|
152
|
-
| `Select` | `@vadimcomanescu/nadicode-design-system/select` | Filter dropdown |
|
|
153
|
-
| `Button` | `@vadimcomanescu/nadicode-design-system/button` | Actions (new, edit, delete) |
|
|
154
|
-
| `Badge` | `@vadimcomanescu/nadicode-design-system/badge` | Status indicators |
|
|
155
|
-
| `Card` | `@vadimcomanescu/nadicode-design-system/card` | Table container |
|
|
156
|
-
| `Sheet` | `@vadimcomanescu/nadicode-design-system/sheet` | Detail side panel |
|
|
157
|
-
| `AlertDialog` | `@vadimcomanescu/nadicode-design-system/alert-dialog` | Delete confirmation |
|
|
158
|
-
| `Typography` | `@vadimcomanescu/nadicode-design-system/typography` | Titles |
|
|
159
|
-
| `Breadcrumb` | `@vadimcomanescu/nadicode-design-system/breadcrumb` | Navigation context |
|
|
160
|
-
| `Skeleton` | `@vadimcomanescu/nadicode-design-system/skeleton` | Loading state |
|
|
161
|
-
| `Empty` | `@vadimcomanescu/nadicode-design-system/empty` | No-data state |
|
|
162
|
-
|
|
163
|
-
### Allowed (optional)
|
|
164
|
-
|
|
165
|
-
`Dialog`, `Tabs`, `DropdownMenu`, `ContextMenu`, `Tooltip`, `Table`, `Checkbox`
|
|
166
|
-
|
|
167
|
-
### Forbidden
|
|
168
|
-
|
|
169
|
-
`HeroBlock`, `PricingBlock`, decorative effects, text effects, `FormWizard`, chart components
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## Required States
|
|
174
|
-
|
|
175
|
-
| State | Trigger | Visual |
|
|
176
|
-
|-------|---------|--------|
|
|
177
|
-
| `loading` | Initial data fetch | Skeleton table rows (5 rows) |
|
|
178
|
-
| `empty` | Zero records | `Empty` with entity icon, "No [entities] yet", "Create your first [entity]" CTA |
|
|
179
|
-
| `has-data` | Data loaded | Full DataTable with records |
|
|
180
|
-
| `filtering` | Active filter/search | Table with filtered results, active filter indicators |
|
|
181
|
-
| `empty-filter` | Filter returns zero | `Empty` with "No results match", "Clear filters" CTA |
|
|
182
|
-
| `error` | API failure | `Alert` variant="destructive" with retry |
|
|
183
|
-
|
|
184
|
-
---
|
|
185
|
-
|
|
186
|
-
## Responsive Contract
|
|
187
|
-
|
|
188
|
-
| Breakpoint | Table | Filters | Detail Panel |
|
|
189
|
-
|------------|-------|---------|--------------|
|
|
190
|
-
| Mobile | Card list (hidden columns) | Filter button -> Sheet | Full-screen Sheet |
|
|
191
|
-
| `sm:` | Table (key columns) | Inline search + filter button | Sheet side="right" |
|
|
192
|
-
| `lg:` | Full table all columns | Persistent search + filter bar | Sheet max-w-lg |
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## Styling Rules
|
|
197
|
-
|
|
198
|
-
- Table container: `glass-panel`
|
|
199
|
-
- Status badges: semantic variants (`success`, `warning`, `destructive`, `default`)
|
|
200
|
-
- Row hover: `hover:bg-surface-hover`
|
|
201
|
-
- Selected rows: `bg-surface-active`
|
|
202
|
-
- No raw palette colors
|
|
203
|
-
|
|
204
|
-
---
|
|
205
|
-
|
|
206
|
-
## Accessibility
|
|
207
|
-
|
|
208
|
-
- Table has proper `<thead>`, `<tbody>` structure
|
|
209
|
-
- Sortable columns have `aria-sort` attribute
|
|
210
|
-
- Row actions have `aria-label`
|
|
211
|
-
- Delete uses `AlertDialog` for confirmation (keyboard trap)
|
|
212
|
-
- Search input has `role="search"` wrapper
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## Reference Implementations
|
|
217
|
-
|
|
218
|
-
- `src/components/blocks/DataGridBlock.tsx`
|
|
219
|
-
- `src/components/blocks/DirectoryBlock.tsx`
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
## Verification
|
|
224
|
-
|
|
225
|
-
```bash
|
|
226
|
-
npx tsc --noEmit
|
|
227
|
-
npm run lint
|
|
228
|
-
npm run test
|
|
229
|
-
npx vitest run src/test/css-variable-usage.test.ts
|
|
230
|
-
```
|