gethtmlpress 0.0.0-stage → 0.1.0
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/LICENSE.md +9 -0
- package/README.md +48 -2
- package/build/actions/binary/resolve.d.ts +7 -0
- package/build/actions/binary/resolve.js +22 -0
- package/build/entrypoints/main.d.ts +2 -0
- package/build/entrypoints/main.js +28 -0
- package/build/settings.d.ts +14 -0
- package/build/settings.js +18 -0
- package/package.json +38 -4
- package/skills/htmlpress-authoring/SKILL.md +151 -0
- package/skills/htmlpress-configuration/SKILL.md +124 -0
- package/skills/htmlpress-customization/SKILL.md +135 -0
- package/skills/htmlpress-deployment/SKILL.md +72 -0
- package/skills/htmlpress-landing/SKILL.md +111 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 Evgeny Karev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,49 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Htmlpress
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Htmlpress turns a folder of HTML pages into a site. Each page keeps its own markup, and
|
|
4
|
+
htmlpress adds one layout, one theme, a navigation and a live-reloading dev server. It is
|
|
5
|
+
made for coding agents: they write plain semantic HTML, and the result looks consistent
|
|
6
|
+
without a framework, a build config or Tailwind.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install --global gethtmlpress
|
|
12
|
+
# or run it without installing
|
|
13
|
+
npx gethtmlpress build docs
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The package carries a prebuilt binary for Linux, macOS and Windows (x64 and arm64)
|
|
17
|
+
through a platform-specific optional dependency; no Rust toolchain is needed.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
htmlpress build docs # render docs/ into docs/.htmlpress/build
|
|
23
|
+
htmlpress start docs # serve it on http://localhost:8000, rebuilding on save
|
|
24
|
+
htmlpress build docs --json # the result as JSON, for scripts and agents
|
|
25
|
+
htmlpress --llms # every command's input and output schema, for agents
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
A page is any `.html` file in the folder: a full document or just a fragment. Its `<title>`
|
|
29
|
+
(else its first `<h1>`) names it in the navigation, `<meta name="order" content="1">` sorts it,
|
|
30
|
+
and `index.html` comes first. Every other file is copied as-is.
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<title>Getting started</title>
|
|
34
|
+
<meta name="order" content="1" />
|
|
35
|
+
|
|
36
|
+
<h1>Getting started</h1>
|
|
37
|
+
<p>Plain HTML, styled by the built-in theme.</p>
|
|
38
|
+
<htmlpress-callout type="warning"
|
|
39
|
+
><p>Light-DOM components cover what HTML lacks.</p></htmlpress-callout
|
|
40
|
+
>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Documentation
|
|
44
|
+
|
|
45
|
+
Read the docs at [htmlpress.dev](https://htmlpress.dev), themselves built with htmlpress.
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Find the htmlpress binary: the env override first, else the matching platform package. */
|
|
2
|
+
export declare function resolveBinary(props: {
|
|
3
|
+
platform: string;
|
|
4
|
+
arch: string;
|
|
5
|
+
env: Record<string, string | undefined>;
|
|
6
|
+
resolvePackage: (specifier: string) => string;
|
|
7
|
+
}): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BINARY_ENV, PACKAGE_NAME, PLATFORMS } from "../../settings.js";
|
|
2
|
+
/** Find the htmlpress binary: the env override first, else the matching platform package. */
|
|
3
|
+
export function resolveBinary(props) {
|
|
4
|
+
const override = props.env[BINARY_ENV];
|
|
5
|
+
if (override)
|
|
6
|
+
return override;
|
|
7
|
+
const key = `${props.platform}-${props.arch}`;
|
|
8
|
+
const platform = PLATFORMS[key];
|
|
9
|
+
if (!platform) {
|
|
10
|
+
const supported = Object.keys(PLATFORMS).join(", ");
|
|
11
|
+
throw new Error(`${PACKAGE_NAME} has no binary for ${key}; supported: ${supported}. ` +
|
|
12
|
+
`Set ${BINARY_ENV} to a binary built with cargo to run it anyway.`);
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
return props.resolvePackage(`${platform.packageName}/bin/${platform.binary}`);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new Error(`${platform.packageName} is not installed. Reinstall ${PACKAGE_NAME} without ` +
|
|
19
|
+
`--no-optional / --omit=optional so the binary for ${key} comes along.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb2x2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2FjdGlvbnMvYmluYXJ5L3Jlc29sdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFdkUsNkZBQTZGO0FBQzdGLE1BQU0sVUFBVSxhQUFhLENBQUMsS0FLN0I7SUFDQyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ3RDLElBQUksUUFBUTtRQUFFLE9BQU8sUUFBUSxDQUFBO0lBRTdCLE1BQU0sR0FBRyxHQUFHLEdBQUcsS0FBSyxDQUFDLFFBQVEsSUFBSSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUE7SUFDN0MsTUFBTSxRQUFRLEdBQUcsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBQy9CLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNkLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ25ELE1BQU0sSUFBSSxLQUFLLENBQ2IsR0FBRyxZQUFZLHNCQUFzQixHQUFHLGdCQUFnQixTQUFTLElBQUk7WUFDbkUsT0FBTyxVQUFVLGlEQUFpRCxDQUNyRSxDQUFBO0lBQ0gsQ0FBQztJQUNELElBQUksQ0FBQztRQUNILE9BQU8sS0FBSyxDQUFDLGNBQWMsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxXQUFXLFFBQVEsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUE7SUFDL0UsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE1BQU0sSUFBSSxLQUFLLENBQ2IsR0FBRyxRQUFRLENBQUMsV0FBVyxnQ0FBZ0MsWUFBWSxXQUFXO1lBQzVFLHFEQUFxRCxHQUFHLGVBQWUsQ0FDMUUsQ0FBQTtJQUNILENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQklOQVJZX0VOViwgUEFDS0FHRV9OQU1FLCBQTEFURk9STVMgfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3MudHNcIlxuXG4vKiogRmluZCB0aGUgaHRtbHByZXNzIGJpbmFyeTogdGhlIGVudiBvdmVycmlkZSBmaXJzdCwgZWxzZSB0aGUgbWF0Y2hpbmcgcGxhdGZvcm0gcGFja2FnZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQmluYXJ5KHByb3BzOiB7XG4gIHBsYXRmb3JtOiBzdHJpbmdcbiAgYXJjaDogc3RyaW5nXG4gIGVudjogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPlxuICByZXNvbHZlUGFja2FnZTogKHNwZWNpZmllcjogc3RyaW5nKSA9PiBzdHJpbmdcbn0pIHtcbiAgY29uc3Qgb3ZlcnJpZGUgPSBwcm9wcy5lbnZbQklOQVJZX0VOVl1cbiAgaWYgKG92ZXJyaWRlKSByZXR1cm4gb3ZlcnJpZGVcblxuICBjb25zdCBrZXkgPSBgJHtwcm9wcy5wbGF0Zm9ybX0tJHtwcm9wcy5hcmNofWBcbiAgY29uc3QgcGxhdGZvcm0gPSBQTEFURk9STVNba2V5XVxuICBpZiAoIXBsYXRmb3JtKSB7XG4gICAgY29uc3Qgc3VwcG9ydGVkID0gT2JqZWN0LmtleXMoUExBVEZPUk1TKS5qb2luKFwiLCBcIilcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtQQUNLQUdFX05BTUV9IGhhcyBubyBiaW5hcnkgZm9yICR7a2V5fTsgc3VwcG9ydGVkOiAke3N1cHBvcnRlZH0uIGAgK1xuICAgICAgICBgU2V0ICR7QklOQVJZX0VOVn0gdG8gYSBiaW5hcnkgYnVpbHQgd2l0aCBjYXJnbyB0byBydW4gaXQgYW55d2F5LmAsXG4gICAgKVxuICB9XG4gIHRyeSB7XG4gICAgcmV0dXJuIHByb3BzLnJlc29sdmVQYWNrYWdlKGAke3BsYXRmb3JtLnBhY2thZ2VOYW1lfS9iaW4vJHtwbGF0Zm9ybS5iaW5hcnl9YClcbiAgfSBjYXRjaCB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7cGxhdGZvcm0ucGFja2FnZU5hbWV9IGlzIG5vdCBpbnN0YWxsZWQuIFJlaW5zdGFsbCAke1BBQ0tBR0VfTkFNRX0gd2l0aG91dCBgICtcbiAgICAgICAgYC0tbm8tb3B0aW9uYWwgLyAtLW9taXQ9b3B0aW9uYWwgc28gdGhlIGJpbmFyeSBmb3IgJHtrZXl9IGNvbWVzIGFsb25nLmAsXG4gICAgKVxuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { resolveBinary } from "../actions/binary/resolve.js";
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
let binary;
|
|
7
|
+
try {
|
|
8
|
+
binary = resolveBinary({
|
|
9
|
+
platform: process.platform,
|
|
10
|
+
arch: process.arch,
|
|
11
|
+
env: process.env,
|
|
12
|
+
resolvePackage: specifier => require.resolve(specifier),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error(`error: ${error instanceof Error ? error.message : String(error)}`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
|
|
20
|
+
if (result.error) {
|
|
21
|
+
console.error(`error: cannot run ${binary}: ${result.error.message}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
// Re-raise a signal so a parent sees the same death the binary had (Ctrl-C under start)
|
|
25
|
+
if (result.signal)
|
|
26
|
+
process.kill(process.pid, result.signal);
|
|
27
|
+
process.exit(result.status ?? 1);
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2VudHJ5cG9pbnRzL21haW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUNBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQTtBQUM5QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzNDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQTtBQUU1RCxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUE7QUFFOUMsSUFBSSxNQUFjLENBQUE7QUFDbEIsSUFBSSxDQUFDO0lBQ0gsTUFBTSxHQUFHLGFBQWEsQ0FBQztRQUNyQixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7UUFDMUIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO1FBQ2xCLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRztRQUNoQixjQUFjLEVBQUUsU0FBUyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztLQUN4RCxDQUFDLENBQUE7QUFDSixDQUFDO0FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztJQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsVUFBVSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0lBQ2pGLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDakIsQ0FBQztBQUVELE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQTtBQUM3RSxJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNqQixPQUFPLENBQUMsS0FBSyxDQUFDLHFCQUFxQixNQUFNLEtBQUssTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFBO0lBQ3JFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDakIsQ0FBQztBQUNELHdGQUF3RjtBQUN4RixJQUFJLE1BQU0sQ0FBQyxNQUFNO0lBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQTtBQUMzRCxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG5pbXBvcnQgeyBzcGF3blN5bmMgfSBmcm9tIFwibm9kZTpjaGlsZF9wcm9jZXNzXCJcbmltcG9ydCB7IGNyZWF0ZVJlcXVpcmUgfSBmcm9tIFwibm9kZTptb2R1bGVcIlxuaW1wb3J0IHsgcmVzb2x2ZUJpbmFyeSB9IGZyb20gXCIuLi9hY3Rpb25zL2JpbmFyeS9yZXNvbHZlLnRzXCJcblxuY29uc3QgcmVxdWlyZSA9IGNyZWF0ZVJlcXVpcmUoaW1wb3J0Lm1ldGEudXJsKVxuXG5sZXQgYmluYXJ5OiBzdHJpbmdcbnRyeSB7XG4gIGJpbmFyeSA9IHJlc29sdmVCaW5hcnkoe1xuICAgIHBsYXRmb3JtOiBwcm9jZXNzLnBsYXRmb3JtLFxuICAgIGFyY2g6IHByb2Nlc3MuYXJjaCxcbiAgICBlbnY6IHByb2Nlc3MuZW52LFxuICAgIHJlc29sdmVQYWNrYWdlOiBzcGVjaWZpZXIgPT4gcmVxdWlyZS5yZXNvbHZlKHNwZWNpZmllciksXG4gIH0pXG59IGNhdGNoIChlcnJvcikge1xuICBjb25zb2xlLmVycm9yKGBlcnJvcjogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YClcbiAgcHJvY2Vzcy5leGl0KDEpXG59XG5cbmNvbnN0IHJlc3VsdCA9IHNwYXduU3luYyhiaW5hcnksIHByb2Nlc3MuYXJndi5zbGljZSgyKSwgeyBzdGRpbzogXCJpbmhlcml0XCIgfSlcbmlmIChyZXN1bHQuZXJyb3IpIHtcbiAgY29uc29sZS5lcnJvcihgZXJyb3I6IGNhbm5vdCBydW4gJHtiaW5hcnl9OiAke3Jlc3VsdC5lcnJvci5tZXNzYWdlfWApXG4gIHByb2Nlc3MuZXhpdCgxKVxufVxuLy8gUmUtcmFpc2UgYSBzaWduYWwgc28gYSBwYXJlbnQgc2VlcyB0aGUgc2FtZSBkZWF0aCB0aGUgYmluYXJ5IGhhZCAoQ3RybC1DIHVuZGVyIHN0YXJ0KVxuaWYgKHJlc3VsdC5zaWduYWwpIHByb2Nlc3Mua2lsbChwcm9jZXNzLnBpZCwgcmVzdWx0LnNpZ25hbClcbnByb2Nlc3MuZXhpdChyZXN1bHQuc3RhdHVzID8/IDEpXG4iXX0=
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Platform {
|
|
2
|
+
/** The npm package that carries this platform's binary. */
|
|
3
|
+
packageName: string;
|
|
4
|
+
/** The Rust target the binary is compiled for. */
|
|
5
|
+
target: string;
|
|
6
|
+
/** The binary's file name inside the package's `bin/`. */
|
|
7
|
+
binary: string;
|
|
8
|
+
}
|
|
9
|
+
/** The npm package users install; it pulls in the one platform package that matches. */
|
|
10
|
+
export declare const PACKAGE_NAME = "gethtmlpress";
|
|
11
|
+
/** An environment variable that points at a binary to run instead of the installed one. */
|
|
12
|
+
export declare const BINARY_ENV = "HTMLPRESS_BINARY";
|
|
13
|
+
/** Every published platform, keyed by `${process.platform}-${process.arch}`. */
|
|
14
|
+
export declare const PLATFORMS: Record<string, Platform>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** The npm package users install; it pulls in the one platform package that matches. */
|
|
2
|
+
export const PACKAGE_NAME = "gethtmlpress";
|
|
3
|
+
/** An environment variable that points at a binary to run instead of the installed one. */
|
|
4
|
+
export const BINARY_ENV = "HTMLPRESS_BINARY";
|
|
5
|
+
/** Every published platform, keyed by `${process.platform}-${process.arch}`. */
|
|
6
|
+
export const PLATFORMS = {
|
|
7
|
+
"linux-x64": createPlatform("linux-x64", "x86_64-unknown-linux-musl"),
|
|
8
|
+
"linux-arm64": createPlatform("linux-arm64", "aarch64-unknown-linux-musl"),
|
|
9
|
+
"darwin-x64": createPlatform("darwin-x64", "x86_64-apple-darwin"),
|
|
10
|
+
"darwin-arm64": createPlatform("darwin-arm64", "aarch64-apple-darwin"),
|
|
11
|
+
"win32-x64": createPlatform("win32-x64", "x86_64-pc-windows-msvc"),
|
|
12
|
+
"win32-arm64": createPlatform("win32-arm64", "aarch64-pc-windows-msvc"),
|
|
13
|
+
};
|
|
14
|
+
function createPlatform(key, target) {
|
|
15
|
+
const binary = key.startsWith("win32") ? "htmlpress.exe" : "htmlpress";
|
|
16
|
+
return { packageName: `@htmlpress/${key}`, target, binary };
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dGluZ3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zZXR0aW5ncy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFTQSx3RkFBd0Y7QUFDeEYsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLGNBQWMsQ0FBQTtBQUUxQywyRkFBMkY7QUFDM0YsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHLGtCQUFrQixDQUFBO0FBRTVDLGdGQUFnRjtBQUNoRixNQUFNLENBQUMsTUFBTSxTQUFTLEdBQTZCO0lBQ2pELFdBQVcsRUFBRSxjQUFjLENBQUMsV0FBVyxFQUFFLDJCQUEyQixDQUFDO0lBQ3JFLGFBQWEsRUFBRSxjQUFjLENBQUMsYUFBYSxFQUFFLDRCQUE0QixDQUFDO0lBQzFFLFlBQVksRUFBRSxjQUFjLENBQUMsWUFBWSxFQUFFLHFCQUFxQixDQUFDO0lBQ2pFLGNBQWMsRUFBRSxjQUFjLENBQUMsY0FBYyxFQUFFLHNCQUFzQixDQUFDO0lBQ3RFLFdBQVcsRUFBRSxjQUFjLENBQUMsV0FBVyxFQUFFLHdCQUF3QixDQUFDO0lBQ2xFLGFBQWEsRUFBRSxjQUFjLENBQUMsYUFBYSxFQUFFLHlCQUF5QixDQUFDO0NBQ3hFLENBQUE7QUFFRCxTQUFTLGNBQWMsQ0FBQyxHQUFXLEVBQUUsTUFBYztJQUNqRCxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQTtJQUN0RSxPQUFPLEVBQUUsV0FBVyxFQUFFLGNBQWMsR0FBRyxFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFBO0FBQzdELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgaW50ZXJmYWNlIFBsYXRmb3JtIHtcbiAgLyoqIFRoZSBucG0gcGFja2FnZSB0aGF0IGNhcnJpZXMgdGhpcyBwbGF0Zm9ybSdzIGJpbmFyeS4gKi9cbiAgcGFja2FnZU5hbWU6IHN0cmluZ1xuICAvKiogVGhlIFJ1c3QgdGFyZ2V0IHRoZSBiaW5hcnkgaXMgY29tcGlsZWQgZm9yLiAqL1xuICB0YXJnZXQ6IHN0cmluZ1xuICAvKiogVGhlIGJpbmFyeSdzIGZpbGUgbmFtZSBpbnNpZGUgdGhlIHBhY2thZ2UncyBgYmluL2AuICovXG4gIGJpbmFyeTogc3RyaW5nXG59XG5cbi8qKiBUaGUgbnBtIHBhY2thZ2UgdXNlcnMgaW5zdGFsbDsgaXQgcHVsbHMgaW4gdGhlIG9uZSBwbGF0Zm9ybSBwYWNrYWdlIHRoYXQgbWF0Y2hlcy4gKi9cbmV4cG9ydCBjb25zdCBQQUNLQUdFX05BTUUgPSBcImdldGh0bWxwcmVzc1wiXG5cbi8qKiBBbiBlbnZpcm9ubWVudCB2YXJpYWJsZSB0aGF0IHBvaW50cyBhdCBhIGJpbmFyeSB0byBydW4gaW5zdGVhZCBvZiB0aGUgaW5zdGFsbGVkIG9uZS4gKi9cbmV4cG9ydCBjb25zdCBCSU5BUllfRU5WID0gXCJIVE1MUFJFU1NfQklOQVJZXCJcblxuLyoqIEV2ZXJ5IHB1Ymxpc2hlZCBwbGF0Zm9ybSwga2V5ZWQgYnkgYCR7cHJvY2Vzcy5wbGF0Zm9ybX0tJHtwcm9jZXNzLmFyY2h9YC4gKi9cbmV4cG9ydCBjb25zdCBQTEFURk9STVM6IFJlY29yZDxzdHJpbmcsIFBsYXRmb3JtPiA9IHtcbiAgXCJsaW51eC14NjRcIjogY3JlYXRlUGxhdGZvcm0oXCJsaW51eC14NjRcIiwgXCJ4ODZfNjQtdW5rbm93bi1saW51eC1tdXNsXCIpLFxuICBcImxpbnV4LWFybTY0XCI6IGNyZWF0ZVBsYXRmb3JtKFwibGludXgtYXJtNjRcIiwgXCJhYXJjaDY0LXVua25vd24tbGludXgtbXVzbFwiKSxcbiAgXCJkYXJ3aW4teDY0XCI6IGNyZWF0ZVBsYXRmb3JtKFwiZGFyd2luLXg2NFwiLCBcIng4Nl82NC1hcHBsZS1kYXJ3aW5cIiksXG4gIFwiZGFyd2luLWFybTY0XCI6IGNyZWF0ZVBsYXRmb3JtKFwiZGFyd2luLWFybTY0XCIsIFwiYWFyY2g2NC1hcHBsZS1kYXJ3aW5cIiksXG4gIFwid2luMzIteDY0XCI6IGNyZWF0ZVBsYXRmb3JtKFwid2luMzIteDY0XCIsIFwieDg2XzY0LXBjLXdpbmRvd3MtbXN2Y1wiKSxcbiAgXCJ3aW4zMi1hcm02NFwiOiBjcmVhdGVQbGF0Zm9ybShcIndpbjMyLWFybTY0XCIsIFwiYWFyY2g2NC1wYy13aW5kb3dzLW1zdmNcIiksXG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVBsYXRmb3JtKGtleTogc3RyaW5nLCB0YXJnZXQ6IHN0cmluZyk6IFBsYXRmb3JtIHtcbiAgY29uc3QgYmluYXJ5ID0ga2V5LnN0YXJ0c1dpdGgoXCJ3aW4zMlwiKSA/IFwiaHRtbHByZXNzLmV4ZVwiIDogXCJodG1scHJlc3NcIlxuICByZXR1cm4geyBwYWNrYWdlTmFtZTogYEBodG1scHJlc3MvJHtrZXl9YCwgdGFyZ2V0LCBiaW5hcnkgfVxufVxuIl19
|
package/package.json
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gethtmlpress",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Turn a folder of HTML pages into a site: one layout, one theme, live reload, made for agents",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agents",
|
|
7
|
+
"html",
|
|
8
|
+
"htmlpress",
|
|
9
|
+
"llm",
|
|
10
|
+
"static-site"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://htmlpress.dev",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Evgeny Karev",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/datisthq/htmlpress.git",
|
|
18
|
+
"directory": "typescript"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"htmlpress": "./build/entrypoints/main.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"build",
|
|
25
|
+
"skills"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"optionalDependencies": {
|
|
33
|
+
"@htmlpress/linux-x64": "0.1.0",
|
|
34
|
+
"@htmlpress/linux-arm64": "0.1.0",
|
|
35
|
+
"@htmlpress/darwin-x64": "0.1.0",
|
|
36
|
+
"@htmlpress/darwin-arm64": "0.1.0",
|
|
37
|
+
"@htmlpress/win32-x64": "0.1.0",
|
|
38
|
+
"@htmlpress/win32-arm64": "0.1.0"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: htmlpress-authoring
|
|
3
|
+
description: Use when writing or editing pages in an htmlpress project — the page contract (title, order, head, metas), headings and the TOC, semantic HTML, the htmlpress-* components, code blocks, math, includes and checking the build.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Htmlpress Authoring
|
|
7
|
+
|
|
8
|
+
An htmlpress project is a folder of `.html` pages. Htmlpress wraps each in one layout with a
|
|
9
|
+
navigation and a theme, so a page carries content only: no `<nav>`, no site header, no styling.
|
|
10
|
+
|
|
11
|
+
## When to use this skill
|
|
12
|
+
|
|
13
|
+
Invoke when the user asks to:
|
|
14
|
+
|
|
15
|
+
- Add, edit, move or reorder pages, or group them in the navigation.
|
|
16
|
+
- Use a callout, tabs, cards, steps or another component, or a code block, formula or diagram.
|
|
17
|
+
- Pull a shared partial or a source file into a page.
|
|
18
|
+
|
|
19
|
+
The config keys are in `htmlpress-configuration`; a different look in `htmlpress-customization`.
|
|
20
|
+
|
|
21
|
+
## A page
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<title>Getting started</title>
|
|
25
|
+
<meta name="description" content="Install and run it in a minute." />
|
|
26
|
+
<meta name="order" content="1" />
|
|
27
|
+
|
|
28
|
+
<h1>Getting started</h1>
|
|
29
|
+
<p>Plain semantic HTML.</p>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- A full document (`<!doctype html>…<body>`) and a bare fragment are read the same way.
|
|
33
|
+
- `<title>` names the page in the navigation and the tab; without it the first `<h1>`, then the
|
|
34
|
+
file name. Give every page one `<title>` and one `<h1>`.
|
|
35
|
+
- `<meta name="order" content="N">` (an integer) sorts the navigation, lower first.
|
|
36
|
+
`index.html` always comes first; unordered pages follow by path, then negative orders
|
|
37
|
+
(`-1` pins a page last).
|
|
38
|
+
- Other `<head>` tags (`<link>`, `<style>`, `<script>`) are kept and added after the theme.
|
|
39
|
+
- The navigation nests pages by folder at any depth (`guides/cli/…` inside `guides/…`), each
|
|
40
|
+
group named by its `index.html`, whose title links to it.
|
|
41
|
+
- Pages are written to the same path, so link between them with relative hrefs
|
|
42
|
+
(`guides/build.html`). Images and other files are copied as-is; a relative `src`,
|
|
43
|
+
`srcset` or `poster` resolves from the source file, even when the page moves.
|
|
44
|
+
- A root `404.html` is the not-found page, kept out of the navigation; without one a built-in
|
|
45
|
+
is used.
|
|
46
|
+
|
|
47
|
+
## Page metas
|
|
48
|
+
|
|
49
|
+
| Meta | Effect |
|
|
50
|
+
| -------------------------------------------- | ------------------------------------------------------------ |
|
|
51
|
+
| `description` | the page's summary for search, previews and `llms.txt` |
|
|
52
|
+
| `image` | its social preview image, relative to the file; needs `site` |
|
|
53
|
+
| `date` (`YYYY-MM-DD`), `author` (repeatable) | dates and signs it (a byline; none with `layout`) |
|
|
54
|
+
| `keywords` (`a, b`) | tags it (a blog post's tag pages) |
|
|
55
|
+
| `label` | a short name in the navigation |
|
|
56
|
+
| `icon` | a Lucide icon; top-level entries and folder index pages |
|
|
57
|
+
| `path` (`/start/`) | serves the page at another URL |
|
|
58
|
+
| `sidebar` (`false`) | built, not listed |
|
|
59
|
+
| `toc` (`false`) | no table of contents |
|
|
60
|
+
| `layout` (`<name>`) | another layout, from `htmlpress-customization` |
|
|
61
|
+
| `language` (`<code>`) | marks the page a translation |
|
|
62
|
+
| `source-url`, `source-action` (`view`) | the page's source link |
|
|
63
|
+
|
|
64
|
+
A file that cannot carry metas, such as a `README.md`, gets them from `patches` in the config.
|
|
65
|
+
|
|
66
|
+
## Translations
|
|
67
|
+
|
|
68
|
+
With `languages` in the config, a translation is `page.<code>.html` beside `page.html`, or a
|
|
69
|
+
file with `<meta name="language" content="<code>">`. It pairs with the original by URL below the
|
|
70
|
+
language prefix, so a renamed one needs the same `<meta name="path">`. Untranslated pages stay
|
|
71
|
+
listed in every language with a badge and link to the original.
|
|
72
|
+
|
|
73
|
+
## Headings
|
|
74
|
+
|
|
75
|
+
- `<h2>` to `<h4>` outside components make the page's table of contents; any `<h2>` to `<h6>`
|
|
76
|
+
without an `id` gets a slug of its text and an anchor link. Give a heading an `id` only when a link needs it fixed.
|
|
77
|
+
- A heading takes `data-toc="false"` (shown, not in the TOC) or `data-toc="only"` (in the TOC,
|
|
78
|
+
not shown); `<htmlpress-toc level="2">` (2–4, default 3) in a page renders its TOC inline.
|
|
79
|
+
|
|
80
|
+
## Semantic HTML first
|
|
81
|
+
|
|
82
|
+
The theme styles the elements themselves: headings, `<p>`, lists, `<table>`, `<pre><code>`,
|
|
83
|
+
`<blockquote>`, `<details>`/`<summary>`, `<figure>`/`<figcaption>`, `<dl>`, `<kbd>`, `<hr>`.
|
|
84
|
+
|
|
85
|
+
- No inline `style`, no classes for looks, no utility CSS: every page should look like the same
|
|
86
|
+
site. A site-wide change is a token (`htmlpress-customization`).
|
|
87
|
+
- An image with `data-theme="light"` or `"dark"` shows in that theme only.
|
|
88
|
+
- `<abbr title>` and footnote references (`<sup><a href="#n1">` to an `<li id="n1">`) show a
|
|
89
|
+
hover hint; headings get a link on their own.
|
|
90
|
+
- Bare URLs and emails in prose become links and GitHub shortcodes (`:rocket:`) become emoji at
|
|
91
|
+
build time; text in links, code and `data-literal` elements stays as written.
|
|
92
|
+
- LaTeX: `$E = mc^2$` inline and `$$…$$` as a block (pandoc's rule keeps `$5 and $10` text; `\$`
|
|
93
|
+
is a dollar), or `<htmlpress-math display>…</htmlpress-math>`; rendered to MathML at build
|
|
94
|
+
time, and invalid LaTeX fails the build.
|
|
95
|
+
- `<htmlpress-include src="partial.html">` pastes in another file by path, relative to the page:
|
|
96
|
+
an `.html` body, rendered `.md`, or any other file as a titled code block that takes
|
|
97
|
+
`data-lines` and the other code block attributes. Exclude the partials folder in the config.
|
|
98
|
+
|
|
99
|
+
## Code blocks
|
|
100
|
+
|
|
101
|
+
- Escape code inside `<pre><code>`: `<` and `&`. Name its language,
|
|
102
|
+
`<pre><code class="language-rust">`, to highlight it at build time; an inline
|
|
103
|
+
`<code class="language-js">` is highlighted too.
|
|
104
|
+
- `data-lines="2,4-5"` marks lines, `data-line-numbers` numbers them, `data-add`/`data-remove`
|
|
105
|
+
show a diff, `data-focus` dims the other lines, `data-error`/`data-warning` flag lines and
|
|
106
|
+
`data-words="a,b"` marks words.
|
|
107
|
+
- `<pre data-title="file.yaml">` adds a title bar with the language's logo;
|
|
108
|
+
`<pre data-collapse="10">` shows 10 lines with an Expand bar.
|
|
109
|
+
- `<pre><code class="language-ansi">` renders terminal color escapes (raw or `[31m`).
|
|
110
|
+
- Every block gets copy and wrap buttons. Tabs holding only code blocks join into one framed block.
|
|
111
|
+
|
|
112
|
+
## Components
|
|
113
|
+
|
|
114
|
+
Only these; anything else is plain HTML. Put block content (`<p>`, `<h3>`, `<pre>`) inside a
|
|
115
|
+
component, not bare text.
|
|
116
|
+
|
|
117
|
+
| Element | Use |
|
|
118
|
+
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
|
|
119
|
+
| `<htmlpress-callout type="…" label="…">` | a note; `type` is `info` (default), `note`, `tip`, `success`, `warning`, `danger` |
|
|
120
|
+
| `<htmlpress-grid cols="2">` + `<htmlpress-card>` | cards in columns (`cols` 2–4, else responsive); `<h3><a>` links a card |
|
|
121
|
+
| `<htmlpress-tabs sync="…">` + `<section title>` | tabs, one per `<section>`; tabs sharing `sync` switch together |
|
|
122
|
+
| `<htmlpress-steps>` + `<ol>` | numbered steps, one per `<li>`, each led by an `<h3>` |
|
|
123
|
+
| `<htmlpress-badge type="…">` | an inline label; `type` as a callout's, `neutral`, `outline`, `ghost` or `link` |
|
|
124
|
+
| `<htmlpress-file-tree>` + nested `<ul>` | a file tree; an `<li>` holding a `<ul>` is a folder |
|
|
125
|
+
| `<htmlpress-table>` + `<table>` | a table sorted by a click on a `<thead>` header |
|
|
126
|
+
| `<htmlpress-zoom>` + `<img>` | an image that opens full screen on click |
|
|
127
|
+
| `<htmlpress-icon name="…">` | an inline Lucide icon; names at htmlpress.dev/authoring/rich-elements.html#icons |
|
|
128
|
+
| `<htmlpress-button type="…">` + `<a>` | a call-to-action link; `type` `secondary`/`outline`/`ghost`/`link`/`positive`/`warning`/`destructive`, `size` `sm`/`lg` |
|
|
129
|
+
| `<htmlpress-package-tabs>` + `<pre><code>` | one `npm`/`npx` command, built into npm, pnpm, yarn and bun tabs |
|
|
130
|
+
| `<htmlpress-terminal title="…">` + `<pre>` | terminal output: `<kbd>` command, `<samp>` output, `<ins>`/`<del>`/`<mark>` colours |
|
|
131
|
+
| `<htmlpress-youtube>` + `<a href>` | a YouTube video player for the linked video |
|
|
132
|
+
| `<htmlpress-soundcloud>` + `<a href>` | a SoundCloud player for the linked track |
|
|
133
|
+
| `<htmlpress-mermaid>` + `<pre>` | a Mermaid diagram from the source in `<pre>` (escape `<` and `&`) |
|
|
134
|
+
|
|
135
|
+
## Verification
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
htmlpress build <root> --json # {"output": "...", "pages": N, "files": N}; errors on stderr
|
|
139
|
+
htmlpress start <root> # http://localhost:8000 (or the next free port to 8009); --host for the network
|
|
140
|
+
htmlpress --llms # every command's input and output schema
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
After editing, run `build --json` and confirm `pages` counts every page and the exit code is 0.
|
|
144
|
+
For a visual check, run `start` and open the page; look at it narrow as well as wide. Never edit
|
|
145
|
+
`.htmlpress/build/`: every build replaces it.
|
|
146
|
+
|
|
147
|
+
## References
|
|
148
|
+
|
|
149
|
+
- Pages: https://htmlpress.dev/authoring/
|
|
150
|
+
- Components: https://htmlpress.dev/authoring/rich-elements.html
|
|
151
|
+
- Code blocks: https://htmlpress.dev/authoring/code-blocks.html
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: htmlpress-configuration
|
|
3
|
+
description: Use when editing htmlpress.yaml — site metadata, base, include/exclude globs, code themes, sections (blog, changelog, custom), links, languages, versions, patches, head tags, agent skills, content signals and the edit link.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Htmlpress Configuration
|
|
7
|
+
|
|
8
|
+
`htmlpress.yaml` at the project root is optional; its keys follow Livemark's config. An unknown
|
|
9
|
+
key is an error, so a typo fails the build instead of being ignored.
|
|
10
|
+
|
|
11
|
+
## When to use this skill
|
|
12
|
+
|
|
13
|
+
Invoke when the user asks to:
|
|
14
|
+
|
|
15
|
+
- Set the site's title, description, logo, favicon, banner or URL.
|
|
16
|
+
- Choose which files become pages, or leave some out.
|
|
17
|
+
- Add a blog, a changelog or another section, or links in the header or sidebar.
|
|
18
|
+
- Publish the site in several languages, or keep docs for older versions.
|
|
19
|
+
- Give a file metas it cannot carry, or publish a Markdown file as a page.
|
|
20
|
+
- Add tags to every page's `<head>`, publish skills or set `robots.txt` signals.
|
|
21
|
+
|
|
22
|
+
## The config shape
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
site: https://example.com
|
|
26
|
+
base: /
|
|
27
|
+
title: Acme
|
|
28
|
+
description: Acme's docs.
|
|
29
|
+
logo: /logo.svg
|
|
30
|
+
favicon: /favicon.svg
|
|
31
|
+
banner: <a href="/blog/">We shipped 2.0</a>
|
|
32
|
+
include: [docs/**/*.html]
|
|
33
|
+
exclude: [docs/includes/**]
|
|
34
|
+
codeThemeLight: catppuccin-latte
|
|
35
|
+
codeThemeDark: catppuccin-mocha
|
|
36
|
+
edit: https://github.com/acme/acme/edit/main/
|
|
37
|
+
links:
|
|
38
|
+
- { title: GitHub, url: https://github.com/acme/acme, position: header, icon: github }
|
|
39
|
+
sections:
|
|
40
|
+
- { title: Blog, prefix: /blog/, type: blog }
|
|
41
|
+
patches:
|
|
42
|
+
- { file: README.md, article: { title: Overview, order: 1 } }
|
|
43
|
+
skills: [.skills/*/SKILL.md]
|
|
44
|
+
contentSignals: { search: true, aiInput: true, aiTrain: false }
|
|
45
|
+
head:
|
|
46
|
+
meta: [{ name: theme-color, content: "#0b5" }]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- `site` — the canonical origin; with it a build writes `sitemap.xml` and absolute feed URLs.
|
|
50
|
+
- `base` — a sub-path such as `/repo/`. Root-relative URLs get it as a prefix, so write them
|
|
51
|
+
without it.
|
|
52
|
+
- `title`, `description`, `logo`, `favicon` (URLs) and `banner` (HTML above the header).
|
|
53
|
+
- `include` — globs of the `.html` files that become pages, default `**/*.html`. Only files under
|
|
54
|
+
a glob's base, its folders before the first wildcard, are read, and they are served without it:
|
|
55
|
+
`docs/**/*.html` serves `docs/guide.html` at `/guide.html`. Other files there are copied as-is.
|
|
56
|
+
- `exclude` — globs left out of the build: partials for includes, drafts.
|
|
57
|
+
- `codeThemeLight`, `codeThemeDark` — the code block themes, by Shiki theme name.
|
|
58
|
+
- `edit` — a URL prefix for an "Edit on GitHub" link.
|
|
59
|
+
|
|
60
|
+
## Sections
|
|
61
|
+
|
|
62
|
+
Each has a `title` and a `prefix`; optional `icon`, `position`, `siteTitle`, `siteLink` and
|
|
63
|
+
`siteDescription`. The sidebar and pager then show only the open section's pages.
|
|
64
|
+
|
|
65
|
+
- `type: article` (the default) — the pages under the prefix.
|
|
66
|
+
- `type: blog` — dated posts (`date`, `author`, `keywords` metas) with tag pages and RSS.
|
|
67
|
+
- `type: changelog` plus `source` — a page per version of a Markdown changelog, or per
|
|
68
|
+
release of a GitHub repository URL (`GITHUB_TOKEN` when set, cached in `.htmlpress/cache/`); `version: true`
|
|
69
|
+
shows the latest version beside the title.
|
|
70
|
+
- `type: custom` plus `url` — a link to anywhere.
|
|
71
|
+
|
|
72
|
+
## Links
|
|
73
|
+
|
|
74
|
+
Each has `title`, `url` and `position: header | sidebar`; optional `icon` and `prefix`, which
|
|
75
|
+
shows the link only under one folder.
|
|
76
|
+
|
|
77
|
+
## Languages
|
|
78
|
+
|
|
79
|
+
`languages` lists each `code` and `label`, optional `locale`, `dir` (`ltr` or `rtl`), `flag` and
|
|
80
|
+
`messages` replacing UI strings. The first is the default; the others are served under
|
|
81
|
+
`/<code>/`. With `languages`, `title`, `description`, `banner` and link and section titles also
|
|
82
|
+
take a map by language code (`title: { en: Docs, es: Documentos }`). Translated pages are in
|
|
83
|
+
`htmlpress-authoring`.
|
|
84
|
+
|
|
85
|
+
## Versions
|
|
86
|
+
|
|
87
|
+
There is no dedicated option. For a few versions on one branch, put each older version's pages
|
|
88
|
+
in a folder with a section of its own (`title: v1`, `prefix: /v1/`, `siteTitle: Acme v1`);
|
|
89
|
+
search stays site-wide, so results mix versions. For majors on their own branches, deploy each
|
|
90
|
+
branch as its own site (`base`, a `banner` linking to the latest) and link them with a `custom`
|
|
91
|
+
section.
|
|
92
|
+
|
|
93
|
+
## Patches
|
|
94
|
+
|
|
95
|
+
Each patch is a `file` and an `article` of metas (`title`, `label`, `description`, `icon`,
|
|
96
|
+
`order`, `path`, `sidebar`, `toc`, `image`, `author`, `date`, `tags`, `sourceUrl`,
|
|
97
|
+
`sourceAction`), set without touching the file; a patched `.md` file such as `README.md` is
|
|
98
|
+
published as a page. A patched path outside the project, through a symlink or into a dot-folder is refused.
|
|
99
|
+
|
|
100
|
+
## Agents and head
|
|
101
|
+
|
|
102
|
+
- `skills` — globs of `SKILL.md` files to publish under `.well-known/agent-skills/`.
|
|
103
|
+
- `contentSignals` — `search`, `aiInput`, `aiTrain` for `robots.txt`.
|
|
104
|
+
- `head` — `meta`, `links`, `scripts`: lists of attribute maps added to every page; a script's
|
|
105
|
+
`children` is its source.
|
|
106
|
+
|
|
107
|
+
## Rules of thumb
|
|
108
|
+
|
|
109
|
+
- Change one key at a time and rebuild: the error names the key.
|
|
110
|
+
- Keep the config for site-wide facts; a page's own facts are its metas (`htmlpress-authoring`).
|
|
111
|
+
- `htmlpress start` rebuilds on a config change; no restart needed.
|
|
112
|
+
|
|
113
|
+
## Verification
|
|
114
|
+
|
|
115
|
+
Run `htmlpress build <root> --json`: exit code 0 and the expected `pages` count. An unknown or
|
|
116
|
+
misspelt key fails here with its name.
|
|
117
|
+
|
|
118
|
+
## References
|
|
119
|
+
|
|
120
|
+
- Configuration: https://htmlpress.dev/customization/configuration-file.html
|
|
121
|
+
- Sections: https://htmlpress.dev/customization/article-sections.html
|
|
122
|
+
- Translations: https://htmlpress.dev/customization/translations.html
|
|
123
|
+
- Versioning: https://htmlpress.dev/customization/versioning.html
|
|
124
|
+
- Patches: https://htmlpress.dev/customization/article-patches.html
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: htmlpress-customization
|
|
3
|
+
description: Use when changing an htmlpress site's look or chrome — overriding --htmlpress-* tokens, escaping the layout, styles or a component into .htmlpress/ with `htmlpress escape`, adding layouts and project components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Htmlpress Customization
|
|
7
|
+
|
|
8
|
+
Htmlpress ships a layout, a theme and a library of components, all compiled into the binary.
|
|
9
|
+
A file under `.htmlpress/` at a built-in's path replaces it; a new name adds one of your own.
|
|
10
|
+
|
|
11
|
+
## When to use this skill
|
|
12
|
+
|
|
13
|
+
Invoke when the user asks to:
|
|
14
|
+
|
|
15
|
+
- Rebrand: colours, fonts, widths, radius.
|
|
16
|
+
- Change the header, sidebar, footer or another part of the chrome.
|
|
17
|
+
- Restyle a component, or add a block the built-in components do not have.
|
|
18
|
+
- Give some pages a different layout, such as a landing page without the sidebar
|
|
19
|
+
(`htmlpress-landing` covers what goes on one).
|
|
20
|
+
|
|
21
|
+
Do not escape for content: a page's own needs are semantic HTML and components
|
|
22
|
+
(`htmlpress-authoring`).
|
|
23
|
+
|
|
24
|
+
## Tokens first
|
|
25
|
+
|
|
26
|
+
Most looks are a token. Override it in `.htmlpress/styles/tokens.css`, or in one page's own
|
|
27
|
+
`<style>` for that page only:
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
:root {
|
|
31
|
+
--htmlpress-accent: oklch(0.55 0.24 27);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`--htmlpress-accent`, `-accent-text`, `-font`, `-mono`, `-bg`, `-surface`, `-text`, `-muted`,
|
|
36
|
+
`-prose`, `-prose-strong`, `-prose-marker`, `-border`, `-shadow`, `-radius`, `-width`,
|
|
37
|
+
`-nav-width`, `-banner`, `-banner-text`, `-highlight`, `-highlight-text` (search matches on
|
|
38
|
+
the page a result opened), and the
|
|
39
|
+
callout and badge tones `-info`, `-success`, `-warning`, `-danger`.
|
|
40
|
+
|
|
41
|
+
## Escaping
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
htmlpress escape # list every file, marking the escaped ones
|
|
45
|
+
htmlpress escape htmlpress-tabs # a component's .css and .js
|
|
46
|
+
htmlpress escape layout.html styles/tokens.css
|
|
47
|
+
htmlpress escape htmlpress-tabs -r docs # in another project folder
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`escape` copies a default to start from and never overwrites a file you already have. Deleting
|
|
51
|
+
an escape restores the default. An escaped copy keeps the code it was copied from, so after an
|
|
52
|
+
upgrade it misses the new defaults: escape only what you change.
|
|
53
|
+
|
|
54
|
+
| Path under `.htmlpress/` | Replaces |
|
|
55
|
+
| ------------------------------------------------ | ----------------------------------------------------------------- |
|
|
56
|
+
| `layout.html` | the page around the content |
|
|
57
|
+
| `layouts/<name>.html` | a layout of your own, picked by `<meta name="layout">` |
|
|
58
|
+
| `styles/tokens.css`, `layout.css`, `content.css` | the global theme: tokens, page globals, content elements |
|
|
59
|
+
| `favicon.svg` | the icon linked when the config sets neither `favicon` nor `logo` |
|
|
60
|
+
| `components/<name>/<name>.css`, `.js` | one component, `<htmlpress-<name>>` without its prefix |
|
|
61
|
+
|
|
62
|
+
## Layouts
|
|
63
|
+
|
|
64
|
+
`layout.html` is plain HTML: htmlpress fills its `<head>` and replaces `<htmlpress-content>`,
|
|
65
|
+
`<htmlpress-brand>`, `<htmlpress-banner>`, `<htmlpress-nav>`, `<htmlpress-links>`,
|
|
66
|
+
`<htmlpress-breadcrumbs>`, `<htmlpress-toc>`, `<htmlpress-pager>`, `<htmlpress-edit>`,
|
|
67
|
+
`<htmlpress-toolbar>`, `<htmlpress-footer>`, `<htmlpress-language>` (the language picker) and
|
|
68
|
+
`<htmlpress-skip>` at build time, every string in the page's language. The interactive ones,
|
|
69
|
+
`<htmlpress-nav-toggle>`, `<htmlpress-search>`, `<htmlpress-theme-toggle>`, `<htmlpress-toc-bar>`
|
|
70
|
+
(the phone's contents bar and sheet) and `<htmlpress-back-to-top>`, run in the browser; the first three get their button at build time,
|
|
71
|
+
so the header is whole on its first frame. A head script sets `data-scripted` on `<html>`:
|
|
72
|
+
without it those buttons stay hidden, so style anything that needs scripts under
|
|
73
|
+
`:root[data-scripted]`. An element with nothing to show is removed.
|
|
74
|
+
|
|
75
|
+
Pages crossfade only their content: `<htmlpress-header>` and `<htmlpress-sidebar>` carry the
|
|
76
|
+
view transition names `htmlpress-header` and `htmlpress-sidebar`, and a hovered link's page is
|
|
77
|
+
prerendered. An escape of either component's `.css` keeps its `view-transition-name`, or it
|
|
78
|
+
crossfades with the content.
|
|
79
|
+
|
|
80
|
+
The frame is elements too, never classes: `<htmlpress-shell>`, `-sidebar`, `-main`, `-header`,
|
|
81
|
+
`-page`, `-aside`, `-skip`, each a component whose `.css` can be escaped.
|
|
82
|
+
|
|
83
|
+
A page with `<meta name="layout" content="landing">` takes `layouts/landing.html` instead. It
|
|
84
|
+
starts bare: only the layout elements you put in it are drawn. A missing layout fails the build.
|
|
85
|
+
|
|
86
|
+
## Project components
|
|
87
|
+
|
|
88
|
+
A folder under `components/` with a new name adds `<htmlpress-<name>>`, each file named like
|
|
89
|
+
the folder:
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<!-- .htmlpress/components/credits/credits.html -->
|
|
93
|
+
<footer><p>Built by my team · 2026</p></footer>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```css
|
|
97
|
+
/* .htmlpress/components/credits/credits.css */
|
|
98
|
+
@scope (htmlpress-credits) {
|
|
99
|
+
:scope {
|
|
100
|
+
display: block;
|
|
101
|
+
}
|
|
102
|
+
p {
|
|
103
|
+
color: var(--htmlpress-muted);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- The `.html` fills every such tag in the layouts and pages at build time; the tag stays, so its
|
|
109
|
+
`.css` scopes to it. A custom element is inline until its CSS says otherwise.
|
|
110
|
+
- Its `.css` and `.js` load only where the tag appears. A name is lowercase letters, digits and
|
|
111
|
+
hyphens.
|
|
112
|
+
- A layout or a component's `.html` may hold any built-in component, but not another project
|
|
113
|
+
component's tag: it is pasted in once, never rewritten again.
|
|
114
|
+
- The markup inside a layout element (`nav`, `toc`, `pager`, …) is built from the site; a
|
|
115
|
+
`components/brand/brand.html` replaces it with static HTML, and the built-in `.css` still
|
|
116
|
+
applies to the tag.
|
|
117
|
+
|
|
118
|
+
## Rules of thumb
|
|
119
|
+
|
|
120
|
+
- A misspelt built-in name (`calout/`) adds a component rather than replacing one; a file
|
|
121
|
+
directly in `components/` fails the build. Check `htmlpress escape` marks the file escaped.
|
|
122
|
+
- To restyle a component from an outer one, beat its `:scope`: write `:scope htmlpress-header`,
|
|
123
|
+
not a bare `htmlpress-header`, which loses on specificity.
|
|
124
|
+
- Use tokens inside your CSS (`var(--htmlpress-muted)`) so dark mode keeps working.
|
|
125
|
+
|
|
126
|
+
## Verification
|
|
127
|
+
|
|
128
|
+
Run `htmlpress build <root> --json` (exit code 0), then `htmlpress start <root>` and look at
|
|
129
|
+
the change in light and dark, wide and phone width. `start` picks up a new or deleted escape
|
|
130
|
+
at once.
|
|
131
|
+
|
|
132
|
+
## References
|
|
133
|
+
|
|
134
|
+
- Overriding: https://htmlpress.dev/customization/overriding-escaping.html
|
|
135
|
+
- Layouts: https://htmlpress.dev/customization/custom-routes.html
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: htmlpress-deployment
|
|
3
|
+
description: Use when publishing an htmlpress site — building into .htmlpress/build/, setting site and base, and wiring Cloudflare, GitHub Pages, Vercel, Netlify or any static host, by hand or from CI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Htmlpress Deployment
|
|
7
|
+
|
|
8
|
+
`htmlpress build` writes a fully static site; every host that serves a directory of files can
|
|
9
|
+
serve it. There is no client-side routing, so no host needs an SPA fallback.
|
|
10
|
+
|
|
11
|
+
## When to use this skill
|
|
12
|
+
|
|
13
|
+
Invoke when the user asks to:
|
|
14
|
+
|
|
15
|
+
- Publish the site, or set up a host or a CI deploy.
|
|
16
|
+
- Serve it under a sub-path such as a GitHub Pages project site.
|
|
17
|
+
- Fix a deploy that 404s, loses its styles or misses `sitemap.xml`.
|
|
18
|
+
|
|
19
|
+
## The build
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
htmlpress build # or `npx gethtmlpress build` in CI, without installing it
|
|
23
|
+
htmlpress preview # serves the production build locally, the way a host will
|
|
24
|
+
htmlpress clear # removes .htmlpress/build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The output is `.htmlpress/build/`: an `.html` per page at its source's path, `404.html`,
|
|
28
|
+
`robots.txt`, `_headers`, a Markdown copy of each page and `llms.txt` for agents, the skills
|
|
29
|
+
under `.well-known/agent-skills/`, the theme under `_htmlpress/`, and every other project file.
|
|
30
|
+
With `site` set it adds `sitemap.xml`. Never edit the output: every build replaces it.
|
|
31
|
+
|
|
32
|
+
## Config that affects deployment
|
|
33
|
+
|
|
34
|
+
- `site` — the final origin (`https://docs.example.com`): `sitemap.xml`, canonical URLs and
|
|
35
|
+
absolute social tags need it.
|
|
36
|
+
- `base` — only for a sub-path (`/my-docs/`). Write links without it; the build prefixes every
|
|
37
|
+
root-relative URL, and `start` and `preview` serve under it too. A custom domain needs no
|
|
38
|
+
`base`.
|
|
39
|
+
|
|
40
|
+
## Hosts
|
|
41
|
+
|
|
42
|
+
| Host | Setup |
|
|
43
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| Cloudflare Workers | `wrangler.jsonc`: `assets.directory: ".htmlpress/build"`, `html_handling: "none"`, `not_found_handling: "404-page"`; `npx wrangler deploy` |
|
|
45
|
+
| GitHub Pages | `site: https://<user>.github.io`, `base: /<repo>/`; `npx gh-pages -d .htmlpress/build --nojekyll --dotfiles`, or the Pages actions uploading `.htmlpress/build` |
|
|
46
|
+
| Vercel | `vercel.json`: `"framework": null`, `"buildCommand": "npx gethtmlpress build"`, `"outputDirectory": ".htmlpress/build"` |
|
|
47
|
+
| Netlify | `netlify.toml`: `[build] command = "npx gethtmlpress build"`, `publish = ".htmlpress/build"` |
|
|
48
|
+
| nginx | `try_files $uri $uri/ =404;` and `error_page 404 /404.html;` |
|
|
49
|
+
| Caddy | `file_server` plus `handle_errors { rewrite * /404.html; file_server }` |
|
|
50
|
+
| S3 + CloudFront | index `index.html`, error `404.html`, a 404 custom error response to `/404.html` |
|
|
51
|
+
|
|
52
|
+
## Rules of thumb
|
|
53
|
+
|
|
54
|
+
- Point the host's not-found page at `404.html`, so unknown paths keep the site's layout.
|
|
55
|
+
- Keep `html_handling: "none"` on Cloudflare: its default redirects `/guide.html` to `/guide`,
|
|
56
|
+
away from the URLs htmlpress links to.
|
|
57
|
+
- Keep `--nojekyll` and `--dotfiles` on a GitHub Pages branch deploy: Jekyll drops the
|
|
58
|
+
`_htmlpress/` theme, and without dot-files `.well-known/` is lost.
|
|
59
|
+
- Files under `_htmlpress/` keep their names between builds: cache them briefly or invalidate
|
|
60
|
+
them on each release.
|
|
61
|
+
- A project's dot-files are never copied: keep an `.htaccess` on the server.
|
|
62
|
+
|
|
63
|
+
## Verification
|
|
64
|
+
|
|
65
|
+
Run `htmlpress build --json` and `htmlpress preview`, then after the deploy open the home page,
|
|
66
|
+
a nested page, an unknown path (the site's 404) and `/robots.txt`. Under a `base`, check that
|
|
67
|
+
styles load and links keep the prefix.
|
|
68
|
+
|
|
69
|
+
## References
|
|
70
|
+
|
|
71
|
+
- Deployment: https://htmlpress.dev/deployment/
|
|
72
|
+
- Static hosting: https://htmlpress.dev/deployment/static-hosting.html
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: htmlpress-landing
|
|
3
|
+
description: Use when designing or rewriting an htmlpress project's landing page — a layout of its own, hero, sections, screenshots and calls to action as project components, taking htmlpress.dev's own landing as the reference.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Htmlpress Landing
|
|
7
|
+
|
|
8
|
+
Guidance for designing the page at `/` of an htmlpress project. The mechanics of a layout and a
|
|
9
|
+
project component are in `htmlpress-customization`; this skill is about what goes on the page.
|
|
10
|
+
|
|
11
|
+
## When to use this skill
|
|
12
|
+
|
|
13
|
+
Invoke when the user asks to:
|
|
14
|
+
|
|
15
|
+
- Build a landing, home or marketing page for the site, or redesign the existing one.
|
|
16
|
+
- Add a hero, feature grid, screenshot carousel or call-to-action section.
|
|
17
|
+
- Make the landing look as polished as htmlpress.dev.
|
|
18
|
+
|
|
19
|
+
## Start from the reference
|
|
20
|
+
|
|
21
|
+
htmlpress.dev's landing is itself an htmlpress page with its own layout and a set of project
|
|
22
|
+
components. Read it before writing anything, see it live, and borrow its structure:
|
|
23
|
+
|
|
24
|
+
- Live: https://htmlpress.dev/
|
|
25
|
+
- Page: https://github.com/datisthq/htmlpress/blob/main/rust/docs/index.html
|
|
26
|
+
- Layout and components: https://github.com/datisthq/htmlpress/tree/main/.htmlpress
|
|
27
|
+
|
|
28
|
+
None of it is in the packages, so fetch it from GitHub. Take the patterns, not the content:
|
|
29
|
+
rewrite every heading and line of copy for the project, and use the project's own screenshots
|
|
30
|
+
and links. Shipping htmlpress' copy, screenshots or Datist credit on someone else's site is a bug.
|
|
31
|
+
|
|
32
|
+
## Skeleton
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<!-- index.html -->
|
|
36
|
+
<title>Home</title>
|
|
37
|
+
<meta name="description" content="What the project does, in one line." />
|
|
38
|
+
<meta name="layout" content="landing" />
|
|
39
|
+
<meta name="sidebar" content="false" />
|
|
40
|
+
|
|
41
|
+
<htmlpress-landing-hero>…</htmlpress-landing-hero>
|
|
42
|
+
<htmlpress-landing-section>…</htmlpress-landing-section>
|
|
43
|
+
<htmlpress-landing-cta>…</htmlpress-landing-cta>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<!-- .htmlpress/layouts/landing.html -->
|
|
48
|
+
<!doctype html>
|
|
49
|
+
<html lang="en">
|
|
50
|
+
<head></head>
|
|
51
|
+
<body>
|
|
52
|
+
<htmlpress-skip><a href="#content">Skip to content</a></htmlpress-skip>
|
|
53
|
+
<htmlpress-landing-page>
|
|
54
|
+
<htmlpress-banner></htmlpress-banner>
|
|
55
|
+
<htmlpress-header role="banner">
|
|
56
|
+
<htmlpress-brand></htmlpress-brand>
|
|
57
|
+
<htmlpress-links></htmlpress-links>
|
|
58
|
+
<htmlpress-search></htmlpress-search>
|
|
59
|
+
<htmlpress-theme-toggle></htmlpress-theme-toggle>
|
|
60
|
+
</htmlpress-header>
|
|
61
|
+
<main id="content"><htmlpress-content></htmlpress-content></main>
|
|
62
|
+
<htmlpress-landing-footer></htmlpress-landing-footer>
|
|
63
|
+
</htmlpress-landing-page>
|
|
64
|
+
<htmlpress-back-to-top></htmlpress-back-to-top>
|
|
65
|
+
</body>
|
|
66
|
+
</html>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The reference runs hero → a differentiator ("Stays out of your way") → a feature grid → an
|
|
70
|
+
audience section (agents) → a final call to action → a credit footer. Pick the sections the
|
|
71
|
+
project has something real to say in; three strong ones beat seven thin ones.
|
|
72
|
+
|
|
73
|
+
## Patterns from the reference
|
|
74
|
+
|
|
75
|
+
- **One component per block** — `landing-hero`, `-section`, `-features`, `-points`, `-cta`,
|
|
76
|
+
`-actions`, `-carousel`, `-window`, `-code`, `-backdrop`, `-footer`, `-page`, each a folder
|
|
77
|
+
under `.htmlpress/components/` with a `.css` scoped to its tag, and `.js` or `.html` only
|
|
78
|
+
where needed. The page holds semantic HTML inside them: `<section>`, `<header>`, `<hgroup>`,
|
|
79
|
+
`<h2>`, `<ul>` of `<li>` cards. No classes.
|
|
80
|
+
- **Section shell** — `<htmlpress-landing-section><section><header><h2>` plus a lede, then the
|
|
81
|
+
body; a two-column section pairs a point list with a visual (`landing-points` beside
|
|
82
|
+
`landing-window`).
|
|
83
|
+
- **Hero** — a short eyebrow `<p>` in an `<hgroup>` with the `<h1>`, a lede, then
|
|
84
|
+
`landing-actions` with two links: the docs first, the source second. A decorative
|
|
85
|
+
`landing-backdrop` takes `aria-hidden="true"`.
|
|
86
|
+
- **Show the product** — real screenshots, not stock art, each shipped light and dark as two
|
|
87
|
+
`<img>` toggled by the theme with an attribute the component's CSS reads; set `width` and
|
|
88
|
+
`height` so nothing shifts. `landing-carousel` turns `<section title>` slides into tabs.
|
|
89
|
+
- **Icons** — inline `<svg aria-hidden="true">` with `currentColor` strokes, so they follow the
|
|
90
|
+
theme.
|
|
91
|
+
- **Colour** — only `--htmlpress-*` tokens and `color-mix(in oklab, …)` of them, so the page
|
|
92
|
+
rebrands and goes dark with the rest of the site.
|
|
93
|
+
|
|
94
|
+
## Rules of thumb
|
|
95
|
+
|
|
96
|
+
- Links are root-relative (`/introduction.html`); `base` is added at build time.
|
|
97
|
+
- Keep the landing out of the sidebar (`sidebar` false) but give it a real `<title>` and
|
|
98
|
+
`description`: it is the site's social preview.
|
|
99
|
+
- Every component must read well with its JS off: the slides are already in the HTML.
|
|
100
|
+
- Check phone width first; a two-column section must fall back to one.
|
|
101
|
+
|
|
102
|
+
## Verification
|
|
103
|
+
|
|
104
|
+
Run `htmlpress build <root> --json`, then `htmlpress start <root>` and look at `/` in light and
|
|
105
|
+
dark, wide and at phone width. Tab through it: the skip link, the actions and the carousel must
|
|
106
|
+
be reachable by keyboard.
|
|
107
|
+
|
|
108
|
+
## References
|
|
109
|
+
|
|
110
|
+
- Layouts: https://htmlpress.dev/customization/custom-routes.html
|
|
111
|
+
- Overriding: https://htmlpress.dev/customization/overriding-escaping.html
|