markupress 0.0.1 → 0.0.2

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 threadlabs-studio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,5 +1,134 @@
1
1
  # Markupress
2
2
 
3
- A forthcoming documentation publishing tool built on HTMLKit, from Threadlabs Studio.
3
+ Build a versioned Markdown documentation site with native HTML Next components, HTMLKit routing and a Looma theme. Markupress provides `build`, `dev`, `preview` and `snapshot` commands. Production output is a portable static directory; controllers enhance the rendered HTML in the browser.
4
4
 
5
- Version 0.0.1 reserves the package name. It contains no implementation or public API.
5
+ The npm package `markupress@0.0.1` only reserves the name. The implementation below is being prepared for the first product release.
6
+
7
+ ## Try the source build
8
+
9
+ Use Node 22.22.2 or later in Node 22, or Node 24.15 or later in Node 24, and pnpm through Corepack:
10
+
11
+ ```sh
12
+ corepack pnpm install --frozen-lockfile
13
+ corepack pnpm build
14
+ node dist/cli.js dev --root examples/site
15
+ node dist/cli.js build --root examples/site
16
+ node dist/cli.js preview --root examples/site
17
+ ```
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.
20
+
21
+ ## Author a site
22
+
23
+ Create `docs/01-index.md` and optionally `markupress.config.json`:
24
+
25
+ ```json
26
+ {
27
+ "title": "Project documentation",
28
+ "contentDir": "docs",
29
+ "base": "/manual/",
30
+ "outDir": "site"
31
+ }
32
+ ```
33
+
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`.
35
+
36
+ ```markdown
37
+ ---
38
+ title: Installation
39
+ description: Install the project and run your first example.
40
+ sidebarLabel: Install
41
+ id: install
42
+ aliases: [/getting-started/]
43
+ ---
44
+ # Installation
45
+
46
+ [Next steps](03-usage.md#usage)
47
+
48
+ <link rel="component" href="../../components/counter.html">
49
+
50
+ <demo-counter></demo-counter>
51
+ ```
52
+
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.
54
+
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.
56
+
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.
58
+
59
+ ## TypeScript controllers
60
+
61
+ Maintain controllers in strict ESM TypeScript, with `.js` references in HTML:
62
+
63
+ ```html
64
+ <template component="demo-counter" controller="./counter.js">
65
+ <defs><state name="count" type="number" value="0"></state></defs>
66
+ <div><button>Increment</button><output $value="$count"></output></div>
67
+ </template>
68
+ ```
69
+
70
+ ```ts
71
+ // counter.ts
72
+ import type { ComponentHost } from '@nextwebwg/html-next/runtime';
73
+
74
+ export default function counter(host: ComponentHost): void {
75
+ host.on('connect', () => {
76
+ const button = host.root.querySelector('button')!;
77
+ const click = () => { host.state.count = Number(host.state.count) + 1; };
78
+ button.addEventListener('click', click);
79
+ return () => button.removeEventListener('click', click);
80
+ });
81
+ }
82
+ ```
83
+
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.
85
+
86
+ ## Versions
87
+
88
+ Record active docs without overwriting an existing edition:
89
+
90
+ ```sh
91
+ markupress snapshot v1
92
+ markupress build
93
+ ```
94
+
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.
96
+
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.
98
+
99
+ For explicit versions, configure their order and labels:
100
+
101
+ ```json
102
+ {
103
+ "versions": [
104
+ { "id": "current", "label": "Next", "directory": "docs" },
105
+ { "id": "v1", "label": "Version 1", "directory": "versioned_docs/v1/_source/docs", "publicDir": "versioned_docs/v1/_source/public" }
106
+ ],
107
+ "defaultVersion": "v1"
108
+ }
109
+ ```
110
+
111
+ Version IDs are URL slugs; they need not follow SemVer. A document's `id` identifies it across versions independently of its filename, route and generated component name. The version selector links to that identity in the other version, even if its route changed. If it is absent, the selector explains the fallback and links to that version's home. Selection lives in the URL and survives reloads.
112
+
113
+ ## Theme and migration inputs
114
+
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.
116
+
117
+ 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
+
119
+ ## Verification and contribution
120
+
121
+ ```sh
122
+ corepack pnpm verify:inner
123
+ corepack pnpm verify:pr
124
+ corepack pnpm exec playwright install chromium
125
+ MARKUPRESS_BROWSER_TEST=1 corepack pnpm exec vitest run tests/package.test.ts --maxWorkers=1
126
+ ```
127
+
128
+ The package contract packs and installs the actual package, runs its CLI, checks frozen imports and checks controller types. The browser proof exercises production and development controllers, keyboard version selection, reloads, mobile navigation and an axe accessibility audit. CI runs that browser proof separately.
129
+
130
+ Foundation pins TypeScript, Vitest, Oxlint and pnpm. [AGENTS.md](AGENTS.md) is the contributor contract; [threadlabs.config.json](threadlabs.config.json) records ownership. The [implementation plan](docs/plans/2026-10-04-1830-feat-markupress-platform-plan.md) defines product boundaries. Publishing uses the protected GitHub release workflow and npm environment.
131
+
132
+ ## License
133
+
134
+ [MIT](LICENSE), copyright Threadlabs Studio contributors.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ import { readFile } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import { parseArgs } from 'node:util';
5
+ import { buildSite, devSite, previewSite } from './site.js';
6
+ import { snapshotVersion } from './versions.js';
7
+ async function main() {
8
+ const { values, positionals } = parseArgs({ allowPositionals: true, options: {
9
+ root: { type: 'string' }, base: { type: 'string' }, port: { type: 'string' }, help: { type: 'boolean', short: 'h' },
10
+ } });
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');
13
+ return;
14
+ }
15
+ const root = resolve(values.root ?? process.cwd());
16
+ let config = {};
17
+ try {
18
+ config = JSON.parse(await readFile(resolve(root, 'markupress.config.json'), 'utf8'));
19
+ }
20
+ catch (error) {
21
+ if (error.code !== 'ENOENT')
22
+ throw error;
23
+ }
24
+ const options = { ...config, root, ...(values.base === undefined ? {} : { base: values.base }),
25
+ ...(values.port === undefined ? {} : { port: Number(values.port) }) };
26
+ const command = positionals[0] ?? 'dev';
27
+ if (command === 'snapshot') {
28
+ if (!positionals[1])
29
+ throw new Error('snapshot requires a version id.');
30
+ const version = await snapshotVersion(positionals[1], options);
31
+ process.stdout.write(`Recorded ${version.id} in ${version.directory}\n`);
32
+ return;
33
+ }
34
+ if (command === 'build') {
35
+ const built = await buildSite(options);
36
+ process.stdout.write(`Generated ${built.routes.length} pages in ${built.outDir}\n`);
37
+ return;
38
+ }
39
+ if (command !== 'dev' && command !== 'preview')
40
+ throw new Error(`Unknown command: ${command}. Use build, dev, or preview.`);
41
+ const server = await (command === 'dev' ? devSite(options) : previewSite(options));
42
+ process.stdout.write(`Markupress ${command}: ${server.url}\n`);
43
+ const close = () => { void server.close().then(() => process.exit(0)); };
44
+ process.once('SIGINT', close);
45
+ process.once('SIGTERM', close);
46
+ }
47
+ void main().catch(error => { process.stderr.write(`${String(error)}\n`); process.exitCode = 1; });
48
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export interface MarkdownOptions {
2
+ readonly file: string;
3
+ readonly pageName: string;
4
+ /** Resolve authored document links and assets from their original source. */
5
+ readonly resolveLink?: (href: string, kind: 'link' | 'asset') => string;
6
+ }
7
+ export interface CompiledMarkdown {
8
+ readonly resource: string;
9
+ readonly title: string;
10
+ readonly label: string;
11
+ readonly id?: string;
12
+ readonly aliases: readonly string[];
13
+ readonly sidebarHidden: boolean;
14
+ }
15
+ export declare function escapeHTML(value: string): string;
16
+ export declare function literal(value: string): string;
17
+ export declare function compileMarkdown(source: string, options: MarkdownOptions): CompiledMarkdown;
18
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,129 @@
1
+ import { basename, resolve } from 'node:path';
2
+ import { pathToFileURL } from 'node:url';
3
+ import { Marked } from 'marked';
4
+ import { parseFragment, serialize, serializeOuter } from 'parse5';
5
+ import { parseDocument } from 'yaml';
6
+ import { stylesheet } from './styles.js';
7
+ export function escapeHTML(value) {
8
+ return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
9
+ }
10
+ // Markdown text is literal author content. Raw HTML tokens retain component expressions.
11
+ export function literal(value) { return value.replace(/\\/g, '\\\\').replace(/{/g, '\\{'); }
12
+ function textContent(node) {
13
+ if ('value' in node)
14
+ return node.value;
15
+ return 'childNodes' in node ? node.childNodes.map(textContent).join('') : '';
16
+ }
17
+ function frontmatter(source, file) {
18
+ const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(source);
19
+ if (match === null)
20
+ return { body: source, fields: {} };
21
+ const document = parseDocument(match[1]);
22
+ if (document.errors.length > 0)
23
+ throw new Error(`${file}: ${document.errors.map(error => error.message).join('; ')}`);
24
+ const fields = document.toJS();
25
+ if (fields === null || typeof fields !== 'object' || Array.isArray(fields))
26
+ throw new Error(`${file}: frontmatter must be a mapping.`);
27
+ return { body: source.slice(match[0].length), fields: fields };
28
+ }
29
+ export function compileMarkdown(source, options) {
30
+ const { body, fields } = frontmatter(source, options.file);
31
+ for (const name of ['title', 'description', 'sidebarLabel', 'id']) {
32
+ if (fields[name] !== undefined && (typeof fields[name] !== 'string' || fields[name] === ''))
33
+ throw new Error(`${options.file}: ${name} must be a nonempty string.`);
34
+ }
35
+ const aliases = fields.aliases ?? [];
36
+ if (fields.sidebarHidden !== undefined && typeof fields.sidebarHidden !== 'boolean')
37
+ throw new Error(`${options.file}: sidebarHidden must be a boolean.`);
38
+ if (!Array.isArray(aliases) || aliases.some(value => typeof value !== 'string'))
39
+ throw new Error(`${options.file}: aliases must be a list of route paths.`);
40
+ const headings = new Map();
41
+ let firstHeading;
42
+ const markdown = new Marked({ async: false, renderer: {
43
+ text(token) { return 'tokens' in token && token.tokens ? this.parser.parseInline(token.tokens) : literal(token.text); },
44
+ codespan({ text }) { return `<code>${literal(escapeHTML(text))}</code>`; },
45
+ code({ text, lang }) { return `<pre><code${lang ? ` class="language-${escapeHTML(lang.split(/\s/)[0])}"` : ''}>${literal(escapeHTML(text))}</code></pre>\n`; },
46
+ heading({ tokens, depth }) {
47
+ const html = this.parser.parseInline(tokens);
48
+ const label = textContent(parseFragment(html)).replace(/\\([\\{])/g, '$1');
49
+ firstHeading ??= label;
50
+ const stem = label.normalize('NFKD').toLowerCase().replace(/[^\p{L}\p{N}]+/gu, '-').replace(/^-|-$/g, '') || 'heading';
51
+ const count = headings.get(stem) ?? 0;
52
+ headings.set(stem, count + 1);
53
+ const id = count === 0 ? stem : `${stem}-${count}`;
54
+ return `<h${depth} id="${escapeHTML(id)}"><a href="#${escapeHTML(id)}">${html}</a></h${depth}>\n`;
55
+ },
56
+ link({ href, title, tokens }) {
57
+ const target = options.resolveLink?.(href, 'link') ?? href;
58
+ return `<a href="${escapeHTML(target)}"${title ? ` title="${escapeHTML(title)}"` : ''}>${this.parser.parseInline(tokens)}</a>`;
59
+ },
60
+ image({ href, title, text }) {
61
+ const target = options.resolveLink?.(href, 'asset') ?? href;
62
+ return `<img src="${escapeHTML(target)}" alt="${escapeHTML(text)}"${title ? ` title="${escapeHTML(title)}"` : ''}>`;
63
+ },
64
+ } });
65
+ markdown.use({ extensions: [{ name: 'native-component', level: 'block',
66
+ start(text) { return text.indexOf('<template'); },
67
+ tokenizer(text) {
68
+ if (!/^ {0,3}<template(?:\s|>)/i.test(text))
69
+ return undefined;
70
+ // Native fragment parsing identifies the carrier boundary, including nested templates.
71
+ // Markdown must never interpret a component's CSS, expressions or internal markup.
72
+ const carrier = parseFragment(text, { sourceCodeLocationInfo: true }).childNodes.find(node => 'tagName' in node);
73
+ if (!carrier || !('tagName' in carrier) || carrier.tagName !== 'template' || !carrier.attrs.some(attr => attr.name === 'component'))
74
+ return undefined;
75
+ const end = carrier.sourceCodeLocation?.endTag?.endOffset;
76
+ if (end === undefined)
77
+ throw new Error(`${options.file}: unclosed native component template.`);
78
+ const raw = text.slice(0, end);
79
+ return { type: 'native-component', raw };
80
+ }, renderer(token) { return token.raw; },
81
+ }] });
82
+ const fragment = parseFragment(markdown.parse(body));
83
+ const declarations = [];
84
+ const metadata = [];
85
+ const original = pathToFileURL(resolve(options.file)).href;
86
+ const rebase = (value) => /^(?:\.\.?\/|\/)/.test(value) ? new URL(value, original).href : value;
87
+ const visit = (node, inCarrier) => {
88
+ if ('tagName' in node) {
89
+ if (node.tagName === 'style')
90
+ for (const child of node.childNodes)
91
+ if ('value' in child)
92
+ child.value = stylesheet(child.value, options.file, true).css;
93
+ for (const attribute of node.attrs) {
94
+ if (attribute.name === 'controller')
95
+ attribute.value = rebase(attribute.value);
96
+ if (node.tagName === 'link' && attribute.name === 'href' && node.attrs.some(attr => attr.name === 'rel' && attr.value.split(/\s+/).includes('component')))
97
+ attribute.value = rebase(attribute.value);
98
+ else if (options.resolveLink && ((attribute.name === 'href' && node.tagName === 'a') || (attribute.name === 'src' && node.tagName === 'img'))) {
99
+ // Markdown-rendered links are already resolved; the callback also accepts final URLs.
100
+ attribute.value = options.resolveLink(attribute.value, attribute.name === 'src' ? 'asset' : 'link');
101
+ }
102
+ }
103
+ if (node.tagName === 'template' && 'content' in node)
104
+ visit(node.content, true);
105
+ }
106
+ if ('childNodes' in node) {
107
+ const kept = [];
108
+ for (const child of node.childNodes) {
109
+ visit(child, inCarrier);
110
+ if (!inCarrier && 'tagName' in child && child.tagName === 'template' && child.attrs.some(attr => attr.name === 'component'))
111
+ declarations.push(serializeOuter(child));
112
+ else if (!inCarrier && 'tagName' in child && child.tagName === 'link' && child.attrs.some(attr => attr.name === 'rel' && attr.value.split(/\s+/).includes('component')))
113
+ declarations.push(serializeOuter(child));
114
+ else if (!inCarrier && 'tagName' in child && ['title', 'meta', 'link'].includes(child.tagName))
115
+ metadata.push(serializeOuter(child));
116
+ else
117
+ kept.push(child);
118
+ }
119
+ node.childNodes = kept;
120
+ }
121
+ };
122
+ visit(fragment, false);
123
+ const title = fields.title ?? firstHeading ?? basename(options.file, '.md').replace(/^\d+-/, '');
124
+ const label = fields.sidebarLabel ?? title;
125
+ const head = `<title>${literal(escapeHTML(title))}</title>` + (fields.description === undefined ? '' : `<meta name="description" content="${escapeHTML(fields.description)}">`);
126
+ return { title, label, aliases, sidebarHidden: fields.sidebarHidden === true, ...(fields.id === undefined ? {} : { id: fields.id }),
127
+ resource: `<meta name="htmlkit:page" content="${escapeHTML(options.pageName)}">\n${declarations.join('\n')}\n<template component="${escapeHTML(options.pageName)}">${head}${metadata.join('')}<article class="markupress-prose">${serialize(fragment)}</article></template>\n` };
128
+ }
129
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ComponentHost } from '@nextwebwg/html-next/runtime';
2
+ /** Native controls and storage own interaction; HTML Next owns reactive state and cleanup. */
3
+ export default function shell(host: ComponentHost): void;
4
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/controllers/shell.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,8FAA8F;AAC9F,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAiCvD"}
@@ -0,0 +1,46 @@
1
+ /** Native controls and storage own interaction; HTML Next owns reactive state and cleanup. */
2
+ export default function shell(host) {
3
+ host.on('connect', () => {
4
+ const document = host.root.ownerDocument;
5
+ const window = document.defaultView;
6
+ let saved = null;
7
+ try {
8
+ saved = window.localStorage.getItem('markupress:theme');
9
+ }
10
+ catch { /* Storage can be disabled while native controls remain usable. */ }
11
+ host.state.dark = saved === 'dark' || (saved === null && window.matchMedia('(prefers-color-scheme: dark)').matches);
12
+ const actions = host.root.querySelector(':scope > header > .actions');
13
+ const applyTheme = () => {
14
+ document.documentElement.dataset.theme = host.state.dark ? 'dark' : 'light';
15
+ };
16
+ applyTheme();
17
+ // HTMLKit head metadata admits no script, so a saved theme lands after first paint. Settle it
18
+ // at once instead of animating controls out of the default theme; user toggles still animate.
19
+ for (const transition of document.getAnimations())
20
+ if (transition instanceof window.CSSTransition)
21
+ transition.finish();
22
+ const click = (event) => {
23
+ const target = event.target;
24
+ if (!(target instanceof window.Element))
25
+ return;
26
+ if (!actions.contains(target))
27
+ return;
28
+ const action = target.closest('[data-action]')?.getAttribute('data-action');
29
+ if (action === 'theme') {
30
+ host.state.dark = !host.state.dark;
31
+ applyTheme();
32
+ const theme = host.state.dark ? 'dark' : 'light';
33
+ try {
34
+ window.localStorage.setItem('markupress:theme', theme);
35
+ }
36
+ catch { /* Theme still applies for this page. */ }
37
+ }
38
+ if (action === 'menu') {
39
+ host.state.menu = !host.state.menu;
40
+ }
41
+ };
42
+ host.root.addEventListener('click', click);
43
+ return () => host.root.removeEventListener('click', click);
44
+ });
45
+ }
46
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/controllers/shell.ts"],"names":[],"mappings":"AAGA,8FAA8F;AAC9F,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAmB;IAC/C,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;QACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAY,CAAC;QACrC,IAAI,KAAK,GAAkB,IAAI,CAAC;QAChC,IAAI,CAAC;YAAC,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,kEAAkE,CAAC,CAAC;QAC7I,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,CAAC,CAAC;QACpH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,4BAA4B,CAAE,CAAC;QACvE,MAAM,UAAU,GAAG,GAAG,EAAE;YACtB,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAC9E,CAAC,CAAC;QACF,UAAU,EAAE,CAAC;QACb,8FAA8F;QAC9F,8FAA8F;QAC9F,KAAK,MAAM,UAAU,IAAI,QAAQ,CAAC,aAAa,EAAE;YAAE,IAAI,UAAU,YAAY,MAAM,CAAC,aAAa;gBAAE,UAAU,CAAC,MAAM,EAAE,CAAC;QACvH,MAAM,KAAK,GAAG,CAAC,KAAY,EAAE,EAAE;YAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YAC5B,IAAI,CAAC,CAAC,MAAM,YAAY,MAAM,CAAC,OAAO,CAAC;gBAAE,OAAO;YAChD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,OAAO;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,YAAY,CAAC,aAAa,CAAC,CAAC;YAC5E,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;gBACvB,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;gBACnC,UAAU,EAAE,CAAC;gBACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;gBACjD,IAAI,CAAC;oBAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,wCAAwC,CAAC,CAAC;YACpH,CAAC;YACD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACrC,CAAC;QACH,CAAC,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC3C,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { compileMarkdown } from './content.js';
2
+ export type { CompiledMarkdown, MarkdownOptions } from './content.js';
3
+ export { buildSite, devSite, prepareSite, previewSite } from './site.js';
4
+ export type { DocumentationPage, DocumentationVersion, MarkupressOptions, PreparedSite } from './site.js';
5
+ export { snapshotVersion, versionLinks } from './versions.js';
6
+ export type { VersionLink } from './versions.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACzE,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC1G,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC9D,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // Public exports are introduced with implemented, verified product behavior.
2
+ export { compileMarkdown } from './content.js';
3
+ export { buildSite, devSite, prepareSite, previewSite } from './site.js';
4
+ export { snapshotVersion, versionLinks } from './versions.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
package/dist/site.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ import { type ApplicationOptions, type ApplicationServer, type BuildResult } from '@nextwebwg/htmlkit';
2
+ export interface DocumentationVersion {
3
+ readonly id: string;
4
+ readonly label?: string;
5
+ readonly directory: string;
6
+ /** Snapshot-owned public assets; active versions use the project's public directory. */
7
+ readonly publicDir?: string;
8
+ }
9
+ export interface MarkupressOptions {
10
+ readonly root?: string;
11
+ readonly contentDir?: string;
12
+ readonly base?: string;
13
+ readonly outDir?: string;
14
+ readonly title?: string;
15
+ readonly versions?: readonly DocumentationVersion[];
16
+ readonly defaultVersion?: string;
17
+ readonly host?: string;
18
+ readonly port?: number;
19
+ }
20
+ export interface DocumentationPage {
21
+ readonly id: string;
22
+ readonly version: string;
23
+ readonly source: string;
24
+ readonly pathname: string;
25
+ readonly label: string;
26
+ readonly pageName: string;
27
+ }
28
+ export interface PreparedSite {
29
+ readonly application: ApplicationOptions;
30
+ readonly documents: readonly DocumentationPage[];
31
+ readonly sourceFiles: readonly string[];
32
+ }
33
+ /** Compile author content into an owned HTMLKit application, preserving original import locations. */
34
+ export declare function prepareSite(options?: MarkupressOptions): Promise<PreparedSite>;
35
+ export declare function buildSite(options?: MarkupressOptions): Promise<BuildResult>;
36
+ export declare function previewSite(options?: MarkupressOptions): Promise<ApplicationServer>;
37
+ export declare function devSite(options?: MarkupressOptions): Promise<ApplicationServer>;
38
+ //# sourceMappingURL=site.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwD,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAI7J,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AACD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACpD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AACD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACjD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAiCD,sGAAsG;AACtG,wBAAsB,WAAW,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAoC;AAoI7H,wBAAsB,SAAS,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAUrF;AACD,wBAAsB,WAAW,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAE7F;AACD,wBAAsB,OAAO,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0BzF"}