markupress 0.0.2 → 0.2.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.
Files changed (49) hide show
  1. package/README.md +292 -22
  2. package/dist/cli.js +1 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/content.d.ts +69 -3
  5. package/dist/content.d.ts.map +1 -1
  6. package/dist/content.js +191 -62
  7. package/dist/content.js.map +1 -1
  8. package/dist/controllers/code.d.ts +7 -0
  9. package/dist/controllers/code.d.ts.map +1 -0
  10. package/dist/controllers/code.js +31 -0
  11. package/dist/controllers/code.js.map +1 -0
  12. package/dist/controllers/outline.d.ts +8 -0
  13. package/dist/controllers/outline.d.ts.map +1 -0
  14. package/dist/controllers/outline.js +45 -0
  15. package/dist/controllers/outline.js.map +1 -0
  16. package/dist/controllers/shell.d.ts +5 -1
  17. package/dist/controllers/shell.d.ts.map +1 -1
  18. package/dist/controllers/shell.js +12 -25
  19. package/dist/controllers/shell.js.map +1 -1
  20. package/dist/index.d.ts +6 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/markdown.d.ts +24 -0
  25. package/dist/markdown.d.ts.map +1 -0
  26. package/dist/markdown.js +46 -0
  27. package/dist/markdown.js.map +1 -0
  28. package/dist/navigation.d.ts +37 -0
  29. package/dist/navigation.d.ts.map +1 -0
  30. package/dist/navigation.js +52 -0
  31. package/dist/navigation.js.map +1 -0
  32. package/dist/site.d.ts +31 -10
  33. package/dist/site.d.ts.map +1 -1
  34. package/dist/site.js +174 -262
  35. package/dist/site.js.map +1 -1
  36. package/dist/theme.d.ts +2 -1
  37. package/dist/theme.d.ts.map +1 -1
  38. package/dist/theme.js +4 -34
  39. package/dist/theme.js.map +1 -1
  40. package/dist/versions.d.ts +4 -1
  41. package/dist/versions.d.ts.map +1 -1
  42. package/dist/versions.js +30 -45
  43. package/dist/versions.js.map +1 -1
  44. package/package.json +22 -12
  45. package/styles/base.css +1 -21
  46. package/styles/prose.css +38 -0
  47. package/theme/outline.html +11 -0
  48. package/theme/shell.html +66 -0
  49. package/theme/theme.css +52 -0
package/README.md CHANGED
@@ -16,45 +16,197 @@ node dist/cli.js build --root examples/site
16
16
  node dist/cli.js preview --root examples/site
17
17
  ```
18
18
 
19
- The example serves at `/manual/`. Open a version-specific link directly to verify that a reload preserves the selected version. The dev server recompiles Markdown edits, additions and deletions; component modules use HTMLKit's Vite pipeline.
19
+ The example serves at `/manual/`. Open a version-specific link directly to verify that a reload preserves the selected version. Markupress is a thin layer over HTMLKit: it translates Markdown and manages versions, and HTMLKit routes, orders, renders, watches and builds the pages. The dev server reloads open pages after any edit, addition or deletion. `build` writes a static site, which is the only production output for now.
20
20
 
21
21
  ## Author a site
22
22
 
23
- Create `docs/01-index.md` and optionally `markupress.config.json`:
23
+ `@nextwebwg/html-next` and `@threadlabs/looma` are peer dependencies, so a site shares one copy of each with its own components. npm installs them with Markupress. Pages link Looma's components by package name, so a pnpm site adds both as its own dependencies:
24
24
 
25
- ```json
26
- {
27
- "title": "Project documentation",
28
- "contentDir": "docs",
29
- "base": "/manual/",
30
- "outDir": "site"
31
- }
25
+ ```sh
26
+ pnpm add markupress @nextwebwg/html-next @threadlabs/looma
32
27
  ```
33
28
 
