docpensieve 0.5.0-beta.2 → 0.5.0-beta.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.
@@ -0,0 +1,230 @@
1
+ ---
2
+ title: Hero
3
+ description: The banner at the head of a page — a name, a sentence, and the way in.
4
+ ---
5
+
6
+ # Hero
7
+
8
+ A landing page opens on three things: what this is, what it does, and where to
9
+ start. `Hero` is the block that holds them, so that the head of a page is a
10
+ component rather than a `div` and a pile of classes.
11
+
12
+ It is **not a card**: no border, no panel. What a banner is made of is space, a
13
+ title large enough to be the first thing read, and one way in that stands out
14
+ from the rest. A frame exists for the page that asks for one, and it is not
15
+ what you get by default.
16
+
17
+ ## A banner
18
+
19
+ <Hero>
20
+
21
+ ## DocPensieve
22
+
23
+ Your Markdown and MDX files become a static site. No runtime to load, one
24
+ version per branch.
25
+
26
+ <HeroActions>[Get started](../guide/installation/) [See the components](./)</HeroActions>
27
+
28
+ </Hero>
29
+
30
+ ```mdx
31
+ <Hero>
32
+
33
+ # My project
34
+
35
+ What it does, in one sentence.
36
+
37
+ <HeroActions>[Get started](../guide/installation/) [Components](./)</HeroActions>
38
+
39
+ </Hero>
40
+ ```
41
+
42
+ Everything inside is ordinary Markdown: a heading, a paragraph, a row of
43
+ links. The component sets the width of the sentence, the spacing, and turns
44
+ the links into something to press — **the first one carries the accent**,
45
+ because a reader should see one way in rather than three.
46
+
47
+ ## Aligned to the start
48
+
49
+ `align="start"` leaves the banner where the text of the page is, which suits a
50
+ section that opens a chapter rather than a site.
51
+
52
+ <Hero align="start">
53
+
54
+ ### A section, not a site
55
+
56
+ The same block, reading from the left.
57
+
58
+ <HeroActions>[Read on](../guide/writing-pages/)</HeroActions>
59
+
60
+ </Hero>
61
+
62
+ ```mdx
63
+ <Hero align="start">
64
+
65
+ ## A section, not a site
66
+
67
+ The same block, reading from the left.
68
+
69
+ </Hero>
70
+ ```
71
+
72
+ Accepted values are `center`, the default, and `start`. Anything else stops the
73
+ build and lists the two — a banner silently ignoring its alignment would look
74
+ like a stylesheet that failed.
75
+
76
+ ## With something to show
77
+
78
+ Put a `HeroVisual` among the children and the banner becomes two columns — the
79
+ words on one side, the picture on the other. Nothing to declare: having a
80
+ visual is what makes it a split, which is the commonest shape of a landing
81
+ page and the reason a project puts a screenshot there.
82
+
83
+ <Hero>
84
+ <HeroText>
85
+
86
+ ### My project
87
+
88
+ What it does, in one sentence, with room to breathe.
89
+
90
+ <HeroActions>[Get started](../guide/installation/) [Components](./)</HeroActions>
91
+
92
+ </HeroText>
93
+ <HeroVisual>
94
+
95
+ ![A page of the site](./icons/banner.svg)
96
+
97
+ </HeroVisual>
98
+ </Hero>
99
+
100
+ ```mdx
101
+ <Hero>
102
+ <HeroText>
103
+
104
+ # My project
105
+
106
+ What it does, in one sentence, with room to breathe.
107
+
108
+ <HeroActions>[Get started](/guide/installation/) [Components](/components/)</HeroActions>
109
+
110
+ </HeroText>
111
+ <HeroVisual>
112
+
113
+ ![A page of the site](./screenshot.png)
114
+
115
+ </HeroVisual>
116
+ </Hero>
117
+ ```
118
+
119
+ `HeroText` holds the words, `HeroVisual` the picture. Below 48rem the two
120
+ columns become one, the picture following the words it illustrates.
121
+
122
+ ## A frame, if you want one
123
+
124
+ `frame` draws the panel a banner does not have by default — a border, and a
125
+ wash of its tone.
126
+
127
+ <Hero frame size="small">
128
+
129
+ ### Framed
130
+
131
+ For a banner that has to be told apart from the page around it.
132
+
133
+ </Hero>
134
+
135
+ ```mdx
136
+ <Hero frame>...</Hero>
137
+ ```
138
+
139
+ ## How much room it takes
140
+
141
+ `size` decides the air around the words, not the look: `small`, `medium` —
142
+ the default — `large`, and `full`, which takes the height of the screen and
143
+ centres its content in it.
144
+
145
+ <Hero size="small">
146
+
147
+ ### A small one
148
+
149
+ For a section that only needs announcing.
150
+
151
+ </Hero>
152
+
153
+ ```mdx
154
+ <Hero size="small">...</Hero>
155
+ <Hero size="large">...</Hero>
156
+ <Hero size="full">...</Hero>
157
+ ```
158
+
159
+ `full` measures the screen as the browser really shows it, so a phone whose
160
+ address bar comes and goes does not push the banner under it.
161
+
162
+ ## The tone it is lit with
163
+
164
+ `tone` names a colour the theme already carries — the same tones an admonition
165
+ takes, because a theme defines a colour per tone, not a colour per component.
166
+ A project that gives `attention` its own colour gives it to both at once.
167
+
168
+ <Hero tone="tip" align="start" size="small">
169
+
170
+ ### Lit by a tone
171
+
172
+ The wash behind the words, and the first way in, follow it.
173
+
174
+ <HeroActions>[Read on](../guide/writing-pages/)</HeroActions>
175
+
176
+ </Hero>
177
+
178
+ ```mdx
179
+ <Hero tone="tip">...</Hero>
180
+ ```
181
+
182
+ Accepted: `note` — the default, which is the accent of the theme — `info`,
183
+ `tip`, `attention` and `danger`. Anything else stops the build and lists them,
184
+ as an unknown size or alignment does: a banner silently ignoring what it was
185
+ asked would look like a stylesheet that failed.
186
+
187
+ ## On a page of your own
188
+
189
+ A banner belongs on a page that opens something: the home page of a version, a
190
+ landing page for a section. The `home` layout of the frontmatter is its usual
191
+ companion, since it drops the menu and the table of contents:
192
+
193
+ ```mdx
194
+ ---
195
+ title: My project
196
+ layout: home
197
+ ---
198
+
199
+ <Hero>
200
+
201
+ # My project
202
+
203
+ ...
204
+ ```
205
+
206
+ ## Properties
207
+
208
+ | Property | Type | Effect |
209
+ | ----------- | -------- | ---------------------------------- |
210
+ | `align` | `string` | `center` (the default) or `start`. |
211
+ | `className` | `string` | Classes added to the banner. |
212
+ | `style` | `object` | Inline styles on the banner. |
213
+
214
+ Its companions, each taking `className` and `style` as well:
215
+
216
+ | Component | What it holds |
217
+ | ------------- | -------------------------------------------------------------------- |
218
+ | `HeroActions` | The row of ways in. Its children are links, as Markdown writes them. |
219
+ | `HeroText` | The words, in a split. Not needed in a single column. |
220
+ | `HeroVisual` | The picture. Its presence is what makes the banner a split. |
221
+
222
+ **One primary action and one alternative** is the shape that reads — a row of
223
+ five buttons is a row of none.
224
+
225
+ The classes are `dp-banner*`, after what the element is rather than after the
226
+ component: a page that already writes a class of its own around a title keeps
227
+ whatever that class did, and adopting the component stays a decision.
228
+
229
+ A row of ways in is a row of choices — [Columns](./columns/) shows how to keep
230
+ several blocks the same height when the banner is followed by cards.
@@ -0,0 +1,130 @@
1
+ ---
2
+ title: Calendar
3
+ description: A month of dates and what happens on them — built at generation, navigable once the page has loaded its script.
4
+ ---
5
+
6
+ # Calendar
7
+
8
+ Dates read badly as a list. A release plan, a course schedule, the weeks of a
9
+ migration: what matters is where they fall, and how far apart. `Calendar`
10
+ draws the months, and puts each event on its day.
11
+
12
+ ## Days and what is on them
13
+
14
+ <Calendar>
15
+ <Event date="2026-10-14" label="Release 0.5" href="../whats-new/" />
16
+ <Event date="2026-10-14" label="Blog post" />
17
+ <Event date="2026-10-28" label="Workshop" />
18
+ </Calendar>
19
+
20
+ ```mdx
21
+ <Calendar>
22
+ <Event date="2026-10-14" label="Release 0.5" href="/whats-new/" />
23
+ <Event date="2026-10-14" label="Blog post" />
24
+ <Event date="2026-10-28" label="Workshop" />
25
+ </Calendar>
26
+ ```
27
+
28
+ A day is written `2026-10-14` — four digits, two, two. Several events may fall
29
+ on the same day, and they are drawn in the order they are written. `href` is
30
+ resolved like any other link of a page: relative to the page, or from the
31
+ version root.
32
+
33
+ The events are written in the page. Nothing is read from the frontmatter of
34
+ other pages: a calendar says what its author put in it, and says it where it
35
+ is read.
36
+
37
+ ## Several months
38
+
39
+ Every month between the first event and the last is drawn — including the ones
40
+ with nothing in them, because a gap is something a reader should see.
41
+
42
+ <Calendar>
43
+ <Event date="2026-11-18" label="Beta" />
44
+ <Event date="2027-01-06" label="Release" />
45
+ </Calendar>
46
+
47
+ ```mdx
48
+ <Calendar>
49
+ <Event date="2026-11-18" label="Beta" />
50
+ <Event date="2027-01-06" label="Release" />
51
+ </Calendar>
52
+ ```
53
+
54
+ Without JavaScript, the months are stacked one after the other and the whole
55
+ calendar is readable. With it, they fold into one, two arrows move between
56
+ them, and today is outlined. The arrows are **written hidden** and revealed by
57
+ the script, so they never appear without the code that makes them work.
58
+
59
+ That script is the client file of the version: a couple of kilobytes, loaded
60
+ only by the pages that hold a calendar, and shared with any other behaviour
61
+ the version uses. See [copyCode](../reference/configuration/) for what that
62
+ file is.
63
+
64
+ ## The small model
65
+
66
+ `compact` draws the grid small and writes the events out under it, at every
67
+ width — beside a paragraph, or in a column of its own.
68
+
69
+ **A narrow screen takes this model whatever the page asked for.** Seven columns
70
+ of full cells on a phone give each day a few millimetres, and a label written
71
+ in one is a word per line. Both forms are in the page and the stylesheet shows
72
+ one, as the menu of the header is written twice: no script decides it, and
73
+ nothing is read twice by a screen reader.
74
+
75
+ <Calendar compact>
76
+ <Event date="2026-10-14" label="Release 0.5" href="../whats-new/" />
77
+ <Event date="2026-10-14" label="Blog post" />
78
+ <Event date="2026-10-28" label="Workshop" />
79
+ </Calendar>
80
+
81
+ ```mdx
82
+ <Calendar compact>
83
+ <Event date="2026-10-14" label="Release 0.5" />
84
+ <Event date="2026-10-28" label="Workshop" />
85
+ </Calendar>
86
+ ```
87
+
88
+ A day that holds something carries a dot, or the number of things it holds —
89
+ a day with three should say three rather than look like a day with one. The
90
+ list underneath is what says what they are: **nothing is only a colour**,
91
+ which no screen reader reads and no colour-blind reader sees.
92
+
93
+ ## The language of the page
94
+
95
+ Month and weekday names come from the language of the page, and so does the
96
+ name a screen reader announces. A French page says `octobre`, an English one
97
+ `October` — nothing to declare.
98
+
99
+ ## What it refuses
100
+
101
+ | Written | What happens |
102
+ | ----------------------------- | ------------------------------------------------------------------ |
103
+ | a calendar with no event | The build stops: an empty calendar shows nothing. |
104
+ | `2026-10` or `14/10/2026` | The build stops, saying how a day is written. |
105
+ | `2026-09-31` | Refused: September has thirty days, so this is a typo, not a date. |
106
+ | an event without a label | The build stops, naming its day. |
107
+ | an `Event` outside a calendar | The build stops: nothing would know which month to draw it in. |
108
+ | anything else inside | The build stops: a calendar holds events. |
109
+
110
+ ## Properties
111
+
112
+ `Calendar`:
113
+
114
+ | Property | Type | Effect |
115
+ | ----------- | --------- | ---------------------------------------------------------------- |
116
+ | `label` | `string` | Name announced to a screen reader. Default: `Calendar`. |
117
+ | `compact` | `boolean` | The small model at every width. A narrow screen takes it anyway. |
118
+ | `className` | `string` | Classes added to the calendar. |
119
+ | `style` | `object` | Inline styles on the calendar. |
120
+
121
+ `Event`:
122
+
123
+ | Property | Type | Effect |
124
+ | -------- | -------- | ---------------------------------------------- |
125
+ | `date` | `string` | The day, `2026-10-14`. Required. |
126
+ | `label` | `string` | What happens that day. Required. |
127
+ | `href` | `string` | Where the event leads. Resolved like any link. |
128
+
129
+ Writing a block twice and showing one is how this site handles a narrow screen
130
+ throughout — [Columns](./columns/) makes the same choice.
@@ -67,9 +67,15 @@ changes the examples too.
67
67
 
