@wizzlethorpe/vaults 0.6.1 → 0.8.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 (102) hide show
  1. package/README.md +135 -17
  2. package/dist/build.js +433 -181
  3. package/dist/build.js.map +1 -1
  4. package/dist/commands/build.js +4 -4
  5. package/dist/commands/build.js.map +1 -1
  6. package/dist/commands/init.js +13 -10
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/password.js +3 -1
  9. package/dist/commands/password.js.map +1 -1
  10. package/dist/commands/patreon.js +30 -20
  11. package/dist/commands/patreon.js.map +1 -1
  12. package/dist/commands/preview.js +10 -8
  13. package/dist/commands/preview.js.map +1 -1
  14. package/dist/commands/push.js +11 -9
  15. package/dist/commands/push.js.map +1 -1
  16. package/dist/commands/role.js +5 -0
  17. package/dist/commands/role.js.map +1 -1
  18. package/dist/config.js +30 -15
  19. package/dist/config.js.map +1 -1
  20. package/dist/escape.js +29 -0
  21. package/dist/escape.js.map +1 -0
  22. package/dist/favicon.js +3 -36
  23. package/dist/favicon.js.map +1 -1
  24. package/dist/foundry-importer.js +61 -0
  25. package/dist/foundry-importer.js.map +1 -0
  26. package/dist/images.js +0 -30
  27. package/dist/images.js.map +1 -1
  28. package/dist/index.js +37 -4
  29. package/dist/index.js.map +1 -1
  30. package/dist/migrate/0.6-legacy-auth-settings.js +96 -0
  31. package/dist/migrate/0.6-legacy-auth-settings.js.map +1 -0
  32. package/dist/migrate/0.7-vaults-dir.js +70 -0
  33. package/dist/migrate/0.7-vaults-dir.js.map +1 -0
  34. package/dist/migrate/registry.js +6 -0
  35. package/dist/migrate/registry.js.map +1 -0
  36. package/dist/migrate/run.js +38 -0
  37. package/dist/migrate/run.js.map +1 -0
  38. package/dist/migrate/types.js +8 -0
  39. package/dist/migrate/types.js.map +1 -0
  40. package/dist/paths.js +66 -0
  41. package/dist/paths.js.map +1 -0
  42. package/dist/render/auth-template.js +23 -141
  43. package/dist/render/auth-template.js.map +1 -1
  44. package/dist/render/bases.js +56 -44
  45. package/dist/render/bases.js.map +1 -1
  46. package/dist/render/callouts.js +29 -10
  47. package/dist/render/callouts.js.map +1 -1
  48. package/dist/render/embed.js +124 -26
  49. package/dist/render/embed.js.map +1 -1
  50. package/dist/render/extensions.js +68 -0
  51. package/dist/render/extensions.js.map +1 -0
  52. package/dist/render/external-links.js +32 -0
  53. package/dist/render/external-links.js.map +1 -0
  54. package/dist/render/footer.js +37 -0
  55. package/dist/render/footer.js.map +1 -0
  56. package/dist/render/frontmatter.js +17 -0
  57. package/dist/render/frontmatter.js.map +1 -0
  58. package/dist/render/handlers/assets.js +123 -0
  59. package/dist/render/handlers/assets.js.map +1 -0
  60. package/dist/render/handlers/builtin/dice.js +78 -0
  61. package/dist/render/handlers/builtin/dice.js.map +1 -0
  62. package/dist/render/handlers/builtin/fm-code.js +50 -0
  63. package/dist/render/handlers/builtin/fm-code.js.map +1 -0
  64. package/dist/render/handlers/builtin/fm.js +83 -0
  65. package/dist/render/handlers/builtin/fm.js.map +1 -0
  66. package/dist/render/handlers/builtin/index.js +10 -0
  67. package/dist/render/handlers/builtin/index.js.map +1 -0
  68. package/dist/render/handlers/builtin/inline-format.js +26 -0
  69. package/dist/render/handlers/builtin/inline-format.js.map +1 -0
  70. package/dist/render/handlers/builtin/statblock.js +491 -0
  71. package/dist/render/handlers/builtin/statblock.js.map +1 -0
  72. package/dist/render/handlers/dispatch.js +182 -0
  73. package/dist/render/handlers/dispatch.js.map +1 -0
  74. package/dist/render/handlers/loader.js +90 -0
  75. package/dist/render/handlers/loader.js.map +1 -0
  76. package/dist/render/handlers/types.js +60 -0
  77. package/dist/render/handlers/types.js.map +1 -0
  78. package/dist/render/image-srcs.js +42 -0
  79. package/dist/render/image-srcs.js.map +1 -0
  80. package/dist/render/layout.js +62 -9
  81. package/dist/render/layout.js.map +1 -1
  82. package/dist/render/pipeline.js +37 -8
  83. package/dist/render/pipeline.js.map +1 -1
  84. package/dist/render/preview.js +10 -5
  85. package/dist/render/preview.js.map +1 -1
  86. package/dist/render/slug.js +5 -0
  87. package/dist/render/slug.js.map +1 -1
  88. package/dist/render/styles.js +118 -11
  89. package/dist/render/styles.js.map +1 -1
  90. package/dist/render/wikilink.js +15 -4
  91. package/dist/render/wikilink.js.map +1 -1
  92. package/dist/scan.js +1 -1
  93. package/dist/scan.js.map +1 -1
  94. package/dist/settings.js +25 -4
  95. package/dist/settings.js.map +1 -1
  96. package/dist/version.js +36 -0
  97. package/dist/version.js.map +1 -0
  98. package/package.json +12 -12
  99. package/dist/api.js +0 -42
  100. package/dist/api.js.map +0 -1
  101. package/dist/render/mcp-template.js +0 -239
  102. package/dist/render/mcp-template.js.map +0 -1
