docpensieve 0.5.0-beta.2 → 0.5.0-beta.4
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/bin/docpensieve.js +2 -0
- package/package.json +5 -5
- package/src/commands/build.js +2 -0
- package/src/commands/dev.js +14 -3
- package/src/commands/init.js +14 -0
- package/src/commands/serve.js +5 -3
- package/src/server.js +48 -14
- package/starter/01-guide/02-first-site.md +4 -0
- package/starter/01-guide/06-deployment.md +30 -0
- package/starter/01-guide/07-migrate-to-beta.md +18 -2
- package/starter/02-components/01-card.mdx +25 -0
- package/starter/02-components/02-columns.mdx +12 -0
- package/starter/02-components/03-time-timer.mdx +19 -0
- package/starter/02-components/04-tooltip.mdx +9 -0
- package/starter/02-components/05-tree.mdx +13 -0
- package/starter/02-components/06-scroll-to-top.mdx +10 -0
- package/starter/02-components/07-skill.mdx +16 -0
- package/starter/02-components/08-logo-icon.mdx +10 -0
- package/starter/02-components/09-for-theme.mdx +6 -0
- package/starter/02-components/10-cards.mdx +9 -0
- package/starter/02-components/11-menu.mdx +22 -0
- package/starter/02-components/12-admonition.mdx +9 -0
- package/starter/02-components/13-snippet.mdx +230 -0
- package/starter/02-components/14-hero.mdx +230 -0
- package/starter/02-components/15-calendar.mdx +130 -0
- package/starter/02-components/index.mdx +9 -3
- package/starter/02-components/snippet-example.js +32 -0
- package/starter/02-components/snippet-example.py +19 -0
- package/starter/03-reference/01-cli.md +13 -7
- package/starter/03-reference/02-configuration.md +52 -0
- package/starter/03-reference/05-api.md +315 -3
- package/starter/05-whats-new.md +57 -0
- package/types/commands/dev.d.ts +2 -1
- package/types/commands/serve.d.ts +2 -1
- package/types/server.d.ts +24 -1
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Snippet
|
|
3
|
+
description: A code block that names a real file of your project, read when the page is generated, so that the example cannot go stale.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Snippet
|
|
7
|
+
|
|
8
|
+
An example written by hand is a copy. It stops being true the day the code
|
|
9
|
+
changes, and nothing reports it: the page goes on showing something that
|
|
10
|
+
worked once. `Snippet` names the file instead, and the file is read when the
|
|
11
|
+
page is generated — there is no copy left to drift.
|
|
12
|
+
|
|
13
|
+
The idea comes from **Christophe Avonture**, who built it for his own site.
|
|
14
|
+
|
|
15
|
+
## Naming a file
|
|
16
|
+
|
|
17
|
+
<Snippet source="./snippet-example.js" />
|
|
18
|
+
|
|
19
|
+
```mdx
|
|
20
|
+
<Snippet source="./snippet-example.js" />
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The file name labels the block, and the highlighting is the one every code
|
|
24
|
+
block gets. A path beginning with `./` or `../` is read **from the page**, as
|
|
25
|
+
a link is; any other path is read **from the root of your project**, so that
|
|
26
|
+
`src/index.js` means the same file from every page.
|
|
27
|
+
|
|
28
|
+
## Part of a file
|
|
29
|
+
|
|
30
|
+
Two ways, and they do not age the same.
|
|
31
|
+
|
|
32
|
+
A **range of lines** is quick to write and means line 12 of the file as it is
|
|
33
|
+
today:
|
|
34
|
+
|
|
35
|
+
<Snippet source="./snippet-example.js" lines="9-10" title="The words it drops" />
|
|
36
|
+
|
|
37
|
+
```mdx
|
|
38
|
+
<Snippet source="./snippet-example.js" lines="9-10" title="The words it drops" />
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Write `lines="9"` for one line, `"9-10"` for a range, `"9-"` from there to the
|
|
42
|
+
end, `"-10"` from the start. It says what the file holds today, and only
|
|
43
|
+
today.
|
|
44
|
+
|
|
45
|
+
A **region** is a marker left in the source file itself, in a comment. It
|
|
46
|
+
follows the code when the code moves, which is the whole point of naming a
|
|
47
|
+
file rather than copying it:
|
|
48
|
+
|
|
49
|
+
<Snippet source="./snippet-example.js" region="guard" title="The guard" />
|
|
50
|
+
|
|
51
|
+
```mdx
|
|
52
|
+
<Snippet source="./snippet-example.js" region="guard" title="The guard" />
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
In the file, the marker is an ordinary comment — the one editors already fold
|
|
56
|
+
on:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
// #region guard
|
|
60
|
+
if (!name) {
|
|
61
|
+
throw new Error('greet needs a name');
|
|
62
|
+
}
|
|
63
|
+
// #endregion
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The indentation the kept lines share is removed, so a region marked inside a
|
|
67
|
+
function does not come out shifted.
|
|
68
|
+
|
|
69
|
+
## Folding a long file
|
|
70
|
+
|
|
71
|
+
`collapsed` puts the block inside a `details`. No script: a long file can sit
|
|
72
|
+
in a page without burying what follows it.
|
|
73
|
+
|
|
74
|
+
<Snippet source="./snippet-example.js" collapsed title="The whole file" />
|
|
75
|
+
|
|
76
|
+
```mdx
|
|
77
|
+
<Snippet source="./snippet-example.js" collapsed title="The whole file" />
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Code you write yourself
|
|
81
|
+
|
|
82
|
+
Without `source`, the component frames the code written in the page. A fenced
|
|
83
|
+
block inside the tag is the dependable way to write it: it carries anything,
|
|
84
|
+
braces and `<` included, and no formatter touches what is inside it.
|
|
85
|
+
|
|
86
|
+
<Snippet title="greet.py">
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
def greet(name, greetings={'en': 'Hello'}):
|
|
90
|
+
return f"{greetings['en']}, {name}!"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
</Snippet>
|
|
94
|
+
|
|
95
|
+
````mdx
|
|
96
|
+
<Snippet title="greet.py">
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
def greet(name, greetings={'en': 'Hello'}):
|
|
100
|
+
return f"{greetings['en']}, {name}!"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
</Snippet>
|
|
104
|
+
````
|
|
105
|
+
|
|
106
|
+
The extension of the title names the language; `lang` says it where the title
|
|
107
|
+
does not, as for a shell:
|
|
108
|
+
|
|
109
|
+
<Snippet title="Build the site" lang="bash">
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm install
|
|
113
|
+
npx docpensieve build
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
</Snippet>
|
|
117
|
+
|
|
118
|
+
````mdx
|
|
119
|
+
<Snippet title="Build the site" lang="bash">
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npm install
|
|
123
|
+
npx docpensieve build
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
</Snippet>
|
|
127
|
+
````
|
|
128
|
+
|
|
129
|
+
### Code typed straight into the tag
|
|
130
|
+
|
|
131
|
+
Code written bare inside the tag is read too, from the page as you typed it —
|
|
132
|
+
indentation kept, nothing taken for Markdown:
|
|
133
|
+
|
|
134
|
+
```mdx
|
|
135
|
+
<Snippet title="who_are_you.py">name = input("What's your name? ")</Snippet>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Two things it cannot carry, both of which happen before any component sees the
|
|
139
|
+
code. A page is MDX, so `{`, `}` and `<` are read as MDX and stop the build on
|
|
140
|
+
a syntax error. And a formatter run over your pages reflows what it takes for
|
|
141
|
+
prose: two lines of shell come back as one. Where either applies — which is
|
|
142
|
+
most real code — use the fenced form above.
|
|
143
|
+
|
|
144
|
+
## The mark of the language
|
|
145
|
+
|
|
146
|
+
A block carries the colour of its language — a rule above it, and a short mark
|
|
147
|
+
beside the file name. The colour is set as a variable on the frame, so the
|
|
148
|
+
theme decides what it paints and a project can set another.
|
|
149
|
+
|
|
150
|
+
The same function, in the other file this page reads. Nothing was said about
|
|
151
|
+
the language: the extension carried it, and with it the mark and the colour.
|
|
152
|
+
|
|
153
|
+
<Snippet source="./snippet-example.py" region="guard" title="The same guard, in Python" />
|
|
154
|
+
|
|
155
|
+
```mdx
|
|
156
|
+
<Snippet source="./snippet-example.py" region="guard" title="The same guard, in Python" />
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
A block the page writes says its language in the fence, and is marked the same
|
|
160
|
+
way:
|
|
161
|
+
|
|
162
|
+
<Snippet title="deploy.yml">
|
|
163
|
+
|
|
164
|
+
```yaml
|
|
165
|
+
steps:
|
|
166
|
+
- run: npx docpensieve build
|
|
167
|
+
- run: npx docpensieve check
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
</Snippet>
|
|
171
|
+
|
|
172
|
+
<Snippet title="A first build" lang="bash">
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npx docpensieve init my-site
|
|
176
|
+
npx docpensieve dev
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
</Snippet>
|
|
180
|
+
|
|
181
|
+
Where a project installs an icon collection and names it, the drawing replaces
|
|
182
|
+
the mark:
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
snippetIcons: 'simple-icons',
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
It is never a reason to fail. The icon is the tool's idea, not something your
|
|
189
|
+
page asked for: a collection you do not have, or a language it does not draw,
|
|
190
|
+
brings back the mark. `icon="simple-icons:docker"` on a single block wins over
|
|
191
|
+
both.
|
|
192
|
+
|
|
193
|
+
### A language nobody marked
|
|
194
|
+
|
|
195
|
+
Twenty-one languages have a mark and a colour. Any other is shown without
|
|
196
|
+
one — the frame, the name, and the code.
|
|
197
|
+
|
|
198
|
+
Highlighting is a separate matter, and a wider one: the highlighter knows
|
|
199
|
+
several hundred languages, and a block in one it does not know comes out as
|
|
200
|
+
plain text rather than stopping the build. You can write a snippet in anything
|
|
201
|
+
your project is written in.
|
|
202
|
+
|
|
203
|
+
## What it refuses
|
|
204
|
+
|
|
205
|
+
Nothing fails quietly, because a snippet that resolved to nothing would leave
|
|
206
|
+
an empty frame — and an empty frame looks deliberate.
|
|
207
|
+
|
|
208
|
+
| Written | What happens |
|
|
209
|
+
| ----------------------------------- | --------------------------------------------------------------- |
|
|
210
|
+
| a file that is not there | The build stops, saying which path was looked for. |
|
|
211
|
+
| a path leading outside the project | Refused: a page is content, and content does not read the disk. |
|
|
212
|
+
| a region no marker opens, or closes | The build stops, naming the region and the file. |
|
|
213
|
+
| a range that reads backwards | The build stops. |
|
|
214
|
+
|
|
215
|
+
## Properties
|
|
216
|
+
|
|
217
|
+
| Property | Type | Effect |
|
|
218
|
+
| ----------- | --------- | --------------------------------------------------------------------------- |
|
|
219
|
+
| `source` | `string` | File to read. From the page with `./` or `../`, from the project otherwise. |
|
|
220
|
+
| `title` | `string` | Label above the block. Defaults to the name of the file. |
|
|
221
|
+
| `lines` | `string` | `8`, `8-14`, `8-` or `-14`. |
|
|
222
|
+
| `region` | `string` | Name marked by `#region` and `#endregion` in the file. |
|
|
223
|
+
| `lang` | `string` | Language for the highlighting, when the extension says the wrong thing. |
|
|
224
|
+
| `collapsed` | `boolean` | Folds the block into a `details`. |
|
|
225
|
+
| `icon` | `string` | An icon for this block, instead of the mark of its language. |
|
|
226
|
+
| `className` | `string` | Classes added to the frame. |
|
|
227
|
+
| `style` | `object` | Inline styles on the frame. |
|
|
228
|
+
|
|
229
|
+
The file this page reads is installed along with it, so every example above
|
|
230
|
+
works in your project exactly as it does here.
|
|
@@ -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
|
+

|
|
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
|
+

|
|
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
|
|
71
|
-
|
|
72
|
-
|
|
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)
|