68
68
  ## Without JavaScript
69
69
 
70
- No component loads a script. Whatever needs interaction therefore goes
71
- through native elements or through CSS: `details` for expanding, a link for
72
- moving, `animation-timeline` for appearing on scroll.
70
+ No component loads a script but one: `Calendar`, whose arrows between months
71
+ come from the client file of the version — and only on the pages that hold a
72
+ calendar. Whatever else needs interaction goes through native elements or
73
+ through CSS: `details` for expanding, a link for moving, `animation-timeline`
74
+ for appearing on scroll.
75
+
76
+ The site itself can add a behaviour to a page — `copyCode` puts a copy button
77
+ on each block of code — but that is a field you turn on, it lands in one file
78
+ shared by the version, and only pages that use it load it.
73
79
 
74
80
  When the browser does not know one of these properties yet, the component stays
75
81
  usable in its simplest state — visible, full, expanded. None of them waits for
@@ -0,0 +1,32 @@
1
+ /**
2
+ * A file the Snippet page reads, rather than quoting.
3
+ *
4
+ * It is installed along with the documentation, so the examples on that page
5
+ * work in your project exactly as they do on this site. Change a line here
6
+ * and the page changes with it — which is the whole point of the component.
7
+ */
8
+
9
+ /** Words a slug drops, so that titles do not all begin alike. */
10
+ const SKIPPED = new Set(['a', 'an', 'the', 'of', 'to']);
11
+
12
+ /**
13
+ * Turns the title of a page into the last segment of its address.
14
+ *
15
+ * @param {string} title Title, as the frontmatter gives it.
16
+ * @returns {string} A slug: lower case, accents dropped, words joined by a dash.
17
+ */
18
+ export function slugOf(title) {
19
+ // #region guard
20
+ if (typeof title !== 'string' || title.trim() === '') {
21
+ throw new TypeError('slugOf needs a title');
22
+ }
23
+ // #endregion
24
+
25
+ return title
26
+ .normalize('NFD')
27
+ .replace(/\p{M}/gu, '')
28
+ .toLowerCase()
29
+ .split(/[^a-z0-9]+/)
30
+ .filter((word) => word && !SKIPPED.has(word))
31
+ .join('-');
32
+ }
@@ -0,0 +1,19 @@
1
+ """A second file, in another language, so the page can show what changes.
2
+
3
+ Nothing here is read by the tool: it is only the source of an example. The
4
+ extension is what tells the block which language it holds, and therefore
5
+ which mark and which colour it carries.
6
+ """
7
+
8
+ SKIPPED = {"a", "an", "the", "of", "to"}
9
+
10
+
11
+ def slug_of(title: str) -> str:
12
+ """Turn the title of a page into the last segment of its address."""
13
+ # #region guard
14
+ if not isinstance(title, str) or not title.strip():
15
+ raise TypeError("slug_of needs a title")
16
+ # #endregion
17
+
18
+ words = "".join(c if c.isalnum() else " " for c in title.lower()).split()
19
+ return "-".join(w for w in words if w not in SKIPPED)
@@ -113,9 +113,14 @@ Development server, which rebuilds on every save.
113
113
  npx docpensieve dev
