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
package/bin/docpensieve.js
CHANGED
|
@@ -63,6 +63,7 @@ program
|
|
|
63
63
|
.command('dev')
|
|
64
64
|
.description('Development server with reload')
|
|
65
65
|
.option('-p, --port <number>', 'listening port', Number, 3000)
|
|
66
|
+
.option('--host <address>', 'address to listen on; 0.0.0.0 opens it to the network', '127.0.0.1')
|
|
66
67
|
.action(async (options) => {
|
|
67
68
|
await dev(options);
|
|
68
69
|
});
|
|
@@ -71,6 +72,7 @@ program
|
|
|
71
72
|
.command('serve')
|
|
72
73
|
.description('Serves the output folder statically')
|
|
73
74
|
.option('-p, --port <number>', 'listening port', Number, 4000)
|
|
75
|
+
.option('--host <address>', 'address to listen on; 0.0.0.0 opens it to the network', '127.0.0.1')
|
|
74
76
|
.option('-d, --dir <dir>', 'folder to serve')
|
|
75
77
|
.action(async (options) => {
|
|
76
78
|
await serve(options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docpensieve",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.4",
|
|
4
4
|
"description": "DocPensieve command-line interface (init, build, check, dev, serve)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"types"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@docpensieve/components": "0.5.0-beta.
|
|
28
|
-
"@docpensieve/core": "0.5.0-beta.
|
|
29
|
-
"@docpensieve/shared": "0.5.0-beta.
|
|
30
|
-
"@docpensieve/theme": "0.5.0-beta.
|
|
27
|
+
"@docpensieve/components": "0.5.0-beta.4",
|
|
28
|
+
"@docpensieve/core": "0.5.0-beta.4",
|
|
29
|
+
"@docpensieve/shared": "0.5.0-beta.4",
|
|
30
|
+
"@docpensieve/theme": "0.5.0-beta.4",
|
|
31
31
|
"chalk": "^6.0.0",
|
|
32
32
|
"chokidar": "^5.0.0",
|
|
33
33
|
"commander": "^15.0.0"
|
package/src/commands/build.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
createRegistry,
|
|
12
12
|
setSiteContext,
|
|
13
13
|
setAdmonitionKinds,
|
|
14
|
+
setSnippetIcons,
|
|
14
15
|
} from '@docpensieve/components';
|
|
15
16
|
import { SiteGenerator, loadConfig, resolveVersion } from '@docpensieve/core';
|
|
16
17
|
|
|
@@ -28,6 +29,7 @@ export async function build(versionSlug, options = {}) {
|
|
|
28
29
|
|
|
29
30
|
// The kinds a project declares, beside the ones shipped.
|
|
30
31
|
setAdmonitionKinds(config.admonitions);
|
|
32
|
+
setSnippetIcons(config.snippetIcons);
|
|
31
33
|
|
|
32
34
|
const generator = new SiteGenerator(config, {
|
|
33
35
|
// `globalComponents: false` removes the shipped components: a project that
|
package/src/commands/dev.js
CHANGED
|
@@ -12,12 +12,20 @@ import {
|
|
|
12
12
|
createRegistry,
|
|
13
13
|
setSiteContext,
|
|
14
14
|
setAdmonitionKinds,
|
|
15
|
+
setSnippetIcons,
|
|
15
16
|
} from '@docpensieve/components';
|
|
16
17
|
import { SiteGenerator, loadConfig } from '@docpensieve/core';
|
|
17
18
|
import { CONFIG_FILENAME, DocPensieveError, THEME_FOLDER } from '@docpensieve/shared';
|
|
18
19
|
import chokidar from 'chokidar';
|
|
19
20
|
|
|
20
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
DEFAULT_HOST,
|
|
23
|
+
RELOAD_PATH,
|
|
24
|
+
createStaticServer,
|
|
25
|
+
exposedNotice,
|
|
26
|
+
isExposed,
|
|
27
|
+
listen,
|
|
28
|
+
} from '../server.js';
|
|
21
29
|
import { createTheme } from '../theme.js';
|
|
22
30
|
|
|
23
31
|
/** Default port of `dev`, distinct from that of `serve`. */
|
|
@@ -40,7 +48,7 @@ const RELOAD_SCRIPT =
|
|
|
40
48
|
`.addEventListener("message",()=>location.reload())</script>`;
|
|
41
49
|
|
|
42
50
|
/**
|
|
43
|
-
* @param {{ port?: number, cwd?: string }} [options]
|
|
51
|
+
* @param {{ port?: number, host?: string, cwd?: string }} [options]
|
|
44
52
|
* @returns {Promise<{
|
|
45
53
|
* server: import('node:http').Server,
|
|
46
54
|
* watcher: import('chokidar').FSWatcher,
|
|
@@ -62,6 +70,7 @@ export async function dev(options = {}) {
|
|
|
62
70
|
// Read again with the rest: a kind added to the configuration must show
|
|
63
71
|
// without restarting the command.
|
|
64
72
|
setAdmonitionKinds(current.admonitions);
|
|
73
|
+
setSnippetIcons(current.snippetIcons);
|
|
65
74
|
const generator = new SiteGenerator(current, {
|
|
66
75
|
// `globalComponents: false` removes the shipped components: a project
|
|
67
76
|
// that defines its own thus avoids a name collision. The option was
|
|
@@ -87,8 +96,10 @@ export async function dev(options = {}) {
|
|
|
87
96
|
},
|
|
88
97
|
});
|
|
89
98
|
|
|
90
|
-
const
|
|
99
|
+
const host = options.host ?? DEFAULT_HOST;
|
|
100
|
+
const port = await listen(server, options.port ?? DEFAULT_PORT, 10, host);
|
|
91
101
|
const url = `http://localhost:${port}${config.baseUrl}`;
|
|
102
|
+
if (isExposed(host)) console.log(exposedNotice(host));
|
|
92
103
|
console.log(`served at ${url}`);
|
|
93
104
|
|
|
94
105
|
// The project's own stylesheets, re-read by every rebuild.
|
package/src/commands/init.js
CHANGED
|
@@ -368,6 +368,16 @@ function renderConfig({ name, theme, siteUrl, version, translation = '' }) {
|
|
|
368
368
|
' // Back-to-top button on every page.',
|
|
369
369
|
' scrollToTop: true,',
|
|
370
370
|
'',
|
|
371
|
+
' // A button copying each block of code. It is the one thing that makes a',
|
|
372
|
+
' // content page load a script — a small file, shared by every page of the',
|
|
373
|
+
' // version — so it stays off until you ask for it.',
|
|
374
|
+
' copyCode: false,',
|
|
375
|
+
'',
|
|
376
|
+
' // Icon collection a code block takes the mark of its language from, for',
|
|
377
|
+
" // instance 'simple-icons' once @iconify-json/simple-icons is installed.",
|
|
378
|
+
' // Left empty, the short name of the language is shown instead.',
|
|
379
|
+
" snippetIcons: '',",
|
|
380
|
+
'',
|
|
371
381
|
' // The header stays at the top of the screen. false lets it scroll away',
|
|
372
382
|
' // with the page, and gives its height back to the text.',
|
|
373
383
|
' stickyHeader: true,',
|
|
@@ -389,6 +399,10 @@ function renderConfig({ name, theme, siteUrl, version, translation = '' }) {
|
|
|
389
399
|
' // A search field in the header, and a search page built with the site.',
|
|
390
400
|
' // Content pages load no script: the search page alone does.',
|
|
391
401
|
' search: true,',
|
|
402
|
+
'',
|
|
403
|
+
' // llms.txt at the root of the site, and a Markdown copy beside each',
|
|
404
|
+
' // page: what a program reads instead of the HTML. It needs no siteUrl.',
|
|
405
|
+
' llms: false,',
|
|
392
406
|
'};',
|
|
393
407
|
'',
|
|
394
408
|
'// Every field is described in the reference of the DocPensieve documentation:',
|
package/src/commands/serve.js
CHANGED
|
@@ -10,13 +10,13 @@ import path from 'node:path';
|
|
|
10
10
|
import { loadConfig } from '@docpensieve/core';
|
|
11
11
|
import { DocPensieveError } from '@docpensieve/shared';
|
|
12
12
|
|
|
13
|
-
import { createStaticServer, listen } from '../server.js';
|
|
13
|
+
import { DEFAULT_HOST, createStaticServer, exposedNotice, isExposed, listen } from '../server.js';
|
|
14
14
|
|
|
15
15
|
/** Default port of `serve`, distinct from that of `dev`. */
|
|
16
16
|
const DEFAULT_PORT = 4000;
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* @param {{ port?: number, dir?: string, cwd?: string }} [options]
|
|
19
|
+
* @param {{ port?: number, host?: string, dir?: string, cwd?: string }} [options]
|
|
20
20
|
* @returns {Promise<{ server: import('node:http').Server, port: number, url: string }>}
|
|
21
21
|
* @throws {DocPensieveError} When the folder to serve does not exist.
|
|
22
22
|
*/
|
|
@@ -34,11 +34,13 @@ export async function serve(options = {}) {
|
|
|
34
34
|
// The site is mounted under the configuration's baseUrl: otherwise the links
|
|
35
35
|
// of the generated pages would not resolve locally.
|
|
36
36
|
const server = createStaticServer({ root, basePath: config.baseUrl });
|
|
37
|
-
const
|
|
37
|
+
const host = options.host ?? DEFAULT_HOST;
|
|
38
|
+
const port = await listen(server, options.port ?? DEFAULT_PORT, 10, host);
|
|
38
39
|
const url = `http://localhost:${port}${config.baseUrl}`;
|
|
39
40
|
|
|
40
41
|
console.log(`${root}`);
|
|
41
42
|
console.log(`served at ${url}`);
|
|
43
|
+
if (isExposed(host)) console.log(exposedNotice(host));
|
|
42
44
|
|
|
43
45
|
return { server, port, url };
|
|
44
46
|
}
|
package/src/server.js
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* @module docpensieve/server
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import { stat } from 'node:fs/promises';
|
|
7
|
+
import { readFile } from 'node:fs/promises';
|
|
9
8
|
import { createServer } from 'node:http';
|
|
10
9
|
import path from 'node:path';
|
|
11
10
|
|
|
@@ -134,9 +133,15 @@ export function createStaticServer({ root, basePath = '/', inject = null, onRelo
|
|
|
134
133
|
return;
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
|
|
136
|
+
// Read whole, then answer. `dev` empties the version folder at every
|
|
137
|
+
// rebuild while a browser may still be asking for it: between a `stat`
|
|
138
|
+
// and a stream the file could vanish, the stream then threw with nobody
|
|
139
|
+
// listening, and the server went down in the middle of a save. Read at
|
|
140
|
+
// once, a file is either there or answered 404 — and its length is the
|
|
141
|
+
// one actually sent, not the one a rebuild was busy changing.
|
|
142
|
+
let body;
|
|
138
143
|
try {
|
|
139
|
-
|
|
144
|
+
body = await readFile(filepath);
|
|
140
145
|
} catch {
|
|
141
146
|
response.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' });
|
|
142
147
|
response.end(`404 — ${url.pathname}`);
|
|
@@ -147,31 +152,49 @@ export function createStaticServer({ root, basePath = '/', inject = null, onRelo
|
|
|
147
152
|
const headers = { 'content-type': type, 'cache-control': 'no-cache' };
|
|
148
153
|
|
|
149
154
|
if (inject && type.startsWith('text/html')) {
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
const body = html.includes('</body>')
|
|
155
|
+
const html = body.toString('utf8');
|
|
156
|
+
const page = html.includes('</body>')
|
|
153
157
|
? html.replace('</body>', `${inject}</body>`)
|
|
154
158
|
: html + inject;
|
|
155
|
-
response.writeHead(200, { ...headers, 'content-length': Buffer.byteLength(
|
|
156
|
-
response.end(
|
|
159
|
+
response.writeHead(200, { ...headers, 'content-length': Buffer.byteLength(page) });
|
|
160
|
+
response.end(page);
|
|
157
161
|
return;
|
|
158
162
|
}
|
|
159
163
|
|
|
160
|
-
response.writeHead(200, { ...headers, 'content-length':
|
|
161
|
-
|
|
164
|
+
response.writeHead(200, { ...headers, 'content-length': body.length });
|
|
165
|
+
response.end(body);
|
|
162
166
|
});
|
|
163
167
|
}
|
|
164
168
|
|
|
169
|
+
/** The loopback address: the site is served to this machine and to no other. */
|
|
170
|
+
export const DEFAULT_HOST = '127.0.0.1';
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Whether an address reaches beyond this machine.
|
|
174
|
+
*
|
|
175
|
+
* @param {string} host
|
|
176
|
+
* @returns {boolean}
|
|
177
|
+
*/
|
|
178
|
+
export function isExposed(host) {
|
|
179
|
+
return !['127.0.0.1', 'localhost', '::1'].includes(host);
|
|
180
|
+
}
|
|
181
|
+
|
|
165
182
|
/**
|
|
166
183
|
* Starts listening, looking for a free port if needed.
|
|
167
184
|
*
|
|
185
|
+
* On this machine only, unless asked otherwise. Called without a host, Node
|
|
186
|
+
* listens on every interface: anyone on the same network — a café, a
|
|
187
|
+
* coworking space — could read the site being written, drafts included.
|
|
188
|
+
*
|
|
168
189
|
* @param {import('node:http').Server} server
|
|
169
190
|
* @param {number} port Desired port.
|
|
170
191
|
* @param {number} [attempts] Number of ports tried from `port` on.
|
|
192
|
+
* @param {string} [host] Address to listen on. `0.0.0.0` opens it to the
|
|
193
|
+
* network, which a phone on the same wifi needs.
|
|
171
194
|
* @returns {Promise<number>} The port actually used.
|
|
172
195
|
* @throws {DocPensieveError} When no port is free in the range.
|
|
173
196
|
*/
|
|
174
|
-
export function listen(server, port, attempts = 10) {
|
|
197
|
+
export function listen(server, port, attempts = 10, host = DEFAULT_HOST) {
|
|
175
198
|
return new Promise((resolve, reject) => {
|
|
176
199
|
let current = port;
|
|
177
200
|
|
|
@@ -181,7 +204,7 @@ export function listen(server, port, attempts = 10) {
|
|
|
181
204
|
// the next one beats forcing --port.
|
|
182
205
|
if (error.code === 'EADDRINUSE' && current < port + attempts - 1) {
|
|
183
206
|
current += 1;
|
|
184
|
-
server.listen(current);
|
|
207
|
+
server.listen(current, host);
|
|
185
208
|
return;
|
|
186
209
|
}
|
|
187
210
|
server.off('error', onError);
|
|
@@ -202,6 +225,17 @@ export function listen(server, port, attempts = 10) {
|
|
|
202
225
|
const address = server.address();
|
|
203
226
|
resolve(typeof address === 'object' && address !== null ? address.port : current);
|
|
204
227
|
});
|
|
205
|
-
server.listen(current);
|
|
228
|
+
server.listen(current, host);
|
|
206
229
|
});
|
|
207
230
|
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Said when the site is opened to the network, so that it is never done
|
|
234
|
+
* without the person knowing.
|
|
235
|
+
*
|
|
236
|
+
* @param {string} host
|
|
237
|
+
* @returns {string}
|
|
238
|
+
*/
|
|
239
|
+
export function exposedNotice(host) {
|
|
240
|
+
return `listening on ${host}: anyone on this network can read the site.`;
|
|
241
|
+
}
|
|
@@ -98,6 +98,10 @@ online.
|
|
|
98
98
|
→ ignores the deployment prefix "/my-project/"
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
Two commands, and the second reads what the first wrote — so they belong
|
|
102
|
+
together. [Deployment](./deployment/) shows how to say that once, in a
|
|
103
|
+
`package.json`, and have a workflow run the same thing you run.
|
|
104
|
+
|
|
101
105
|
It is the check to run after any change of `baseUrl`, of folder structure or of
|
|
102
106
|
URL. When something does not add up, [When it breaks](./when-it-breaks/) lists
|
|
103
107
|
the failures this tool produces, by the symptom you see.
|
|
@@ -88,6 +88,32 @@ the tool through `npx`, which takes the latest published version. To pin it
|
|
|
88
88
|
from one build to the next, declare `docpensieve` in a `package.json` and add
|
|
89
89
|
`npm ci` before the build.
|
|
90
90
|
|
|
91
|
+
## One command, for you and for the machine
|
|
92
|
+
|
|
93
|
+
Two commands are one too many to remember, and a workflow should run exactly
|
|
94
|
+
what you run. A `package.json` is the place to say it once:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"scripts": {
|
|
99
|
+
"docs": "docpensieve dev",
|
|
100
|
+
"check": "docpensieve build && docpensieve check"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`npm run check` then generates the site and reads it back. A dead link, a
|
|
106
|
+
nesting the markup cannot carry, a page that stops the build: each one fails
|
|
107
|
+
the command, on your machine and in your workflow, in the same way and with
|
|
108
|
+
the same message.
|
|
109
|
+
|
|
110
|
+
The `&&` is the point of it. `check` reads what `build` wrote, so a check run
|
|
111
|
+
on its own tells you about the site as it was the last time it was generated —
|
|
112
|
+
which, the day you forget, is the day it matters.
|
|
113
|
+
|
|
114
|
+
With that in place the recipe above becomes `npm ci` and `npm run check`, and
|
|
115
|
+
the version of the tool stops depending on the day the workflow ran.
|
|
116
|
+
|
|
91
117
|
## Reading back before publishing
|
|
92
118
|
|
|
93
119
|
A generated site can compile without error and contain dead links.
|
|
@@ -134,6 +160,10 @@ For pages that are news rather than reference — release notes, a changelog —
|
|
|
134
160
|
give them a `date` and set `feed: true`: `feed.xml` then lists them, newest
|
|
135
161
|
first. The fields are in the [configuration reference](../reference/configuration/).
|
|
136
162
|
|
|
163
|
+
For programs that read documentation on someone's behalf, `llms: true` writes
|
|
164
|
+
`llms.txt` at the root and a Markdown copy beside each page — the text
|
|
165
|
+
without the markup. It needs no `siteUrl`.
|
|
166
|
+
|
|
137
167
|
## What the reader downloads
|
|
138
168
|
|
|
139
169
|
The build keeps it light on its own. The stylesheet is minified — a third to
|
|
@@ -31,8 +31,24 @@ npx docpensieve check
|
|
|
31
31
|
|
|
32
32
|
## What changes on its own
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
- **`dev` and `serve` listen on this machine only.** They used to listen on
|
|
35
|
+
every interface, so anyone on the same network could read the site being
|
|
36
|
+
written. To look at it from a phone on the same wifi, say so:
|
|
37
|
+
`npx docpensieve dev --host 0.0.0.0`.
|
|
38
|
+
- **Code blocks carry a background of their own.** A block in a language the
|
|
39
|
+
highlighter does not know used to sit on the bare page; it now looks like
|
|
40
|
+
every other block.
|
|
41
|
+
- **An error keeps its hint.** An error the tool raises while a page compiles
|
|
42
|
+
no longer comes out as a generic syntax complaint.
|
|
43
|
+
|
|
44
|
+
## What is worth turning on
|
|
45
|
+
|
|
46
|
+
- [Snippet](../components/snippet/), to show a real file rather than a copy.
|
|
47
|
+
- [Hero](../components/hero/) and [Calendar](../components/calendar/).
|
|
48
|
+
- `copyCode`, a copy button on every code block — off by default, since it is
|
|
49
|
+
what makes a page load a script. See [the reference](../reference/configuration/).
|
|
50
|
+
- `snippetIcons`, if your project installs an icon collection.
|
|
51
|
+
- `llms`, for `llms.txt` and a Markdown copy of each page.
|
|
36
52
|
|
|
37
53
|
## What to check afterwards
|
|
38
54
|
|
|
@@ -341,3 +341,28 @@ in none: a class of yours always wins, even to undo the default style.
|
|
|
341
341
|
</Card>
|
|
342
342
|
|
|
343
343
|
</ForTheme>
|
|
344
|
+
|
|
345
|
+
The commonest row is a row of cards; [Columns](./columns/) shows how to keep
|
|
346
|
+
them the same height, which a grid alone does not.
|
|
347
|
+
|
|
348
|
+
## Properties
|
|
349
|
+
|
|
350
|
+
`Card`:
|
|
351
|
+
|
|
352
|
+
| Property | Type | Effect |
|
|
353
|
+
| ----------- | --------- | ---------------------------------------------------------------- |
|
|
354
|
+
| `elevated` | `boolean` | Adds a shadow. |
|
|
355
|
+
| `href` | `string` | Makes the whole card a link, resolved like any link of the page. |
|
|
356
|
+
| `className` | `string` | Classes added to the card. |
|
|
357
|
+
| `style` | `object` | Inline styles on the card. |
|
|
358
|
+
|
|
359
|
+
`CardImage`:
|
|
360
|
+
|
|
361
|
+
| Property | Type | Effect |
|
|
362
|
+
| -------------------------- | -------- | ---------------------------------------------------------------- |
|
|
363
|
+
| `src` | `string` | The image, resolved like any link of the page. |
|
|
364
|
+
| `alt` | `string` | What the image shows. Empty by default: the image is decorative. |
|
|
365
|
+
| `loading` | `string` | `lazy`, the default, or `eager`. |
|
|
366
|
+
| `title`, `srcSet`, `sizes` | `string` | Passed to the image as they are. |
|
|
367
|
+
|
|
368
|
+
`CardHeader`, `CardBody` and `CardFooter` take `className` and `style`.
|
|
@@ -287,3 +287,15 @@ window to check.
|
|
|
287
287
|
|
|
288
288
|
The most frequent row is a row of cards; [Card](./card/) shows how to keep
|
|
289
289
|
them to the same height, which a grid alone does not do.
|
|
290
|
+
|
|
291
|
+
## Properties
|
|
292
|
+
|
|
293
|
+
`Column`:
|
|
294
|
+
|
|
295
|
+
| Property | Type | Effect |
|
|
296
|
+
| ----------- | -------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
297
|
+
| `span` | `number` | Tracks taken out of twelve — `6` for a half, `8` for two thirds. Without it, the columns share the space equally. |
|
|
298
|
+
| `className` | `string` | Classes added to the column. |
|
|
299
|
+
| `style` | `object` | Inline styles on the column. |
|
|
300
|
+
|
|
301
|
+
`Columns` takes `className` and `style`. A `Column` outside a `Columns` stops the build.
|
|
@@ -122,3 +122,22 @@ names the faulty value and recalls the expected format.
|
|
|
122
122
|
Announcing a release is what this is usually for, and [Versions](../guide/versions/)
|
|
123
123
|
covers the rest of that cycle — the banner a prerelease carries on its own,
|
|
124
124
|
and the day the two tracks swap.
|
|
125
|
+
|
|
126
|
+
## Properties
|
|
127
|
+
|
|
128
|
+
`TimeTimer`:
|
|
129
|
+
|
|
130
|
+
| Property | Type | Effect |
|
|
131
|
+
| ---------- | --------- | ------------------------------------------------------------------------------------- |
|
|
132
|
+
| `date` | `string` | A single day, `DD/MM/YYYY`, optionally followed by `HH:mm`. The year may be left out. |
|
|
133
|
+
| `start` | `string` | Start of a period, in the same format, with `duration`. |
|
|
134
|
+
| `duration` | `string` | Length of the period from `start`: `30d`, `2h`, `45m`. |
|
|
135
|
+
| `strict` | `boolean` | Reads the dates in UTC rather than in local time. |
|
|
136
|
+
| `now` | `Date` | For tests only: without it, the moment of the build stands. |
|
|
137
|
+
|
|
138
|
+
The fallbacks each take one bound:
|
|
139
|
+
|
|
140
|
+
| Property | Type | Effect |
|
|
141
|
+
| --------------------------- | -------- | ----------------------------------------------------------------------- |
|
|
142
|
+
| `start` on `FallbackBefore` | `string` | From when the content before the period shows. Without it, from always. |
|
|
143
|
+
| `end` on `FallbackAfter` | `string` | Until when the content after the period shows. Without it, for good. |
|
|
@@ -138,3 +138,12 @@ unnoticed for a long time. So does an unknown side.
|
|
|
138
138
|
|
|
139
139
|
A tooltip explains a term without leaving the sentence. A remark that needs
|
|
140
140
|
its own space is an [Admonition](./admonition/) instead.
|
|
141
|
+
|
|
142
|
+
## Properties
|
|
143
|
+
|
|
144
|
+
| Property | Type | Effect |
|
|
145
|
+
| ----------- | -------- | ------------------------------------------------------------------ |
|
|
146
|
+
| `text` | `string` | Content of the bubble. Required: an empty bubble would never show. |
|
|
147
|
+
| `placement` | `string` | `top`, the default, `bottom`, `left` or `right`. |
|
|
148
|
+
| `className` | `string` | Classes added to the term. |
|
|
149
|
+
| `style` | `object` | Inline styles on the term. |
|
|
@@ -195,3 +195,16 @@ label is refused too.
|
|
|
195
195
|
A tree is how this documentation shows the shape of a project. What those
|
|
196
196
|
folders become once built — the order, the addresses — is in
|
|
197
197
|
[Writing pages](../guide/writing-pages/).
|
|
198
|
+
|
|
199
|
+
## Properties
|
|
200
|
+
|
|
201
|
+
`TreeItem`:
|
|
202
|
+
|
|
203
|
+
| Property | Type | Effect |
|
|
204
|
+
| ----------- | --------------- | ------------------------------------------- |
|
|
205
|
+
| `label` | text or element | What the line shows. |
|
|
206
|
+
| `open` | `boolean` | Opens the branch as soon as the page opens. |
|
|
207
|
+
| `className` | `string` | Classes added to the line. |
|
|
208
|
+
| `style` | `object` | Inline styles on the line. |
|
|
209
|
+
|
|
210
|
+
`Tree` takes `className` and `style`.
|
|
@@ -144,3 +144,13 @@ build is enough to keep it right.
|
|
|
144
144
|
|
|
145
145
|
Setting one up takes a few lines in the pipeline that already builds the
|
|
146
146
|
site: [Deployment](../guide/deployment/) has the recipe.
|
|
147
|
+
|
|
148
|
+
## Properties
|
|
149
|
+
|
|
150
|
+
| Property | Type | Effect |
|
|
151
|
+
| ----------- | -------- | ------------------------------------------------------------------------------------------------------------- |
|
|
152
|
+
| `label` | `string` | Name read by a screen reader. By default, the words of the page's language — "Back to top", "Retour en haut". |
|
|
153
|
+
| `className` | `string` | Classes added to the button. |
|
|
154
|
+
| `style` | `object` | Inline styles on the button. |
|
|
155
|
+
|
|
156
|
+
Its children, when it has any, replace the arrow.
|
|
@@ -274,3 +274,19 @@ is full from the start — the value stays readable, which is what matters.
|
|
|
274
274
|
A level outside 0–100 stops the build, as does a gauge without a name, a level
|
|
275
275
|
that is not a number, or an unknown `shape`. A silent or overflowing bar goes
|
|
276
276
|
unnoticed on review.
|
|
277
|
+
|
|
278
|
+
## Properties
|
|
279
|
+
|
|
280
|
+
| Property | Type | Effect |
|
|
281
|
+
| ----------- | --------------- | ------------------------------------------------------------------------------ |
|
|
282
|
+
| `name` | text or element | What is measured. |
|
|
283
|
+
| `level` | `number` | The level, as a percentage. |
|
|
284
|
+
| `showValue` | `boolean` | Shows the percentage. On by default; off, the gauge still announces its value. |
|
|
285
|
+
| `shape` | `string` | `bar`, the default, or `circle`. |
|
|
286
|
+
| `icon` | element | Shown before the name — a `LogoIcon` fits there. |
|
|
287
|
+
| `color` | `string` | Colour of the fill: any CSS colour, the accent by default. |
|
|
288
|
+
| `label` | `string` | Name for screen readers, when `name` is not text. |
|
|
289
|
+
| `className` | `string` | Classes added to the gauge. |
|
|
290
|
+
| `style` | `object` | Inline styles on the gauge. |
|
|
291
|
+
|
|
292
|
+
Its children stand as a comment under the gauge.
|
|
@@ -171,3 +171,13 @@ A component loads no JavaScript, and this one is not going to introduce any.
|
|
|
171
171
|
|
|
172
172
|
A kind of admonition takes its mark through this same component — see
|
|
173
173
|
[Admonition](./admonition/).
|
|
174
|
+
|
|
175
|
+
## Properties
|
|
176
|
+
|
|
177
|
+
| Property | Type | Effect |
|
|
178
|
+
| ----------- | -------- | --------------------------------------------------------------------------------------- |
|
|
179
|
+
| `src` | `string` | An SVG of the project, or `prefix:name` from an installed icon collection. |
|
|
180
|
+
| `label` | `string` | What the icon means. Without it, the icon is decorative and hidden from screen readers. |
|
|
181
|
+
| `size` | `string` | Any CSS length. |
|
|
182
|
+
| `className` | `string` | Classes added to the icon. |
|
|
183
|
+
| `style` | `object` | Inline styles on the icon. |
|
|
@@ -46,3 +46,9 @@ without a word.
|
|
|
46
46
|
|
|
47
47
|
Which theme a project runs is one field of its configuration, and the whole
|
|
48
48
|
of what it changes is in [Themes](../guide/themes/).
|
|
49
|
+
|
|
50
|
+
## Properties
|
|
51
|
+
|
|
52
|
+
| Property | Type | Effect |
|
|
53
|
+
| ----------- | -------- | ---------------------------------------------------------------- |
|
|
54
|
+
| `framework` | `string` | `tailwind` or `custom`: the content shows only under that theme. |
|
|
@@ -74,3 +74,12 @@ themes, so this needs no variant:
|
|
|
74
74
|
Like every component here, the grid is built at the build. What reaches the
|
|
75
75
|
reader is a list of links: it works with JavaScript turned off, and a card
|
|
76
76
|
never waits for anything to become clickable.
|
|
77
|
+
|
|
78
|
+
## Properties
|
|
79
|
+
|
|
80
|
+
| Property | Type | Effect |
|
|
81
|
+
| ----------- | -------- | ----------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| `of` | `string` | `all`, the default; `series` for the sub-folders alone; `pages` for the pages beside the index alone. |
|
|
83
|
+
| `from` | `string` | Slug of another folder to list, instead of the one holding the page. |
|
|
84
|
+
| `className` | `string` | Classes added to the grid. |
|
|
85
|
+
| `style` | `object` | Inline styles on the grid. |
|
|
@@ -127,3 +127,25 @@ A `MenuLink` or a `MenuGroup` written outside a `Menu` stops the build, and so
|
|
|
127
127
|
does an entry without a target or a group without a title. Each of these would
|
|
128
128
|
otherwise render something that looks like a menu and leads nowhere — the kind
|
|
129
129
|
of fault a review does not catch.
|
|
130
|
+
|
|
131
|
+
## Properties
|
|
132
|
+
|
|
133
|
+
`Menu`:
|
|
134
|
+
|
|
135
|
+
| Property | Type | Effect |
|
|
136
|
+
| -------- | -------- | ----------------------------------------------------------------------------------------------------------- |
|
|
137
|
+
| `label` | `string` | Name for screen readers, and label of the button it folds into. By default, the page's own word for a menu. |
|
|
138
|
+
|
|
139
|
+
`MenuLink`:
|
|
140
|
+
|
|
141
|
+
| Property | Type | Effect |
|
|
142
|
+
| -------- | -------- | ------------------------------------------------- |
|
|
143
|
+
| `href` | `string` | Where it leads, resolved like any link. Required. |
|
|
144
|
+
|
|
145
|
+
`MenuGroup`:
|
|
146
|
+
|
|
147
|
+
| Property | Type | Effect |
|
|
148
|
+
| -------- | -------- | ------------------------------- |
|
|
149
|
+
| `title` | `string` | Heading of the group. Required. |
|
|
150
|
+
|
|
151
|
+
All three take `className` and `style`.
|
|
@@ -152,3 +152,12 @@ Its orphan branch keeps what was built, and the history keeps the sources.
|
|
|
152
152
|
Like every component here, it is rendered at the build. It is an `aside`
|
|
153
153
|
announced as a note, with its icon hidden from screen readers — the title
|
|
154
154
|
beside it already says the kind, and saying it twice helps nobody.
|
|
155
|
+
|
|
156
|
+
## Properties
|
|
157
|
+
|
|
158
|
+
| Property | Type | Effect |
|
|
159
|
+
| ----------- | -------- | ---------------------------------------------------------------------------------------------------------- |
|
|
160
|
+
| `type` | `string` | The kind: `note`, the default, `info`, `tip`, `attention`, `alert`, `danger`, or one the project declares. |
|
|
161
|
+
| `title` | `string` | Replaces the label of the kind, for this block alone. |
|
|
162
|
+
| `className` | `string` | Classes added to the block. |
|
|
163
|
+
| `style` | `object` | Inline styles on the block. |
|