dogsbay 0.2.0-beta.2 → 0.2.0-beta.21
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/dist/commands/agent.js +305 -0
- package/dist/commands/site-build.js +66 -15
- package/dist/commands/site-dev.js +181 -23
- package/dist/commands/site-init.js +193 -32
- package/dist/config/defaults.js +8 -1
- package/dist/config/load.js +6 -32
- package/dist/config/to-astro-options.js +1 -0
- package/dist/import-content.js +13 -12
- package/dist/index.js +19 -4
- package/dist/passthrough-astro.js +152 -0
- package/dist/registry.js +8 -0
- package/package.json +11 -9
- package/skills/platform/agent-readiness/SKILL.md +262 -0
- package/skills/platform/cli-commands/SKILL.md +205 -0
- package/skills/platform/config-yml/SKILL.md +219 -0
- package/skills/platform/frontmatter-fields/SKILL.md +310 -0
- package/skills/platform/markdown-directives/SKILL.md +329 -0
- package/skills/platform/multi-source/SKILL.md +294 -0
- package/skills/platform/nav-file/SKILL.md +107 -0
- package/skills/platform/openapi-source/SKILL.md +237 -0
- package/skills/platform/plugin-api/SKILL.md +280 -0
- package/skills/platform/project-anatomy/SKILL.md +156 -0
- package/skills/platform/taxonomy-config/SKILL.md +392 -0
- package/skills/platform/theme-tokens/SKILL.md +276 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dogsbay:taxonomy-config
|
|
3
|
+
description: Configure user-defined taxonomies (tags, types, audience, status) in dogsbay.config.yml. Dogsbay provides the slot, the user defines the categories. Use when adding tagging schemes, custom badges, or facet UI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Taxonomy configuration
|
|
7
|
+
|
|
8
|
+
Dogsbay does **not** prescribe what categories a doc site uses
|
|
9
|
+
for tagging. It provides:
|
|
10
|
+
|
|
11
|
+
- A frontmatter slot for tag values
|
|
12
|
+
- A config slot (`taxonomies:`) for declaring tag schemes
|
|
13
|
+
- Audit rules + display components that consume the schemes
|
|
14
|
+
- Browse pages (`/tags/`, `/by-type/`, etc.) per declared
|
|
15
|
+
taxonomy
|
|
16
|
+
|
|
17
|
+
What goes IN the schemes is the user's call. Dogsbay's role is
|
|
18
|
+
to make the slot work consistently.
|
|
19
|
+
|
|
20
|
+
## Where taxonomy values live
|
|
21
|
+
|
|
22
|
+
Per-page in frontmatter:
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
---
|
|
26
|
+
title: Configuring environments
|
|
27
|
+
description: …
|
|
28
|
+
type: how-to # built-in field (treated as a taxonomy)
|
|
29
|
+
status: stable # built-in
|
|
30
|
+
audience: [developer, ops] # built-in
|
|
31
|
+
tags: # free-form tag list
|
|
32
|
+
- concept/environments
|
|
33
|
+
- difficulty/intermediate
|
|
34
|
+
- kind/configuration
|
|
35
|
+
---
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Five built-in field names (`tags`, `type`, `status`, `audience`,
|
|
39
|
+
`category`) are treated as taxonomies if declared in
|
|
40
|
+
`dogsbay.config.yml`. Custom names work too — just declare them
|
|
41
|
+
in the config.
|
|
42
|
+
|
|
43
|
+
## Declaring a taxonomy
|
|
44
|
+
|
|
45
|
+
In `dogsbay.config.yml`:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
taxonomies:
|
|
49
|
+
tags:
|
|
50
|
+
indexPath: /tags # browse page (default: /<name>)
|
|
51
|
+
prefixes: # display config per top-level slug prefix
|
|
52
|
+
concept:
|
|
53
|
+
label: Concept
|
|
54
|
+
color: blue
|
|
55
|
+
difficulty:
|
|
56
|
+
label: Difficulty
|
|
57
|
+
color: amber
|
|
58
|
+
kind:
|
|
59
|
+
label: Kind
|
|
60
|
+
color: emerald
|
|
61
|
+
labels: # display label overrides per slug
|
|
62
|
+
"concept/a11y": Accessibility # /tags/concept/a11y → "Concept: Accessibility"
|
|
63
|
+
"difficulty/intermediate": Intermediate
|
|
64
|
+
type:
|
|
65
|
+
indexPath: /by-type
|
|
66
|
+
values: # closed list (audit rule fails on unknown values)
|
|
67
|
+
- tutorial
|
|
68
|
+
- how-to
|
|
69
|
+
- reference
|
|
70
|
+
- explanation
|
|
71
|
+
status:
|
|
72
|
+
indexPath: /by-status
|
|
73
|
+
values: [draft, preview, stable, deprecated]
|
|
74
|
+
audience:
|
|
75
|
+
indexPath: /by-audience
|
|
76
|
+
values: [developer, ops, security, end-user]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Each taxonomy declaration produces:
|
|
80
|
+
|
|
81
|
+
- A browse index at `/tags/`, `/by-type/`, etc.
|
|
82
|
+
- Per-term pages (`/tags/concept/a11y`)
|
|
83
|
+
- A faceted-search checkbox group in the `Cmd+K` search dialog,
|
|
84
|
+
emitted automatically as `data-pagefind-filter="<name>:<value>"`
|
|
85
|
+
divs on every page that declares the taxonomy
|
|
86
|
+
|
|
87
|
+
## Discovery model — chips vs. facets vs. browse
|
|
88
|
+
|
|
89
|
+
Taxonomies play two distinct roles in a doc site:
|
|
90
|
+
|
|
91
|
+
- **Associative tags** — answer *"what other pages are like this
|
|
92
|
+
one?"*. Primary mode: chips on the article header, link to
|
|
93
|
+
related pages. The `tags:` taxonomy is the canonical example.
|
|
94
|
+
- **Descriptive metadata** — answers *"what kind of doc is this,
|
|
95
|
+
is it for me?"*. Primary mode: faceted search + browse-by-axis
|
|
96
|
+
pages. `audience`, `difficulty`, `team`, `status`, `type` all
|
|
97
|
+
fit here.
|
|
98
|
+
|
|
99
|
+
Dogsbay surfaces them as follows:
|
|
100
|
+
|
|
101
|
+
| Surface | Built-ins (tags, type, status) | Custom taxonomies (difficulty, team, …) |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| Chips on article header | ✅ rendered | ❌ not rendered (use a custom layout to add) |
|
|
104
|
+
| Pagefind facet checkbox | ✅ automatic | ✅ automatic |
|
|
105
|
+
| Browse pages (`/tags/`, `/by-difficulty/`) | ✅ from `indexPath` | ✅ from `indexPath` |
|
|
106
|
+
| Sidebar nav entry | ❌ writer adds via `nav.yml` | ❌ writer adds via `nav.yml` |
|
|
107
|
+
|
|
108
|
+
The chip cluster on the page header deliberately stays small —
|
|
109
|
+
adding every taxonomy as a chip would crowd the article. Search
|
|
110
|
+
facets are the discovery path for descriptive metadata, and
|
|
111
|
+
browse pages are the catalogue path. Add browse pages to the
|
|
112
|
+
sidebar nav (see "Surfacing browse pages" below) when discovery
|
|
113
|
+
matters.
|
|
114
|
+
|
|
115
|
+
## Faceted search comes free
|
|
116
|
+
|
|
117
|
+
Every taxonomy declared in `dogsbay.config.yml` automatically
|
|
118
|
+
appears as a checkbox group in the `Cmd+K` search dialog. No
|
|
119
|
+
extra config — declaring it produces the `<div
|
|
120
|
+
data-pagefind-filter="<name>:<value>">` markers on every
|
|
121
|
+
matching page, Pagefind discovers them at index time, and the
|
|
122
|
+
search UI renders one column per taxonomy with checkboxes per
|
|
123
|
+
distinct value, sorted by frequency.
|
|
124
|
+
|
|
125
|
+
Display labels for the checkboxes flow from
|
|
126
|
+
`taxonomies.<name>.prefixes` and `taxonomies.<name>.labels` (the
|
|
127
|
+
same display config that drives chips). When unset, raw slugs
|
|
128
|
+
appear ("intermediate", "developer").
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
taxonomies:
|
|
132
|
+
difficulty:
|
|
133
|
+
indexPath: /by-difficulty
|
|
134
|
+
values: [beginner, intermediate, advanced]
|
|
135
|
+
prefixes:
|
|
136
|
+
beginner: { label: Beginner, color: emerald }
|
|
137
|
+
intermediate: { label: Intermediate, color: amber }
|
|
138
|
+
advanced: { label: Advanced, color: rose }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Above declaration ⇒ search dialog grows a "Difficulty" column
|
|
142
|
+
with three labelled checkboxes, with counts.
|
|
143
|
+
|
|
144
|
+
## Surfacing browse pages
|
|
145
|
+
|
|
146
|
+
Browse pages (`/by-difficulty/`, `/by-audience/`, etc.) exist
|
|
147
|
+
the moment you declare a taxonomy with an `indexPath`, but
|
|
148
|
+
nothing links to them by default. The standard pattern is a
|
|
149
|
+
"Browse" group at the bottom of `nav.yml`:
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
# nav.yml
|
|
153
|
+
- Guides:
|
|
154
|
+
- Getting started: /getting-started
|
|
155
|
+
- Configuration: /config
|
|
156
|
+
- Browse:
|
|
157
|
+
- By type: /by-type/
|
|
158
|
+
- By audience: /by-audience/
|
|
159
|
+
- By difficulty: /by-difficulty/
|
|
160
|
+
- Tags: /tags/
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Nav entries accept absolute paths to internal pages. The
|
|
164
|
+
"Browse" group is conventional, not enforced — pick the IA that
|
|
165
|
+
fits the site.
|
|
166
|
+
|
|
167
|
+
## Hierarchical tags via slug prefixes
|
|
168
|
+
|
|
169
|
+
Tags can have slash-separated prefixes that the display layer
|
|
170
|
+
treats as namespaces:
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
tags:
|
|
174
|
+
- concept/accessibility
|
|
175
|
+
- concept/observability
|
|
176
|
+
- difficulty/beginner
|
|
177
|
+
- difficulty/advanced
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Renders as two-part chips: `Concept: Accessibility`,
|
|
181
|
+
`Difficulty: Beginner`. The prefix maps to a colour via
|
|
182
|
+
`taxonomies.tags.prefixes.<prefix>.color`; the leaf maps to a
|
|
183
|
+
human label via `taxonomies.tags.labels.<full-slug>`.
|
|
184
|
+
|
|
185
|
+
This is the slot for "we want categories of tags but don't want
|
|
186
|
+
to invent five separate frontmatter fields." Slash separation
|
|
187
|
+
is the convention; the parser doesn't enforce it.
|
|
188
|
+
|
|
189
|
+
### `hierarchical:` controls prefix browsing
|
|
190
|
+
|
|
191
|
+
When `hierarchical: true`, declaring tag `concept/rag` also
|
|
192
|
+
emits a `/tags/concept/` browse page that aggregates every
|
|
193
|
+
`concept/*` tag. Term-page breadcrumbs (`Tags / Concept / RAG`)
|
|
194
|
+
become clickable.
|
|
195
|
+
|
|
196
|
+
When `hierarchical: false`, only leaf-tag pages (`/tags/concept/rag/`)
|
|
197
|
+
exist; the prefix is purely visual styling on chips.
|
|
198
|
+
|
|
199
|
+
**The default is auto-derived:** when you declare `prefixes:`,
|
|
200
|
+
`hierarchical` defaults to `true` (the writer signalled they
|
|
201
|
+
want prefixes to be real browsable categories). When
|
|
202
|
+
`prefixes:` is absent, `hierarchical` defaults to `false`. Set
|
|
203
|
+
the flag explicitly to override.
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
# Auto-hierarchical — prefixes declared, /tags/concept/ exists
|
|
207
|
+
taxonomies:
|
|
208
|
+
tags:
|
|
209
|
+
prefixes:
|
|
210
|
+
concept: { color: blue }
|
|
211
|
+
|
|
212
|
+
# Flat — prefixes are pure styling, /tags/concept/ does NOT exist
|
|
213
|
+
taxonomies:
|
|
214
|
+
tags:
|
|
215
|
+
hierarchical: false
|
|
216
|
+
prefixes:
|
|
217
|
+
concept: { color: blue }
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Closed-list taxonomies
|
|
221
|
+
|
|
222
|
+
`values:` makes a taxonomy closed — pages declaring a value
|
|
223
|
+
outside the list fire the `taxonomy/unknown-value` audit rule.
|
|
224
|
+
Use for taxonomies where you want type-safety:
|
|
225
|
+
|
|
226
|
+
```yaml
|
|
227
|
+
taxonomies:
|
|
228
|
+
status:
|
|
229
|
+
values: [draft, preview, stable, deprecated]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
A page with `status: production` fails `dogsbay site check`.
|
|
233
|
+
|
|
234
|
+
Without `values:`, the taxonomy is open — any string is
|
|
235
|
+
accepted. Useful for free-form tags.
|
|
236
|
+
|
|
237
|
+
### `status: draft` is special-cased
|
|
238
|
+
|
|
239
|
+
The `draft` value of the `status` taxonomy is **also** a
|
|
240
|
+
build-time visibility gate — equivalent to `draft: true` in
|
|
241
|
+
frontmatter. A page with `status: draft` is dropped from
|
|
242
|
+
`dogsbay site build` (production) and the build line prints
|
|
243
|
+
"(N drafts excluded)". `dogsbay site dev` always includes
|
|
244
|
+
drafts so the writer can preview; `--include-drafts` is the
|
|
245
|
+
escape hatch for production builds.
|
|
246
|
+
|
|
247
|
+
The other three values (`preview`, `stable`, `deprecated`) are
|
|
248
|
+
pure taxonomy — they render as a `<StatusBadge>` chip and
|
|
249
|
+
populate `/by-status/`, but don't gate visibility.
|
|
250
|
+
|
|
251
|
+
This is the only built-in taxonomy with overloaded semantics.
|
|
252
|
+
If a writer wants `draft` to be only-a-taxonomy (no
|
|
253
|
+
exclusion), the workaround is to use a different value name
|
|
254
|
+
(e.g. `status: in-progress`) and customize the badge labels via
|
|
255
|
+
`taxonomies.status.labels`.
|
|
256
|
+
|
|
257
|
+
**Agents should not proactively stamp `status: draft` on new
|
|
258
|
+
pages.** In a git-backed site (the common case), in-progress
|
|
259
|
+
work is already isolated by branch — the page is a draft
|
|
260
|
+
because the PR isn't merged, not because of frontmatter. Adding
|
|
261
|
+
`status: draft` then layers an invisible build-time gate on
|
|
262
|
+
top of the branch isolation, so when the PR merges the page
|
|
263
|
+
*still* doesn't ship until someone notices and removes the
|
|
264
|
+
frontmatter. That's a confusion trap.
|
|
265
|
+
|
|
266
|
+
Use `status:` only when:
|
|
267
|
+
|
|
268
|
+
1. The writer explicitly asked for it ("mark this draft").
|
|
269
|
+
2. There's no git workflow (single-author site editing
|
|
270
|
+
directly on `main`).
|
|
271
|
+
3. The page is a long-lived `preview` / `deprecated` /
|
|
272
|
+
`stable` lifecycle marker (not draft).
|
|
273
|
+
|
|
274
|
+
Default to no `status` field on new pages. Branches handle
|
|
275
|
+
draft state.
|
|
276
|
+
|
|
277
|
+
## Display palette
|
|
278
|
+
|
|
279
|
+
The closed colour palette for prefix chips and badges:
|
|
280
|
+
|
|
281
|
+
`blue`, `amber`, `emerald`, `violet`, `rose`, `slate`
|
|
282
|
+
|
|
283
|
+
These resolve to theme tokens — they look correct in any theme
|
|
284
|
+
the site uses. Don't pass arbitrary hex codes here; the palette
|
|
285
|
+
is intentional.
|
|
286
|
+
|
|
287
|
+
## Audit rule integration
|
|
288
|
+
|
|
289
|
+
`dogsbay site check` ships a few taxonomy-related rules
|
|
290
|
+
(currently in the `seo/` and (planned) `taxonomy/` categories):
|
|
291
|
+
|
|
292
|
+
- `seo/missing-tags` — page has no tags (configurable threshold)
|
|
293
|
+
- `taxonomy/unknown-value` — frontmatter value not in declared
|
|
294
|
+
`values:`
|
|
295
|
+
- `taxonomy/orphan-term` — taxonomy term page exists but no page
|
|
296
|
+
references it
|
|
297
|
+
- `taxonomy/duplicate-display-label` — two slugs map to the same
|
|
298
|
+
display string
|
|
299
|
+
|
|
300
|
+
Plugins and patterns can register additional taxonomy-aware
|
|
301
|
+
rules.
|
|
302
|
+
|
|
303
|
+
## Browse + facet UI
|
|
304
|
+
|
|
305
|
+
`<TaxonomyIndex>` and `<TaxonomyTerm>` components render the
|
|
306
|
+
browse pages — they read `siteConfig.taxonomyDisplay` and
|
|
307
|
+
`siteConfig.taxonomyIndexPaths` (both populated from the config
|
|
308
|
+
at build time).
|
|
309
|
+
|
|
310
|
+
`<TagList>` renders chip-style tags in page headers. Reads the
|
|
311
|
+
prefix colours and label overrides.
|
|
312
|
+
|
|
313
|
+
`<SearchFacets>` renders facet checkboxes ("Concept:
|
|
314
|
+
Accessibility", "How-to") — reads the same display config.
|
|
315
|
+
|
|
316
|
+
## Per-page taxonomy values flow
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
content/page.md frontmatter
|
|
320
|
+
↓ (parsed by importer)
|
|
321
|
+
ExportPage.meta.taxonomies = { tags: [...], type: ..., ... }
|
|
322
|
+
↓ (rendered into page)
|
|
323
|
+
data-pagefind-filter attributes (search facets)
|
|
324
|
+
TagList component (visual chips)
|
|
325
|
+
TaxonomyIndex pages (browse)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Each step is platform-mechanical. The categories (concept,
|
|
329
|
+
difficulty, audience values, etc.) are user-defined.
|
|
330
|
+
|
|
331
|
+
## Common patterns
|
|
332
|
+
|
|
333
|
+
### Diátaxis-style content typing
|
|
334
|
+
|
|
335
|
+
When `@dogsbay/pattern-diataxis` is installed, it pre-declares:
|
|
336
|
+
|
|
337
|
+
```yaml
|
|
338
|
+
taxonomies:
|
|
339
|
+
type:
|
|
340
|
+
values: [tutorial, how-to, reference, explanation]
|
|
341
|
+
prefixes:
|
|
342
|
+
tutorial: { color: emerald }
|
|
343
|
+
"how-to": { color: blue }
|
|
344
|
+
reference: { color: amber }
|
|
345
|
+
explanation: { color: violet }
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The pattern owns the values; the user can extend with their own.
|
|
349
|
+
|
|
350
|
+
### Custom team taxonomies
|
|
351
|
+
|
|
352
|
+
```yaml
|
|
353
|
+
taxonomies:
|
|
354
|
+
team:
|
|
355
|
+
values: [platform, billing, identity, search]
|
|
356
|
+
indexPath: /by-team
|
|
357
|
+
release:
|
|
358
|
+
indexPath: /releases
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Each team owns a subset of pages. The `/by-team/platform/` page
|
|
362
|
+
lists every page that declares `team: platform` in frontmatter.
|
|
363
|
+
|
|
364
|
+
### Free-form tags only
|
|
365
|
+
|
|
366
|
+
```yaml
|
|
367
|
+
taxonomies:
|
|
368
|
+
tags:
|
|
369
|
+
indexPath: /tags
|
|
370
|
+
prefixes:
|
|
371
|
+
concept: { color: blue }
|
|
372
|
+
kind: { color: emerald }
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
No `values:` — any tag is valid. Just hierarchical display
|
|
376
|
+
config for the prefixes the writer uses.
|
|
377
|
+
|
|
378
|
+
## Common mistakes
|
|
379
|
+
|
|
380
|
+
- ❌ Putting tag display config (colours, labels) in
|
|
381
|
+
per-page frontmatter — that's site-wide, belongs in
|
|
382
|
+
`dogsbay.config.yml`. Frontmatter just lists which taxonomies
|
|
383
|
+
apply to this page.
|
|
384
|
+
- ❌ Using `tagPrefixes` directly in `dogsbay.config.yml` —
|
|
385
|
+
legacy field, deprecated. Use
|
|
386
|
+
`taxonomies.tags.prefixes` instead.
|
|
387
|
+
- ❌ Mixing prefix-based and free-form tags inconsistently —
|
|
388
|
+
pick one approach per taxonomy. If `tags` uses `concept/...`
|
|
389
|
+
prefixes, every tag should follow that pattern.
|
|
390
|
+
- ❌ Declaring `values: [draft, …]` and then using `Draft` (with
|
|
391
|
+
capital) in frontmatter — values match exactly; case
|
|
392
|
+
matters.
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dogsbay:theme-tokens
|
|
3
|
+
description: The 60 design tokens Dogsbay ships, how theme.css works, and how to override colours, fonts, radius, or swap themes wholesale. Use when customising visual design or troubleshooting theming issues.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Theme tokens
|
|
7
|
+
|
|
8
|
+
Dogsbay ships ~60 design tokens grouped by purpose. They live
|
|
9
|
+
in `astro/src/styles/theme.css` (scaffold-once — yours to edit
|
|
10
|
+
freely) and are consumed by the 72 components via Tailwind's
|
|
11
|
+
`@theme` directive.
|
|
12
|
+
|
|
13
|
+
Two themes ship out of the box:
|
|
14
|
+
|
|
15
|
+
- `default` — shadcn-zinc-style (clean, neutral)
|
|
16
|
+
- `material` — Material-Design-inspired (denser, more chromed)
|
|
17
|
+
|
|
18
|
+
Set in `dogsbay.config.yml`:
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
theme: default # or "material"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## The token groups
|
|
25
|
+
|
|
26
|
+
### Shadcn baseline (25 tokens)
|
|
27
|
+
|
|
28
|
+
Standard shadcn UI tokens. Every component reads from these:
|
|
29
|
+
|
|
30
|
+
```css
|
|
31
|
+
:root {
|
|
32
|
+
--background: oklch(1 0 0);
|
|
33
|
+
--foreground: oklch(0.145 0.014 285.823);
|
|
34
|
+
--card: oklch(1 0 0);
|
|
35
|
+
--card-foreground: …;
|
|
36
|
+
--popover, --popover-foreground;
|
|
37
|
+
--primary, --primary-foreground;
|
|
38
|
+
--secondary, --secondary-foreground;
|
|
39
|
+
--muted, --muted-foreground;
|
|
40
|
+
--accent, --accent-foreground;
|
|
41
|
+
--destructive, --destructive-foreground;
|
|
42
|
+
--border;
|
|
43
|
+
--input;
|
|
44
|
+
--ring;
|
|
45
|
+
--radius: 0.625rem;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Override any of these to reskin the whole site. Want emerald
|
|
50
|
+
buttons? Set `--primary` to an emerald oklch value; every
|
|
51
|
+
component using `bg-primary` updates.
|
|
52
|
+
|
|
53
|
+
### Sidebar (8 tokens)
|
|
54
|
+
|
|
55
|
+
`--sidebar`, `--sidebar-foreground`, `--sidebar-primary`,
|
|
56
|
+
`--sidebar-primary-foreground`, `--sidebar-accent`,
|
|
57
|
+
`--sidebar-accent-foreground`, `--sidebar-border`,
|
|
58
|
+
`--sidebar-ring`.
|
|
59
|
+
|
|
60
|
+
These let the sidebar diverge from the main content panel —
|
|
61
|
+
useful for sites with a darker nav bar over a lighter content
|
|
62
|
+
area.
|
|
63
|
+
|
|
64
|
+
### Admonitions (13 tokens)
|
|
65
|
+
|
|
66
|
+
One per callout type:
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
--note: oklch(0.637 0.174 259.126);
|
|
70
|
+
--abstract: …;
|
|
71
|
+
--info: …;
|
|
72
|
+
--tip: …;
|
|
73
|
+
--success: …;
|
|
74
|
+
--question: …;
|
|
75
|
+
--warning: …;
|
|
76
|
+
--failure: …;
|
|
77
|
+
--danger: …;
|
|
78
|
+
--bug: …;
|
|
79
|
+
--example: …;
|
|
80
|
+
--quote: oklch(0.65 0 0);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`--note-foreground` is also exposed for callouts that need
|
|
84
|
+
explicit text contrast.
|
|
85
|
+
|
|
86
|
+
### Code (3 tokens)
|
|
87
|
+
|
|
88
|
+
`--code-background`, `--code-foreground`, `--font-code`.
|
|
89
|
+
|
|
90
|
+
The `<CodeBlock>` and inline `<code>` components read these.
|
|
91
|
+
Default to a slightly-different background from `--background`
|
|
92
|
+
so code stands out.
|
|
93
|
+
|
|
94
|
+
### API panel (2 tokens)
|
|
95
|
+
|
|
96
|
+
`--api-panel-bg`, `--api-panel-fg`.
|
|
97
|
+
|
|
98
|
+
The dark right-column panel on OpenAPI endpoint pages.
|
|
99
|
+
**Always dark**, regardless of light/dark mode — it's a stylistic
|
|
100
|
+
choice that matches Stripe / Mintlify API doc convention.
|
|
101
|
+
|
|
102
|
+
### API semantic (17 tokens)
|
|
103
|
+
|
|
104
|
+
HTTP methods, type badges, status codes, role indicators —
|
|
105
|
+
everything `<MethodBadge>`, `<EndpointCard>`, `<ParameterTable>`,
|
|
106
|
+
`<ResponseTabs>`, `<SchemaViewer>`, etc. consume:
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
--api-get: oklch(0.723 0.15 162); /* green */
|
|
110
|
+
--api-post: oklch(0.637 0.174 259); /* blue */
|
|
111
|
+
--api-put: oklch(0.74 0.175 63); /* orange */
|
|
112
|
+
--api-patch: oklch(0.7 0.18 45); /* amber */
|
|
113
|
+
--api-delete: oklch(0.614 0.194 22); /* red */
|
|
114
|
+
--api-head: oklch(0.534 0.222 286); /* violet */
|
|
115
|
+
--api-required: oklch(0.614 0.194 22); /* red */
|
|
116
|
+
--api-deprecated: oklch(0.74 0.175 63); /* orange */
|
|
117
|
+
--api-type-string: oklch(0.723 0.15 162);
|
|
118
|
+
--api-type-number: oklch(0.637 0.174 259);
|
|
119
|
+
--api-type-boolean: oklch(0.74 0.175 63);
|
|
120
|
+
--api-type-object: oklch(0.534 0.222 286);
|
|
121
|
+
--api-type-array: oklch(0.7 0.18 45);
|
|
122
|
+
--api-status-2xx: oklch(0.723 0.15 162);
|
|
123
|
+
--api-status-3xx: oklch(0.637 0.174 259);
|
|
124
|
+
--api-status-4xx: oklch(0.74 0.175 63);
|
|
125
|
+
--api-status-5xx: oklch(0.614 0.194 22);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
These are present in the scaffold even if the user isn't
|
|
129
|
+
shipping OpenAPI yet — adding an OpenAPI source later doesn't
|
|
130
|
+
require theme.css changes.
|
|
131
|
+
|
|
132
|
+
### Fonts (3 tokens)
|
|
133
|
+
|
|
134
|
+
`--font-sans`, `--font-heading`, `--font-code`.
|
|
135
|
+
|
|
136
|
+
Defaults are system fonts. Override at the top of `theme.css`:
|
|
137
|
+
|
|
138
|
+
```css
|
|
139
|
+
:root {
|
|
140
|
+
--font-sans: "Inter", system-ui, sans-serif;
|
|
141
|
+
--font-heading: "Inter Display", "Inter", sans-serif;
|
|
142
|
+
--font-code: "JetBrains Mono", ui-monospace, monospace;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Light vs dark
|
|
147
|
+
|
|
148
|
+
`theme.css` defines `:root { ... }` for light mode and `.dark
|
|
149
|
+
{ ... }` for dark mode. The user's OS preference + the
|
|
150
|
+
`<ThemeToggle>` component switch which class is applied to
|
|
151
|
+
`<html>`.
|
|
152
|
+
|
|
153
|
+
Dark-mode tokens override the same names with darker values.
|
|
154
|
+
Both modes share radius, fonts, and the dark API panel
|
|
155
|
+
(intentionally constant — see "API panel" above).
|
|
156
|
+
|
|
157
|
+
## Override patterns
|
|
158
|
+
|
|
159
|
+
### Tweak one colour
|
|
160
|
+
|
|
161
|
+
Edit `theme.css`:
|
|
162
|
+
|
|
163
|
+
```css
|
|
164
|
+
:root {
|
|
165
|
+
--primary: oklch(0.5 0.18 145); /* greenish primary */
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.dark {
|
|
169
|
+
--primary: oklch(0.65 0.16 145); /* lighter green for dark mode */
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Swap themes wholesale
|
|
174
|
+
|
|
175
|
+
`global.css` imports `theme.css`. To switch themes, change the
|
|
176
|
+
import:
|
|
177
|
+
|
|
178
|
+
```css
|
|
179
|
+
/* Was: */
|
|
180
|
+
@import "./theme.css";
|
|
181
|
+
|
|
182
|
+
/* Now: */
|
|
183
|
+
@import "./theme-material.css";
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Both files ship by default. `theme-material.css` lives in the
|
|
187
|
+
scaffold alongside `theme.css` for easy A/B-ing.
|
|
188
|
+
|
|
189
|
+
### Custom theme from scratch
|
|
190
|
+
|
|
191
|
+
Copy `theme.css` to `theme-mybrand.css`, edit, swap the import.
|
|
192
|
+
|
|
193
|
+
The recommended editing path: keep the structure (light root +
|
|
194
|
+
dark class + same token names), change values. Components find
|
|
195
|
+
the tokens by name — renaming a token breaks the components.
|
|
196
|
+
|
|
197
|
+
## Tailwind config consumption
|
|
198
|
+
|
|
199
|
+
`@theme inline { --color-primary: var(--primary); ... }` in
|
|
200
|
+
`theme.css` makes every token usable as a Tailwind utility:
|
|
201
|
+
|
|
202
|
+
- `bg-primary` → `var(--primary)`
|
|
203
|
+
- `text-api-get` → `var(--api-get)`
|
|
204
|
+
- `border-sidebar-border`
|
|
205
|
+
- etc.
|
|
206
|
+
|
|
207
|
+
This is why the components use `class="bg-api-get/20
|
|
208
|
+
text-api-get"` and Just Work in any theme. The tokens are the
|
|
209
|
+
contract; the colours are the override surface.
|
|
210
|
+
|
|
211
|
+
## Typography
|
|
212
|
+
|
|
213
|
+
Two opt-in typography enhancements (pulled from theme tokens):
|
|
214
|
+
|
|
215
|
+
- `font-heading` — applied to `<h1>` / `<h2>` / `<h3>` if
|
|
216
|
+
`--font-heading` differs from `--font-sans`. Set both to
|
|
217
|
+
the same value for "headings look like body".
|
|
218
|
+
- `font-code` — applied to `<pre>`, `<code>`, syntax-highlighted
|
|
219
|
+
blocks.
|
|
220
|
+
|
|
221
|
+
## Common patterns
|
|
222
|
+
|
|
223
|
+
### Default theme (no edits)
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
theme: default
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`theme.css` ships, you don't touch it. Works for 80% of sites.
|
|
230
|
+
|
|
231
|
+
### Brand-tinted defaults
|
|
232
|
+
|
|
233
|
+
Edit just `--primary` + `--accent` to brand colours. Leave the
|
|
234
|
+
rest alone. The site looks "yours" without 50 lines of CSS.
|
|
235
|
+
|
|
236
|
+
### Dark-only or light-only
|
|
237
|
+
|
|
238
|
+
The scaffold supports both modes via the `.dark` class. To
|
|
239
|
+
force dark-only:
|
|
240
|
+
|
|
241
|
+
```css
|
|
242
|
+
:root,
|
|
243
|
+
.dark {
|
|
244
|
+
/* dark token values */
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
(The `<ThemeToggle>` component still exists; it just toggles
|
|
249
|
+
between two identical themes. Hide it via DocsHeader prop if
|
|
250
|
+
preferred.)
|
|
251
|
+
|
|
252
|
+
### Swap to Material
|
|
253
|
+
|
|
254
|
+
```yaml
|
|
255
|
+
theme: material
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Replace `default` with `material` in the config; `dogsbay site
|
|
259
|
+
init` re-emits `global.css` with the right import.
|
|
260
|
+
|
|
261
|
+
## Common mistakes
|
|
262
|
+
|
|
263
|
+
- ❌ Using arbitrary Tailwind colours (`bg-emerald-500`) in
|
|
264
|
+
scaffolded components — bypasses the token system, breaks
|
|
265
|
+
theme switching. Use `bg-primary` / `bg-api-get` / etc.
|
|
266
|
+
- ❌ Editing tokens INSIDE `:root` that are meant to be derived
|
|
267
|
+
from another (`--ring` is supposed to follow `--primary` in
|
|
268
|
+
the default theme; overriding directly produces inconsistent
|
|
269
|
+
state).
|
|
270
|
+
- ❌ Setting tokens via inline `style="..."` on individual
|
|
271
|
+
elements — works but defeats the cascade. Update `theme.css`
|
|
272
|
+
instead.
|
|
273
|
+
- ❌ Forgetting that the API panel is always dark — overriding
|
|
274
|
+
`--api-panel-bg` to a light value makes white text on white
|
|
275
|
+
background. The panel is intentionally a constant; reskin
|
|
276
|
+
individual API tokens (`--api-get`, etc.) instead.
|