114
114
  ```
115
115
 
116
- | Option | Effect |
117
- | --------------------- | ------------------------------- |
118
- | `-p, --port <number>` | Listening port. Default: `3000` |
116
+ | Option | Effect |
117
+ | --------------------- | ------------------------------------------------------------- |
118
+ | `-p, --port <number>` | Listening port. Default: `3000` |
119
+ | `--host <address>` | Address to listen on. Default: `127.0.0.1`, this machine only |
120
+
121
+ `0.0.0.0` opens the server to the network — to look at the site from a phone on
122
+ the same wifi. Anyone on that network can then read it, drafts included, and
123
+ the command says so when it starts.
119
124
 
120
125
  ## `serve`
121
126
 
@@ -125,10 +130,11 @@ Serves the output folder statically, without rebuilding anything.
125
130
  npx docpensieve serve
126
131
  ```
127
132
 
128
- | Option | Effect |
129
- | --------------------- | ------------------------------- |
130
- | `-p, --port <number>` | Listening port. Default: `4000` |
131
- | `-d, --dir <dir>` | Folder to serve |
133
+ | Option | Effect |
134
+ | --------------------- | ------------------------------------------------------------- |
135
+ | `-p, --port <number>` | Listening port. Default: `4000` |
136
+ | `--host <address>` | Address to listen on. Default: `127.0.0.1`, this machine only |
137
+ | `-d, --dir <dir>` | Folder to serve |
132
138
 
