@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,254 +0,0 @@
|
|
|
1
|
-
# Recipe: Auth
|
|
2
|
-
|
|
3
|
-
Login, signup, password reset, and 2FA flows with split-screen or centered layout.
|
|
4
|
-
|
|
5
|
-
## Route Patterns
|
|
6
|
-
|
|
7
|
-
- `/login`
|
|
8
|
-
- `/signup`
|
|
9
|
-
- `/reset-password`
|
|
10
|
-
- `/verify` (2FA challenge)
|
|
11
|
-
|
|
12
|
-
## Shell
|
|
13
|
-
|
|
14
|
-
`auth-shell` (AuthLayout: split-screen or centered, minimal chrome)
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## Layout Blueprint (Desktop)
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
+------------------------------------------------+
|
|
22
|
-
| |
|
|
23
|
-
| +--------------------+ +-------------------+ |
|
|
24
|
-
| | | | | |
|
|
25
|
-
| | Brand Panel | | Auth Card | |
|
|
26
|
-
| | (illustration, | | (glass-floating) | |
|
|
27
|
-
| | testimonial, | | | |
|
|
28
|
-
| | or shader bg) | | Logo | |
|
|
29
|
-
| | | | Title | |
|
|
30
|
-
| | | | Subtitle | |
|
|
31
|
-
| | | | | |
|
|
32
|
-
| | | | [Email input] | |
|
|
33
|
-
| | | | [Password input] | |
|
|
34
|
-
| | | | | |
|
|
35
|
-
| | | | [Sign In] | |
|
|
36
|
-
| | | | Or continue with | |
|
|
37
|
-
| | | | [Google] [GitHub] | |
|
|
38
|
-
| | | | | |
|
|
39
|
-
| | | | Forgot password? | |
|
|
40
|
-
| | | | Don't have acct? | |
|
|
41
|
-
| +--------------------+ +-------------------+ |
|
|
42
|
-
| |
|
|
43
|
-
+------------------------------------------------+
|
|
44
|
-
|
|
45
|
-
Mobile: Brand panel hidden, auth card full-width centered
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## Section Sequence
|
|
51
|
-
|
|
52
|
-
### 1. Auth Layout Wrapper
|
|
53
|
-
|
|
54
|
-
```tsx
|
|
55
|
-
<AuthLayout>
|
|
56
|
-
{/* AuthLayout provides split-screen on desktop, centered on mobile */}
|
|
57
|
-
<LoginBlock
|
|
58
|
-
type="login"
|
|
59
|
-
variant="glass-panel"
|
|
60
|
-
showSocial
|
|
61
|
-
title="Welcome back"
|
|
62
|
-
description="Sign in to your account"
|
|
63
|
-
onLogin={handleLogin}
|
|
64
|
-
forgotPasswordHref="/reset-password"
|
|
65
|
-
signUpHref="/signup"
|
|
66
|
-
/>
|
|
67
|
-
</AuthLayout>
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### 2. Login Form (within LoginBlock or custom)
|
|
71
|
-
|
|
72
|
-
```tsx
|
|
73
|
-
<Card className="glass-floating p-8 w-full max-w-md">
|
|
74
|
-
<div className="flex flex-col items-center mb-6">
|
|
75
|
-
<Logo className="h-8 mb-4" />
|
|
76
|
-
<Heading level={3} size="subsection" >Welcome back</Heading>
|
|
77
|
-
<Typography variant="small" className="text-text-secondary mt-1">
|
|
78
|
-
Sign in to your account
|
|
79
|
-
</Typography>
|
|
80
|
-
</div>
|
|
81
|
-
|
|
82
|
-
{error && <Alert variant="destructive" className="mb-4">{error}</Alert>}
|
|
83
|
-
|
|
84
|
-
<form onSubmit={handleSubmit} className="space-y-4">
|
|
85
|
-
<div>
|
|
86
|
-
<Label htmlFor="email">Email</Label>
|
|
87
|
-
<Input id="email" type="email" placeholder="name@example.com" />
|
|
88
|
-
</div>
|
|
89
|
-
<div>
|
|
90
|
-
<Label htmlFor="password">Password</Label>
|
|
91
|
-
<PasswordInput id="password" />
|
|
92
|
-
</div>
|
|
93
|
-
<Button type="submit" className="w-full" disabled={isSubmitting}>
|
|
94
|
-
{isSubmitting ? <Spinner className="mr-2" /> : null}
|
|
95
|
-
Sign In
|
|
96
|
-
</Button>
|
|
97
|
-
</form>
|
|
98
|
-
|
|
99
|
-
<div className="relative my-6">
|
|
100
|
-
<Separator />
|
|
101
|
-
<span className="absolute left-1/2 -translate-x-1/2 -translate-y-1/2 bg-surface px-2 text-text-tertiary text-sm">
|
|
102
|
-
Or continue with
|
|
103
|
-
</span>
|
|
104
|
-
</div>
|
|
105
|
-
|
|
106
|
-
<div className="grid grid-cols-2 gap-3">
|
|
107
|
-
<Button variant="outline"><BrandIcons.Google className="mr-2 h-4 w-4" /> Google</Button>
|
|
108
|
-
<Button variant="outline"><BrandIcons.GitHub className="mr-2 h-4 w-4" /> GitHub</Button>
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
<div className="mt-6 text-center space-y-2">
|
|
112
|
-
<a href="/reset-password" className="text-sm text-link">Forgot password?</a>
|
|
113
|
-
<p className="text-sm text-text-secondary">
|
|
114
|
-
Don't have an account? <a href="/signup" className="text-link">Sign up</a>
|
|
115
|
-
</p>
|
|
116
|
-
</div>
|
|
117
|
-
</Card>
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### 3. 2FA Challenge (separate route)
|
|
121
|
-
|
|
122
|
-
```tsx
|
|
123
|
-
<Card className="glass-floating p-8 w-full max-w-md text-center">
|
|
124
|
-
<Heading level={3} size="subsection" >Two-factor authentication</Heading>
|
|
125
|
-
<Typography variant="small" className="text-text-secondary mt-2 mb-6">
|
|
126
|
-
Enter the 6-digit code from your authenticator app
|
|
127
|
-
</Typography>
|
|
128
|
-
<InputOTP maxLength={6} onComplete={handleVerify}>
|
|
129
|
-
<InputOTPGroup>
|
|
130
|
-
<InputOTPSlot index={0} />
|
|
131
|
-
<InputOTPSlot index={1} />
|
|
132
|
-
<InputOTPSlot index={2} />
|
|
133
|
-
</InputOTPGroup>
|
|
134
|
-
<InputOTPSeparator />
|
|
135
|
-
<InputOTPGroup>
|
|
136
|
-
<InputOTPSlot index={3} />
|
|
137
|
-
<InputOTPSlot index={4} />
|
|
138
|
-
<InputOTPSlot index={5} />
|
|
139
|
-
</InputOTPGroup>
|
|
140
|
-
</InputOTP>
|
|
141
|
-
<Button className="w-full mt-6" disabled={isSubmitting}>Verify</Button>
|
|
142
|
-
</Card>
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## Animation Storyboard
|
|
148
|
-
|
|
149
|
-
```
|
|
150
|
-
ANIMATION STORYBOARD
|
|
151
|
-
====================
|
|
152
|
-
BUDGET: 350ms | SPRING: gentle | REDUCED: opacity-only
|
|
153
|
-
|
|
154
|
-
T+0ms [layout] Split-screen panels visible (instant)
|
|
155
|
-
T+0ms [brand] Brand panel bg/shader (instant)
|
|
156
|
-
T+100ms [card] Auth card scales in {scaleIn, gentle}
|
|
157
|
-
T+200ms [logo] Logo fades in {fadeIn, snappy}
|
|
158
|
-
T+250ms [fields] Form fields stagger {blockStagger, 60ms, max 4}
|
|
159
|
-
T+350ms [cta] Sign-in button fades in {fadeIn, snappy}
|
|
160
|
-
|
|
161
|
-
REDUCED MOTION: Card and all children visible immediately
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## Required Components
|
|
167
|
-
|
|
168
|
-
| Component | Import Path | Purpose |
|
|
169
|
-
|-----------|-------------|---------|
|
|
170
|
-
| `AuthLayout` | `@vadimcomanescu/nadicode-design-system/catalog/components` via `seedComponents` | Split-screen wrapper |
|
|
171
|
-
| `LoginBlock` | `@vadimcomanescu/nadicode-design-system/catalog/components` via `seedComponents` | Pre-built login form |
|
|
172
|
-
| `SignUpBlock` | `@vadimcomanescu/nadicode-design-system/catalog/components` via `seedComponents` | Pre-built signup form |
|
|
173
|
-
| `Card` | `@vadimcomanescu/nadicode-design-system/card` | Auth card container |
|
|
174
|
-
| `Input` | `@vadimcomanescu/nadicode-design-system/input` | Email, name fields |
|
|
175
|
-
| `PasswordInput` | `@vadimcomanescu/nadicode-design-system/password-input` | Password with toggle |
|
|
176
|
-
| `Label` | `@vadimcomanescu/nadicode-design-system/label` | Stacked labels |
|
|
177
|
-
| `Button` | `@vadimcomanescu/nadicode-design-system/button` | Submit, social login |
|
|
178
|
-
| `Alert` | `@vadimcomanescu/nadicode-design-system/alert` | Error messages |
|
|
179
|
-
| `Logo` | `@vadimcomanescu/nadicode-design-system/logo` | Brand mark |
|
|
180
|
-
| `BrandIcons` | `@vadimcomanescu/nadicode-design-system/brand-icons` | Google, GitHub icons |
|
|
181
|
-
| `Separator` | `@vadimcomanescu/nadicode-design-system/separator` | "Or" divider |
|
|
182
|
-
| `InputOTP` | `@vadimcomanescu/nadicode-design-system/input-otp` | 2FA code entry |
|
|
183
|
-
| `Spinner` | `@vadimcomanescu/nadicode-design-system/spinner` | Submit loading |
|
|
184
|
-
| `Typography` | `@vadimcomanescu/nadicode-design-system/typography` | Headings, descriptions |
|
|
185
|
-
|
|
186
|
-
### Allowed (optional)
|
|
187
|
-
|
|
188
|
-
`PasswordRecoveryBlock`, `ResetPasswordBlock`, `TwoFactorChallengeBlock`, `TwoFactorSetupBlock`, `AccountLockedBlock`, `AuthSuccessBlock`, `Checkbox` (remember me), `ShaderBackground`
|
|
189
|
-
|
|
190
|
-
### Forbidden
|
|
191
|
-
|
|
192
|
-
`Sidebar`, `DataTable`, chart components, `NavigationMenu`, decorative effects (except on brand panel)
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## Required States
|
|
197
|
-
|
|
198
|
-
| State | Trigger | Visual |
|
|
199
|
-
|-------|---------|--------|
|
|
200
|
-
| `default` | Page loaded | Form ready for input |
|
|
201
|
-
| `submitting` | Form submitted | Button shows Spinner, form disabled |
|
|
202
|
-
| `error` | Auth failure | `Alert` variant="destructive" with message |
|
|
203
|
-
| `success` | Auth succeeded | Redirect to dashboard (or `AuthSuccessBlock`) |
|
|
204
|
-
| `2fa-challenge` | Server requests 2FA | Show 2FA code entry screen |
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## Responsive Contract
|
|
209
|
-
|
|
210
|
-
| Breakpoint | Layout | Card Width |
|
|
211
|
-
|------------|--------|------------|
|
|
212
|
-
| Mobile | Centered card, no brand panel | Full width, max-w-md, px-4 |
|
|
213
|
-
| `lg:` | Split screen: brand (50%) + form (50%) | max-w-md centered in right half |
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
## Styling Rules
|
|
218
|
-
|
|
219
|
-
- Auth card: `glass-floating p-8`
|
|
220
|
-
- Brand panel: full-height, may use `ShaderBackground` or illustration
|
|
221
|
-
- Labels: stacked above inputs (always)
|
|
222
|
-
- Social buttons: `variant="outline"`, 2-column grid
|
|
223
|
-
- Links: `text-link` token
|
|
224
|
-
- Error: `Alert` at top of form, not inline per-field (for auth errors)
|
|
225
|
-
|
|
226
|
-
---
|
|
227
|
-
|
|
228
|
-
## Accessibility
|
|
229
|
-
|
|
230
|
-
- Form inputs have associated labels
|
|
231
|
-
- Error alert uses `role="alert"`
|
|
232
|
-
- Social login buttons include brand name in text
|
|
233
|
-
- OTP input is keyboard-navigable (auto-advance)
|
|
234
|
-
- Focus moves to first field on mount
|
|
235
|
-
- Escape key behavior is handled (no accidental navigation away)
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## Reference Implementations
|
|
240
|
-
|
|
241
|
-
- `src/components/blocks/LoginBlock.tsx`
|
|
242
|
-
- `src/components/blocks/AuthLayout.tsx`
|
|
243
|
-
- `src/app/login/vanta/*/page.tsx` (7 variants)
|
|
244
|
-
|
|
245
|
-
---
|
|
246
|
-
|
|
247
|
-
## Verification
|
|
248
|
-
|
|
249
|
-
```bash
|
|
250
|
-
npx tsc --noEmit
|
|
251
|
-
npm run lint
|
|
252
|
-
npm run test
|
|
253
|
-
npx vitest run src/test/css-variable-usage.test.ts
|
|
254
|
-
```
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
# Recipe: Blog / Content
|
|
2
|
-
|
|
3
|
-
Blog index, article pages, and changelog display with reading-optimized layout.
|
|
4
|
-
|
|
5
|
-
## Route Patterns
|
|
6
|
-
|
|
7
|
-
- `/blog` (index with post cards)
|
|
8
|
-
- `/blog/[slug]` (individual article)
|
|
9
|
-
- `/changelog` (version changelog)
|
|
10
|
-
|
|
11
|
-
## Shell
|
|
12
|
-
|
|
13
|
-
`marketing-shell` (HeaderBlock + FooterBlock)
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Layout Blueprint: Blog Index (Desktop)
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
+------------------------------------------------+
|
|
21
|
-
| HeaderBlock |
|
|
22
|
-
+------------------------------------------------+
|
|
23
|
-
| |
|
|
24
|
-
| Blog [Category filter] |
|
|
25
|
-
| Latest thoughts and updates |
|
|
26
|
-
| |
|
|
27
|
-
| +--------------------+ +-------------------+ |
|
|
28
|
-
| | Featured Post | | Post 2 | |
|
|
29
|
-
| | (large card) | | (standard card) | |
|
|
30
|
-
| | | +-------------------+ |
|
|
31
|
-
| | | | Post 3 | |
|
|
32
|
-
| | | | (standard card) | |
|
|
33
|
-
| +--------------------+ +-------------------+ |
|
|
34
|
-
| |
|
|
35
|
-
| +----------+ +----------+ +----------+ |
|
|
36
|
-
| | Post 4 | | Post 5 | | Post 6 | |
|
|
37
|
-
| +----------+ +----------+ +----------+ |
|
|
38
|
-
| |
|
|
39
|
-
| [Load More / Pagination] |
|
|
40
|
-
+------------------------------------------------+
|
|
41
|
-
| FooterBlock |
|
|
42
|
-
+------------------------------------------------+
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Layout Blueprint: Article Page (Desktop)
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
+------------------------------------------------+
|
|
49
|
-
| HeaderBlock |
|
|
50
|
-
+------------------------------------------------+
|
|
51
|
-
| |
|
|
52
|
-
| max-w-3xl centered |
|
|
53
|
-
| |
|
|
54
|
-
| Category Badge 5 min read |
|
|
55
|
-
| Article Title (h1) |
|
|
56
|
-
| Published Jan 1, 2025 by Author Name |
|
|
57
|
-
| |
|
|
58
|
-
| [Article hero image] |
|
|
59
|
-
| |
|
|
60
|
-
| Article body content with prose styling... |
|
|
61
|
-
| Headings, paragraphs, code blocks, |
|
|
62
|
-
| images, blockquotes... |
|
|
63
|
-
| |
|
|
64
|
-
| --- |
|
|
65
|
-
| Author card |
|
|
66
|
-
| Share buttons |
|
|
67
|
-
| |
|
|
68
|
-
| Related Posts (3 cards) |
|
|
69
|
-
| |
|
|
70
|
-
+------------------------------------------------+
|
|
71
|
-
| FooterBlock |
|
|
72
|
-
+------------------------------------------------+
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Section Sequence: Blog Index
|
|
78
|
-
|
|
79
|
-
### 1. Page Header
|
|
80
|
-
|
|
81
|
-
```tsx
|
|
82
|
-
<section className="py-12 md:py-16">
|
|
83
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
84
|
-
<div className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
|
|
85
|
-
<div>
|
|
86
|
-
<Heading level={1} size="display" >Blog</Heading>
|
|
87
|
-
<Typography variant="lead" className="text-text-secondary mt-2">
|
|
88
|
-
Latest thoughts and updates
|
|
89
|
-
</Typography>
|
|
90
|
-
</div>
|
|
91
|
-
<Select value={category} onValueChange={setCategory}>
|
|
92
|
-
<SelectTrigger className="w-48"><SelectValue placeholder="All categories" /></SelectTrigger>
|
|
93
|
-
<SelectContent>{/* Category options */}</SelectContent>
|
|
94
|
-
</Select>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
</section>
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### 2. Featured + Recent Posts Grid
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
<section className="pb-16">
|
|
104
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
105
|
-
{/* Featured row */}
|
|
106
|
-
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
|
107
|
-
<Card className="glass-panel overflow-hidden lg:row-span-2">
|
|
108
|
-
{/* Featured post with large image */}
|
|
109
|
-
<img src={featured.image} alt="" className="w-full h-48 lg:h-64 object-cover" />
|
|
110
|
-
<div className="p-6">
|
|
111
|
-
<Badge variant="outline">{featured.category}</Badge>
|
|
112
|
-
<Heading level={3} size="subsection" className="mt-3">{featured.title}</Heading>
|
|
113
|
-
<Typography variant="p" className="text-text-secondary mt-2 line-clamp-3">
|
|
114
|
-
{featured.excerpt}
|
|
115
|
-
</Typography>
|
|
116
|
-
<div className="flex items-center gap-2 mt-4 text-text-tertiary text-sm">
|
|
117
|
-
<Avatar className="h-6 w-6"><AvatarImage src={featured.author.avatar} /></Avatar>
|
|
118
|
-
<span>{featured.author.name}</span>
|
|
119
|
-
<span>-</span>
|
|
120
|
-
<span>{featured.date}</span>
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
</Card>
|
|
124
|
-
<div className="space-y-6">
|
|
125
|
-
{recentPosts.slice(0, 2).map(post => (
|
|
126
|
-
<Card key={post.id} className="glass-panel p-6">
|
|
127
|
-
<Badge variant="outline">{post.category}</Badge>
|
|
128
|
-
<Heading level={4} size="title" className="mt-2">{post.title}</Heading>
|
|
129
|
-
<Typography variant="small" className="text-text-secondary mt-1 line-clamp-2">
|
|
130
|
-
{post.excerpt}
|
|
131
|
-
</Typography>
|
|
132
|
-
</Card>
|
|
133
|
-
))}
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
|
|
137
|
-
{/* Remaining posts grid */}
|
|
138
|
-
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
139
|
-
{remainingPosts.map(post => (
|
|
140
|
-
<Card key={post.id} className="glass-panel p-6">
|
|
141
|
-
<Badge variant="outline">{post.category}</Badge>
|
|
142
|
-
<Heading level={4} size="title" className="mt-2">{post.title}</Heading>
|
|
143
|
-
<Typography variant="small" className="text-text-secondary mt-1 line-clamp-2">
|
|
144
|
-
{post.excerpt}
|
|
145
|
-
</Typography>
|
|
146
|
-
</Card>
|
|
147
|
-
))}
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
{/* Pagination */}
|
|
151
|
-
<div className="mt-12 flex justify-center">
|
|
152
|
-
<Pagination current={page} total={totalPages} onPageChange={setPage} />
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
</section>
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Article Page: Prose Content
|
|
159
|
-
|
|
160
|
-
```tsx
|
|
161
|
-
<article className="max-w-3xl mx-auto px-4 sm:px-6 py-12 md:py-16">
|
|
162
|
-
<header className="mb-8">
|
|
163
|
-
<div className="flex items-center gap-3 mb-4">
|
|
164
|
-
<Badge variant="outline">{post.category}</Badge>
|
|
165
|
-
<Typography variant="small" className="text-text-tertiary">
|
|
166
|
-
{post.readingTime} min read
|
|
167
|
-
</Typography>
|
|
168
|
-
</div>
|
|
169
|
-
<Heading level={1} size="display" >{post.title}</Heading>
|
|
170
|
-
<div className="flex items-center gap-3 mt-4 text-text-secondary">
|
|
171
|
-
<Avatar><AvatarImage src={post.author.avatar} /></Avatar>
|
|
172
|
-
<div>
|
|
173
|
-
<Typography variant="small" className="font-medium text-text-primary">
|
|
174
|
-
{post.author.name}
|
|
175
|
-
</Typography>
|
|
176
|
-
<Typography variant="small">{post.date}</Typography>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
</header>
|
|
180
|
-
|
|
181
|
-
{/* Prose content */}
|
|
182
|
-
<div className="prose prose-neutral dark:prose-invert max-w-none">
|
|
183
|
-
{post.content}
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
{/* Author card + share */}
|
|
187
|
-
<Separator className="my-12" />
|
|
188
|
-
<Card className="glass-panel p-6 flex items-center gap-4">
|
|
189
|
-
<Avatar className="h-12 w-12"><AvatarImage src={post.author.avatar} /></Avatar>
|
|
190
|
-
<div>
|
|
191
|
-
<Heading level={4} size="title" >{post.author.name}</Heading>
|
|
192
|
-
<Typography variant="small" className="text-text-secondary">{post.author.bio}</Typography>
|
|
193
|
-
</div>
|
|
194
|
-
</Card>
|
|
195
|
-
</article>
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## Animation Storyboard
|
|
201
|
-
|
|
202
|
-
```
|
|
203
|
-
ANIMATION STORYBOARD
|
|
204
|
-
====================
|
|
205
|
-
BUDGET: 600ms (index) / 300ms (article) | SPRING: snappy | REDUCED: opacity-only
|
|
206
|
-
|
|
207
|
-
BLOG INDEX:
|
|
208
|
-
T+0ms [nav] Header visible (instant)
|
|
209
|
-
T+50ms [header] Blog title + filter {fadeInUp, snappy}
|
|
210
|
-
T+130ms [featured] Featured post card {fadeInUp, snappy}
|
|
211
|
-
T+210ms [recent] Recent post cards stagger {blockStagger, 80ms}
|
|
212
|
-
T+450ms [grid] Remaining posts stagger {blockStagger, 80ms, max 6}
|
|
213
|
-
|
|
214
|
-
ARTICLE:
|
|
215
|
-
T+0ms [nav] Header visible (instant)
|
|
216
|
-
T+50ms [meta] Category + reading time {fadeIn, snappy}
|
|
217
|
-
T+100ms [title] Article title {fadeInUp, snappy}
|
|
218
|
-
T+200ms [content] Article body fades in {fadeIn, gentle}
|
|
219
|
-
|
|
220
|
-
REDUCED MOTION: All items visible immediately
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
## Required Components
|
|
226
|
-
|
|
227
|
-
| Component | Import Path | Purpose |
|
|
228
|
-
|-----------|-------------|---------|
|
|
229
|
-
| `Card` | `@vadimcomanescu/nadicode-design-system/card` | Post cards |
|
|
230
|
-
| `Badge` | `@vadimcomanescu/nadicode-design-system/badge` | Category tags |
|
|
231
|
-
| `Avatar` | `@vadimcomanescu/nadicode-design-system/avatar` | Author avatars |
|
|
232
|
-
| `Typography` | `@vadimcomanescu/nadicode-design-system/typography` | Headings, body |
|
|
233
|
-
| `Pagination` | `@vadimcomanescu/nadicode-design-system/pagination` | Blog index pages |
|
|
234
|
-
| `Separator` | `@vadimcomanescu/nadicode-design-system/separator` | Content dividers |
|
|
235
|
-
| `Select` | `@vadimcomanescu/nadicode-design-system/select` | Category filter |
|
|
236
|
-
| `HeaderBlock` | `@vadimcomanescu/nadicode-design-system/catalog/components` via `seedComponents` | Site navigation |
|
|
237
|
-
| `FooterBlock` | `@vadimcomanescu/nadicode-design-system/catalog/components` via `seedComponents` | Site footer |
|
|
238
|
-
| `ScrollFadeIn` | `@vadimcomanescu/nadicode-design-system/scroll-fade-in` | Below-fold animations |
|
|
239
|
-
| `Button` | `@vadimcomanescu/nadicode-design-system/button` | Share, read more |
|
|
240
|
-
|
|
241
|
-
### Allowed (optional)
|
|
242
|
-
|
|
243
|
-
`ChangelogBlock`, `NewsletterBlock`, `Tabs`, `Input` (search), `Breadcrumb`, `Tooltip`, `CodeBlock`
|
|
244
|
-
|
|
245
|
-
### Forbidden
|
|
246
|
-
|
|
247
|
-
`Sidebar`, `DataTable`, `FormWizard`, chart components, agentic components
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
## Required States
|
|
252
|
-
|
|
253
|
-
| State | Trigger | Visual |
|
|
254
|
-
|-------|---------|--------|
|
|
255
|
-
| `loading` | Fetching posts | Skeleton post cards |
|
|
256
|
-
| `empty` | No posts (unlikely for blog) | `Empty` with "No posts yet" |
|
|
257
|
-
| `has-data` | Posts loaded | Full grid layout |
|
|
258
|
-
| `category-filtered` | Category selected | Filtered post grid |
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
## Responsive Contract
|
|
263
|
-
|
|
264
|
-
| Breakpoint | Blog Index Grid | Article Width |
|
|
265
|
-
|------------|----------------|---------------|
|
|
266
|
-
| Mobile | 1 col | Full width, px-4 |
|
|
267
|
-
| `sm:` | 2 col | max-w-3xl, px-6 |
|
|
268
|
-
| `lg:` | Featured 2-col + 3-col grid | max-w-3xl, px-6 |
|
|
269
|
-
|
|
270
|
-
---
|
|
271
|
-
|
|
272
|
-
## Styling Rules
|
|
273
|
-
|
|
274
|
-
- Post cards: `glass-panel` with overflow-hidden for images
|
|
275
|
-
- Article prose: Tailwind typography plugin (`prose prose-neutral dark:prose-invert`)
|
|
276
|
-
- Reading width: `max-w-3xl` (768px) for article content
|
|
277
|
-
- Category badges: `variant="outline"`
|
|
278
|
-
- No raw palette colors
|
|
279
|
-
|
|
280
|
-
---
|
|
281
|
-
|
|
282
|
-
## Accessibility
|
|
283
|
-
|
|
284
|
-
- Blog index is a `<main>` with article cards as `<article>` elements
|
|
285
|
-
- Article page uses semantic `<article>`, `<header>`, heading hierarchy
|
|
286
|
-
- Images have alt text
|
|
287
|
-
- Pagination uses `<nav>` with `aria-label="Blog pagination"`
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
## Reference Implementations
|
|
292
|
-
|
|
293
|
-
- `src/app/blog/page.tsx`
|
|
294
|
-
- `src/app/changelog/page.tsx`
|
|
295
|
-
- `src/components/blocks/ChangelogBlock.tsx`
|
|
296
|
-
- `src/components/blocks/NewsletterBlock.tsx`
|
|
297
|
-
|
|
298
|
-
---
|
|
299
|
-
|
|
300
|
-
## Verification
|
|
301
|
-
|
|
302
|
-
```bash
|
|
303
|
-
npx tsc --noEmit
|
|
304
|
-
npm run lint
|
|
305
|
-
npm run test
|
|
306
|
-
npx vitest run src/test/css-variable-usage.test.ts
|
|
307
|
-
```
|