docpensieve 0.1.0 → 0.1.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.
Files changed (42) hide show
  1. package/README.md +5 -2
  2. package/bin/docpensieve.js +1 -0
  3. package/package.json +8 -6
  4. package/src/commands/dev.js +1 -1
  5. package/src/commands/init.js +214 -39
  6. package/starter/01-guide/01-installation.md +79 -0
  7. package/starter/01-guide/02-first-site.md +97 -0
  8. package/starter/01-guide/03-writing-pages.md +138 -0
  9. package/starter/01-guide/04-versions.md +179 -0
  10. package/starter/01-guide/05-themes.md +116 -0
  11. package/starter/01-guide/06-deployment.md +124 -0
  12. package/starter/01-guide/index.md +38 -0
  13. package/starter/02-components/01-card.mdx +195 -0
  14. package/starter/02-components/02-columns.mdx +193 -0
  15. package/starter/02-components/03-time-timer.mdx +120 -0
  16. package/starter/02-components/04-tooltip.mdx +100 -0
  17. package/starter/02-components/05-tree.mdx +163 -0
  18. package/starter/02-components/06-scroll-to-top.mdx +103 -0
  19. package/starter/02-components/07-skill.mdx +214 -0
  20. package/starter/02-components/08-logo-icon.mdx +122 -0
  21. package/starter/02-components/icons/banner.svg +15 -0
  22. package/starter/02-components/icons/book.svg +4 -0
  23. package/starter/02-components/icons/lightning.svg +3 -0
  24. package/starter/02-components/icons/shield.svg +4 -0
  25. package/starter/02-components/icons/star.svg +3 -0
  26. package/starter/02-components/index.md +41 -0
  27. package/starter/03-reference/01-cli.md +134 -0
  28. package/starter/03-reference/02-configuration.md +132 -0
  29. package/starter/03-reference/03-frontmatter.md +110 -0
  30. package/starter/03-reference/04-theme.md +149 -0
  31. package/starter/03-reference/index.md +32 -0
  32. package/starter/04-architecture.md +106 -0
  33. package/starter/icons/blocks.svg +6 -0
  34. package/starter/icons/book.svg +4 -0
  35. package/starter/icons/branch.svg +6 -0
  36. package/starter/icons/compass.svg +4 -0
  37. package/starter/icons/lightning.svg +3 -0
  38. package/starter/icons/list.svg +4 -0
  39. package/starter/icons/shield.svg +4 -0
  40. package/starter/icons/star.svg +3 -0
  41. package/starter/index.mdx +244 -0
  42. package/types/commands/init.d.ts +7 -4
