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
@@ -14,6 +14,9 @@ export declare function versionLinks(documents: readonly {
14
14
  readonly id: string;
15
15
  readonly label?: string;
16
16
  }[], id: string, selected: string, base: string): readonly VersionLink[];
17
- /** Snapshot author content without overwriting an existing edition. The manifest preserves explicit ordering. */
17
+ /**
18
+ * Snapshot author content into `versions/<id>/` without overwriting an existing edition. The snapshot is staged in a
19
+ * dot folder and renamed into place, so a version appears whole or not at all.
20
+ */
18
21
  export declare function snapshotVersion(id: string, options?: MarkupressOptions): Promise<DocumentationVersion>;
19
22
  //# sourceMappingURL=versions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../src/versions.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,oBAAoB,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAG3F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AACD,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,QAAQ,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,WAAW,EAAE,CAO1Q;AAED,iHAAiH;AACjH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuEhH"}
1
+ {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../src/versions.ts"],"names":[],"mappings":"AAKA,OAAO,EAA2B,KAAK,oBAAoB,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAGvG,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AACD,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,QAAQ,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,WAAW,EAAE,CAO1Q;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA8DhH"}
package/dist/versions.js CHANGED
@@ -1,8 +1,9 @@
1
- import { cp, mkdir, readFile, realpath, rename, rm, writeFile } from 'node:fs/promises';
1
+ import { existsSync } from 'node:fs';
2
+ import { cp, mkdir, readFile, realpath, rename, rm } from 'node:fs/promises';
2
3
  import { resolve, join, relative, isAbsolute, dirname } from 'node:path';
3
4
  import { fileURLToPath } from 'node:url';
4
5
  import { buildApplication, createApplication } from '@nextwebwg/htmlkit';
5
- import { prepareSite } from './site.js';
6
+ import { siteOptions, snapshotOf } from './site.js';
6
7
  import { stylesheet } from './styles.js';
7
8
  /** URLs are projected from logical identity; renaming a route never changes the switch target. */
8
9
  export function versionLinks(documents, versions, id, selected, base) {
@@ -13,7 +14,10 @@ export function versionLinks(documents, versions, id, selected, base) {
13
14
  note: target ? '' : `This document is unavailable in ${version.label ?? version.id}; open its documentation home.` };
14
15
  });
15
16
  }