133
139
  It is the command that faithfully reproduces what a host will do: to check what
134
140
  will be published, chain `build` then `serve`.
@@ -65,6 +65,8 @@ can change.
65
65
  | `stickyHeader` | `true` | The header stays at the top of the screen; `false` lets it scroll away |
66
66
  | `globalComponents` | `true` | Shipped components available without an import |
67
67
  | `scrollToTop` | `true` | Back-to-top button on every page |
68
+ | `copyCode` | `false` | A button copying each block of code — the one field that makes a content page load a script |
69
+ | `snippetIcons` | `''` | Icon collection a code block takes the mark of its language from, `'simple-icons'` |
68
70
  | `jsonld` | `{ enabled: true }` | Structured data |
69
71
  | `lang` | `'en'` | Language of the site: `<html lang>`, and the wording of the shell |
70
72
  | `ui` | `{}` | Wording of the shell, by language — corrects a word, or adds a language |
@@ -135,6 +137,23 @@ The search page is kept out of search engines (`noindex`) and out of the
135
137
  sitemap. A page of your own at `/search/` would take its place: the build
136
138
  refuses it, and `search: false` frees the address.
137
139
 
140
+ ## `copyCode`
141
+
142
+ `copyCode: true` puts a button on every block of code, which copies it.
143
+
144
+ It is off by default, because it is the one field that makes an ordinary page
145
+ load a script. Turned on, the behaviour is written **once per version**, in
146
+ `assets/client.js` beside the stylesheet, and shared by every page and every
147
+ language — a reader who has it in cache pays for it once. Only the pages that
148
+ hold a block of code load it; the others go on loading nothing.
149
+
150
+ About two kilobytes, compressed. No framework, no hydration: the code is plain
151
+ DOM, and the button is drawn by the script itself. Without JavaScript the
152
+ block is exactly what it was, text you can select — nothing is missing but
153
+ the button.
154
+
155
+ The label follows the language of the page, in English and in French.
156
+
138
157
  ## `versions`
139
158
 
140
159
  ```js