@@ -0,0 +1,134 @@
1
+ ---
2
+ title: Commands
3
+ description: init, build, check, dev and serve, with their arguments and options.
4
+ tags: [reference, cli]
5
+
6
+ jsonld:
7
+ type: TechArticle
8
+ breadcrumbs: true
9
+ ---
10
+
11
+ # Commands
12
+
13
+ ```bash
14
+ npx docpensieve <command> [arguments] [options]
15
+ ```
16
+
17
+ ## `init`
18
+
19
+ Sets up a documentation project.
20
+
21
+ ```bash
22
+ npx docpensieve init [dir]
23
+ ```
24
+
25
+ | Option | Effect |
26
+ | -------------------------- | --------------------------------------- |
27
+ | `[dir]` | Target folder. Default: `.` |
28
+ | `-n, --name <name>` | Project name |
29
+ | `-t, --theme <framework>` | `tailwind` or `custom` |
30
+ | `-u, --site-url <url>` | Public URL of the site |
31
+ | `--version-name <version>` | First version, `1.0` for instance |
32
+ | `-y, --yes` | Accepts the defaults without a dialogue |
33
+ | `-f, --force` | Overwrites an existing configuration |
34
+ | `--minimal` | Leaves DocPensieve's documentation out |
35
+
36
+ Without `--force`, the command refuses to overwrite an existing configuration.
37
+
38
+ Unless `--minimal` is given, the command installs DocPensieve's documentation
39
+ in the new site, in `docs/<version>/99-docpensieve/`: a **DocPensieve** section
40
+ at the end of the menu, matching the installed version. Delete that folder when
41
+ you no longer need it.
42
+
43
+ ## `build`
44
+
45
+ Generates the site.
46
+
47
+ ```bash
48
+ npx docpensieve build [version]
49
+ ```
50
+
51
+ | Option | Effect |
52
+ | ----------------- | ---------------------------------------------------- |
53
+ | `[version]` | Version slug. When omitted, every version is built |
54
+ | `-o, --out <dir>` | Output folder. Default: the one in the configuration |
55
+
56
+ With a slug, only that version is written, in `versions/<slug>/`. That form
57
+ writes **neither the manifest nor the root redirect**: after adding or
58
+ removing a version, run a full build.
59
+
60
+ ## `check`
61
+
62
+ Reads the produced site back: internal links and markup.
63
+
64
+ ```bash
65
+ npx docpensieve check
66
+ ```
67
+
68
+ | Option | Effect |
69
+ | ----------------- | ------------------------------------------------------ |
70
+ | `-d, --dir <dir>` | Folder to check. Default: the one in the configuration |
71
+
72
+ ### Links
73
+
74
+ - a target that **ignores the deployment prefix** — the file exists, but the
75
+ link will lead nowhere once online. It is the symptom of a URL that escaped
76
+ resolution;
77
+ - a target that **matches no produced file**.
78
+
79
+ External targets, anchors and `mailto:` are left alone. A target that comes
80
+ back several times in a page is reported only once.
81
+
82
+ ### Markup
83
+
84
+ - a **paragraph nested** in another one;
85
+ - a **paragraph inside an element that only accepts text**, a `span` for
86
+ instance;
87
+ - a **block element inside a paragraph**, a heading for instance.
88
+
89
+ They usually come from the same source, described in
90
+ [Writing pages](../guide/writing-pages/): the content of a JSX tag left alone on
91
+ its line becomes a paragraph. The browser then silently undoes the nesting, the
92
+ wrapper disappears, and the intended layout with it.
93
+
94
+ If anything is left to fix, the command exits with code 1: it therefore fails a
95
+ continuous integration run without any particular setting.
96
+
97
+ ## `dev`
98
+
99
+ Development server, which rebuilds on every save.
100
+
101
+ ```bash
102
+ npx docpensieve dev
103
+ ```
104
+
105
+ | Option | Effect |
106
+ | --------------------- | ------------------------------- |
107
+ | `-p, --port <number>` | Listening port. Default: `3000` |
108
+
109
+ ## `serve`
110
+
111
+ Serves the output folder statically, without rebuilding anything.
112
+
113
+ ```bash
114
+ npx docpensieve serve
115
+ ```
116
+
117
+ | Option | Effect |
118
+ | --------------------- | ------------------------------- |
119
+ | `-p, --port <number>` | Listening port. Default: `4000` |
120
+ | `-d, --dir <dir>` | Folder to serve |
121
+
122
+ It is the command that faithfully reproduces what a host will do: to check what
123
+ will be published, chain `build` then `serve`.
124
+
125
+ ## Exit codes
126
+
127
+ | Code | Meaning |
128
+ | ---- | -------------------------------------------------------------- |
129
+ | `0` | Everything went well |
130
+ | `1` | Expected error — message and hint shown, without a stack trace |
131
+ | `2` | Feature not written yet |
132
+
133
+ An unexpected error comes out with its full stack trace: it is a defect of the
134
+ generator, not of the documentation it is given.
@@ -0,0 +1,132 @@
1
+ ---
2
+ title: Configuration
3
+ description: Every field of docpensieve.config.mjs, its default value and its effect.
4
+ tags: [reference, configuration]
5
+
6
+ jsonld:
7
+ type: TechArticle
8
+ breadcrumbs: true
9
+ ---
10
+
11
+ # Configuration
12
+
13
+ The `docpensieve.config.mjs` file, at the root of the project.
14
+
15
+ It is an ES module — hence `.mjs`, which Node reads as one whatever the
16
+ project's `package.json` says. `docpensieve.config.js` works too, in a project
17
+ whose `package.json` declares `"type": "module"`; with both files present, the
18
+ build stops rather than pick one.
19
+
20
+ ```js
21
+ /** @type {import('@docpensieve/core').DocPensieveConfig} */
22
+ export default {
23
+ projectName: 'My documentation',
24
+ siteUrl: 'https://example.com/my-project',
25
+
26
+ versions: [{ slug: 'v1.0', name: '1.0', folder: 'docs/v1.0', current: true }],
27
+
28
+ outDir: 'dist',
29
+
30
+ theme: {
31
+ framework: 'tailwind',
32
+ darkMode: 'class',
33
+ },
34
+
35
+ sidebar: 'auto',
36
+ globalComponents: true,
37
+ jsonld: { enabled: true },
38
+ };
39
+ ```
40
+
41
+ The `@type` comment gives autocompletion and type checking in the editor
42
+ without importing anything: the file stays readable even where DocPensieve
43
+ only runs through `npx`. In a project that installs it as a dependency,
44
+ `defineConfig` from `@docpensieve/core` does the same.
45
+
46
+ `docpensieve init` writes this file with **every field** in it — set to its
47
+ default, or commented out with an example — so that it also tells you what you
48
+ can change.
49
+
50
+ ## The fields
51
+
52
+ | Field | Default | Effect |
53
+ | ------------------ | ------------------- | --------------------------------------------------------------------------- |
54
+ | `projectName` | `'Documentation'` | Name shown in the header and in the JSON-LD |
55
+ | `siteUrl` | `''` | Public URL. Used for the `canonical` and the JSON-LD |
56
+ | `baseUrl` | `'/'` | Deployment prefix. Derived from `siteUrl` when omitted |
57
+ | `outDir` | `'dist'` | Output folder, relative to the root |
58
+ | `versions` | `[]` | At least one entry |
59
+ | `theme` | see below | Styling |
60
+ | `sidebar` | `'auto'` | `'auto'`: the sidebar follows the file tree. The only value written so far |
61
+ | `globalComponents` | `true` | Shipped components available without an import |
62
+ | `scrollToTop` | `true` | Back-to-top button on every page |
63
+ | `jsonld` | `{ enabled: true }` | Structured data |
64
+ | `lang` | `'en'` | Language of the document, in `<html lang>`. The shell's labels stay English |
65
+
66
+ ## `versions`
67
+
68
+ ```js
69
+ versions: [
70
+ { slug: 'v2.0', name: '2.0', folder: 'docs/v2.0', current: true },
71
+ { slug: 'v1.0', name: '1.0', folder: 'docs/v1.0', archived: true },
72
+ ],
73
+ ```
74
+
75
+ | Field | Role |
76
+ | ------------ | ---------------------------------------------------------------- |
77
+ | `slug` | URL and branch identifier |
78
+ | `name` | Label shown in the switcher |
79
+ | `folder` | Source folder, relative to the root |
80
+ | `current` | Version served by default. At most one |
81
+ | `archived` | Version kept but no longer maintained. Banner, but stays indexed |
82
+ | `prerelease` | Version in preparation. Banner **and** `noindex` |
83
+
84
+ ## `theme`
85
+
86
+ ```js
87
+ theme: {
88
+ framework: 'tailwind',
89
+ darkMode: 'class',
90
+ tokens: { '--dp-accent': 'oklch(55% 0.2 250)' },
91
+ css: '.dp-article h2 { letter-spacing: -0.01em; }',
92
+ source: '@import "tailwindcss";',
93
+ },
94
+ ```
95
+
96
+ | Field | Effect |
97
+ | ----------- | ----------------------------------------- |
98
+ | `framework` | `'tailwind'` or `'custom'` |
99
+ | `darkMode` | Dark theme strategy |
100
+ | `tokens` | Redefined `--dp-*` tokens |
101
+ | `css` | CSS appended to the produced stylesheet |
102
+ | `source` | Stylesheet handed to the utility compiler |
103
+
104
+ The available tokens are listed in [Themes](../guide/themes/).
105
+
106
+ ## `baseUrl`, and why you rarely write it
107
+
108
+ A `siteUrl` with a sub-path already gives it: `https://example.com/my-project`
109
+ produces `baseUrl: '/my-project/'`. Writing it is only useful to depart from
110
+ it.
111
+
112
+ The prefix is normalised with both its slashes. It is what prefixes every
113
+ internal link: if it is wrong, every link is.
114
+
115
+ ## What is refused
116
+
117
+ | Case | Message |
118
+ | ---------------------------------- | --------------------------------- |
119
+ | The configuration is not an object | An example of the expected export |
120
+ | No version declared | An example of a complete entry |
121
+ | Two versions with the same slug | The offending slug |
122
+ | Several `current` versions | The list of those found |
123
+ | Unknown `framework` | The accepted values |
124
+ | Requested slug not found | The available slugs |
125
+
126
+ Each one stops the build with a message and a hint, without a stack trace.
127
+
128
+ ## What is filled in automatically
129
+
130
+ If **no** version carries `current`, the first in the list becomes current. A
131
+ single-version configuration therefore has nothing to specify — this field only
132
+ starts to matter from the second version on.
@@ -0,0 +1,110 @@
1
+ ---
2
+ title: Frontmatter
3
+ description: The fields recognised at the top of a page, and what they produce.
4
+ tags: [reference, frontmatter]
5
+
6
+ jsonld:
7
+ type: TechArticle
8
+ breadcrumbs: true
9
+ faq:
10
+ - question: Is the frontmatter mandatory?
11
+ answer: No. Without a title, the project name stands in; without a date, no date is published.
12
+ - question: How do I keep a page offline?
13
+ answer: 'Set draft: true in its frontmatter. It stays in the repository, absent from the output.'
14
+ ---
15
+
16
+ # Frontmatter
17
+
18
+ A YAML block at the top of the file, between two lines of three dashes.
19
+ Everything in it is optional.
20
+
21
+ ```yaml
22
+ ---
23
+ title: Installation
24
+ description: What you need, and how to set up a project.
25
+ date: 2026-09-09
26
+ modified: 2026-09-14
27
+ authors: [Valentin Chevoleau]
28
+ tags: [guide, installation]
29
+ preview: ./screenshot.png
30
+ draft: false
31
+ layout: doc
32
+
33
+ jsonld:
34
+ type: TechArticle
35
+ breadcrumbs: true
36
+ ---
37
+ ```
38
+
39
+ ## The fields
40
+
41
+ | Field | Effect |
42
+ | ------------- | --------------------------------------------------------- |
43
+ | `title` | `<title>` tag, menu entry, breadcrumb, JSON-LD `headline` |
44
+ | `description` | `description` metadata and JSON-LD `description` |
45
+ | `date` | Publication date |
46
+ | `modified` | Last modification date. Default: the publication date |
47
+ | `authors` | List of authors |
48
+ | `tags` | Keywords, carried over as `keywords` |
49
+ | `preview` | Image of the page. The path is resolved like a link |
50
+ | `draft` | `true` keeps the page out of the output |
51
+ | `layout` | `doc` (default) or `home` |
52
+ | `jsonld` | Structured data settings |
53
+
54
+ ## `layout`
55
+
56
+ `doc` is the documentation layout: menu on the left, table of contents on the
57
+ right, content held to reading width.
58
+
59
+ `home` removes all three. It is what a home page expects, where columns and
60
+ cards take the whole surface.
61
+
62
+ ```yaml
63
+ layout: home
64
+ ```
65
+
66
+ An unknown value stops the build. A typo would otherwise render the page in a
67
+ layout other than the intended one, without a word.
68
+
69
+ ## `jsonld`
70
+
71
+ ```yaml
72
+ jsonld:
73
+ type: TechArticle
74
+ breadcrumbs: true
75
+ faq:
76
+ - question: Do I need a frontmatter?
77
+ answer: No, everything in it is optional.
78
+ ```
79
+
80
+ | Field | Effect |
81
+ | ------------- | --------------------------------------------- |
82
+ | `type` | `Article`, `TechArticle` or `BlogPosting` |
83
+ | `breadcrumbs` | `false` removes the breadcrumb |
84
+ | `faq` | Questions and answers, published as `FAQPage` |
85
+
86
+ Every `faq` entry must carry `question` **and** `answer`: if one of them is
87
+ missing, the build stops and says so.
88
+
89
+ The questions must **also appear in the text of the page**. Search engines
90
+ reject markup that describes invisible content: a FAQ present only in the
91
+ frontmatter exposes the page to losing its structured data.
92
+
93
+ A `type` outside the list is refused the same way. This very page carries a
94
+ `faq`: its JSON-LD contains the block.
95
+
96
+ ## What does not need to be written
97
+
98
+ The URL, the place in the menu, the breadcrumb and the `canonical` link are
99
+ derived from the file path and the configuration. Nothing to repeat in the
100
+ frontmatter, and nothing to keep up to date when a file is moved.
101
+
102
+ ## Frequently asked questions
103
+
104
+ ### Is the frontmatter mandatory?
105
+
106
+ No. Without a title, the project name stands in; without a date, no date is published.
107
+
108
+ ### How do I keep a page offline?
109
+
110
+ Set `draft: true` in its frontmatter. It stays in the repository, absent from the output.
@@ -0,0 +1,149 @@
1
+ ---
2
+ title: Theme
3
+ description: Slots, tokens and styling options, one by one.
4
+ tags: [reference, theme]
5
+
6
+ jsonld:
7
+ type: TechArticle
8
+ breadcrumbs: true
9
+ ---
10
+
11
+ # Theme
12
+
13
+ To learn how to use it, see [Themes](../guide/themes/). This page lists what
14
+ exists.
15
+
16
+ ## The options
17
+
18
+ ```js
19
+ theme: {
20
+ framework: 'tailwind',
21
+ darkMode: 'class',
22
+ tokens: { '--dp-accent': 'oklch(55% 0.2 250)' },
23
+ css: '.dp-article h2 { letter-spacing: -0.01em; }',
24
+ source: '@import "tailwindcss";',
25
+ },
26
+ ```
27
+
28
+ | Field | Default | Effect |
29
+ | ----------- | ------------------------ | ----------------------------------------------------- |
30
+ | `framework` | `'tailwind'` | `'tailwind'` or `'custom'` |
31
+ | `darkMode` | `'class'` | Dark theme strategy |
32
+ | `tokens` | — | Redefined `--dp-*` tokens, merged with the provider's |
33
+ | `css` | `''` | CSS appended to the produced stylesheet |
34
+ | `source` | `@import "tailwindcss";` | Stylesheet handed to the utility compiler |
35
+
36
+ `source` only concerns the `tailwind` provider: it is the entry stylesheet it
37
+ compiles. Replacing it lets you add directives — a `@theme` block, for
38
+ instance — without leaving the mechanism. `@plugin` directives are not
39
+ supported yet and stop the build.
40
+
41
+ ## The tokens
42
+
43
+ Fifteen tokens, which both providers define and the components read. A
44
+ redefined token propagates everywhere, without any component having to know.
45
+
46
+ | Token | Role |
47
+ | -------------------- | --------------------------------------------------- |
48
+ | `--dp-bg` | Page background |
49
+ | `--dp-bg-soft` | Background of recessed areas — gauge tracks, hovers |
50
+ | `--dp-text` | Body text |
51
+ | `--dp-text-soft` | Secondary text — captions, card footers |
52
+ | `--dp-border` | Visible borders |
53
+ | `--dp-rule` | Discreet rules — tree separators |
54
+ | `--dp-accent` | Accent colour — links, fills |
55
+ | `--dp-accent-soft` | Accent background — banners |
56
+ | `--dp-shadow` | Colour of drop shadows |
57
+ | `--dp-radius` | Corner rounding |
58
+ | `--dp-font` | Font family of the text |
59
+ | `--dp-font-mono` | Monospaced family — code, trees |
60
+ | `--dp-content-width` | Reading width. `none` by default |
61
+ | `--dp-sidebar-width` | Menu column |
62
+ | `--dp-toc-width` | Table of contents column |
63
+
64
+ Some components add their own, documented on their page: `--dp-skill-size` for
65
+ a circle gauge, `--dp-skill-color` for the tint of a gauge,
66
+ `--dp-logo-icon-size` for an icon.
67
+
68
+ ## The slots
69
+
70
+ The templates write no class. They ask for the class of each slot, and the
71
+ theme answers. A provider only redefines what it changes; everything else keeps
72
+ the `dp-*` class below.
73
+
74
+ | Slot | Default class | Where |
75
+ | --------------- | ------------------------- | ----------------------------------------------- |
76
+ | `skip` | `dp-skip` | Skip link to the content |
77
+ | `header` | `dp-header` | Site header |
78
+ | `brand` | `dp-brand` | Project name, in the header |
79
+ | `versions` | `dp-versions` | Version switcher |
80
+ | `versionsList` | `dp-versions-list` | Open list of the switcher |
81
+ | `shell` | `dp-shell` | Menu / content / table of contents grid |
82
+ | `shellWide` | `dp-shell dp-shell--wide` | The same, without menu or table of contents |
83
+ | `sidebar` | `dp-sidebar` | Menu column |
84
+ | `nav` | `dp-nav` | Navigation list |
85
+ | `navItem` | `dp-nav-item` | Navigation entry |
86
+ | `navItemParent` | `dp-nav-item--parent` | Entry that holds a section |
87
+ | `navLink` | `dp-nav-link` | Navigation link |
88
+ | `navLabel` | `dp-nav-label` | Section label, not clickable |
89
+ | `notice` | `dp-notice` | Banner of the versions that are not the current |
90
+ | `skillIcon` | `dp-skill-icon` | Icon before the name of a gauge |
91
+ | `main` | `dp-main` | Main area |
92
+ | `article` | `dp-article` | Page content |
93
+ | `toc` | `dp-toc` | Table of contents column |
94
+ | `tocTitle` | `dp-toc-title` | Title of the table of contents |
95
+ | `tocList` | `dp-toc-list` | List of the table of contents |
96
+ | `tocItem` | `dp-toc-item` | Entry of the table of contents |
97
+ | `footer` | `dp-footer` | Page footer |
98
+ | `scrollTop` | `dp-scroll-top` | Back-to-top button |
99
+ | `scrollTopIcon` | `dp-scroll-top-icon` | Arrow of that button |
100
+
101
+ A slot can carry **variants**, suffixed `--variant`: `column` gives
102
+ `dp-column--span-8`, `skill` gives `dp-skill--circle`.
103
+
104
+ ## How a slot is rendered
105
+
106
+ Always in **triple braces**, in the templates:
107
+
108
+ ```hbs
109
+ <nav class="{{{cls.sidebar}}}">
110
+ ```
111
+
112
+ Double braces would escape the content, and a utility class such as
113
+ `aria-[current=page]` would become `aria-[current&#x3D;page]` — a silent
114
+ selector, without the slightest error.
115
+
116
+ ## The stylesheets
117
+
118
+ The delivered stylesheet is assembled from four pieces, in this order:
119
+
120
+ | Stylesheet | Content |
121
+ | ------------------- | -------------------------------------------------- |
122
+ | `structure.css` | Grid, sticky columns, accessibility. Shared by all |
123
+ | `prose.css` | Typography of the content |
124
+ | a skin or a bridge | `custom.css`, or `tailwind-bridge.css` |
125
+ | the components' one | The `dp-*` rules of the shipped components |
126
+
127
+ Then comes what the project adds through `theme.css`.
128
+
129
+ The layout is **never** duplicated in a provider: it lives in `structure.css`,
130
+ which both share. A provider only takes care of the styling.
131
+
132
+ ## Layer order
133
+
134
+ Under the `tailwind` theme, the stylesheet declares its layers in this order:
135
+
136
+ ```css
137
+ @layer theme, base, components, utilities;
138
+ ```
139
+
140
+ Component rules live in `components`, **below** the utilities. A `className`
141
+ set at use therefore always wins, whatever the place of the rule in the file.
142
+
143
+ The `custom` theme has no utility layer: its stylesheets are in no layer, and
144
+ therefore come before the component rules, which stay in the `components`
145
+ layer.
146
+
147
+ What `theme.css` adds is in no layer: without a layer, a rule wins over all
148
+ those that have one. That is what lets you write a fix there without worrying
149
+ about specificity.
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Reference
3
+ description: Commands, configuration and frontmatter, field by field.
4
+ tags: [reference]
5
+
6
+ jsonld:
7
+ type: TechArticle
8
+ breadcrumbs: true
9
+ ---
10
+
11
+ # Reference
12
+
13
+ - **[Commands](./cli/)** — `init`, `build`, `check`, `dev`, `serve`
14
+ and their options.
15
+ - **[Configuration](./configuration/)** — every field of
16
+ `docpensieve.config.mjs`, its default value and its effect.
17
+ - **[Frontmatter](./frontmatter/)** — the fields recognised at the top
18
+ of a page.
19
+ - **[Theme](./theme/)** — slots, tokens and styling options.
20
+
21
+ To learn how to use them rather than look them up, the [guide](../guide/) is the
22
+ right starting point.
23
+
24
+ ## Errors
25
+
26
+ Every expected error carries a message and an **actionable hint**. An invalid
27
+ configuration, an unknown version slug, a value out of range: each one says
28
+ what is wrong and what is expected instead.
29
+
30
+ Nothing fails silently. A component that cannot render what it is asked for
31
+ stops the build rather than produce an inert element — a tag that does nothing
32
+ goes unnoticed on review, an error does not.
@@ -0,0 +1,106 @@
1
+ ---
2
+ title: Architecture
3
+ description: How a page becomes HTML, and why it works that way.
4
+ tags: [architecture]
5
+
6
+ jsonld:
7
+ type: TechArticle
8
+ breadcrumbs: true
9
+ ---
10
+
11
+ # Architecture
12
+
13
+ ## The journey of a page
14
+
15
+ ```
16
+ .md / .mdx file
17
+
18
+
19
+ loading frontmatter detached, slug derived from the path
20
+
21
+
22
+ compilation MDX → React component
23
+
24
+
25
+ rendering React → HTML string, once and for all
26
+
27
+
28
+ shell header, menu, table of contents, footer
29
+
30
+
31
+ page written a folder, an index.html
32
+ ```
33
+
34
+ Once every page is written, and **only then**, the stylesheet is compiled: a
35
+ utility theme needs to know which classes were actually used.
36
+
37
+ ## React does not leave the build
38
+
39
+ Components are rendered to HTML during the build. The delivered site loads no
40
+ runtime: what reaches the reader is markup and a stylesheet.
41
+
42
+ That explains the shape of the shipped components. None of them has state or
43
+ an event listener, because there would be nothing to bring them to life.
44
+ Whatever needs interaction goes through a native element — `details` for
45
+ expanding, a link for moving — or through CSS.
46
+
47
+ This constraint is also what guarantees that a page stays readable in ten
48
+ years: there is nothing that can stop working.
49
+
50
+ ## Templates do not render content
51
+
52
+ A template engine builds the shell: header, menu, table of contents, version
53
+ switcher, footer. The content comes from the MDX compilation.
54
+
55
+ The two do not mix, and that is deliberate. The content is written by the
56
+ author and can contain anything; the shell is written once and must never
57
+ depend on what a page contains.
58
+
59
+ ## The packages
60
+
61
+ ```
62
+ shared constants, errors, slugs — depends on nothing
63
+ core configuration, loading, compilation, JSON-LD, generation
64
+ theme stylings, each answering the same contract
65
+ components components available in pages
66
+ cli the commands
67
+ ```
68
+
69
+ **The graph never goes up.** The engine imports neither the stylings nor the
70
+ components: the commands hand them over. That is what lets it be tested
71
+ without React or CSS, and what keeps a circular dependency from settling in
72
+ unnoticed.
73
+
74
+ ## Theme slots
75
+
76
+ The templates contain no class. They ask the theme for the class of each slot,
77
+ and the theme answers — a simple class, or a handful of utilities.
78
+
79
+ Two practical consequences:
80
+
81
+ - changing styling requires touching no template;
82
+ - a styling only needs to redefine what it changes.
83
+
84
+ Components follow the same rule, with a fallback: when there is no answer, they
85
+ take a `dp-*` class that their own stylesheet styles from the theme tokens.
86
+ They therefore follow the active palette without knowing anything about it.
87
+
88
+ ## URLs
89
+
90
+ A relative target resolves against the folder of the page's file. An absolute
91
+ target starts from the **version root**, not from the domain: a documentation
92
+ does not know it may be served under a sub-path.
93
+
94
+ That rewrite happens on the tree built from the Markdown — hence **before** the
95
+ components are rendered. A component that produces a URL must therefore resolve
96
+ it itself, following the same rules. That is why every rendered page is
97
+ announced to the components, just as the class table is announced to them.
98
+
99
+ ## Nothing fails silently
100
+
101
+ It is the rule that runs through everything else. An unknown value, a missing
102
+ parent, a file not found: each one stops the build with a message and a hint.
103
+
104
+ The alternative — rendering an empty element, ignoring a prop, falling back on
105
+ a default value — produces pages that look right and are not. Those faults are
106
+ only discovered in production, long afterwards.
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
2
+ <rect x="3" y="3" width="7.5" height="7.5" rx="1.5" />
3
+ <rect x="13.5" y="3" width="7.5" height="7.5" rx="1.5" />
4
+ <rect x="3" y="13.5" width="7.5" height="7.5" rx="1.5" />
5
+ <rect x="13.5" y="13.5" width="7.5" height="7.5" rx="1.5" />
6
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
3
+ <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
4
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
2
+ <circle cx="6" cy="5" r="2.5" />
3
+ <circle cx="6" cy="19" r="2.5" />
4
+ <circle cx="18" cy="12" r="2.5" />
5
+ <path d="M6 7.5v9M8.5 5h5a4 4 0 0 1 4 4v.5" />
6
+ </svg>