@@ -0,0 +1,182 @@
1
+ // Unified plugin that runs registered handlers over the markdown AST.
2
+ // Inline-code `prefix: …` and fenced code ```lang … ``` blocks are
3
+ // dispatched to the matching InlineHandler / CodeBlockHandler. Handler
4
+ // output is re-parsed (or wrapped as raw HTML) so downstream wikilink /
5
+ // embed passes still see it. Handler-emitted markdown is recursively
6
+ // dispatched, bounded by MAX_DEPTH.
7
+ import { unified } from "unified";
8
+ import remarkParse from "remark-parse";
9
+ import remarkGfm from "remark-gfm";
10
+ /** Cap on handler-emits-handler recursion. Realistically nothing legitimate nests this deep. */
11
+ const MAX_DEPTH = 10;
12
+ /**
13
+ * Pattern for an inline-handler invocation inside arbitrary text:
14
+ * `` `prefix: content` ``. `prefix` matches the InlineHandler discriminator
15
+ * shape (lowercase letter then word chars / dashes). A fresh RegExp is
16
+ * built per call (rather than module-level) because /g + recursion +
17
+ * shared regex state is a hang waiting to happen.
18
+ */
19
+ const INLINE_HANDLER_PATTERN = "`([a-z][\\w-]*):\\s*([^`]*)`";
20
+ /**
21
+ * Substitute inline-handler matches in a plain string with their HTML
22
+ * output. Bounded by MAX_DEPTH so a handler whose HTML output happens to
23
+ * contain another `` `prefix: …` `` pattern still terminates.
24
+ */
25
+ async function applyInlineHandlersImpl(text, registry, ctx, depth) {
26
+ if (depth > MAX_DEPTH)
27
+ return text;
28
+ const re = new RegExp(INLINE_HANDLER_PATTERN, "g");
29
+ let out = "";
30
+ let last = 0;
31
+ let m;
32
+ while ((m = re.exec(text)) !== null) {
33
+ const prefix = m[1];
34
+ const content = (m[2] ?? "").trim();
35
+ const handler = registry.inline.get(prefix);
36
+ if (!handler)
37
+ continue;
38
+ const result = await handler.render(content, ctx);
39
+ if ("markdown" in result) {
40
+ // Markdown output can't be safely spliced into a non-markdown context
41
+ // without re-running the full pipeline. Skip; the original text stays.
42
+ continue;
43
+ }
44
+ out += text.slice(last, m.index);
45
+ out += await applyInlineHandlersImpl(result.html, registry, ctx, depth + 1);
46
+ last = m.index + m[0].length;
47
+ }
48
+ out += text.slice(last);
49
+ return out;
50
+ }
51
+ /**
52
+ * Single sub-parser instance reused across every handler that returns
53
+ * markdown. Hoisted so the .use() chain isn't rebuilt per call.
54
+ */
55
+ const SUB_PARSER = unified().use(remarkParse).use(remarkGfm);
56
+ function asHtmlNode(html) {
57
+ return { type: "html", value: html };
58
+ }
59
+ /** Parse a markdown string into a list of mdast block-level children. */
60
+ function parseMarkdownBlocks(source) {
61
+ return SUB_PARSER.parse(source).children;
62
+ }
63
+ /**
64
+ * Parse a markdown string and pull out its inline (phrasing) content. Drops
65
+ * the surrounding paragraph wrapper so the inline content can be spliced
66
+ * into a phrasing context.
67
+ */
68
+ function parseMarkdownInline(source) {
69
+ const blocks = parseMarkdownBlocks(source);
70
+ const out = [];
71
+ for (const block of blocks) {
72
+ if (block.type === "paragraph") {
73
+ out.push(...block.children);
74
+ }
75
+ else {
76
+ // Block-level output in an inline context: drop. A handler author who
77
+ // needs block flow should use a code-block handler, not an inline one.
78
+ // Empty html node keeps the document well-formed.
79
+ out.push(asHtmlNode(""));
80
+ }
81
+ }
82
+ return out;
83
+ }
84
+ function outputToBlock(out) {
85
+ if ("markdown" in out)
86
+ return parseMarkdownBlocks(out.markdown);
87
+ return [asHtmlNode(out.html)];
88
+ }
89
+ function outputToInline(out) {
90
+ if ("markdown" in out)
91
+ return parseMarkdownInline(out.markdown);
92
+ return [asHtmlNode(out.html)];
93
+ }
94
+ /**
95
+ * Walk the AST forward, applying any matching handler to each inline-code
96
+ * and code node. After a substitution, the replacements get re-walked at
97
+ * depth+1 — this handles both:
98
+ * (a) **vertical** recursion: a paragraph the handler emitted contains
99
+ * further handler-eligible inline nodes (e.g., a `dice:` inside a
100
+ * custom code-block's emitted markdown).
101
+ * (b) **horizontal** recursion: the replacement is itself directly
102
+ * handler-eligible (e.g., a `loop:` handler emitting another
103
+ * `loop:`). Bounded by MAX_DEPTH so a self-emitting handler can't
104
+ * loop forever.
105
+ */
106
+ async function walkAndSubstitute(parent, registry, context, depth) {
107
+ if (depth > MAX_DEPTH) {
108
+ console.warn(` handlers: recursion depth ${depth} exceeded; stopping`);
109
+ return;
110
+ }
111
+ let i = 0;
112
+ while (i < parent.children.length) {
113
+ const node = parent.children[i];
114
+ const replacements = await dispatchOne(node, registry, context);
115
+ if (replacements !== null) {
116
+ parent.children.splice(i, 1, ...replacements);
117
+ // Wrap the replacement slice and re-walk it at depth+1. The nested
118
+ // walk handles both horizontal and vertical recursion for the new
119
+ // content. Splice back the (possibly further-substituted) result.
120
+ const synth = { children: parent.children.slice(i, i + replacements.length) };
121
+ await walkAndSubstitute(synth, registry, context, depth + 1);
122
+ parent.children.splice(i, replacements.length, ...synth.children);
123
+ i += synth.children.length;
124
+ continue;
125
+ }
126
+ if (Array.isArray(node.children)) {
127
+ await walkAndSubstitute(node, registry, context, depth + 1);
128
+ }
129
+ i += 1;
130
+ }
131
+ }
132
+ /**
133
+ * Returns the replacement nodes for `node` if a handler matched, else null.
134
+ * Inline-code nodes return PhrasingContent[]; code nodes return RootContent[].
135
+ * The caller is responsible for splicing into the right parent.
136
+ */
137
+ async function dispatchOne(node, registry, context) {
138
+ if (node?.type === "inlineCode") {
139
+ const value = node.value;
140
+ const colon = value.indexOf(":");
141
+ if (colon < 1)
142
+ return null;
143
+ const prefix = value.slice(0, colon).trim();
144
+ const handler = registry.inline.get(prefix);
145
+ if (!handler)
146
+ return null;
147
+ const content = value.slice(colon + 1).trim();
148
+ // Inline handlers never see a code-block meta string. Spread to a fresh
149
+ // context so a handler that mutates ctx (it shouldn't, but) can't leak
150
+ // state across dispatches.
151
+ return outputToInline(await handler.render(content, { ...context, codeBlockMeta: "" }));
152
+ }
153
+ if (node?.type === "code") {
154
+ const lang = (node.lang ?? "").trim();
155
+ if (!lang)
156
+ return null;
157
+ const handler = registry.codeBlock.get(lang);
158
+ if (!handler)
159
+ return null;
160
+ // node.meta is whatever follows the lang on the fence — `lang foo bar`.
161
+ // Pass it through so handlers like `fm` can use it as a language hint
162
+ // for the rendered <pre><code class="language-…">.
163
+ const meta = (node.meta ?? "").trim();
164
+ return outputToBlock(await handler.render(node.value, { ...context, codeBlockMeta: meta }));
165
+ }
166
+ return null;
167
+ }
168
+ export function handlersPlugin(opts) {
169
+ const { registry, context: baseContext } = opts;
170
+ // Build the full HandlerContext once, with applyInlineHandlers closing
171
+ // over the registry. Self-reference goes through the resulting context
172
+ // so handler authors who chain calls see the same object.
173
+ const context = {
174
+ ...baseContext,
175
+ applyInlineHandlers: (text) => applyInlineHandlersImpl(text, registry, context, 0),
176
+ codeBlockMeta: "",
177
+ };
178
+ return () => async (tree) => {
179
+ await walkAndSubstitute(tree, registry, context, 0);
180
+ };
181
+ }
182
+ //# sourceMappingURL=dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../../src/render/handlers/dispatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ // Discover and load custom handlers from a vault's `.vaults/handlers/`
2
+ // directory. Each handler file is dynamically imported; it must export a
3
+ // `handler` (single Handler) or `handlers` (Handler[]) named export.
4
+ //
5
+ // Returns the absolute on-disk path each handler was loaded from. The path
6
+ // is the anchor for resolving asset paths declared on the handler (see
7
+ // HandlerAssets in types.ts).
8
+ //
9
+ // Trust model: handlers are loaded and executed verbatim. Anyone running
10
+ // `vaults push` is trusting the vault's contents. Same trust model as
11
+ // `npm install` for any project they choose to build.
12
+ import { readdir, stat } from "node:fs/promises";
13
+ import { join, resolve } from "node:path";
14
+ import { pathToFileURL } from "node:url";
15
+ const HANDLER_DIR = ".vaults/handlers";
16
+ // Handler modules are `.mjs` (Node ESM). `.js` files in the same directory
17
+ // are treated as browser-side runtime assets and skipped by the loader —
18
+ // they get picked up via the `assets.scripts` declaration on a handler.
19
+ const SUPPORTED_EXTENSIONS = [".mjs"];
20
+ /**
21
+ * Returns user-defined handlers discovered in `<vaultPath>/.vaults/handlers/`.
22
+ * Returns an empty array if the directory doesn't exist; this is the common
23
+ * case (most vaults won't ship handlers).
24
+ *
25
+ * Each handler module's named exports are inspected:
26
+ * - `handler` (single Handler) is registered as one handler.
27
+ * - `handlers` (Handler[]) is spread into the result.
28
+ *
29
+ * Modules that throw on import or that export neither name produce a
30
+ * warning but do not abort the build.
31
+ */
32
+ export async function loadUserHandlers(vaultPath) {
33
+ const dir = join(vaultPath, HANDLER_DIR);
34
+ let entries;
35
+ try {
36
+ entries = await readdir(dir);
37
+ }
38
+ catch (err) {
39
+ if (err.code === "ENOENT")
40
+ return [];
41
+ throw err;
42
+ }
43
+ const results = [];
44
+ for (const name of entries.sort()) {
45
+ if (!SUPPORTED_EXTENSIONS.some((ext) => name.endsWith(ext)))
46
+ continue;
47
+ const path = resolve(dir, name);
48
+ let info;
49
+ try {
50
+ info = await stat(path);
51
+ }
52
+ catch {
53
+ continue;
54
+ }
55
+ if (!info.isFile())
56
+ continue;
57
+ const url = pathToFileURL(path).href;
58
+ let mod;
59
+ try {
60
+ mod = await import(url);
61
+ }
62
+ catch (err) {
63
+ console.warn(` handlers: failed to import ${name}: ${err.message}`);
64
+ continue;
65
+ }
66
+ const single = mod.handler;
67
+ const many = mod.handlers;
68
+ if (Array.isArray(many)) {
69
+ for (const h of many) {
70
+ if (isHandlerLike(h))
71
+ results.push({ handler: h, sourcePath: path });
72
+ }
73
+ }
74
+ if (isHandlerLike(single))
75
+ results.push({ handler: single, sourcePath: path });
76
+ if (single == null && !Array.isArray(many)) {
77
+ console.warn(` handlers: ${name} exports neither 'handler' nor 'handlers'; skipped`);
78
+ }
79
+ }
80
+ return results;
81
+ }
82
+ function isHandlerLike(v) {
83
+ if (!v || typeof v !== "object")
84
+ return false;
85
+ const o = v;
86
+ if (typeof o.render !== "function")
87
+ return false;
88
+ return typeof o.inline === "string" || typeof o.codeBlock === "string";
89
+ }
90
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/render/handlers/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ // Handler API for custom inline / code-block transforms.
2
+ //
3
+ // Vault authors drop `.vaults/handlers/<name>.{js,mjs}` files into their
4
+ // vault. Each file exports `handler` (or `handlers: Handler[]`) and the
5
+ // loader registers them alongside vaults-cli's built-in handlers.
6
+ //
7
+ // At render time, the dispatch plugin (handlers/dispatch.ts) walks the
8
+ // markdown AST. For each inline-code node `` `prefix: …` `` it looks up an
9
+ // InlineHandler keyed on `prefix`. For each fenced ``` ```lang ``` block it
10
+ // looks up a CodeBlockHandler keyed on `lang`. The handler's `render()` is
11
+ // called with the content and a HandlerContext, and the returned markdown
12
+ // or HTML replaces the matched node in the AST. Handlers may also ship
13
+ // `assets.{styles,scripts}` to opt their generated markup into runtime
14
+ // CSS / JS bundles.
15
+ /**
16
+ * Build the dispatch registry from built-in + user handlers. User handlers
17
+ * register after built-ins so they win on prefix/lang collision (documented
18
+ * "user override" semantics) — but a *silent* override is a footgun: the
19
+ * built-in's contract may change between CLI versions and the user's
20
+ * shadowing handler keeps an old shape, breaking quietly. Surface every
21
+ * shadow at registration time with a console.warn so the override is at
22
+ * least visible in build logs.
23
+ *
24
+ * Pass user handlers as `[]` if there are none — callers shouldn't need to
25
+ * gate on emptiness.
26
+ */
27
+ export function buildRegistry(builtin, user = []) {
28
+ const inline = new Map();
29
+ const codeBlock = new Map();
30
+ const builtinInlineIds = new Set();
31
+ const builtinCodeBlockIds = new Set();
32
+ for (const h of builtin) {
33
+ if ("inline" in h) {
34
+ inline.set(h.inline, h);
35
+ builtinInlineIds.add(h.inline);
36
+ }
37
+ else {
38
+ codeBlock.set(h.codeBlock, h);
39
+ builtinCodeBlockIds.add(h.codeBlock);
40
+ }
41
+ }
42
+ for (const h of user) {
43
+ if ("inline" in h) {
44
+ if (builtinInlineIds.has(h.inline)) {
45
+ console.warn(`handlers: user inline handler 'inline: "${h.inline}"' shadows the built-in `
46
+ + `with the same prefix. Override is intentional? OK; otherwise rename the user handler.`);
47
+ }
48
+ inline.set(h.inline, h);
49
+ }
50
+ else {
51
+ if (builtinCodeBlockIds.has(h.codeBlock)) {
52
+ console.warn(`handlers: user code-block handler 'codeBlock: "${h.codeBlock}"' shadows the built-in `
53
+ + `with the same lang tag. Override is intentional? OK; otherwise rename the user handler.`);
54
+ }
55
+ codeBlock.set(h.codeBlock, h);
56
+ }
57
+ }
58
+ return { inline, codeBlock };
59
+ }
60
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/render/handlers/types.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,yEAAyE;AACzE,wEAAwE;AACxE,kEAAkE;AAClE,EAAE;AACF,uEAAuE;AACvE,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,uEAAuE;AACvE,uEAAuE;AACvE,oBAAoB;AA8FpB;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,OAAkB,EAAE,OAAkB,EAAE;IACpE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;IACtD,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC3C,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAU,CAAC;IAE9C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACxB,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YAC9B,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnC,OAAO,CAAC,IAAI,CACV,2CAA2C,CAAC,CAAC,MAAM,0BAA0B;sBAC3E,uFAAuF,CAC1F,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzC,OAAO,CAAC,IAAI,CACV,kDAAkD,CAAC,CAAC,SAAS,0BAA0B;sBACrF,yFAAyF,CAC5F,CAAC;YACJ,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,42 @@
1
+ // Normalise plain markdown image URLs (`![alt](path/to/foo.webp)`) to the
2
+ // absolute, slugified URL the build emits for that image. Without this the
3
+ // `<img src>` keeps the author's relative path verbatim — fine in a browser
4
+ // loading the page from `/Features/Images.html` (which resolves
5
+ // `../attachments/foo.webp` correctly), but broken anywhere else that loads
6
+ // the rendered HTML out of context: most notably the Foundry module's
7
+ // journal-page sheet, which runs from `/game` and ends up pointing at
8
+ // `/attachments/foo.webp` as if it lived at the world root.
9
+ //
10
+ // Wikilink-style image embeds (`![[foo.webp]]`) already resolve through the
11
+ // embed plugin, which writes the absolute URL directly. This plugin is the
12
+ // matching pass for the standard markdown form.
13
+ //
14
+ // External URLs (`https://`, `data:`) and references to images we didn't
15
+ // build are left untouched so the author can still link out or surface
16
+ // missing-image cases through the normal warning flow downstream.
17
+ import { visit } from "unist-util-visit";
18
+ import { slugify } from "./slug.js";
19
+ import { IMAGE_EXT_RE } from "./extensions.js";
20
+ export function imageSrcsPlugin(opts) {
21
+ const { context } = opts;
22
+ return () => (tree) => {
23
+ visit(tree, "image", (node) => {
24
+ const url = node.url;
25
+ if (!url)
26
+ return;
27
+ if (/^(https?:|data:|blob:|mailto:|#)/i.test(url))
28
+ return;
29
+ if (url.startsWith("/"))
30
+ return;
31
+ const basename = url.split("/").pop().split("#")[0].split("?")[0];
32
+ if (!IMAGE_EXT_RE.test(basename))
33
+ return;
34
+ const slug = slugify(decodeURIComponent(basename));
35
+ const entry = context.images.get(slug);
36
+ if (!entry)
37
+ return;
38
+ node.url = "/" + entry.outputPath.split("/").map(encodeURIComponent).join("/");
39
+ });
40
+ };
41
+ }
42
+ //# sourceMappingURL=image-srcs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-srcs.js","sourceRoot":"","sources":["../../src/render/image-srcs.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,gEAAgE;AAChE,4EAA4E;AAC5E,sEAAsE;AACtE,sEAAsE;AACtE,4DAA4D;AAC5D,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAC3E,gDAAgD;AAChD,EAAE;AACF,yEAAyE;AACzE,uEAAuE;AACvE,kEAAkE;AAIlE,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,MAAM,UAAU,eAAe,CAAC,IAAgC;IAC9D,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACzB,OAAO,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE;QACpB,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,IAAW,EAAE,EAAE;YACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YACrB,IAAI,CAAC,GAAG;gBAAE,OAAO;YACjB,IAAI,mCAAmC,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,OAAO;YAC1D,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO;YAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;YACrE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACzC,MAAM,IAAI,GAAG,OAAO,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;YACnD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { htmlEscape as esc, htmlAttr as attr } from "../escape.js";
1
2
  /**
2
3
  * Standalone 404 page using the same shell as a regular article (sidebar,
3
4
  * search, sitemap), so a missing page still leaves the reader inside the
@@ -19,7 +20,7 @@ export function renderLayout(input) {
19
20
  const breadcrumbs = renderBreadcrumbs(input.pagePath, input.vaultName);
20
21
  const sitemap = renderSitemap(input.pages, input.pagePath);
21
22
  return `<!doctype html>
22
- <html lang="en">
23
+ <html lang="en" data-theme="${attr(input.theme)}">
23
24
  <head>
24
25
  <meta charset="utf-8">
25
26
  <meta name="viewport" content="width=device-width,initial-scale=1">
@@ -27,7 +28,9 @@ export function renderLayout(input) {
27
28
  <link rel="icon" href="/favicon.ico">
28
29
  <link rel="stylesheet" href="/styles.css">
29
30
  <link rel="stylesheet" href="/user.css">
31
+ ${input.hasHandlerCss ? `<link rel="stylesheet" href="/_handlers.css">` : ""}${input.hasHandlerJs ? `\n<script src="/_handlers.js" defer></script>` : ""}
30
32
  ${renderSocialMeta(input)}
33
+ ${THEME_BOOT_SCRIPT}
31
34
  </head>
32
35
  <body${input.centerImages ? ` class="center-images"` : ""}${input.defaultImageWidth ? ` style="--default-img-width: ${attr(input.defaultImageWidth)}"` : ""}>
33
36
  <div class="app-grid">
@@ -37,7 +40,12 @@ ${renderSocialMeta(input)}
37
40
  <input id="vault-search" type="search" placeholder="Search…" aria-label="Search vault" autocomplete="off">
38
41
  <div class="search-results" role="listbox"></div>
39
42
  </div>
40
- ${input.authConfigured ? '<div class="auth-box" id="vault-auth"></div>' : ''}
43
+ <div class="sidebar-row">
44
+ <button id="theme-toggle" type="button" class="theme-toggle" aria-label="Toggle dark mode" title="Toggle dark mode">
45
+ <span class="theme-toggle-icon" aria-hidden="true"></span>
46
+ </button>
47
+ ${input.authConfigured ? '<div class="auth-box" id="vault-auth"></div>' : ''}
48
+ </div>
41
49
  ${sitemap}
42
50
  </aside>
43
51
  <main>
@@ -47,6 +55,7 @@ ${renderSocialMeta(input)}
47
55
  ${input.bodyHtml}
48
56
  ${renderMeta(input.mtime, input.birthtime)}
49
57
  </article>
58
+ ${input.footerHtml ? `<footer class="site-footer">${input.footerHtml}</footer>` : ""}
50
59
  </main>
51
60
  <aside class="rightbar">
52
61
  <details class="toc" open>
@@ -62,6 +71,7 @@ ${TOC_SCRIPT}
62
71
  ${SEARCH_SCRIPT}
63
72
  ${LIGHTBOX_SCRIPT}
64
73
  ${AUTH_SCRIPT}
74
+ ${THEME_TOGGLE_SCRIPT}
65
75
  ${BASES_SCRIPT}
66
76
  ${FRONTMATTER_SCRIPT}
67
77
  </body>
@@ -239,12 +249,6 @@ function sitemapItem(p, currentPath) {
239
249
  const cur = p.path === currentPath ? ' aria-current="page"' : "";
240
250
  return `<li><a href="${attr(href)}"${cur} class="internal internal-link">${esc(p.title)}</a></li>`;
241
251
  }
242
- function esc(s) {
243
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
244
- }
245
- function attr(s) {
246
- return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
247
- }
248
252
  // Opens the Explorer <details> on desktop so its [open] state matches the
249
253
  // CSS-forced visibility. On mobile we leave it closed so the user has a
250
254
  // collapsed sitemap by default.
@@ -373,7 +377,7 @@ const AUTH_SCRIPT = `<script>
373
377
  box.classList.remove('auth-signed-out');
374
378
  box.classList.add('auth-signed-in');
375
379
  box.innerHTML =
376
- '<div class="auth-status">Signed in as <strong>' + esc(role) + '</strong></div>' +
380
+ '<div class="auth-status"><strong>' + esc(role) + '</strong></div>' +
377
381
  '<a class="auth-action" href="/logout?next=' + next + '">Sign out</a>';
378
382
  } else {
379
383
  box.classList.remove('auth-signed-in');
@@ -390,6 +394,55 @@ const AUTH_SCRIPT = `<script>
390
394
  function esc(s) { return String(s).replace(/[<>&]/g, c => ({'<':'&lt;','>':'&gt;','&':'&amp;'}[c])); }
391
395
  })();
392
396
  </script>`;
397
+ // Boot script: runs in <head> before any paint so the visitor's stored theme
398
+ // preference (or the OS preference for "auto") wins immediately, no
399
+ // flash-of-wrong-theme. Reads localStorage.vaultTheme; falls back to the
400
+ // data-theme value the server emitted on <html>. Sets an effective-theme
401
+ // data attribute the toggle uses to flip the icon without re-deriving.
402
+ const THEME_BOOT_SCRIPT = `<script>
403
+ (function () {
404
+ try {
405
+ const html = document.documentElement;
406
+ const stored = localStorage.getItem('vaultTheme');
407
+ if (stored === 'light' || stored === 'dark' || stored === 'auto') html.setAttribute('data-theme', stored);
408
+ } catch (e) { /* localStorage may be blocked; the SSR data-theme stays in effect */ }
409
+ })();
410
+ </script>`;
411
+ // Click handler: cycles through light → dark → auto, persisting to
412
+ // localStorage. The button icon swaps based on the effective theme so the
413
+ // affordance always shows what's currently active. Listens for OS-pref
414
+ // changes too so the icon updates live when the visitor flips their
415
+ // system theme while on the page.
416
+ const THEME_TOGGLE_SCRIPT = `<script>
417
+ (function () {
418
+ const btn = document.getElementById('theme-toggle');
419
+ if (!btn) return;
420
+ const html = document.documentElement;
421
+ const mql = window.matchMedia('(prefers-color-scheme: dark)');
422
+ const SUN = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>';
423
+ const MOON = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>';
424
+ const icon = btn.querySelector('.theme-toggle-icon');
425
+ function effective() {
426
+ const t = html.getAttribute('data-theme') || 'auto';
427
+ if (t === 'light' || t === 'dark') return t;
428
+ return mql.matches ? 'dark' : 'light';
429
+ }
430
+ function paint() {
431
+ const eff = effective();
432
+ if (icon) icon.innerHTML = eff === 'dark' ? SUN : MOON;
433
+ btn.setAttribute('aria-pressed', eff === 'dark' ? 'true' : 'false');
434
+ btn.title = eff === 'dark' ? 'Switch to light mode' : 'Switch to dark mode';
435
+ }
436
+ paint();
437
+ mql.addEventListener('change', paint);
438
+ btn.addEventListener('click', function () {
439
+ const next = effective() === 'dark' ? 'light' : 'dark';
440
+ html.setAttribute('data-theme', next);
441
+ try { localStorage.setItem('vaultTheme', next); } catch (e) { /* blocked storage */ }
442
+ paint();
443
+ });
444
+ })();
445
+ </script>`;
393
446
  const LIGHTBOX_SCRIPT = `<script>
394
447
  (function () {
395
448
  let onKey = null;
@@ -1 +1 @@
1
- {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/render/layout.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/render/layout.ts"],"names":[],"mappings":"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"}