16
- /** Snapshot author content without overwriting an existing edition. The manifest preserves explicit ordering. */
17
+ /**
18
+ * Snapshot author content into `versions/<id>/` without overwriting an existing edition. The snapshot is staged in a
19
+ * dot folder and renamed into place, so a version appears whole or not at all.
20
+ */
17
21
  export async function snapshotVersion(id, options = {}) {
18
22
  if (!/^[A-Za-z0-9_-]+$/.test(id) || id === 'current')
19
23
  throw new Error('Snapshot id must be a URL slug other than current.');
@@ -23,7 +27,7 @@ export async function snapshotVersion(id, options = {}) {
23
27
  const relation = relative(root, source);
24
28
  if (isAbsolute(relation) || relation.startsWith('..'))
25
29
  throw new Error('Snapshot contentDir must be inside the project.');
26
- const snapshots = join(root, 'versioned_docs');
30
+ const snapshots = join(root, 'versions');
27
31
  await mkdir(snapshots, { recursive: true });
28
32
  const lock = join(snapshots, '.snapshot-lock');
29
33
  try {
@@ -31,39 +35,24 @@ export async function snapshotVersion(id, options = {}) {
31
35
  }
32
36
  catch (error) {
33
37
  if (error.code === 'EEXIST')
34
- throw new Error('Another snapshot owns versioned_docs/.snapshot-lock; finish or recover that operation first.');
38
+ throw new Error('Another snapshot owns versions/.snapshot-lock; finish or recover that operation first.');
35
39
  throw error;
36
40
  }
37
41
  const destination = join(snapshots, id);
38
- let owned = false;
42
+ const staging = join(snapshots, `.${id}-pending`);
39
43
  try {
40
- const manifest = join(snapshots, 'versions.json');
41
- let versions = [];
42
- try {
43
- versions = JSON.parse(await readFile(manifest, 'utf8'));
44
- }
45
- catch (error) {
46
- if (error.code !== 'ENOENT')
47
- throw error;
48
- }
49
- if (versions.some(version => version.id === id))
44
+ if (existsSync(destination))
50
45
  throw new Error(`Documentation version ${id} already exists.`);
51
- try {
52
- await mkdir(destination);
53
- owned = true;
54
- }
55
- catch (error) {
56
- if (error.code === 'EEXIST')
57
- throw new Error(`Documentation version ${id} already exists.`);
58
- throw error;
59
- }
46
+ await rm(staging, { recursive: true, force: true });
47
+ await mkdir(staging);
60
48
  // Let HTMLKit/Vite identify the authored HTML, module, stylesheet and asset closure.
61
49
  // Mirroring project-relative paths keeps imports valid without rewriting source code.
62
- const prepared = await prepareSite({ ...options, versions: [{ id: 'current', directory: relation }], defaultVersion: 'current' });
63
- const validation = join(destination, '.validation');
64
- const built = await buildApplication({ ...prepared.application, outDir: validation });
65
- const inputs = new Set([...built.browserInputs, ...prepared.sourceFiles]);
66
- const application = await createApplication(prepared.application);
50
+ const site = siteOptions({ ...options, versions: [{ id: 'current', directory: relation }], defaultVersion: 'current' });
51
+ const validation = join(staging, '.validation');
52
+ const built = await buildApplication({ ...site, outDir: validation });
53
+ const application = await createApplication(site);
54
+ // Files that Markdown references, which HTMLKit serves, belong to the snapshot too.
55
+ const inputs = new Set([...built.browserInputs, ...application.files.values()]);
67
56
  try {
68
57
  for (const pathname of await application.entries()) {
69
58
  for (const component of (await application.render(pathname)).components) {
@@ -72,6 +61,10 @@ export async function snapshotVersion(id, options = {}) {
72
61
  inputs.add(file.startsWith('file:') ? fileURLToPath(file) : file);
73
62
  for (const dependency of stylesheet(component.definition.css, fileURLToPath(file), false).files)
74
63
  inputs.add(dependency);
64
+ // HTMLKit delivers a component's imported stylesheets apart from its local CSS, nested imports included.
65
+ for (const sheet of component.definition.stylesheets ?? [])
66
+ if (sheet.url.startsWith('file:'))
67
+ inputs.add(fileURLToPath(sheet.url));
75
68
  }
76
69
  }
77
70
  }
@@ -86,39 +79,31 @@ export async function snapshotVersion(id, options = {}) {
86
79
  for (const dependency of stylesheet(await readFile(input, 'utf8'), input, false).files)
87
80
  inputs.add(dependency);
88
81
  }
89
- const mirror = join(destination, '_source');
90
- await cp(source, join(mirror, relation), { recursive: true, dereference: false });
82
+ await cp(source, join(staging, relation), { recursive: true, dereference: false });
91
83
  for (const input of inputs) {
92
84
  const file = input.split('?')[0];
93
85
  if (file.endsWith('.htmlkit.css'))
94
86
  continue; // HTMLKit's virtual inline stylesheet, not an authored file.
95
87
  const path = relative(canonicalRoot, await realpath(file));
96
- if (isAbsolute(path) || path.startsWith('..') || path.split(/[/\\]/).some(part => ['node_modules', '.markupress', 'versioned_docs'].includes(part)))
88
+ if (isAbsolute(path) || path.startsWith('..') || path.split(/[/\\]/).includes('node_modules') || /^versions[/\\]/.test(path))
97
89
  continue;
98
- const target = join(mirror, path);
90
+ const target = join(staging, path);
99
91
  await mkdir(dirname(target), { recursive: true });
100
92
  await cp(file, target);
101
93
  }
102
- let publicDir;
103
94
  try {
104
- await cp(join(root, 'public'), join(mirror, 'public'), { recursive: true, dereference: false });
105
- publicDir = `versioned_docs/${id}/_source/public`;
95
+ await cp(join(root, 'public'), join(staging, 'public'), { recursive: true, dereference: false });
106
96
  }
107
97
  catch (error) {
108
98
  if (error.code !== 'ENOENT')
109
99
  throw error;
110
100
  }
111
101
  await rm(validation, { recursive: true, force: true });
112
- const version = { id, label: id, directory: `versioned_docs/${id}/_source/${relation.replace(/\\/g, '/')}`, ...(publicDir ? { publicDir } : {}) };
113
- const pending = join(snapshots, '.versions-pending.json');
114
- await writeFile(pending, JSON.stringify([...versions, version], null, 2) + '\n');
115
- await rename(pending, manifest);
116
- owned = false;
117
- return version;
102
+ await rename(staging, destination);
103
+ return snapshotOf(root, id, relation.replace(/\\/g, '/'));
118
104
  }
119
105
  finally {
120
- if (owned)
121
- await rm(destination, { recursive: true, force: true });
106
+ await rm(staging, { recursive: true, force: true });
122
107
  await rm(lock, { recursive: true, force: true });
123
108
  }
124
109
  }
@@ -1 +1 @@
1
- {"version":3,"file":"versions.js","sourceRoot":"","sources":["../src/versions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"versions.js","sourceRoot":"","sources":["../src/versions.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markupress",
3
- "version": "0.0.2",
3
+ "version": "0.2.0",
4
4
  "description": "Versioned Markdown documentation built on HTMLKit and native declarative components.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -11,11 +11,15 @@
11
11
  "import": "./dist/index.js"
12
12
  },
13
13
  "./controllers/shell.js": "./dist/controllers/shell.js",
14
- "./styles/base.css": "./styles/base.css"
14
+ "./controllers/code.js": "./dist/controllers/code.js",
15
+ "./controllers/outline.js": "./dist/controllers/outline.js",
16
+ "./styles/base.css": "./styles/base.css",
17
+ "./styles/prose.css": "./styles/prose.css"
15
18
  },
16
19
  "files": [
17
20
  "dist",
18
- "styles"
21
+ "styles",
22
+ "theme"
19
23
  ],
20
24
  "engines": {
21
25
  "node": ">=22.22.2 <23 || >=24.15 <25"
@@ -36,11 +40,15 @@
36
40
  },
37
41
  "devDependencies": {
38
42
  "@types/node": "22.20.1",
39
- "oxlint": "1.81.0",
43
+ "oxlint": "1.88.0",
40
44
  "typescript": "7.0.2",
41
- "vitest": "5.0.0",
42
- "playwright": "1.63.0",
43
- "@axe-core/playwright": "4.13.0"
45
+ "vitest": "5.0.4",
46
+ "playwright": "1.64.0",
47
+ "@axe-core/playwright": "4.13.0",
48
+ "@nextwebwg/html-next": "1.0.0-alpha.52",
49
+ "@threadlabs/looma": "0.28.18",
50
+ "@types/markdown-it": "14.2.0",
51
+ "jsdom": "30.1.2"
44
52
  },
45
53
  "publishConfig": { "access": "public" },
46
54
  "repository": {
@@ -52,14 +60,16 @@
52
60
  "url": "https://github.com/threadlabs-studio/markupress/issues"
53
61
  },
54
62
  "dependencies": {
55
- "@nextwebwg/htmlkit": "1.0.0-alpha.35",
56
- "marked": "18.1.0",
63
+ "@nextwebwg/htmlkit": "1.0.0-alpha.52",
57
64
  "parse5": "8.0.1",
58
65
  "yaml": "2.9.1",
59
- "@threadlabs/looma": "0.26.0",
60
- "postcss": "8.5.29",
66
+ "postcss": "8.5.30",
61
67
  "postcss-value-parser": "4.2.0",
62
- "@nextwebwg/html-next": "1.0.0-alpha.35"
68
+ "shiki": "4.5.0"
69
+ },
70
+ "peerDependencies": {
71
+ "@nextwebwg/html-next": "1.0.0-alpha.52",
72
+ "@threadlabs/looma": "^0.28.18"
63
73
  },
64
74
  "bin": {
65
75
  "markupress": "./dist/cli.js"
package/styles/base.css CHANGED
@@ -1,24 +1,4 @@
1
- /* Page-wide defaults; component styles remain owned by their native resource. */
1
+ /* Page-wide defaults, delivered through HTMLKit's css option; components keep their own styles. */
2
2
  html { background: var(--ui-surface); }
3
3
  body { margin: 0; }
4
4
  *, *::before, *::after { box-sizing: border-box; }
5
- /* Documentation typography spans the projected page's own component region. */
6
- .markupress-prose a { color: var(--ui-accent); text-underline-offset: .2em; }
7
- .markupress-prose h1 { font-size: clamp(1.8rem, 5vw, 2.7rem); line-height: 1.2; }
8
- .markupress-prose h2, .markupress-prose h3 { margin-top: 2rem; scroll-margin-top: 2rem; }
9
- .markupress-prose h1 a, .markupress-prose h2 a, .markupress-prose h3 a { color: inherit; text-decoration: none; }
10
- .markupress-prose pre { overflow: auto; max-width: 100%; padding: 1rem; background: var(--ui-surface-sunken); border-radius: .5rem; }
11
- .markupress-prose code { font-size: .9em; }
12
- .markupress-prose img, .markupress-prose svg { max-width: 100%; }
13
- .markupress-prose table { border-collapse: collapse; display: block; max-width: 100%; overflow: auto; }
14
- .markupress-prose th, .markupress-prose td { border: 1px solid var(--ui-border, #8885); padding: .4rem .75rem; }
15
- .markupress-prose :focus-visible { outline: 2px solid var(--ui-accent); outline-offset: 3px; }
16
- /* HTMLKit provides native navigation without presentation; this theme owns its appearance. */
17
- .site [data-component~="htmlkit-navigation"] ul { margin: 0; padding: 0; list-style: none; }
18
- .site [data-component~="htmlkit-navigation"] li { margin: .25rem 0; }
19
- .site [data-component~="htmlkit-navigation"] a { display: block; color: var(--ui-text); padding: .3rem .5rem; border-radius: .25rem; text-decoration: none; }
20
- .site [data-component~="htmlkit-navigation"] a:hover { background: var(--ui-surface-sunken); }
21
- .site [data-component~="htmlkit-navigation"] a[aria-current="page"] { color: var(--ui-accent); font-weight: 600; background: var(--ui-surface-sunken); }
22
- .site [data-component~="htmlkit-navigation"] [data-depth="2"] { padding-left: .75rem; }
23
- .site [data-component~="htmlkit-navigation"] [data-depth="3"] { padding-left: 1.5rem; }
24
- .site [data-component~="htmlkit-navigation"] :focus-visible { outline: 2px solid var(--ui-accent); outline-offset: 2px; }
@@ -0,0 +1,38 @@
1
+ /* Documentation typography. Each Markdown page component imports this, so its selectors match inside
2
+ that page only and stop at any component the page embeds. The page root itself is .markupress-prose. */
3
+ a { color: var(--ui-accent); text-underline-offset: .2em; }
4
+ h1 { font-size: clamp(1.8rem, 5vw, 2.7rem); line-height: 1.2; }
5
+ h2, h3 { margin-top: 2rem; scroll-margin-top: 2rem; }
6
+ h1 a, h2 a, h3 a { color: inherit; text-decoration: none; }
7
+ pre { overflow: auto; max-width: 100%; padding: 1rem; background: var(--ui-surface-sunken); border-radius: .5rem; }
8
+ figure.code { margin: 1rem 0; }
9
+ figure.code figcaption { margin-bottom: .25rem; font: .85rem ui-monospace, monospace; color: var(--ui-text-muted, inherit); }
10
+ code { font-size: .9em; }
11
+ img, svg { max-width: 100%; }
12
+ table { border-collapse: collapse; display: block; max-width: 100%; overflow: auto; }
13
+ th, td { border: 1px solid var(--ui-border, #8885); padding: .4rem .75rem; }
14
+ :focus-visible { outline: 2px solid var(--ui-accent); outline-offset: 3px; }
15
+ /* Looma Markdown's inline elements and blocks, drawn with the tokens LoomaEditor uses for them. */
16
+ [data-looma-chip] {
17
+ --_chip-surface: var(--ui-surface-subtle); --_chip-text: var(--ui-text-secondary);
18
+ padding: .08em .45em; border: var(--ui-border-width, 1px) solid color-mix(in srgb, var(--_chip-surface) 75%, var(--_chip-text) 25%);
19
+ border-radius: var(--ui-radius-round, 999px); background: var(--_chip-surface); color: var(--_chip-text);
20
+ font-size: var(--ui-font-size-sm, .85em); font-weight: var(--ui-font-medium, 500); box-decoration-break: clone;
21
+ }
22
+ [data-looma-chip][data-color="blue"] { --_chip-surface: var(--ui-info-soft); --_chip-text: var(--ui-info-subtle-text); }
23
+ [data-looma-chip][data-color="green"] { --_chip-surface: var(--ui-success-soft); --_chip-text: var(--ui-success-subtle-text); }
24
+ [data-looma-chip][data-color="yellow"] { --_chip-surface: var(--ui-warning-soft); --_chip-text: var(--ui-warning-subtle-text); }
25
+ [data-looma-chip][data-color="red"] { --_chip-surface: var(--ui-danger-soft); --_chip-text: var(--ui-danger-subtle-text); }
26
+ [data-looma-chip][data-color="purple"] { --_chip-surface: var(--ui-accent-soft); --_chip-text: var(--ui-accent-subtle-text); }
27
+ .looma-mention { padding: .08em .28em; border-radius: var(--ui-radius-sm, 4px); background: var(--ui-accent-soft); color: var(--ui-accent-active, var(--ui-accent)); font-weight: var(--ui-font-medium, 500); white-space: nowrap; }
28
+ ul[data-type="taskList"] { padding-left: .25rem; list-style: none; }
29
+ ul[data-type="taskList"] input { margin: 0 .5rem 0 0; accent-color: var(--ui-accent-solid, var(--ui-accent)); }
30
+ nav[data-looma-toc] { margin: 1rem 0; }
31
+ nav[data-looma-toc] :is(ol, ul, div)[role="list"] { margin: .25rem 0; padding-left: 1.25rem; }
32
+ nav[data-looma-toc] > [role="list"] { padding-left: 0; }
33
+ nav[data-looma-toc][data-format="numbered"] > ol, nav[data-looma-toc][data-format="bulleted"] > ul { padding-left: 1.25rem; }
34
+ figure:not(.code) { margin: 1.5rem 0; }
35
+ figure:not(.code) > figcaption { margin-top: .5rem; font-size: .9rem; color: var(--ui-text-muted, inherit); }
36
+ img[data-placement="center"] { display: block; margin-inline: auto; }
37
+ img[data-placement="wrap-left"] { float: left; margin: 0 1rem 1rem 0; }
38
+ img[data-placement="wrap-right"] { float: right; margin: 0 0 1rem 1rem; }
@@ -0,0 +1,11 @@
1
+ <template component="markupress-outline" controller="../dist/controllers/outline.js">
2
+ <defs><prop name="items" type="list(object({ id: string, href: string, label: string, depth: number }))" required>The page's headings, in order</prop></defs>
3
+ <nav aria-labelledby="markupress-outline-title"><strong id="markupress-outline-title">On this page</strong><ul><li $each="item of $items" from:data-depth="$item.depth"><a from:href="$item.href">{$item.label}</a></li></ul></nav>
4
+ <style>
5
+ nav { font-size: .875rem; } strong { display: block; margin-bottom: .5rem; }
6
+ ul { margin: 0; padding: 0; list-style: none; border-inline-start: 1px solid var(--ui-border, #8885); }
7
+ li { margin: 0; } li[data-depth="3"] a { padding-inline-start: 1.75rem; }
8
+ a { display: block; padding: .2rem 0 .2rem 1rem; margin-inline-start: -1px; border-inline-start: 2px solid transparent; color: var(--ui-text-muted, inherit); text-decoration: none; }
9
+ a:hover { color: var(--ui-text); } a[aria-current="location"] { border-color: var(--ui-accent); color: var(--ui-accent); }
10
+ :focus-visible { outline: 2px solid var(--ui-accent); outline-offset: 2px; }
11
+ </style></template>
@@ -0,0 +1,66 @@
1
+ <link rel="component" href="@threadlabs/looma/components/ui-button/ui-button.html">
2
+ <link rel="component" href="@threadlabs/looma/components/ui-badge/ui-badge.html">
3
+ <link rel="component" href="./outline.html">
4
+ <template component="markupress-shell" controller="../dist/controllers/shell.js">
5
+ <title>{$title}</title><link $if="$favicon" rel="icon" from:href="$favicon"><defs>
6
+ <prop name="title" type="string" required>Site title</prop>
7
+ <prop name="home" type="string" required>Home URL</prop>
8
+ <prop name="logo" type="object({ light: string, dark: string })" nullable>Logo images for the light and dark themes</prop>
9
+ <prop name="favicon" type="string" nullable>Site icon URL</prop>
10
+ <prop name="badge" type="string" default="">Badge beside the title</prop>
11
+ <prop name="nav" type="list(object({ label: string, href: string, current: string, icon: string }))" required>Top navigation: the sections, then the configured links, each with an icon URL or ""</prop>
12
+ <prop name="sidebar" type="list(object({ label: string, current: string, depth: number, href?: string, open?: boolean, children?: list(object({ label: string, ... })), ... }))" required>The section's sidebar: pages and links, and folders and groups with children, as &lt;hk-nav&gt; renders them</prop>
13
+ <prop name="contents" type="list(object({ label: string, href: string, description: string }))" required>A generated index's pages and folders</prop>
14
+ <prop name="outline" type="list(object({ id: string, href: string, label: string, depth: number }))" required>The page's headings</prop>
15
+ <prop name="footer" type="object({ columns: list(object({ title: string, items: list(object({ label: string, href: string, current: string })) })), copyright: string })" required>Footer link columns and copyright</prop>
16
+ <prop name="versions" type="list(object({ href: string, label: string, current: string, note: string }))" required>Documentation versions</prop>
17
+ <prop name="crumbs" type="list(object({ href: string, label: string, current: string, depth: number, pageName: string, ... }))" required>Trail from the version home to this page</prop>
18
+ <prop name="previous" type="object({ href: string, label: string, current: string, depth: number, pageName: string, ... })" nullable>The page before this one</prop>
19
+ <prop name="next" type="object({ href: string, label: string, current: string, depth: number, pageName: string, ... })" nullable>The page after this one</prop>
20
+ <state name="dark" type="boolean" value="false"></state></defs>
21
+ <div class="site"><a class="skip" href="#documentation-content">Skip to content</a>
22
+ <header>
23
+ <span class="menu"><ui-button variant="ghost" tone="neutral" popovertarget="documentation-navigation">Navigation</ui-button></span>
24
+ <a class="brand" from:href="$home"><template $if="$logo"><img class="logo logo-light" from:src="$logo.light" alt=""><img class="logo logo-dark" from:src="$logo.dark" alt=""></template>{$title}</a>
25
+ <ui-badge $if="$badge" tone="accent">{$badge}</ui-badge>
26
+ <nav class="top" $if="$nav.length" aria-label="Main"><ul><li $each="item of $nav">
27
+ <a from:href="$item.href" from:aria-current="$item.current"><template $match><img $when="$item.icon" from:src="$item.icon" from:alt="$item.label"><template $else>{$item.label}</template></template></a>
28
+ </li></ul></nav>
29
+ <div class="actions"><ui-button variant="ghost" tone="neutral" data-action="theme" from:aria-pressed="$dark">Dark theme</ui-button></div></header>
30
+ <div class="columns"><aside id="documentation-navigation" popover aria-label="Documentation">
31
+ <hk-nav from:items="$sidebar" label="Documentation"></hk-nav>
32
+ <nav class="versions" aria-label="Documentation versions"><strong>Versions</strong><ul><li $each="version of $versions"><a from:href="$version.href" from:aria-current="$version.current">{$version.label}</a><small $if="$version.note">{$version.note}</small></li></ul></nav>
33
+ </aside><main id="documentation-content" tabindex="-1"><hk-breadcrumbs from:items="$crumbs"></hk-breadcrumbs><slot name="page"></slot>
34
+ <ul class="contents" $if="$contents.length"><li $each="entry of $contents"><a from:href="$entry.href">{$entry.label}</a><p $if="$entry.description">{$entry.description}</p></li></ul><hk-pager from:previous="$previous" from:next="$next"></hk-pager></main>
35
+ <aside class="outline" $if="$outline.length" aria-label="On this page"><markupress-outline from:items="$outline"></markupress-outline></aside></div>
36
+ <footer $if="$footer.columns.length or $footer.copyright"><div class="footer-columns" $if="$footer.columns.length"><div $each="column of $footer.columns"><strong>{$column.title}</strong><ul><li $each="link of $column.items"><a from:href="$link.href" from:aria-current="$link.current">{$link.label}</a></li></ul></div></div>
37
+ <p $if="$footer.copyright">{$footer.copyright}</p></footer></div>
38
+ <style>
39
+ :host { display: block; background: var(--ui-surface); color: var(--ui-text); font: 1rem/1.7 system-ui, sans-serif; min-height: 100vh; }
40
+ .site { display: flex; flex-direction: column; min-height: 100vh; }
41
+ header { position: sticky; top: 0; z-index: 2; display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; border-bottom: 1px solid var(--ui-border, #8885); padding: .75rem max(1rem, calc((100vw - 90rem) / 2)); background: var(--ui-surface); }
42
+ .brand { display: flex; align-items: center; gap: .5rem; color: inherit; font-size: 1.15rem; font-weight: 700; text-decoration: none; } .logo { block-size: 2rem; inline-size: auto; }
43
+ .actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-inline-start: auto; }
44
+ header ul { display: flex; flex-wrap: wrap; gap: .25rem 1rem; margin: 0; padding: 0; list-style: none; }
45
+ header a { color: inherit; text-decoration: none; } header a:hover, header a[aria-current="page"], header a[aria-current="true"] { color: var(--ui-accent); }
46
+ .top ul { align-items: center; } .top img { display: block; block-size: 1.25rem; inline-size: auto; }
47
+ .columns { display: flex; gap: 3rem; flex: 1; inline-size: 100%; max-inline-size: 90rem; margin: auto; padding: 2rem 1.5rem; }
48
+ #documentation-navigation { flex: 0 0 15rem; } main { min-width: 0; flex: 1; max-width: 65ch; } .outline { flex: 0 0 13rem; }
49
+ /* Wide screens show the sidebar in the page; narrow ones open it as a native popover, which needs no script. */
50
+ @media (min-width: 769px) { #documentation-navigation { display: block; position: static; inset: auto; margin: 0; padding: 0; border: 0; background: none; color: inherit; overflow: visible; }
51
+ #documentation-navigation, .outline { position: sticky; top: 5rem; align-self: flex-start; max-block-size: calc(100vh - 6rem); overflow: auto; } .menu { display: none; } }
52
+ @media (max-width: 1199px) { .outline { display: none; } }
53
+ @media (max-width: 768px) { header { position: static; } .columns { display: block; padding: 1rem; }
54
+ #documentation-navigation { inset: 0 auto 0 0; block-size: 100%; max-block-size: none; inline-size: min(20rem, 85vw); margin: 0; padding: 1rem; border: 0; border-inline-end: 1px solid var(--ui-border, #8885); background: var(--ui-surface); color: var(--ui-text); }
55
+ #documentation-navigation::backdrop { background: rgb(0 0 0 / .4); } }
56
+ .versions ul { margin: 0; padding: 0; list-style: none; } .versions li { margin: .4rem 0; } .versions { margin-top: 2rem; }
57
+ a { color: var(--ui-accent); text-underline-offset: .2em; } a[aria-current="page"] { font-weight: 700; } small { display: block; color: var(--ui-text-muted, inherit); line-height: 1.4; } :focus-visible { outline: 2px solid var(--ui-accent); outline-offset: 3px; }
58
+ .skip { position: absolute; top: .5rem; left: 1rem; transform: translateY(-200%); padding: .5rem 1rem; background: var(--ui-surface); z-index: 3; } .skip:focus { transform: none; }
59
+ footer { border-top: 1px solid var(--ui-border, #8885); padding: 2rem max(1.5rem, calc((100vw - 90rem) / 2)); color: var(--ui-text-muted, inherit); font-size: .9rem; }
60
+ .footer-columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); gap: 1.5rem; } footer ul { margin: .5rem 0 0; padding: 0; list-style: none; } footer li { margin: .25rem 0; } footer strong { color: var(--ui-text); }
61
+ footer p { margin: 1.5rem 0 0; }
62
+ .contents { display: grid; gap: .75rem; margin: 1.5rem 0; padding: 0; list-style: none; }
63
+ .contents li { padding: .75rem 1rem; border: 1px solid var(--ui-border, #8885); border-radius: var(--ui-radius-md, .5rem); }
64
+ .contents a { font-weight: 600; } .contents p { margin: .25rem 0 0; color: var(--ui-text-muted, inherit); }
65
+ @media (max-width: 640px) { header { padding-inline: 1rem; } }
66
+ </style></template>
@@ -0,0 +1,52 @@
1
+ /* Global, so it reaches HTMLKit's built-in navigation, breadcrumbs and pager inside the shell; the shell's own <style> is scoped and stops at them. */
2
+ [data-component~="markupress-shell"] :is([data-component="hk-breadcrumbs"], [data-component="hk-pager"]) a {
3
+ color: var(--ui-accent); text-underline-offset: .2em;
4
+ }
5
+ [data-component~="markupress-shell"] [data-component="hk-breadcrumbs"] a[aria-current="page"] { font-weight: 700; }
6
+ [data-component~="markupress-shell"] [data-component="hk-breadcrumbs"] ol { display: flex; flex-wrap: wrap; gap: .25rem .5rem; margin: 0 0 1.5rem; padding: 0; list-style: none; font-size: .875rem; }
7
+ [data-component~="markupress-shell"] [data-component="hk-breadcrumbs"] li + li::before { content: "/"; margin-inline-end: .5rem; color: var(--ui-text-muted, inherit); }
8
+ [data-component~="markupress-shell"] [data-component="hk-pager"] { display: flex; justify-content: space-between; gap: 1rem; margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--ui-border, #8885); }
9
+ [data-component~="markupress-shell"] [data-component="hk-pager"] a { display: grid; }
10
+ [data-component~="markupress-shell"] [data-component="hk-pager"] a[rel="next"] { margin-inline-start: auto; text-align: end; }
11
+ [data-component~="markupress-shell"] [data-component="hk-pager"] small { color: var(--ui-text-muted, inherit); }
12
+ /* The sidebar is HTMLKit's <hk-nav>: nested lists, with each folder and group in a native <details>. */
13
+ [data-component~="markupress-shell"] [data-component="hk-nav"] ul { margin: 0; padding: 0; list-style: none; }
14
+ [data-component~="markupress-shell"] [data-component="hk-nav"] li { margin: .4rem 0; }
15
+ [data-component~="markupress-shell"] [data-component="hk-nav"] details ul { padding-inline-start: .75rem; }
16
+ [data-component~="markupress-shell"] [data-component="hk-nav"] summary { cursor: pointer; font-weight: 600; }
17
+ [data-component~="markupress-shell"] [data-component="hk-nav"] a { color: var(--ui-accent); text-underline-offset: .2em; }
18
+ [data-component~="markupress-shell"] [data-component="hk-nav"] a[aria-current="page"] { font-weight: 700; }
19
+ /* Shared blocks. Markdown inside a callout or tabs is projected into a Looma component, where the page's scoped
20
+ prose styles never reach (HTML Next styling: a page's rules stop at every nested component), so these global
21
+ rules space the blocks and repeat the prose code styles inside them. Details is native and needs no script. */
22
+ .markupress-prose :is([data-component~="ui-callout"], [data-component~="ui-tabs"], details) { margin-block: 1rem; }
23
+ .markupress-prose details { padding: .5rem 1rem; border: 1px solid var(--ui-border, #8885); border-radius: var(--ui-radius-md, .5rem); }
24
+ .markupress-prose summary { cursor: pointer; font-weight: 600; }
25
+ .markupress-prose [data-component~="ui-callout"] :is(p, ul, ol, pre, figure, table, details) { margin-block: .5rem; }
26
+ .markupress-prose [data-component~="ui-callout"] :is(p, ul, ol, pre, figure, table, details):first-child { margin-block-start: 0; }
27
+ .markupress-prose [data-component~="ui-callout"] :is(p, ul, ol, pre, figure, table, details):last-child { margin-block-end: 0; }
28
+ .markupress-prose :is([data-component~="ui-callout"], [data-component~="ui-tabs"]) pre { overflow: auto; max-width: 100%; padding: 1rem; background: var(--ui-surface-sunken); border-radius: .5rem; }
29
+ .markupress-prose :is([data-component~="ui-callout"], [data-component~="ui-tabs"]) code { font-size: .9em; }
30
+ .markupress-prose :is([data-component~="ui-callout"], [data-component~="ui-tabs"]) figure.code { margin: 1rem 0; }
31
+ .markupress-prose :is([data-component~="ui-callout"], [data-component~="ui-tabs"]) figure.code > pre { margin: 0; }
32
+ .markupress-prose [data-component~="ui-tabs"] figure.code:only-child { margin: 0; }
33
+ .markupress-prose .code-group section { padding-inline: 0; }
34
+ /* Code blocks. Highlighted lines and line numbers are classes written at build time; a highlighted line tints the page
35
+ surface, which contrasts more with the code than the block's sunken surface does. The copy and wrap buttons stay
36
+ hidden until the page's code controller connects, and show while the block is hovered or holds focus. */
37
+ .markupress-prose figure.code { position: relative; }
38
+ .markupress-prose .code-actions { position: absolute; inset-block-start: .5rem; inset-inline-end: .5rem; display: flex; gap: .25rem; opacity: 0; transition: opacity var(--ui-motion-fast, .12s); }
39
+ .markupress-prose figure.code > figcaption ~ .code-actions { inset-block-start: 0; }
40
+ .markupress-prose .code-actions[hidden] { display: none; }
41
+ .markupress-prose figure.code:is(:hover, :focus-within) .code-actions { opacity: 1; }
42
+ @media (hover: none) { .markupress-prose .code-actions { opacity: 1; } }
43
+ .markupress-prose .code-actions button { padding: .3rem .5rem; border: 1px solid var(--ui-border, #8885); border-radius: var(--ui-radius-sm, .25rem); background: var(--ui-surface); color: var(--ui-text); font: .75rem/1 system-ui, sans-serif; cursor: pointer; }
44
+ .markupress-prose .code-actions button[aria-pressed="true"] { border-color: var(--ui-accent); }
45
+ .markupress-prose pre.wrap { white-space: pre-wrap; overflow-wrap: anywhere; }
46
+ .markupress-prose pre .line.highlighted { display: inline-block; box-sizing: content-box; min-inline-size: 100%; margin-inline: -1rem; padding-inline: 1rem; background: color-mix(in srgb, var(--ui-accent) 10%, var(--ui-surface)); box-shadow: inset 2px 0 var(--ui-accent); }
47
+ .markupress-prose pre.line-numbers code { counter-reset: line; }
48
+ .markupress-prose pre.line-numbers .line::before { counter-increment: line; content: counter(line); display: inline-block; inline-size: 2ch; margin-inline-end: 1.5ch; text-align: end; color: var(--ui-text-muted, #888); user-select: none; }
49
+ /* The logo for the theme in use: the head script sets data-theme before first paint, and without it the light logo shows. */
50
+ [data-component~="markupress-shell"] .logo-dark { display: none; }
51
+ :root[data-theme="dark"] [data-component~="markupress-shell"] .logo-dark { display: inline; }
52
+ :root[data-theme="dark"] [data-component~="markupress-shell"] .logo-light { display: none; }