34
- Every version needs an `index.md` at its root; a numeric prefix such as `01-index.md` is allowed. `base` starts and ends with `/`. Configuration is JSON. The programmatic `buildSite`, `devSite`, `previewSite` and `prepareSite` APIs accept the same options plus `root`, `host` and `port`.
29
+ A site needs no configuration. `docs/index.md` is a complete site, and `markupress dev` serves it. Files in known places shape the rest:
30
+
31
+ | File | Is |
32
+ | --- | --- |
33
+ | `docs/index.md` | The version home, which every version needs. A number prefix such as `01.index.md` is allowed. |
34
+ | `docs/<folder>/index.md` | The folder's page and its metadata (see [Folders](#navigation-logo-and-footer)). Each top-level folder with an index page is a section: a top navigation link with its own sidebar. |
35
+ | `docs/404.md` | The not-found page. |
36
+ | `docs/_footer.md` | The footer: a heading per column, a list of links under each, and a copyright paragraph. |
37
+ | `public/logo.svg`, `public/logo-dark.svg` | The logo before the title, and its dark-theme version. |
38
+ | `public/favicon.svg` | The site icon. |
39
+ | `app/layouts/default.html` | A layout that replaces the Markupress shell (see [Layouts](#layouts)). |
40
+ | `htmlkit.config.ts` | HTMLKit options and plugins. |
41
+ | `versions/<id>/` | A recorded version, written by `markupress snapshot` (see [Versions](#versions)). |
42
+
43
+ Pages and their front matter come next, and `markupress.config.json` comes last: plain JSON data for the title, the base path and a few more settings (see [Configuration](#configuration)).
44
+
45
+ The `markupress` command and these APIs also load the site's `htmlkit.config.ts` (or `.js`) with HTMLKit's `loadConfig`, and add `markupress()` after its plugins, so HTMLKit plugins and options compose with Markupress:
46
+
47
+ ```ts
48
+ // htmlkit.config.ts
49
+ import { defineConfig } from '@nextwebwg/htmlkit';
50
+ import { sitemap } from './plugins/sitemap.js';
51
+
52
+ export default defineConfig({ plugins: [sitemap()], redirects: { '/start/': '/guide/install/' } });
53
+ ```
54
+
55
+ `base` and `outDir` from `markupress.config.json` or the command line win over the HTMLKit config's; without either, they are `/` and `site`. `markupress()` includes the `markdown()` plugin, so the HTMLKit config lists neither.
56
+
57
+ The same pieces work as HTMLKit plugins. `markupress(options)` adds versioned documentation with this theme. `markdown()` alone makes any HTMLKit site's `.md` files into pages, with no versions or theme:
58
+
59
+ ```ts
60
+ import { defineConfig } from '@nextwebwg/htmlkit';
61
+ import { markdown } from 'markupress';
62
+
63
+ export default defineConfig({ plugins: [markdown()] });
64
+ ```
35
65
 
36
66
  ```markdown
37
67
  ---
38
68
  title: Installation
39
69
  description: Install the project and run your first example.
40
- sidebarLabel: Install
41
70
  id: install
42
71
  aliases: [/getting-started/]
43
72
  ---
44
73
  # Installation
45
74
 
46
- [Next steps](03-usage.md#usage)
75
+ [Next steps](03.usage.md#usage)
47
76
 
48
77
  <link rel="component" href="../../components/counter.html">
49
78
 
50
79
  <demo-counter></demo-counter>
51
80
  ```
52
81
 
53
- `01-guide/02-install.md` becomes `/v/current/guide/install/`. Numeric prefixes order HTMLKit navigation and disappear from URLs. The unversioned `/guide/install/` alias selects the configured default version. Changing `02-` to `10-` changes ordering without changing the path. Duplicate paths or document IDs fail with both source filenames.
82
+ `01.guide/02.install.md` becomes `/v/current/guide/install/`. Numeric prefixes order HTMLKit navigation and disappear from URLs. The unversioned `/guide/install/` alias selects the configured default version. Changing `02.` to `10.` changes ordering without changing the path. Duplicate paths or document IDs fail with both source filenames.
83
+
84
+ Markdown text and fenced examples are literal, including braces and component syntax. Raw HTML outside fences can declare or use native components. Resource links remain relative to the original Markdown file. A component declared in Markdown is hoisted alongside the generated page carrier; its expressions retain HTML Next semantics. Explicit `<title>`, `<meta>` and non-component `<link>` elements also become page metadata.
85
+
86
+ ### Front matter
54
87
 
55
- Markdown text and fenced examples are literal, including braces and component syntax. Raw HTML outside fences can declare or use native components. Resource links remain relative to the original Markdown file. A component declared in Markdown is hoisted alongside the generated page carrier; its expressions retain HTML Next semantics. Frontmatter title and description become metadata inside the owning page component. Explicit `<title>`, `<meta>` and non-component `<link>` elements also become page metadata.
88
+ Front matter is a YAML mapping. Each field becomes HTMLKit page metadata or page data, and an unknown or mistyped field fails the build with the Markdown file's path, the field and the expected type.
89
+
90
+ | Field | Type | Effect |
91
+ | --- | --- | --- |
92
+ | `title` | string | The document `<title>`, the navigation, breadcrumb and pager label (HTMLKit `hk:label`), and `page.title`. Defaults to the first heading, then the file name. On a folder's index page it labels the folder. |
93
+ | `description` | string | `<meta name="description">`, and the page's line in its folder's generated index. |
94
+ | `order` | whole number | The page's place among its folder's pages, in place of its file's number prefix (HTMLKit `hk:order`). On a folder's index page it places the whole folder, and on the version home it is an error. |
95
+ | `navigation` | `hidden` or `collapsed` | `hidden` leaves the page out of navigation and keeps its route (HTMLKit `hk:navigation`). On a folder's index page, `collapsed` starts the folder's sidebar group closed. |
96
+ | `id` | string | The document identity across versions, independent of the file name and route. |
97
+ | `aliases` | list of route paths | Further URLs serving the page, relative to its version (HTMLKit `hk:alias`). |
98
+ | `layout` | string or `false` | An HTMLKit layout, `app/layouts/<name>.html`, in place of the site's layout for this page (HTMLKit `hk:layout`). `false` renders the page with no layout. |
99
+ | `outline` | `false` or `[min, max]` | The heading levels in the page's "On this page" outline, `[2, 3]` by default. `false` gives an empty outline. |
100
+ | `head` | mapping | `meta` (name to content), `og` (Open Graph property without `og:`, to content) and `canonical` (a URL), rendered into the document head. |
101
+ | `editLink` | URL or `false` | The page's "Edit this page" URL, as `page.editLink` for the layout. `false` asks the layout to show none. |
102
+
103
+ ```yaml
104
+ ---
105
+ title: Installation
106
+ outline: [2, 4]
107
+ editLink: https://github.com/org/repo/edit/main/docs/01.guide/02.install.md
108
+ head:
109
+ meta: { keywords: "install, setup" }
110
+ og: { image: https://example.com/social.png, type: article }
111
+ canonical: https://example.com/guide/install/
112
+ ---
113
+ ```
56
114
 
57
- Heading IDs are deterministic (`installation`, then `installation-1` for a duplicate). Relative `.md` links resolve to the corresponding version-specific document, retaining fragments and queries; missing documents fail at build time. Relative assets are copied, and image paths starting with `/` resolve from that edition's public directory under the deployment base. Remote links remain unchanged. `sidebarHidden: true` hides a document from navigation while keeping its route available. Aliases do not add duplicate sidebar entries.
115
+ Number prefixes order pages, and `order` takes the place of a file's prefix: `order: 2` on `install.md` orders it as `02.install.md` would. Pages with the same number sort by name.
116
+
117
+ Every heading has an anchor, derived by the Looma Markdown rule: the text is normalized to NFC and lowercased, letters, numbers and combining marks in any script stay, and every other run of characters becomes one hyphen. "Über uns" is `über-uns`, "設定 と 使い方" is `設定-と-使い方`, and a duplicate takes the first free suffix (`installation-1`). `## Setup {#install}` sets the ID to `install` and removes the marker from the heading. A custom ID is reserved for its heading, so a generated ID skips it. Relative `.md` links resolve to the corresponding version-specific document, retaining fragments and queries; missing documents fail at build time. Relative assets are copied, and image paths starting with `/` resolve from that edition's public directory under the deployment base. Remote links remain unchanged. `navigation: hidden` hides a document from navigation while keeping its route available. Aliases do not add duplicate sidebar entries.
118
+
119
+ Markupress renders [Looma Markdown](https://github.com/threadlabs-studio/looma/blob/main/apps/docs/docs/looma-markdown.md): CommonMark with GitHub Flavored Markdown (tables, task lists, strikethrough and autolinks), plus Looma's blocks and inline elements. It parses with Looma's markdown-it plugin and is tested against Looma Markdown's conformance fixtures, so a document reads the same in Markupress, Looma's components and LoomaEditor. A container's name is matched without regard to case, and the rest of the opening line is its title:
120
+
121
+ ````markdown
122
+ ::: warning Before you upgrade
123
+ Back up your data first.
124
+ :::
125
+
126
+ > [!TIP]
127
+ > Alerts take the tones NOTE, TIP, IMPORTANT, WARNING and CAUTION.
128
+
129
+ ::: details Show the output {open}
130
+ Starts expanded.
131
+ :::
132
+
133
+ ::: code-group
134
+ ```sh title="pnpm"
135
+ pnpm add markupress
136
+ ```
137
+
138
+ ```sh title="npm"
139
+ npm install markupress
140
+ ```
141
+ :::
142
+
143
+ ::: tabs
144
+ == Examples
145
+ Usage examples.
146
+
147
+ == API
148
+ The reference.
149
+ :::
150
+
151
+ ::toc{depth=2}
152
+
153
+ Status :chip[Ready]{tone=green}, owned by :mention[Ada Lovelace]{id=u1}.
154
+
155
+ - [x] Read the changelog
156
+ - [ ] Run the migration
157
+
158
+ ::: figure The build, from *source* to release
159
+ ![The build pipeline](./pipeline.svg){width=640 placement=center}
160
+ :::
161
+ ````
162
+
163
+ | Markdown | Renders |
164
+ | --- | --- |
165
+ | `::: note`, `tip`, `info`, `important`, `warning`, `danger` or `caution`, with an optional title | `<ui-callout tone="…" heading="Title">`. `caution` is `danger`, and `note` is the muted aside. |
166
+ | `> [!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]` or `[!CAUTION]` alone on a quote's first line | An untitled `<ui-callout>`: NOTE is `note` and CAUTION is `danger`. |
167
+ | `::: details Title`, with `{open}` to start expanded | Native `<details><summary>Title</summary>`, which opens without JavaScript. The title defaults to "Details". |
168
+ | `::: tabs` with `== Label` panels | `<ui-tabs group="tabs">`, one `<section aria-label="Label">` per panel. |
169
+ | `::: code-group` with a fence per panel | `<ui-tabs group="code-group">`, each panel labelled by its fence's `title`, or its language. `== Label` panels also work. |
170
+ | `::: figure Caption` | `<figure>` with the caption, inline Markdown, as its `<figcaption>`. |
171
+ | `::toc{depth=2 format=numbered}` | A table of contents linking the page's headings by their anchors. `depth` is 1 to 3 (default 3), and `format` is `plain`, `bulleted` or `numbered`. |
172
+ | `:chip[Label]{tone=green}` | An inline chip. Its tone is a hue: `neutral` (the default), `blue`, `green`, `yellow`, `red` or `purple`. |
173
+ | `:mention[Name]{id=u1}` | A mention of the entity `u1`, shown as `@Name`. |
174
+ | `- [x] Done` | A task list, when every item of the list starts with `[ ]` or `[x]`. |
175
+ | `![Alt](./image.svg){width=640 height=360 placement=wrap-left}` | An image with its size in CSS pixels and a placement: `center`, `wrap-left` or `wrap-right`. |
176
+
177
+ Tabs in one group keep one selection across the page, matched by label, and remember it for the next visit: choosing "npm" in one code group switches every code group. `::: tabs name` or `::: code-group name` sets the group. Without JavaScript every panel shows. Any other container name stays text. A closing `:::` closes the innermost open container, and a fence's content is code, so a `:::` line inside a fence stays code. Give an outer container more colons (`::::` around `:::`) so the nesting shows in the source. Titles and labels are literal text.
178
+
179
+ A page links the Looma components its blocks use by package name, as the theme links `ui-button`, so `@threadlabs/looma` resolves from the site. The Markupress theme spaces the blocks and styles the Markdown inside them.
180
+
181
+ Fenced code is highlighted at build time with [Shiki](https://shiki.style), so pages load no highlighting JavaScript. Any language Shiki bundles, such as `html`, `css`, `less`, `js`, `ts`, `tsx`, `jsx`, `json`, `bash`, `vue`, `svelte`, `md` or `yaml`, is loaded the first time a fence uses it. Unknown languages stay plain text. A `title` in the fence's info string adds a caption:
182
+
183
+ ````markdown
184
+ ```ts title="app/pages/index.ts"
185
+ export const count = 1;
186
+ ```
187
+ ````
188
+
189
+ Each code block renders as `<figure class="code">`, with the title as its `<figcaption>`.
190
+
191
+ The fence's info string also highlights and numbers lines, at build time with no client JavaScript:
192
+
193
+ ````markdown
194
+ ```ts {1,3-4} :line-numbers
195
+ const a = 1;
196
+ const b = 2; // [!code highlight]
197
+ const c = 3;
198
+ const d = 4;
199
+ ```
200
+ ````
201
+
202
+ - `{1,3-4}` highlights lines 1, 3 and 4, with or without a space after the language (```` ```ts{1} ````).
203
+ - A `// [!code highlight]` comment at the end of a line highlights that line, and the comment is removed. `#`, `--`, `/* */` and `<!-- -->` comments work too. `[!code highlight:3]` covers three lines, and a marker alone on its line applies to the lines after it.
204
+ - `:line-numbers` numbers the lines. The `lineNumbers: true` option, in `markupress.config.json`, `markupress()` or `markdown()`, numbers every block, and `:no-line-numbers` opts a block out.
205
+ - Line highlighting and numbers apply to languages Shiki highlights and to plain text (`text`, `txt`, `plain` or `plaintext`). A fence with an unknown language or no language stays escaped text, without its `[!code highlight]` comments.
206
+
207
+ Every code block has Copy and Wrap buttons. Copy puts the code on the clipboard, without line numbers or highlight comments. Wrap toggles line wrapping. They are native buttons, reached with Tab, and a page with code loads a small controller (`markupress/controllers/code.js`) that handles them through one delegated listener. The buttons stay hidden until that controller runs, so without JavaScript a code block is only its code. The theme shows them while the block is hovered or holds focus, and always on touch screens.
208
+
209
+ Highlighting uses the `github-light-default` and `github-dark-default` themes. Each token's color is `light-dark(light, dark)`, so it follows the page's `color-scheme`. The Markupress theme sets the color scheme from its dark-theme button or the reader's system preference through Looma's `[data-theme]` themes, so code switches with the rest of the page. On another HTMLKit site, set `color-scheme: light dark` to follow the system, or set `color-scheme` on `[data-theme]` as Looma does. Each token also carries `--shiki-light` and `--shiki-dark`, so a site can switch with any selector instead, for example `.dark .shiki span { color: var(--shiki-dark) !important; }`. Browsers without `light-dark()` show unhighlighted text. The site's stylesheet owns the code block's background; the Markupress theme uses Looma's sunken surface (`--ui-surface-sunken`). There, comments measure 3.98:1 in the light theme and 4.42:1 in the dark theme, and light-theme function names 4.42:1, below the 4.5:1 the other token colors reach.
58
210
 
59
211
  ## TypeScript controllers
60
212
 
@@ -63,7 +215,7 @@ Maintain controllers in strict ESM TypeScript, with `.js` references in HTML:
63
215
  ```html
64
216
  <template component="demo-counter" controller="./counter.js">
65
217
  <defs><state name="count" type="number" value="0"></state></defs>
66
- <div><button>Increment</button><output $value="$count"></output></div>
218
+ <div><button>Increment</button><output>{$count}</output></div>
67
219
  </template>
68
220
  ```
69
221
 
@@ -81,7 +233,7 @@ export default function counter(host: ComponentHost): void {
81
233
  }
82
234
  ```
83
235
 
84
- HTMLKit resolves `counter.js` to `counter.ts` in development and bundles its JavaScript for production. Vite transpiles; it does not type-check. Install TypeScript and `@nextwebwg/html-next` as direct development dependencies when importing its controller types, and run your project's strict TypeScript check separately. Markupress maintains its controllers with TypeScript 7. Checked JSDoc is an authoring option for your own controllers.
236
+ HTMLKit resolves `counter.js` to `counter.ts` in development and bundles its JavaScript for production. Vite transpiles; it does not type-check. Install TypeScript as a development dependency when importing HTML Next's controller types, and run your project's strict TypeScript check separately. Markupress maintains its controllers with TypeScript 7. Checked JSDoc is an authoring option for your own controllers.
85
237
 
86
238
  ## Versions
87
239
 
@@ -92,17 +244,17 @@ markupress snapshot v1
92
244
  markupress build
93
245
  ```
94
246
 
95
- The command validates a build and writes `versioned_docs/v1/`, then atomically appends its descriptor to `versioned_docs/versions.json`. It mirrors Markdown, public assets and project-local component, controller, stylesheet and asset dependencies, preserving relative imports. Existing snapshots are never replaced. Keep those files in version control. Package imports continue to use the project's installed dependencies and lockfile; snapshots freeze authored sources rather than vendoring npm packages.
247
+ The command validates a build and writes `versions/v1/`, a copy of the project's layout: `versions/v1/docs/` and `versions/v1/public/`. It stages the copy in a `.`-prefixed folder and renames it into place, so a version appears whole. The folders in `versions/` are the version list: the current version first, then each snapshot, highest number first (`v10`, `v2`, `v1`), labelled by its folder name. It mirrors Markdown, public assets and project-local component, controller, stylesheet and asset dependencies, preserving relative imports. Existing snapshots are never replaced. Keep those files in version control. Package imports continue to use the project's installed dependencies and lockfile; snapshots freeze authored sources rather than vendoring npm packages.
96
248
 
97
- Use relative project-local imports for snapshot content. Absolute filesystem imports and remote resources retain their external ownership. If a snapshot process crashes, check that it has stopped before removing its `versioned_docs/.snapshot-lock` directory and recovering any incomplete destination.
249
+ Use relative project-local imports for snapshot content. Absolute filesystem imports and remote resources retain their external ownership. If a snapshot process crashes, check that it has stopped before removing its `versions/.snapshot-lock` directory; the next snapshot replaces any `.<id>-pending` folder it left.
98
250
 
99
- For explicit versions, configure their order and labels:
251
+ The `versions` option sets the versions, their order and their labels in place of the folder list:
100
252
 
101
253
  ```json
102
254
  {
103
255
  "versions": [
104
256
  { "id": "current", "label": "Next", "directory": "docs" },
105
- { "id": "v1", "label": "Version 1", "directory": "versioned_docs/v1/_source/docs", "publicDir": "versioned_docs/v1/_source/public" }
257
+ { "id": "v1", "label": "Version 1", "directory": "versions/v1/docs", "publicDir": "versions/v1/public" }
106
258
  ],
107
259
  "defaultVersion": "v1"
108
260
  }
@@ -112,10 +264,128 @@ Version IDs are URL slugs; they need not follow SemVer. A document's `id` identi
112
264
 
113
265
  ## Theme and migration inputs
114
266
 
115
- The default theme imports Looma's button resources and CSS exports selectively, with HTMLKit's generic navigation component. It includes a skip link, native version links, a responsive navigation toggle and a saved light/dark preference. It uses the platform's existing runtime.
267
+ The default theme imports Looma's button and badge resources and CSS exports selectively. Its shell has a skip link, a top navigation bar, a grouped sidebar per section, native version links, an "on this page" outline, a footer and a saved light/dark preference, which an inline head script applies before first paint. It uses the platform's existing runtime.
268
+
269
+ Styles follow the component boundaries. Looma's tokens, its light and dark themes and the document defaults (`styles/base.css`) are page-wide, delivered through HTMLKit's `css` option. Each Markdown page component imports the documentation typography (`styles/prose.css`), so it styles that page and stops at any component the page embeds. The shell's own `<style>` styles the header, sidebar, columns and footer. `theme/theme.css` is page-wide too, because HTMLKit's built-in breadcrumbs and pager have no styles of their own and no component's scoped style reaches them; it also picks the logo for the theme in use. With `markdown()` alone, `markdown({ styles: [file] })` makes every Markdown page component import the given stylesheet files.
270
+
271
+ ### Navigation, logo and footer
272
+
273
+ The shell around the pages comes from the content. **Top navigation.** Each top-level folder with an index page is a section, linked from the top navigation by its index page's `title`, in navigation order. The `nav` option adds links after the sections. A link to the page being read, or to a section holding it, is marked current. **Logo and icon.** `public/logo.svg` is the logo, `public/logo-dark.svg` replaces it in the dark theme, and `public/favicon.svg` is the site icon. **Badge.** A site with several versions shows the selected version's label beside the title. **Footer.** `_footer.md` in a version's content directory is that version's footer. HTMLKit routes no file whose name starts with `_`, so the footer has no URL of its own:
274
+
275
+ ```markdown
276
+ ## Docs
277
+
278
+ - [Tokens](/tokens/)
279
+ - [Proposal](https://nextwebwg.org/declarative-components/)
280
+
281
+ ## Project
282
+
283
+ - [GitHub](https://github.com/threadlabs-studio/looma)
284
+
285
+ Copyright 2026 Threadlabs Studio contributors.
286
+ ```
287
+
288
+ Each heading starts a column, and each item in the list below it is a link. A paragraph after the lists is the copyright line. Anything else in the file fails the build with the file's path.
289
+
290
+ In the footer and the `nav` option, an `href` starting with `/` is a page path in the version being read, so `/components/` opens that version's components. Other links stay as written.
291
+
292
+ **Sidebars.** Each top-level folder of a version is a section with its own sidebar, generated from the folder's pages; a page at the version's root shows every page. Folders, `order` and `navigation` front matter shape every sidebar.
293
+
294
+ **Folders.** A folder is a page: its index page (`index.md`, or `01.index.md` with a number prefix) is the folder's entry, at the folder's URL, and its front matter is the folder's metadata. A generated sidebar is HTMLKit's navigation tree, rendered by `<hk-nav>`: each folder below the section is a labelled group, a native `<details>` that collapses without JavaScript, nested as deep as the folders go, and its summary links to the index page.
295
+
296
+ ```markdown
297
+ ---
298
+ title: Forms # labels the folder in the sidebar, breadcrumbs and pager
299
+ description: Form controls.
300
+ order: 3 # places the folder among its siblings like a 03. folder prefix
301
+ navigation: collapsed # starts the group closed, except on the pages inside it
302
+ ---
303
+ ```
304
+
305
+ A group starts open unless its index page says `navigation: collapsed`, and a group holding the current page always starts open. A folder without an index page is labelled by its name. To group pages under a label with no folder URL of its own, use an HTMLKit route group: a folder named in parentheses, such as `03.(Getting started)/`, labels and orders its pages and adds no URL segment. Navigation, breadcrumbs and the previous/next links follow the same order.
306
+
307
+ **Generated index.** An index page with front matter and an empty body lists its folder: below its `title` as the heading, each page and folder directly inside it links to that page with its `description`, in navigation order. A route group's pages appear in its place, and hidden pages stay out. The list comes from HTMLKit's navigation tree, so it follows every page added, renamed or reordered.
308
+
309
+ **Outline.** A page with headings in its `outline` range (h2 and h3 by default) shows them in an "On this page" outline beside the content on wide screens. The links are plain fragment links. A small controller (`markupress/controllers/outline.js`, also exported) marks the heading being read with `aria-current="location"`, using an IntersectionObserver; without JavaScript only that marking is missing.
310
+
311
+ **Narrow screens.** Below 769px the sidebar is a drawer: a native popover, closed until the Navigation button opens it, and it opens without JavaScript. Escape or a tap outside closes it, and following a link in it closes it.
312
+
313
+ **Not found.** A `404.md` in the default version's content directory is the site's not-found page (HTMLKit's not-found page, R7). It renders in the shell for every unmatched path, including those under `/v/<id>/`, with status 404 in `dev` and `preview`, and `build` writes it to `404.html`. It is no page of its version, so it has no URL of its own and no sidebar entry.
314
+
315
+ ### Layouts
316
+
317
+ `app/layouts/default.html` replaces the Markupress shell with the site's own HTML Next layout for every documentation page, as it is the default layout of the site's other HTMLKit pages. The layout renders `<slot name="page">` where the page goes, and receives Markupress's loader data as props. It receives each prop it declares with `<prop>`, so it declares only the data it uses:
318
+
319
+ ```html
320
+ <template component="site-layout"><defs>
321
+ <prop name="navigation" type="list(object({ href: string, label: string, current: string, ... }))" required>Links</prop>
322
+ <prop name="outline" type="list(object({ href: string, label: string, depth: number, ... }))" required>On this page</prop>
323
+ <prop name="page" type="object({ title: string, editLink?: string, ... })" required>Page metadata</prop></defs>
324
+ <div class="site">
325
+ <nav><a $each="item of $navigation" from:href="$item.href" from:aria-current="$item.current">{$item.label}</a></nav>
326
+ <main><slot name="page"></slot></main>
327
+ <aside><a $each="heading of $outline" from:href="$heading.href">{$heading.label}</a></aside>
328
+ </div>
329
+ </template>
330
+ ```
331
+
332
+ | Prop | Value |
333
+ | --- | --- |
334
+ | `title` | The site title (`title` option, default "Documentation"). |
335
+ | `home` | The site's base URL. |
336
+ | `navigation` | HTMLKit navigation items for the selected version: `href`, `label`, `current` (`"page"` or `"false"`), `depth` and `pageName`. |
337
+ | `sidebar` | The page's section sidebar, in `<hk-nav>`'s tree shape: entries with `label`, `current`, `open`, `depth` and `children`, and an `href` on a page. A folder with an index page has both `href` and `children`. Pass it to `<hk-nav from:items="$sidebar">`. |
338
+ | `nav` | The sections, then the `nav` option's links: each has `label`, `href`, `current` and `icon` (a URL, or `""`). |
339
+ | `footer` | `_footer.md`'s `columns`, each a `title` and `items` of links with `label`, `href` and `current`, and its `copyright`. |
340
+ | `logo`, `favicon`, `badge` | The logo's `light` and `dark` URLs, the icon URL (both `null` when absent), and the badge text. |
341
+ | `crumbs` | Navigation items from the version home down to this page. |
342
+ | `previous`, `next` | The neighbouring navigation items, absent at either end. |
343
+ | `versions` | Version links: `href`, `label`, `current` and `note`, which explains a fallback to that version's home. |
344
+ | `outline` | The page's headings in its `outline` range: `id`, `href` (`#id`), `label` and `depth`. |
345
+ | `contents` | A generated index's entries, `label`, `href` and `description`, and an empty list on every other page. |
346
+ | `page` | The page's front matter, plus its resolved `title` and document `id`. |
347
+
348
+ Markupress gives the layout its loader data, so the layout has no `default.server.ts` of its own. A folder's `_layout.html` inside a version's content wraps that folder's pages inside the site layout, as in any HTMLKit site. Its `_layout.server.ts` loader reads all of the data above from `parent.markupress`:
349
+
350
+ ```ts
351
+ export function load({ parent }) { return { props: { section: parent.markupress.page.title } }; }
352
+ ```
353
+
354
+ A layout receives exactly the props its component declares, which HTMLKit gives the loader as `propNames`. Declare navigation items with an open object type, which ends in `...`, so items keep passing as HTMLKit adds fields such as a route group's `group`.
355
+
356
+ HTMLKit plugins compose with Markupress through the site's `htmlkit.config.ts`, which the `markupress` command loads (see [Author a site](#author-a-site)).
116
357
 
117
358
  Existing Markdown, HTML/CSS/Less/JavaScript/TypeScript examples, local assets, heading anchors and route aliases are migration inputs. The installed consumer fixture checks those under a nested base. A live Jess/Less documentation migration and visual/content parity comparison remain separate work.
118
359
 
360
+ ## Configuration
361
+
362
+ `markupress.config.json` is plain JSON data, read by the `markupress` command. Every key is optional:
363
+
364
+ ```json
365
+ {
366
+ "title": "Looma",
367
+ "base": "/looma/",
368
+ "nav": [
369
+ { "label": "HTML Next", "href": "https://nextwebwg.org/declarative-components/" },
370
+ { "label": "GitHub", "href": "https://github.com/threadlabs-studio/looma", "icon": "/github.svg" }
371
+ ]
372
+ }
373
+ ```
374
+
375
+ | Option | Default | Does |
376
+ | --- | --- | --- |
377
+ | `title` | `"Documentation"` | The site title in the top bar. |
378
+ | `base` | `/` | The URL path the site is served under. It starts and ends with `/`. |
379
+ | `contentDir` | `docs` | The current version's content directory. |
380
+ | `outDir` | `site` | Where `build` writes the static site. |
381
+ | `versions`, `defaultVersion` | the folders in `versions/`, `current` | The versions and their order and labels, and the version the site root serves (see [Versions](#versions)). |
382
+ | `lineNumbers` | `false` | Numbers the lines of every code block. |
383
+ | `nav` | none | Links after the sections in the top navigation: `{ "label", "href" }`, with an optional `icon` image shown in place of the label. |
384
+ | `logo` | `public/logo.svg` and `public/logo-dark.svg` | One image path, or `{ "light", "dark" }`, in place of the logo files. |
385
+ | `favicon` | `public/favicon.svg` | The site icon's path, in place of the icon file. |
386
+
387
+ Image paths starting with `/` are files in `public/`. An unknown key fails with the list of options. The programmatic `buildSite`, `devSite` and `previewSite` APIs, and the `markupress()` plugin, take the same options plus `root`, `host` and `port`; `siteOptions` returns the HTMLKit options they use.
388
+
119
389
  ## Verification and contribution
120
390
 
121
391
  ```sh
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ async function main() {
9
9
  root: { type: 'string' }, base: { type: 'string' }, port: { type: 'string' }, help: { type: 'boolean', short: 'h' },
10
10
  } });
11
11
  if (values.help) {
12
- process.stdout.write('Usage: markupress build|dev|preview [--root directory] [--base /docs/] [--port 3000]\n markupress snapshot <version-id> [--root directory]\nConfiguration: markupress.config.json\n');
12
+ process.stdout.write('Usage: markupress build|dev|preview [--root directory] [--base /docs/] [--port 3000]\n markupress snapshot <version-id> [--root directory]\nConfiguration: markupress.config.json, and htmlkit.config.ts for HTMLKit options and plugins\n');
13
13
  return;
14
14
  }
15
15
  const root = resolve(values.root ?? process.cwd());
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/content.d.ts CHANGED
@@ -3,16 +3,82 @@ export interface MarkdownOptions {
3
3
  readonly pageName: string;
4
4
  /** Resolve authored document links and assets from their original source. */
5
5
  readonly resolveLink?: (href: string, kind: 'link' | 'asset') => string;
6
+ /** Stylesheet files the page component imports, so their rules style this page's own region. */
7
+ readonly styles?: readonly string[];
8
+ /** Number the lines of highlighted code blocks unless a fence says `:no-line-numbers`. */
9
+ readonly lineNumbers?: boolean;
10
+ /** Front matter the page's own fields override, such as a site-wide default. */
11
+ readonly frontmatter?: FrontMatter;
12
+ }
13
+ /** A page's validated front matter. Unknown or mistyped fields fail with the Markdown file's name. */
14
+ export interface FrontMatter {
15
+ readonly title?: string;
16
+ /** `<meta name="description">`, and the page's line in its folder's generated index. */
17
+ readonly description?: string;
18
+ /** The page's place among its folder's pages, as a number prefix gives it; on an index page, the folder's place (HTMLKit `hk:order`). */
19
+ readonly order?: number;
20
+ /**
21
+ * `hidden` leaves the page out of navigation and keeps its route (HTMLKit `hk:navigation`). On a folder's index
22
+ * page, `collapsed` starts the folder's sidebar group closed.
23
+ */
24
+ readonly navigation?: 'hidden' | 'collapsed';
25
+ readonly id?: string;
26
+ readonly aliases?: readonly string[];
27
+ /** An HTMLKit layout name (app/layouts/<name>.html) in place of the site's layout, or false for none. */
28
+ readonly layout?: string | false;
29
+ /** The heading levels the page's outline lists, such as [2, 3], or false for no outline. */
30
+ readonly outline?: false | readonly [number, number];
31
+ readonly head?: {
32
+ /** `<meta name content>` by name. */
33
+ readonly meta?: Readonly<Record<string, string | number>>;
34
+ /** Open Graph `<meta property="og:…" content>` by property name without its `og:` prefix. */
35
+ readonly og?: Readonly<Record<string, string | number>>;
36
+ readonly canonical?: string;
37
+ };
38
+ /** This page's "Edit this page" URL, or false to show none. */
39
+ readonly editLink?: string | false;
40
+ }
41
+ /** A heading the page's outline lists. */
42
+ export interface OutlineItem {
43
+ readonly id: string;
44
+ /** The heading's fragment link, `#id`. */
45
+ readonly href: string;
46
+ readonly label: string;
47
+ readonly depth: number;
6
48
  }
7
49
  export interface CompiledMarkdown {
8
50
  readonly resource: string;
9
51
  readonly title: string;
10
- readonly label: string;
11
52
  readonly id?: string;
12
53
  readonly aliases: readonly string[];
13
- readonly sidebarHidden: boolean;
54
+ readonly frontmatter: FrontMatter;
55
+ /** The headings in the page's `outline` range, [2, 3] by default, in document order. */
56
+ readonly outline: readonly OutlineItem[];
57
+ /** An index page with an empty body: its layout lists the folder's pages below its title. */
58
+ readonly generated: boolean;
14
59
  }
60
+ /** Whether a Markdown file is its folder's index page, which HTMLKit reads as the folder's own entry. */
61
+ export declare const isIndex: (file: string) => boolean;
15
62
  export declare function escapeHTML(value: string): string;
16
63
  export declare function literal(value: string): string;
17
- export declare function compileMarkdown(source: string, options: MarkdownOptions): CompiledMarkdown;
64
+ /** A Markdown document rendered by Looma Markdown and Markupress's presentation, before Markupress's page layer. */
65
+ export interface RenderedMarkdown {
66
+ /** The document's HTML, as HTML Next template content: Markdown text escapes its braces. */
67
+ readonly html: string;
68
+ /** The front matter mapping as parsed, before any host schema reads it. */
69
+ readonly frontmatter: Readonly<Record<string, unknown>>;
70
+ /** The document after its front matter. */
71
+ readonly body: string;
72
+ /** Every heading, in document order. */
73
+ readonly headings: readonly OutlineItem[];
74
+ readonly hasCode: boolean;
75
+ /** The Looma components the document's blocks render. */
76
+ readonly components: ReadonlySet<string>;
77
+ }
78
+ /**
79
+ * The Looma Markdown layer: splits the front matter, parses with Looma's plugin and renders with Markupress's
80
+ * presentation. Front matter fields are left to the host; compileMarkdown validates Markupress's.
81
+ */
82
+ export declare function renderMarkdown(source: string, options: Pick<MarkdownOptions, 'file' | 'lineNumbers'>): Promise<RenderedMarkdown>;
83
+ export declare function compileMarkdown(source: string, options: MarkdownOptions): Promise<CompiledMarkdown>;
18
84
  //# sourceMappingURL=content.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,KAAK,MAAM,CAAC;CACzE;AACD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAA8D;AAgB5G,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,gBAAgB,CAkF1F"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"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"}