@deckio/deck-engine 0.2.1 → 0.2.3
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/instructions/AGENTS.md +12 -0
- package/instructions/deck-project.instructions.md +6 -0
- package/instructions/shadcn-components.instructions.md +283 -0
- package/instructions/shadcn-setup.instructions.md +117 -0
- package/instructions/slide-css.instructions.md +8 -0
- package/instructions/slide-jsx.instructions.md +20 -0
- package/package.json +2 -1
- package/scripts/sync-version-from-npm.mjs +68 -0
- package/skills/deck-add-slide/SKILL.md +29 -0
- package/skills/deck-validate-project/SKILL.md +38 -0
- package/styles/global.css +7 -1
- package/themes/descriptors/funky-punk.md +231 -0
- package/themes/descriptors/shadcn-design-system.md +467 -0
- package/themes/descriptors/shadcn.md +356 -106
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
# Design System Supplement — shadcn
|
|
2
|
+
|
|
3
|
+
## Metadata
|
|
4
|
+
|
|
5
|
+
- **Design system id:** `shadcn`
|
|
6
|
+
- **Supplements theme descriptors:** `shadcn.md` (primary), but orthogonal to theme choice
|
|
7
|
+
- **Activates when:** `deck.config.js` includes `designSystem: 'shadcn'`
|
|
8
|
+
- **Read this file when:** You need to understand how shadcn/ui components compose together in slide context, how to maintain visual coherence across a deck, or how the design system layer relates to the theme layer
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## What this file is
|
|
13
|
+
|
|
14
|
+
This is the **design system supplement** — it documents how components work _together_ to build coherent slides. The theme descriptor (`shadcn.md`) covers what's available and how to use individual components. This file covers **composition patterns, visual rhythm, and design system coherence**.
|
|
15
|
+
|
|
16
|
+
The design system layer is orthogonal to theme choice:
|
|
17
|
+
- `theme` controls visual appearance (colors, tokens, mood)
|
|
18
|
+
- `designSystem` controls component infrastructure (what components exist, how they compose)
|
|
19
|
+
- You can have `theme: "shadcn"` with or without `designSystem: "shadcn"`
|
|
20
|
+
- When `designSystem: "shadcn"` is active, this supplement applies regardless of theme
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Component composition patterns
|
|
25
|
+
|
|
26
|
+
### Slide anatomy
|
|
27
|
+
|
|
28
|
+
Every shadcn slide follows this structural hierarchy:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
Slide (engine primitive — positioning, transitions)
|
|
32
|
+
└── content-frame + content-gutter (engine layout — max-width, padding)
|
|
33
|
+
└── Slide body (CSS module — flex column, gap)
|
|
34
|
+
├── Header region (Badge + heading + subtitle)
|
|
35
|
+
├── Content region (Cards, Alerts, Separators, custom blocks)
|
|
36
|
+
├── Action region (Buttons)
|
|
37
|
+
└── BottomBar (engine primitive — deck title, page number)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Rules:**
|
|
41
|
+
- `Slide` + `BottomBar` always come from `@deckio/deck-engine`
|
|
42
|
+
- `content-frame` and `content-gutter` are required CSS classes on the body wrapper
|
|
43
|
+
- Everything between header and actions is the content region — compose freely with components
|
|
44
|
+
|
|
45
|
+
### Header pattern
|
|
46
|
+
|
|
47
|
+
The header is the most consistent element across slides. Always follow this order:
|
|
48
|
+
|
|
49
|
+
```jsx
|
|
50
|
+
<div className={styles.header}>
|
|
51
|
+
<Badge variant="secondary">Category label</Badge> {/* optional kicker */}
|
|
52
|
+
<h2 className={styles.title}>Main heading</h2> {/* required */}
|
|
53
|
+
<p className={styles.subtitle}>Supporting text</p> {/* optional */}
|
|
54
|
+
</div>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Badge kickers use `variant="secondary"` or `variant="outline"` — never `default` (too heavy for a label)
|
|
58
|
+
- Title uses `var(--foreground)`, clamp sizing `clamp(28px, 3.2vw, 36px)`
|
|
59
|
+
- Subtitle uses `var(--muted-foreground)`, clamp sizing `clamp(16px, 1.6vw, 19px)`
|
|
60
|
+
- Header gap: 12px between elements
|
|
61
|
+
|
|
62
|
+
### Card grid pattern
|
|
63
|
+
|
|
64
|
+
Cards are the primary content container. Use grids of 2–4 columns:
|
|
65
|
+
|
|
66
|
+
```jsx
|
|
67
|
+
<div className={styles.grid}>
|
|
68
|
+
<Card>
|
|
69
|
+
<CardHeader>
|
|
70
|
+
<CardTitle>Title</CardTitle>
|
|
71
|
+
<CardDescription>Detail</CardDescription>
|
|
72
|
+
</CardHeader>
|
|
73
|
+
<CardContent>
|
|
74
|
+
<p>Body content</p>
|
|
75
|
+
</CardContent>
|
|
76
|
+
</Card>
|
|
77
|
+
{/* ... more cards */}
|
|
78
|
+
</div>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```css
|
|
82
|
+
.grid {
|
|
83
|
+
display: grid;
|
|
84
|
+
grid-template-columns: repeat(2, minmax(0, 1fr)); /* 2-col default */
|
|
85
|
+
gap: var(--spacing-md, 20px);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* 3-col for feature showcases */
|
|
89
|
+
.gridThree { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
90
|
+
|
|
91
|
+
/* 4-col for metric dashboards (tight) */
|
|
92
|
+
.gridFour { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Visual rhythm rules:**
|
|
96
|
+
- 2 columns: general content, comparisons, before/after
|
|
97
|
+
- 3 columns: feature showcases, step sequences
|
|
98
|
+
- 4 columns: metric dashboards, KPI rows (use sparingly — tight at 1280×720)
|
|
99
|
+
- Never mix column counts within a single slide
|
|
100
|
+
- Card gap: 20px (consistent across all grid sizes)
|
|
101
|
+
|
|
102
|
+
### Alert as framing device
|
|
103
|
+
|
|
104
|
+
Alerts work as contextual framing — use them to set up the content that follows:
|
|
105
|
+
|
|
106
|
+
```jsx
|
|
107
|
+
<Alert>
|
|
108
|
+
<Info className="size-4" />
|
|
109
|
+
<AlertTitle>Context setter</AlertTitle>
|
|
110
|
+
<AlertDescription>
|
|
111
|
+
Frame the problem or key insight before diving into detail cards.
|
|
112
|
+
</AlertDescription>
|
|
113
|
+
</Alert>
|
|
114
|
+
|
|
115
|
+
<Separator />
|
|
116
|
+
|
|
117
|
+
<div className={styles.grid}>
|
|
118
|
+
{/* Detail cards follow the alert */}
|
|
119
|
+
</div>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- Place alerts **before** card grids, not inside them
|
|
123
|
+
- Use `<Separator />` between alert and grid for visual breathing room
|
|
124
|
+
- Destructive variant (`variant="destructive"`) only for genuine warnings
|
|
125
|
+
- One alert per slide maximum
|
|
126
|
+
|
|
127
|
+
### Button action row
|
|
128
|
+
|
|
129
|
+
Buttons anchor the bottom of the content region:
|
|
130
|
+
|
|
131
|
+
```jsx
|
|
132
|
+
<div className={styles.actions}>
|
|
133
|
+
<Button>Primary action</Button>
|
|
134
|
+
<Button variant="outline">Secondary action</Button>
|
|
135
|
+
<Button variant="ghost">Tertiary</Button>
|
|
136
|
+
</div>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- Maximum 3 buttons per action row
|
|
140
|
+
- Primary (default variant) always comes first
|
|
141
|
+
- `variant="outline"` for secondary actions
|
|
142
|
+
- `variant="ghost"` for tertiary/de-emphasized actions
|
|
143
|
+
- Gap: 12px between buttons
|
|
144
|
+
- Align left (`justify-content: flex-start`) — never center button rows
|
|
145
|
+
|
|
146
|
+
### Separator usage
|
|
147
|
+
|
|
148
|
+
Separators create visual breaks between content sections:
|
|
149
|
+
|
|
150
|
+
```jsx
|
|
151
|
+
<Header />
|
|
152
|
+
<Alert />
|
|
153
|
+
<Separator /> {/* between framing and detail */}
|
|
154
|
+
<CardGrid />
|
|
155
|
+
<Separator /> {/* between detail and actions */}
|
|
156
|
+
<Actions />
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
- Maximum 2 separators per slide
|
|
160
|
+
- Never stack separators adjacent to each other
|
|
161
|
+
- Horizontal orientation (default) for content breaks
|
|
162
|
+
- Vertical orientation for inline element separation (rare in slides)
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Variant usage guide
|
|
167
|
+
|
|
168
|
+
### Button variants in slide context
|
|
169
|
+
|
|
170
|
+
| Variant | Slide use case | Visual weight |
|
|
171
|
+
|---|---|---|
|
|
172
|
+
| `default` | Primary CTA, "next step", key action | Heavy — filled primary color |
|
|
173
|
+
| `destructive` | Delete, remove, warning actions | Heavy — filled destructive color |
|
|
174
|
+
| `outline` | Secondary action, "learn more", alternatives | Medium — bordered |
|
|
175
|
+
| `secondary` | Supplementary action, metadata links | Medium — muted fill |
|
|
176
|
+
| `ghost` | Tertiary action, navigation hints | Light — text only |
|
|
177
|
+
| `link` | Inline text links within content | Minimal — underlined text |
|
|
178
|
+
|
|
179
|
+
### Badge variants in slide context
|
|
180
|
+
|
|
181
|
+
| Variant | Slide use case |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `secondary` | Default kicker/label above headings |
|
|
184
|
+
| `outline` | Subtle categorization, metadata tags |
|
|
185
|
+
| `default` | Status indicators (use sparingly — high contrast) |
|
|
186
|
+
| `destructive` | Warning/error status |
|
|
187
|
+
| `ghost` | Rarely used in slides; available for custom overlays |
|
|
188
|
+
| `link` | Rarely used in slides; available for badge links |
|
|
189
|
+
|
|
190
|
+
### Alert variants in slide context
|
|
191
|
+
|
|
192
|
+
| Variant | Slide use case |
|
|
193
|
+
|---|---|
|
|
194
|
+
| `default` | Context-setting, key insight framing, pro tips |
|
|
195
|
+
| `destructive` | Critical warnings, breaking changes, blockers |
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Composition with Radix primitives
|
|
200
|
+
|
|
201
|
+
Preinstalled components build on Radix UI. When adding components via CLI/MCP, they follow the same patterns:
|
|
202
|
+
|
|
203
|
+
### `asChild` pattern
|
|
204
|
+
|
|
205
|
+
`asChild` replaces the default rendered element with the child element, forwarding all props:
|
|
206
|
+
|
|
207
|
+
```jsx
|
|
208
|
+
{/* Button renders as <a> tag with Button styling */}
|
|
209
|
+
<Button asChild variant="outline">
|
|
210
|
+
<a href="https://github.com/project" target="_blank">
|
|
211
|
+
View on GitHub
|
|
212
|
+
</a>
|
|
213
|
+
</Button>
|
|
214
|
+
|
|
215
|
+
{/* Badge renders as <a> tag */}
|
|
216
|
+
<Badge asChild variant="secondary">
|
|
217
|
+
<a href="/changelog">v2.0</a>
|
|
218
|
+
</Badge>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**When to use:** Links that should look like buttons, or any case where the semantic HTML element differs from the visual component.
|
|
222
|
+
|
|
223
|
+
### Compound component composition
|
|
224
|
+
|
|
225
|
+
shadcn components use the compound component pattern — compose by nesting:
|
|
226
|
+
|
|
227
|
+
```jsx
|
|
228
|
+
{/* Card with action button in header (v4 pattern) */}
|
|
229
|
+
<Card>
|
|
230
|
+
<CardHeader>
|
|
231
|
+
<CardTitle>Feature</CardTitle>
|
|
232
|
+
<CardDescription>Description</CardDescription>
|
|
233
|
+
<CardAction>
|
|
234
|
+
<Button variant="outline" size="sm">Edit</Button>
|
|
235
|
+
</CardAction>
|
|
236
|
+
</CardHeader>
|
|
237
|
+
<CardContent>
|
|
238
|
+
<p>Content</p>
|
|
239
|
+
</CardContent>
|
|
240
|
+
<CardFooter>
|
|
241
|
+
<Button>Save</Button>
|
|
242
|
+
</CardFooter>
|
|
243
|
+
</Card>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
- Always maintain the nesting order: Header → Content → Footer
|
|
247
|
+
- `CardAction` goes inside `CardHeader` (v4 auto-positions it)
|
|
248
|
+
- Don't skip levels (no `CardTitle` outside `CardHeader`)
|
|
249
|
+
|
|
250
|
+
### `data-slot` styling hooks
|
|
251
|
+
|
|
252
|
+
Every component emits `data-slot` for external styling:
|
|
253
|
+
|
|
254
|
+
```css
|
|
255
|
+
/* Override Card background in a specific slide */
|
|
256
|
+
.specialSlide [data-slot="card"] {
|
|
257
|
+
background: color-mix(in srgb, var(--card) 80%, var(--accent) 20%);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* Style all badges in this slide */
|
|
261
|
+
.specialSlide [data-slot="badge"] {
|
|
262
|
+
text-transform: uppercase;
|
|
263
|
+
letter-spacing: 0.05em;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Prefer this over className overrides** when you need slide-scoped component styling. It targets component identity, not implementation-specific class names.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Mixing preinstalled + added components
|
|
272
|
+
|
|
273
|
+
When you add new components via `npx shadcn@latest add`, they automatically inherit the token system. Visual coherence is maintained because:
|
|
274
|
+
|
|
275
|
+
1. **Same token foundation** — all shadcn components read from `--background`, `--foreground`, `--border`, `--radius`, etc.
|
|
276
|
+
2. **Same utility layer** — Tailwind classes resolve to the same theme bridge
|
|
277
|
+
3. **Same `cn()` utility** — className composition is consistent
|
|
278
|
+
4. **Same `data-slot` convention** — styling hooks work the same way
|
|
279
|
+
|
|
280
|
+
### Coherence checklist when adding components
|
|
281
|
+
|
|
282
|
+
- ✅ The new component reads from the same CSS variables — no configuration needed
|
|
283
|
+
- ✅ Border radius matches via `--radius` token
|
|
284
|
+
- ✅ Colors match via semantic tokens (not hardcoded values)
|
|
285
|
+
- ⚠️ Check font sizing — some components may use `text-sm` which maps to Tailwind's scale. Verify it aligns with slide heading/body sizes
|
|
286
|
+
- ⚠️ Check spacing — component internal padding uses Tailwind spacing. Verify it doesn't look cramped or loose at 1280×720 slide dimensions
|
|
287
|
+
- ⚠️ Animation — added components may include transitions. Ensure they don't conflict with ReactBits animations on the same slide
|
|
288
|
+
|
|
289
|
+
### Example: adding Dialog for a detail overlay
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
npx shadcn@latest add dialog
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
```jsx
|
|
296
|
+
import { Button } from '@/components/ui/button'
|
|
297
|
+
import {
|
|
298
|
+
Dialog, DialogContent, DialogDescription,
|
|
299
|
+
DialogHeader, DialogTitle, DialogTrigger
|
|
300
|
+
} from '@/components/ui/dialog'
|
|
301
|
+
|
|
302
|
+
{/* Inside your slide content */}
|
|
303
|
+
<Dialog>
|
|
304
|
+
<DialogTrigger asChild>
|
|
305
|
+
<Button variant="outline">View details</Button>
|
|
306
|
+
</DialogTrigger>
|
|
307
|
+
<DialogContent>
|
|
308
|
+
<DialogHeader>
|
|
309
|
+
<DialogTitle>Feature deep-dive</DialogTitle>
|
|
310
|
+
<DialogDescription>
|
|
311
|
+
Extended information that doesn't fit on the slide surface.
|
|
312
|
+
</DialogDescription>
|
|
313
|
+
</DialogHeader>
|
|
314
|
+
<p>Detailed content here.</p>
|
|
315
|
+
</DialogContent>
|
|
316
|
+
</Dialog>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Note: Dialogs render as overlays — they work in dev mode but may not export/screenshot correctly. Use with awareness of the export pipeline.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Deck-specific design tokens
|
|
324
|
+
|
|
325
|
+
These tokens extend the shadcn vocabulary for presentation-specific needs. They are defined in the theme CSS (`shadcn.css`), not by shadcn/ui itself:
|
|
326
|
+
|
|
327
|
+
### Slide composition tokens
|
|
328
|
+
|
|
329
|
+
| Token | Purpose | Default (shadcn theme) |
|
|
330
|
+
|---|---|---|
|
|
331
|
+
| `--slide-bg` | Full slide background behind content frame | Same as `--background` |
|
|
332
|
+
| `--content-max-width` | Maximum width of `content-frame` | `1100px` |
|
|
333
|
+
| `--content-gutter` | Horizontal padding inside `content-gutter` | `48px` |
|
|
334
|
+
| `--surface-overlay` | Card/surface overlay for frosted effects | Translucent white/black |
|
|
335
|
+
| `--surface-overlay-heavy` | Stronger overlay for modal-like surfaces | Higher opacity overlay |
|
|
336
|
+
| `--border-subtle` | Lighter border for decorative separation | Lower opacity border |
|
|
337
|
+
| `--shadow-elevated` | Elevated card shadow | Subtle box-shadow value |
|
|
338
|
+
|
|
339
|
+
### Typography tokens
|
|
340
|
+
|
|
341
|
+
| Token | Purpose |
|
|
342
|
+
|---|---|
|
|
343
|
+
| `--font-family-body` | Body text font (Inter / system) |
|
|
344
|
+
| `--font-family-mono` | Code block font |
|
|
345
|
+
| `--font-size-body` | Base body text size |
|
|
346
|
+
| `--font-size-small` | Caption/small text |
|
|
347
|
+
| `--font-weight-normal` | Body weight |
|
|
348
|
+
| `--font-weight-semibold` | Heading weight |
|
|
349
|
+
| `--font-weight-bold` | Strong emphasis weight |
|
|
350
|
+
| `--line-height-body` | Body line height |
|
|
351
|
+
|
|
352
|
+
### Spacing tokens
|
|
353
|
+
|
|
354
|
+
| Token | Purpose |
|
|
355
|
+
|---|---|
|
|
356
|
+
| `--spacing-xs` | Tight spacing (4px) |
|
|
357
|
+
| `--spacing-sm` | Small spacing (8–12px) |
|
|
358
|
+
| `--spacing-md` | Medium spacing (16–20px) |
|
|
359
|
+
| `--spacing-lg` | Large spacing (24–32px) |
|
|
360
|
+
| `--spacing-xl` | Section spacing (40–48px) |
|
|
361
|
+
|
|
362
|
+
These tokens are **safe to use in CSS modules** alongside shadcn's Tailwind utilities. They bridge the gap between the component library's utility-first approach and the deck engine's CSS variable system.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Visual coherence rules
|
|
367
|
+
|
|
368
|
+
These rules ensure every slide in a deck feels like it belongs to the same family:
|
|
369
|
+
|
|
370
|
+
### Typography hierarchy
|
|
371
|
+
|
|
372
|
+
1. **Slide title:** `clamp(28px, 3.2vw, 36px)`, weight 700, `var(--foreground)`
|
|
373
|
+
2. **Card titles:** Let `CardTitle` handle it (built-in `text-lg font-semibold`)
|
|
374
|
+
3. **Body text:** `clamp(14px, 1.2vw, 16px)`, `var(--foreground)` or `var(--muted-foreground)`
|
|
375
|
+
4. **Labels/kickers:** Badge component — never manual `font-size: 12px` spans
|
|
376
|
+
5. **Code:** `var(--font-family-mono)`, `text-sm`
|
|
377
|
+
|
|
378
|
+
### Color usage
|
|
379
|
+
|
|
380
|
+
| Role | Token | When to use |
|
|
381
|
+
|---|---|---|
|
|
382
|
+
| Page background | `--background` | Slide surface |
|
|
383
|
+
| Primary text | `--foreground` | Headings, body text |
|
|
384
|
+
| Secondary text | `--muted-foreground` | Subtitles, descriptions, metadata |
|
|
385
|
+
| Content surfaces | `--card` / `--card-foreground` | Card backgrounds |
|
|
386
|
+
| Interactive | `--primary` / `--primary-foreground` | Buttons (default variant), links |
|
|
387
|
+
| Neutral interactive | `--secondary` / `--secondary-foreground` | Badge kickers, secondary buttons |
|
|
388
|
+
| Emphasis | `--accent` / `--accent-foreground` | Hover states, highlights |
|
|
389
|
+
| Error/warning | `--destructive` / `--destructive-foreground` | Destructive buttons, error alerts |
|
|
390
|
+
| Borders | `--border` | Card borders, separators |
|
|
391
|
+
| Focus | `--ring` | Focus rings on interactive elements |
|
|
392
|
+
|
|
393
|
+
**Never use decorative palette tokens** (`--blue-glow`, `--purple`, etc.) for content structure. They exist for optional ambient effects only.
|
|
394
|
+
|
|
395
|
+
### Spacing rhythm
|
|
396
|
+
|
|
397
|
+
- Header-to-content gap: 24px (`--spacing-lg`)
|
|
398
|
+
- Between content blocks: 20px (`--spacing-md`)
|
|
399
|
+
- Inside card headers/content: handled by component (don't override)
|
|
400
|
+
- Action row gap: 12px (`--spacing-sm`)
|
|
401
|
+
- Slide bottom padding: 44px (BottomBar clearance)
|
|
402
|
+
|
|
403
|
+
### Border radius
|
|
404
|
+
|
|
405
|
+
- All components use `--radius` (0.625rem in shadcn theme)
|
|
406
|
+
- Don't mix `border-radius: var(--radius)` with hardcoded values
|
|
407
|
+
- Pill shapes (`border-radius: 9999px`) only for Badge — it handles this internally
|
|
408
|
+
|
|
409
|
+
### Animation discipline
|
|
410
|
+
|
|
411
|
+
- ReactBits components handle their own animation — don't layer CSS animations on top
|
|
412
|
+
- Entrance animations (stagger, fade-in) belong in CSS modules, not inline styles
|
|
413
|
+
- Maximum 2 animated elements per slide to avoid visual noise
|
|
414
|
+
- Prefer `opacity` + `transform` animations (GPU-accelerated) over `width`/`height`/`margin`
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## Decision: CSS modules vs Tailwind utilities
|
|
419
|
+
|
|
420
|
+
Both are valid in shadcn slides. Here's when to use which:
|
|
421
|
+
|
|
422
|
+
| Use CSS modules for | Use Tailwind utilities for |
|
|
423
|
+
|---|---|
|
|
424
|
+
| Slide-level layout (grid, flex, positioning) | Component className overrides |
|
|
425
|
+
| Slide-specific animations (keyframes, stagger) | Quick spacing/color tweaks on components |
|
|
426
|
+
| Complex responsive patterns | One-off utility classes on wrapper divs |
|
|
427
|
+
| Anything that needs a named class for `styles.x` | Anything the component already supports via `className` |
|
|
428
|
+
|
|
429
|
+
**Example of correct mixing:**
|
|
430
|
+
|
|
431
|
+
```jsx
|
|
432
|
+
{/* CSS module for layout, Tailwind for component tweaks */}
|
|
433
|
+
<div className={styles.grid}>
|
|
434
|
+
<Card className="shadow-md"> {/* Tailwind override */}
|
|
435
|
+
<CardHeader>
|
|
436
|
+
<CardTitle className="text-xl">Big</CardTitle> {/* Tailwind override */}
|
|
437
|
+
</CardHeader>
|
|
438
|
+
<CardContent>
|
|
439
|
+
<p>Content</p>
|
|
440
|
+
</CardContent>
|
|
441
|
+
</Card>
|
|
442
|
+
</div>
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Never do this:**
|
|
446
|
+
```jsx
|
|
447
|
+
{/* Don't rebuild Card with CSS modules */}
|
|
448
|
+
<div className={styles.card}>
|
|
449
|
+
<div className={styles.cardHeader}>...</div>
|
|
450
|
+
</div>
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Relationship to other descriptors
|
|
456
|
+
|
|
457
|
+
```
|
|
458
|
+
deck.config.js
|
|
459
|
+
├── theme: 'shadcn' → loads shadcn.md (theme descriptor)
|
|
460
|
+
│ ↳ tokens, visual identity, what to import
|
|
461
|
+
├── designSystem: 'shadcn' → loads shadcn-design-system.md (this file)
|
|
462
|
+
│ ↳ composition patterns, coherence rules
|
|
463
|
+
└── both active together → full shadcn authoring experience
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
The theme descriptor answers: **"What do I have and how do I use each piece?"**
|
|
467
|
+
This supplement answers: **"How do the pieces work together to make a coherent deck?"**
|