@apisurf/canonui 0.1.1

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,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Luka Vidakovic
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # @apisurf/canonui
2
+
3
+ The `canonui` command: build and preview the documents that [`canon`](../cli) holds.
4
+
5
+ ```sh
6
+ npm i -g @apisurf/canonui
7
+ canonui ls # what is in the database, and what to build
8
+ canonui build retry-guide # -> ./dist/retry-guide
9
+ canonui serve retry-guide # build it, then open it in a browser
10
+ canonui open ./public # serve a folder that is already built
11
+ canonui help
12
+ ```
13
+
14
+ Four commands, none of which writes anything. `canon` is the agent's half of the
15
+ pair — it creates and edits content, one record per command — and this is the
16
+ human's: it opens the same database read-only, says what is in it, and turns a
17
+ document into a folder of static files.
18
+
19
+ It is usable on its own. `canonui ls` prints the slugs the other commands take, and
20
+ `build` and `serve` resolve the only document themselves when there is one — so
21
+ nothing here sends you to `canon` to find out what to type.
22
+
23
+ Everything is documented in the command itself — `canonui help`, then
24
+ `canonui help <command>` — and in the [repository README](../../README.md).
25
+
26
+ ## What is in here
27
+
28
+ Two halves of one package, and the seam between them is a JSON file.
29
+
30
+ | File | What it is |
31
+ | ---------------- | ------------------------------------------------------------- |
32
+ | `src/bin.ts` | Argument parsing and dispatch. One parser per command |
33
+ | `src/list.ts` | `ls`, and the document `build` picks when given none |
34
+ | `src/db.ts` | Opening the file `canon` owns, read-only and unmigrated |
35
+ | `src/build.ts` | Open the database, reduce a document to a snapshot, render it |
36
+ | `src/serve.ts` | `serve` — build a document, then hand it to the server |
37
+ | `src/open.ts` | `open` — work out which built folder was meant |
38
+ | `src/http.ts` | The static file server both of them end at |
39
+ | `src/render.ts` | Spawning Astro with the theme, parameterised by environment |
40
+ | `src/help.ts` | Every help page. One screen each |
41
+ | `src/howto.ts` | Worked examples: preview, publish, snapshot |
42
+ | `src/format.ts` | The listing `ls` prints, and its JSON |
43
+ | `src/version.ts` | The build's version, and the schema it expects |
44
+ | `theme/` | The Astro theme — the only part that renders anything |
45
+
46
+ Only `src/` links against SQLite, and only `theme/` knows what HTML is. That is
47
+ what lets `canonui build --snapshot-only` hand the same input to some other
48
+ renderer, and what lets the theme be worked on without a database in reach.
49
+
50
+ ## The theme
51
+
52
+ One document builds into one page. One layout with three named slots (`head`,
53
+ `aside`, `footer`) and a default behind each, one component per block type, and
54
+ one stylesheet of plain CSS with tokens on `:root`.
55
+
56
+ The page is two columns: the document — title, description, a copy button, then
57
+ every block in order — and a rail listing its titled blocks and the headings
58
+ inside markdown blocks. There is no framework, and the client-side runtime is
59
+ four small scripts: the wide toggle, the copy button, the rail's scroll
60
+ tracking, and mermaid when the document holds a diagram — bundled into the site
61
+ rather than fetched from a CDN, so it works offline.
62
+
63
+ | File | What it is |
64
+ | ------------------------------ | ----------------------------------------------- |
65
+ | `theme/layouts/Site.astro` | The shell, and every slot a theme would replace |
66
+ | `theme/components/Block.astro` | One block, drawn according to its type |
67
+ | `theme/components/Toc.astro` | The contents rail |
68
+ | `theme/components/Copy.astro` | The button that copies the document as markdown |
69
+ | `theme/pages/index.astro` | The document, at `/` |
70
+ | `theme/styles/theme.css` | The whole of the styling |
71
+ | `theme/lib/snapshot.ts` | The snapshot, read once at build time |
72
+
73
+ ### The markdown twin
74
+
75
+ `/index.md` is written by the command rather than the theme, with
76
+ `bundleDocument` — the same function behind `canon cat`, so what a reader copies
77
+ out of the site is byte for byte `canon cat --toc --no-meta`. The theme builds on
78
+ a machine that has no workspace to resolve that function from; the command
79
+ already carries it, which is what keeps the site and the CLI one renderer. The
80
+ copy button fetches it rather than embedding it, so the button wants the site
81
+ served rather than opened off the disk, where `fetch` has no origin to work
82
+ from; everything else on the page works either way.
83
+
84
+ The theme sits under `theme/` rather than Astro's default `src/`, which this
85
+ package uses for the command itself. `astro.config.mjs` points `srcDir` at it.
86
+
87
+ ## Build parameters
88
+
89
+ `src/render.ts` passes these to Astro as environment variables, so the package
90
+ stays immutable at build time and two builds cannot race over a config file.
91
+
92
+ | Variable | What it sets |
93
+ | ----------------- | ----------------------------------------------- |
94
+ | `CANON_SITE_DATA` | Path to the snapshot JSON. Required |
95
+ | `CANON_OUT_DIR` | Absolute path to write the site to. Required |
96
+ | `CANON_BASE` | Sub-path the site is served under, e.g. `/docs` |
97
+ | `CANON_SITE_URL` | Canonical origin, for absolute URLs |
@@ -0,0 +1,30 @@
1
+ import { defineConfig } from "astro/config";
2
+
3
+ /**
4
+ * One Astro project, many sites.
5
+ *
6
+ * The theme is fixed; what changes per build is the snapshot it reads and where
7
+ * the output lands, and both arrive as environment variables rather than as a
8
+ * generated config file. That keeps this package immutable at build time — two
9
+ * `canonui build` runs for different documents cannot race over a file in here.
10
+ *
11
+ * CANON_SITE_DATA path to the document snapshot JSON (required)
12
+ * CANON_OUT_DIR absolute path to write the site to (required)
13
+ * CANON_BASE sub-path the site will be served under, e.g. /docs
14
+ * CANON_SITE_URL canonical origin, for absolute URLs in the output
15
+ *
16
+ * The theme sits under theme/ rather than the default src/, which this package
17
+ * uses for the canonui command itself. Astro's usual output directory is likewise
18
+ * given up: dist/ holds the compiled CLI, so a build that somehow arrived here
19
+ * without CANON_OUT_DIR must land somewhere it cannot overwrite the binary.
20
+ */
21
+ export default defineConfig({
22
+ srcDir: "./theme",
23
+ outDir: process.env.CANON_OUT_DIR ?? "./.astro-out",
24
+ ...(process.env.CANON_SITE_URL ? { site: process.env.CANON_SITE_URL } : {}),
25
+ ...(process.env.CANON_BASE ? { base: process.env.CANON_BASE } : {}),
26
+ build: { format: "directory" },
27
+ // The output is opened over a plain static server with no build step of its
28
+ // own, so nothing may depend on a dev-time transform being available.
29
+ devToolbar: { enabled: false },
30
+ });