mr-md 1.1.0-alpha.0 → 2.0.0-beta

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/dist/builder.d.ts CHANGED
@@ -44,7 +44,7 @@ export declare class LessonBuilder {
44
44
  add(src: `${string}.mp4` | `${string}.webm` | `${string}.mov`, opts?: Omit<MediaOptions, "kind">): this;
45
45
  add(src: `${string}.mp3` | `${string}.wav` | `${string}.ogg` | `${string}.m4a`, opts?: Omit<MediaOptions, "kind">): this;
46
46
  add(src: `${string}.png` | `${string}.jpg` | `${string}.jpeg` | `${string}.gif` | `${string}.svg` | `${string}.webp` | `${string}.avif`, opts?: Omit<MediaOptions, "kind">): this;
47
- add(src: string, opts?: any): this;
47
+ add(src: string, opts?: unknown): this;
48
48
  /**
49
49
  * Creates a major chapter heading (H1) and a top-level sidebar navigation entry.
50
50
  * @param src Path to a markdown file or raw markdown string.
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"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"}
package/dist/builder.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import { render, renderChapter } from "./renderer/index.js";
4
- import { copyCoreAssets } from "./renderer/html.js";
5
4
  function getCallerDir() {
6
5
  const err = new Error();
7
6
  const stack = err.stack?.split("\n");
@@ -52,7 +51,7 @@ export class LessonBuilder {
52
51
  this.options = {
53
52
  outDir: options.outDir ?? (callerDir ? path.join(callerDir, "out") : "./out"),
54
53
  contentBase: options.contentBase ?? callerDir ?? ".",
55
- theme: options.theme ?? "light",
54
+ theme: options.theme ?? "auto",
56
55
  palette: options.palette ?? "ink",
57
56
  strict: options.strict ?? process.env.NODE_ENV !== "development",
58
57
  preset: {
@@ -142,7 +141,6 @@ export class LessonBuilder {
142
141
  _getMeta() {
143
142
  return this.meta;
144
143
  }
145
- // biome-ignore lint/suspicious/noExplicitAny: Overload implementation
146
144
  add(src, opts = {}) {
147
145
  const lower = src.toLowerCase();
148
146
  if (lower.endsWith(".md") || lower.endsWith(".mdx"))
@@ -379,7 +377,6 @@ export class LessonBuilder {
379
377
  fs.mkdirSync(outDir, { recursive: true });
380
378
  const outPath = path.join(outDir, `${this.meta.slug}.html`);
381
379
  fs.writeFileSync(outPath, html, "utf-8");
382
- copyCoreAssets(outDir);
383
380
  const relPath = path.relative(process.cwd(), outPath);
384
381
  console.log(` ✓ Built lesson (${this.blocks.length} blocks) → ${relPath}`);
385
382
  return outPath;
@@ -510,7 +507,7 @@ export class ChapterBuilder {
510
507
  this.options = {
511
508
  outDir: options.outDir ?? (callerDir ? path.join(callerDir, "out") : "./out"),
512
509
  contentBase: options.contentBase ?? callerDir ?? ".",
513
- theme: options.theme ?? "light",
510
+ theme: options.theme ?? "auto",
514
511
  palette: options.palette ?? "ink",
515
512
  strict: options.strict ?? process.env.NODE_ENV !== "development",
516
513
  preset: {
@@ -568,7 +565,6 @@ export class ChapterBuilder {
568
565
  fs.mkdirSync(outDir, { recursive: true });
569
566
  const outPath = path.join(outDir, `${this.meta.slug}.html`);
570
567
  fs.writeFileSync(outPath, html, "utf-8");
571
- copyCoreAssets(outDir);
572
568
  const relPath = path.relative(process.cwd(), outPath);
573
569
  console.log(` ✓ Built chapter (${this.lessonBuilders.length} lessons) → ${relPath}`);
574
570
  return outPath;
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAGA,wBAAsB,OAAO,kBAkD5B"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAGA,wBAAsB,OAAO,kBA6F5B"}
package/dist/cli/init.js CHANGED
@@ -44,5 +44,46 @@ export const firstLesson = lesson("First Lesson", { contentBase: import.meta.dir
44
44
  `, "utf-8");
45
45
  console.log(" Created: chapters/01-chapter/lessons/01-lesson/lesson.ts");
46
46
  }
47
- console.log("Done! You can now run `bun chapters/01-chapter/chapter.ts` to build your project.");
47
+ const packageJsonPath = path.resolve(process.cwd(), "package.json");
48
+ let pkg = {};
49
+ if (fs.existsSync(packageJsonPath)) {
50
+ try {
51
+ pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
52
+ }
53
+ catch (e) {
54
+ console.error(" Failed to parse existing package.json, ignoring.");
55
+ }
56
+ }
57
+ else {
58
+ pkg = {
59
+ name: "my-md-project",
60
+ version: "1.0.0",
61
+ private: true
62
+ };
63
+ }
64
+ pkg.scripts = {
65
+ ...(pkg.scripts || {}),
66
+ build: "bun chapters/01-chapter/chapter.ts",
67
+ dev: "md dev",
68
+ g: "md g",
69
+ generate: "md generate"
70
+ };
71
+ let mrMdVersion = "latest";
72
+ try {
73
+ // Find mr-md's own package.json to get its version
74
+ const __dirname = path.dirname(new URL(import.meta.url).pathname);
75
+ const ownPkgPath = path.resolve(__dirname, "../../package.json");
76
+ const ownPkg = JSON.parse(fs.readFileSync(ownPkgPath, "utf-8"));
77
+ mrMdVersion = ownPkg.version;
78
+ }
79
+ catch (e) {
80
+ // Fallback if unable to read
81
+ }
82
+ pkg.dependencies = {
83
+ ...(pkg.dependencies || {}),
84
+ "mr-md": mrMdVersion
85
+ };
86
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
87
+ console.log(" Updated: package.json");
88
+ console.log("\nDone! You can now run `npm run dev` or `bun run dev` to start the local development server.");
48
89
  }
package/dist/cli.js CHANGED
File without changes
@@ -132,6 +132,22 @@ function bkWireInteractiveFrames() {
132
132
  document.querySelectorAll(".bk-embed-interactive").forEach((frame) => {
133
133
  obs.observe(frame);
134
134
  });
135
+
136
+ document.addEventListener('contentvisibilityautostatechange', (e) => {
137
+ const frame = e.target;
138
+ if (frame && frame.classList && frame.classList.contains('bk-embed-interactive')) {
139
+ const iframe = frame.querySelector('iframe');
140
+ if (!iframe || !iframe.contentWindow) return;
141
+
142
+ if (e.skipped) {
143
+ iframe.contentWindow.postMessage({ type: "bk:pause" }, "*");
144
+ } else {
145
+ if (frame.dataset.isAnimation === "true" || frame.classList.contains("is-interactive")) {
146
+ iframe.contentWindow.postMessage({ type: "bk:play" }, "*");
147
+ }
148
+ }
149
+ }
150
+ }, { capture: true });
135
151
  }
136
152
 
137
153
  function bkWireSidebarToggle() {
@@ -148,15 +164,58 @@ function bkWireSidebarToggle() {
148
164
  );
149
165
  }
150
166
 
167
+ function bkBroadcastTheme(targetWindow) {
168
+ const root = document.documentElement;
169
+ const styles = getComputedStyle(root);
170
+ const state = {
171
+ theme: root.dataset.theme || "light",
172
+ palette: root.dataset.palette || "ink",
173
+ ui: root.dataset.ui || "standard",
174
+ colors: {
175
+ bg: styles.getPropertyValue('--bg').trim(),
176
+ paper: styles.getPropertyValue('--paper').trim(),
177
+ line: styles.getPropertyValue('--line').trim(),
178
+ 'line-strong': styles.getPropertyValue('--line-strong').trim(),
179
+ text: styles.getPropertyValue('--text').trim(),
180
+ 'text-light': styles.getPropertyValue('--text-light').trim(),
181
+ accent: styles.getPropertyValue('--accent').trim(),
182
+ 'accent-soft': styles.getPropertyValue('--accent-soft').trim()
183
+ }
184
+ };
185
+ if (targetWindow) {
186
+ targetWindow.postMessage({ type: "bk:theme-sync", state }, "*");
187
+ } else {
188
+ document.querySelectorAll(".bk-embed-interactive iframe").forEach(iframe => {
189
+ if (iframe.contentWindow) iframe.contentWindow.postMessage({ type: "bk:theme-sync", state }, "*");
190
+ });
191
+ }
192
+ }
193
+
194
+ window.addEventListener("message", function(e) {
195
+ if (e.data && e.data.type === "bk:request-theme") {
196
+ // Small delay to ensure CSS has applied if this happens right on load
197
+ requestAnimationFrame(() => bkBroadcastTheme(e.source));
198
+ }
199
+ });
200
+
201
+ // Watch for OS theme changes if on auto
202
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
203
+ if (document.documentElement.dataset.theme === "auto") {
204
+ bkBroadcastTheme();
205
+ }
206
+ });
207
+
151
208
  function bkWireThemeControls() {
152
209
  const root = document.documentElement;
153
210
  const button = document.getElementById("bk-settings-button");
154
211
  const panel = document.getElementById("bk-theme-panel");
155
212
  const themeBtns = document.querySelectorAll("#bk-theme-icons button");
156
- const paletteBtns = document.querySelectorAll("#bk-palette-icons button");
213
+ const paletteBtns = document.querySelectorAll("#bk-palette-icons button");
214
+ const uiBtns = document.querySelectorAll("#bk-ui-icons button");
157
215
  let savedTheme = localStorage.getItem("bk-theme");
158
216
  if (!savedTheme) savedTheme = "auto";
159
217
  const savedPalette = localStorage.getItem("bk-palette");
218
+ const savedUi = localStorage.getItem("bk-ui");
160
219
 
161
220
  function updateThemeBtn(val) {
162
221
  themeBtns.forEach(b => {
@@ -165,21 +224,55 @@ function bkWireThemeControls() {
165
224
  });
166
225
  }
167
226
 
227
+ const proPalettes = {
228
+ ink: "elixir",
229
+ field: "trunk",
230
+ ember: "lava"
231
+ };
232
+
233
+ const proIcons = {
234
+ elixir: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3v4.4L4.8 14.5a2.5 2.5 0 0 0 2.2 3.5h10a2.5 2.5 0 0 0 2.2-3.5L15 7.4V3"></path><path d="M9 14h6"></path><path d="M10 3h4"></path></svg>',
235
+ trunk: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m8 3 4 8 5-5 5 15H2L8 3z"></path></svg>',
236
+ lava: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m3 21 4.5-9"></path><path d="M16.5 12 21 21"></path><path d="m11 21 1.4-2.8"></path><path d="m15 21-1.4-2.8"></path><path d="M11 6a3 3 0 0 1 2-2 3 3 0 0 1 2 2"></path><path d="M12 12a3 3 0 0 0 3-3"></path><path d="M9 12a3 3 0 0 1-3-3"></path><path d="M12 21v-3.5"></path><path d="M10 18h4"></path></svg>'
237
+ };
238
+
239
+ const normalIcons = {
240
+ ink: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z"></path></svg>',
241
+ field: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z"></path><path d="M2 21c0-3 1.85-5.36 5.08-6C9.5 14.52 12 13 13 12"></path></svg>',
242
+ ember: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8.5 14.5A2.5 2.5 0 0011 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 11-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 002.5 2.5z"></path></svg>'
243
+ };
244
+
168
245
  function updatePaletteBtn(val) {
169
246
  paletteBtns.forEach(b => {
170
- if(b.dataset.palette === val) b.classList.add("active");
247
+ const basePalette = b.dataset.palette;
248
+
249
+ if (val === proPalettes[basePalette]) {
250
+ b.innerHTML = proIcons[val];
251
+ } else {
252
+ b.innerHTML = normalIcons[basePalette];
253
+ }
254
+
255
+ if(basePalette === val || proPalettes[basePalette] === val) b.classList.add("active");
256
+ else b.classList.remove("active");
257
+ });
258
+ }
259
+
260
+ function updateUiBtn(val) {
261
+ uiBtns.forEach(b => {
262
+ if(b.dataset.ui === val) b.classList.add("active");
171
263
  else b.classList.remove("active");
172
264
  });
173
265
  }
174
266
 
175
267
  if (savedTheme) {
176
268
  updateThemeBtn(savedTheme);
177
- root.setAttribute("data-theme", savedTheme);
178
269
  }
179
270
  if (savedPalette) {
180
271
  const normalizedPalette = savedPalette === "green" ? "field" : savedPalette;
181
272
  updatePaletteBtn(normalizedPalette);
182
- root.setAttribute("data-palette", normalizedPalette);
273
+ }
274
+ if (savedUi) {
275
+ updateUiBtn(savedUi);
183
276
  }
184
277
 
185
278
  button &&
@@ -210,15 +303,42 @@ function bkWireThemeControls() {
210
303
  localStorage.setItem("bk-theme", val);
211
304
  updateThemeBtn(val);
212
305
  root.setAttribute("data-theme", val);
306
+ bkBroadcastTheme();
307
+ });
308
+ });
309
+
310
+ paletteBtns.forEach(btn => {
311
+ btn.addEventListener("click", (e) => {
312
+ const baseVal = btn.dataset.palette;
313
+ let currentVal = root.getAttribute("data-palette") || "ink";
314
+ let newVal = baseVal;
315
+
316
+ if (e.detail === 2) {
317
+ if (currentVal === proPalettes[baseVal]) {
318
+ newVal = baseVal;
319
+ } else {
320
+ newVal = proPalettes[baseVal];
321
+ }
322
+ } else {
323
+ if (currentVal === proPalettes[baseVal]) {
324
+ newVal = proPalettes[baseVal];
325
+ }
326
+ }
327
+
328
+ localStorage.setItem("bk-palette", newVal);
329
+ updatePaletteBtn(newVal);
330
+ root.setAttribute("data-palette", newVal);
331
+ bkBroadcastTheme();
213
332
  });
214
333
  });
215
334
 
216
- paletteBtns.forEach(btn => {
335
+ uiBtns.forEach(btn => {
217
336
  btn.addEventListener("click", () => {
218
- const val = btn.dataset.palette;
219
- localStorage.setItem("bk-palette", val);
220
- updatePaletteBtn(val);
221
- root.setAttribute("data-palette", val);
337
+ const val = btn.dataset.ui;
338
+ localStorage.setItem("bk-ui", val);
339
+ updateUiBtn(val);
340
+ root.setAttribute("data-ui", val);
341
+ bkBroadcastTheme();
222
342
  });
223
343
  });
224
344
  }
@@ -1 +1 @@
1
- {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/renderer/blocks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAA0B,MAAM,aAAa,CAAC;AAC/E,OAAO,EACN,WAAW,EAKX,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,KAAK,OAAO,EAAmC,MAAM,YAAY,CAAC;AAG3E,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO3C;AACD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3C;AAID,iBAAS,WAAW,CACnB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,YAAY,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,CAuBxC;AAED,iBAAS,gBAAgB,CACxB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,YAAY,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,CA+QxC;AA4KD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/renderer/blocks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAA0B,MAAM,aAAa,CAAC;AAC/E,OAAO,EACN,WAAW,EAKX,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,KAAK,OAAO,EAAmC,MAAM,YAAY,CAAC;AAG3E,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO3C;AACD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3C;AAID,iBAAS,WAAW,CACnB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,YAAY,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,CAuBxC;AAED,iBAAS,gBAAgB,CACxB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,YAAY,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,CAiRxC;AA2MD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC"}
@@ -125,6 +125,7 @@ function renderBlockInner(block, idx, options) {
125
125
  </div>
126
126
  <iframe srcdoc="${iframeDoc(simSrc, propsJson, false, block.dependencies)}"
127
127
  sandbox="allow-scripts"
128
+ loading="lazy"
128
129
  style="width:100%;height:100%;border:none;display:block;">
129
130
  </iframe>
130
131
  </div>
@@ -141,6 +142,7 @@ function renderBlockInner(block, idx, options) {
141
142
  </div>
142
143
  <iframe srcdoc="${iframeDoc(animSrc, "{}", block.loop)}"
143
144
  sandbox="allow-scripts"
145
+ loading="lazy"
144
146
  style="width:100%;height:100%;border:none;display:block;">
145
147
  </iframe>
146
148
  </div>`, block.accent ?? "neutral"),
@@ -282,6 +284,26 @@ ${scriptTags}
282
284
  window.__simProps=${props};
283
285
  window.__loop=${loop ?? false};
284
286
  window.bkSetupCalled = false;
287
+ window.__bkTheme = { colors: {}, theme: "light", palette: "ink", ui: "standard" };
288
+ window.bkColor = function(name) { return window.__bkTheme.colors[name] || "#000000"; };
289
+ window.bkUi = function() { return window.__bkTheme.ui; };
290
+ window.bkThemeMode = function() {
291
+ const rootTheme = window.__bkTheme.theme;
292
+ if (rootTheme === "auto") {
293
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? "dark" : "light";
294
+ }
295
+ return rootTheme;
296
+ };
297
+ window.addEventListener("message", function(e) {
298
+ if (e.data && e.data.type === "bk:theme-sync") {
299
+ window.__bkTheme = e.data.state;
300
+ window.dispatchEvent(new CustomEvent("bk:theme-changed", { detail: window.__bkTheme }));
301
+ }
302
+ });
303
+ if (window.parent && window.parent !== window) {
304
+ window.parent.postMessage({ type: "bk:request-theme" }, "*");
305
+ }
306
+
285
307
  window.bkCanvasPoint = function(event, canvas) {
286
308
  const c = canvas || event.currentTarget || event.target;
287
309
  const rect = c.getBoundingClientRect();
@@ -373,6 +395,17 @@ window.bkSetup = function(requestedW, requestedH, loopFn) {
373
395
  }
374
396
  });
375
397
 
398
+ window.addEventListener("bk:theme-changed", () => {
399
+ if (!window.__loop && window.innerWidth >= 32 && window.innerHeight >= 32) {
400
+ if (!loopId) {
401
+ ctx.save();
402
+ ctx.scale(cachedFit.scale, cachedFit.scale);
403
+ loopFn(ctx, cachedFit.width, cachedFit.height);
404
+ ctx.restore();
405
+ }
406
+ }
407
+ });
408
+
376
409
  window.addEventListener("message", (event) => {
377
410
  if (!event.data) return;
378
411
  if (event.data.type === "bk:play") {
@@ -0,0 +1,7 @@
1
+ import type { BuildOptions, Lesson } from "../types.js";
2
+ import type { NavItem } from "./utils.js";
3
+ declare function renderNavItem(item: NavItem): string;
4
+ declare function renderPage(lesson: Lesson, navItems: NavItem[], bodyHtml: string, opts: BuildOptions): string;
5
+ declare function copyCoreAssets(outDir: string): void;
6
+ export { copyCoreAssets, renderNavItem, renderPage };
7
+ //# sourceMappingURL=html-neo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-neo.d.ts","sourceRoot":"","sources":["../../src/renderer/html-neo.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,iBAAS,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAU5C;AAsBD,iBAAS,UAAU,CAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,YAAY,GAChB,MAAM,CA0HR;AAID,iBAAS,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAa5C;AAED,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,173 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { fileURLToPath } from "url";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = path.dirname(__filename);
6
+ import { escHtml } from "./blocks.js";
7
+ // ─── Page shell ───────────────────────────────────────────────────────────────
8
+ function renderNavItem(item) {
9
+ const kindClass = item.kind === "heading"
10
+ ? "bk-nav-heading"
11
+ : item.kind === "quiz"
12
+ ? "bk-nav-quiz"
13
+ : item.kind === "simulation"
14
+ ? "bk-nav-sim"
15
+ : "bk-nav-sub";
16
+ return `<a href="#${item.id}" class="bk-nav-item ${kindClass}" data-id="${item.id}">${escHtml(item.label)}</a>`;
17
+ }
18
+ function renderEndNav(lesson) {
19
+ const { prevSlug, prevTitle, nextSlug, nextTitle } = lesson.meta;
20
+ if (!prevSlug && !nextSlug)
21
+ return "";
22
+ return `<nav class="bk-end-nav" aria-label="Lesson navigation" style="grid-template-columns: repeat(2, minmax(0, 1fr));">
23
+ ${prevSlug ? `
24
+ <a class="bk-end-link bk-end-link--prev" href="${prevSlug}.html">
25
+ <span>Previous Lesson</span>
26
+ <strong>${escHtml(prevTitle || "Previous")}</strong>
27
+ </a>
28
+ ` : `<div class="bk-end-link" style="visibility:hidden"></div>`}
29
+ ${nextSlug ? `
30
+ <a class="bk-end-link bk-end-link--next" href="${nextSlug}.html">
31
+ <span>Next Lesson</span>
32
+ <strong>${escHtml(nextTitle || "Next")}</strong>
33
+ </a>
34
+ ` : `<div class="bk-end-link" style="visibility:hidden"></div>`}
35
+ </nav>`;
36
+ }
37
+ function renderPage(lesson, navItems, bodyHtml, opts) {
38
+ const theme = opts.theme ?? "auto";
39
+ const schemeAttr = `data-theme="${theme}"`;
40
+ const preset = opts.preset ?? {};
41
+ const layout = preset.layout ?? "lesson";
42
+ const density = preset.density ?? "comfortable";
43
+ const tone = preset.tone ?? "scholarly";
44
+ const palette = opts.palette ?? "ink";
45
+ const navHtml = navItems.map(renderNavItem).join("\n");
46
+ const endNavHtml = renderEndNav(lesson);
47
+ return `<!DOCTYPE html>
48
+ <html lang="en" data-palette="${palette}" ${schemeAttr}>
49
+ <head>
50
+ <meta charset="UTF-8">
51
+ <meta name="viewport" content="width=device-width, initial-scale=1">
52
+ <title>${escHtml(lesson.meta.title)}</title>
53
+ ${lesson.meta.description ? `<meta name="description" content="${escHtml(lesson.meta.description)}">` : ""}
54
+ <link rel="preconnect" href="https://fonts.googleapis.com">
55
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
56
+ <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
57
+ <link href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&family=Syne:wght@600;700;800&display=swap" rel="stylesheet">
58
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.47/dist/katex.min.css">
59
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11.11.1/styles/github-dark.min.css">
60
+ ${opts.head ?? ""}
61
+ <link rel="stylesheet" href="assets/theme.css">
62
+ <style>
63
+ ${opts.font ? `:root { --font-sans: ${opts.font}, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }` : ""}
64
+ </style>
65
+ <script type="speculationrules">
66
+ {
67
+ "prefetch": [{
68
+ "where": { "href_matches": "/*" },
69
+ "eagerness": "eager"
70
+ }],
71
+ "prerender": [{
72
+ "where": { "href_matches": "/*" },
73
+ "eagerness": "moderate"
74
+ }]
75
+ }
76
+ </script>
77
+ <link rel="expect" href="#bk-content" blocking="render">
78
+ <script blocking="render">
79
+ const savedTheme = localStorage.getItem("bk-theme");
80
+ const savedPalette = localStorage.getItem("bk-palette");
81
+ if (savedTheme) document.documentElement.setAttribute("data-theme", savedTheme);
82
+ if (savedPalette) {
83
+ const normalizedPalette = savedPalette === "green" ? "field" : savedPalette;
84
+ document.documentElement.setAttribute("data-palette", normalizedPalette);
85
+ }
86
+ </script>
87
+ </head>
88
+ <body class="bk-layout-${layout} bk-density-${density} bk-tone-${tone}">
89
+ <div class="bk-shell">
90
+ <aside class="bk-sidebar">
91
+ <div class="bk-sidebar-inner">
92
+ <div class="bk-sidebar-header">
93
+ ${lesson.meta.parentSlug ? `<div style="margin-top: 8px;"><a href="${lesson.meta.parentSlug}.html" class="bk-back-link" aria-label="Back to Chapter" style="margin-bottom: 12px;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5"/><path d="M12 19l-7-7 7-7"/></svg>Back to Chapter</a></div>` : `<div style="margin-top: 8px;"></div>`}
94
+ <div class="bk-sidebar-title">${escHtml(lesson.meta.title)}</div>
95
+ ${lesson.meta.author ? `<div class="bk-sidebar-author">By ${escHtml(lesson.meta.author)}</div>` : ""}
96
+ ${lesson.meta.tags?.length ? `<div class="bk-tag-row">${lesson.meta.tags.map((tag) => `<span>${escHtml(tag)}</span>`).join("")}</div>` : ""}
97
+ </div>
98
+ <nav class="bk-nav">${navHtml}</nav>
99
+ <div class="bk-sidebar-footer">
100
+ <button class="bk-icon-btn bk-settings-button" id="bk-settings-button" type="button" aria-expanded="false" aria-controls="bk-theme-panel" title="Display settings">
101
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
102
+ <span class="bk-sr-only">Display settings</span>
103
+ </button>
104
+ <div class="bk-theme-panel" id="bk-theme-panel" aria-label="Display settings" hidden>
105
+ <div class="bk-theme-row">
106
+ <span>Theme</span>
107
+ <div class="bk-segmented-control" id="bk-theme-icons">
108
+ <button type="button" class="bk-segment-btn ${theme === "light" ? "active" : ""}" data-theme="light" title="Light" aria-label="Light theme">
109
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>
110
+ </button>
111
+ <button type="button" class="bk-segment-btn ${theme === "auto" ? "active" : (!theme ? "active" : "")}" data-theme="auto" title="System" aria-label="System theme">
112
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg>
113
+ </button>
114
+ <button type="button" class="bk-segment-btn ${theme === "dark" ? "active" : ""}" data-theme="dark" title="Dark" aria-label="Dark theme">
115
+ <svg width="16" height="16" viewBox="0 0 24 24" 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"></path></svg>
116
+ </button>
117
+ </div>
118
+ </div>
119
+ <div class="bk-theme-row">
120
+ <span>Palette</span>
121
+ <div class="bk-segmented-control" id="bk-palette-icons">
122
+ <button type="button" class="bk-segment-btn ${palette === "ink" ? "active" : ""}" data-palette="ink" title="Ink" aria-label="Ink palette">
123
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z"></path></svg>
124
+ </button>
125
+ <button type="button" class="bk-segment-btn ${palette === "field" ? "active" : ""}" data-palette="field" title="Field" aria-label="Field palette">
126
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z"></path><path d="M2 21c0-3 1.85-5.36 5.08-6C9.5 14.52 12 13 13 12"></path></svg>
127
+ </button>
128
+ <button type="button" class="bk-segment-btn ${palette === "ember" ? "active" : ""}" data-palette="ember" title="Ember" aria-label="Ember palette">
129
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8.5 14.5A2.5 2.5 0 0011 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 11-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 002.5 2.5z"></path></svg>
130
+ </button>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ </aside>
137
+ <button class="bk-sidebar-collapse-floating" id="bk-sidebar-collapse" aria-label="Collapse sidebar">
138
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
139
+ </button>
140
+ <main class="bk-main">
141
+ <button class="bk-sidebar-expand" id="bk-sidebar-expand" type="button" aria-label="Expand sidebar">
142
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
143
+ </button>
144
+ <article class="bk-content" id="bk-content">
145
+ <header class="bk-hero">
146
+ <p class="bk-eyebrow">Interactive Lesson</p>
147
+ <h1 style="view-transition-name: title-${lesson.meta.slug}">${escHtml(lesson.meta.title)}</h1>
148
+ ${lesson.meta.description ? `<p class="bk-deck">${escHtml(lesson.meta.description)}</p>` : ""}
149
+ </header>
150
+ ${bodyHtml}
151
+ ${endNavHtml}
152
+ </article>
153
+ </main>
154
+ </div>
155
+ <script src="assets/app.js" defer></script>
156
+ </body>
157
+ </html>`;
158
+ }
159
+ // ─── Core Assets ────────────────────────────────────────────────────────────────
160
+ function copyCoreAssets(outDir) {
161
+ const assetsDir = path.join(outDir, "assets");
162
+ if (!fs.existsSync(assetsDir))
163
+ fs.mkdirSync(assetsDir, { recursive: true });
164
+ const cssPath = path.join(__dirname, "../styles/theme.css");
165
+ if (fs.existsSync(cssPath)) {
166
+ fs.copyFileSync(cssPath, path.join(assetsDir, "theme.css"));
167
+ }
168
+ const jsPath = path.join(__dirname, "../client/app.js");
169
+ if (fs.existsSync(jsPath)) {
170
+ fs.copyFileSync(jsPath, path.join(assetsDir, "app.js"));
171
+ }
172
+ }
173
+ export { copyCoreAssets, renderNavItem, renderPage };
@@ -2,6 +2,7 @@ import type { BuildOptions, Lesson } from "../types.js";
2
2
  import type { NavItem } from "./utils.js";
3
3
  declare function renderNavItem(item: NavItem): string;
4
4
  declare function renderPage(lesson: Lesson, navItems: NavItem[], bodyHtml: string, opts: BuildOptions): string;
5
- declare function copyCoreAssets(outDir: string): void;
6
- export { copyCoreAssets, renderNavItem, renderPage };
5
+ declare function pageCSS(): string;
6
+ declare function clientScript(): string;
7
+ export { clientScript, pageCSS, renderNavItem, renderPage };
7
8
  //# sourceMappingURL=html.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/renderer/html.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,iBAAS,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAU5C;AAsBD,iBAAS,UAAU,CAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,YAAY,GAChB,MAAM,CAgGR;AAID,iBAAS,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAa5C;AAED,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/renderer/html.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,iBAAS,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAU5C;AAsBD,iBAAS,UAAU,CAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,YAAY,GAChB,MAAM,CA6HR;AAID,iBAAS,OAAO,IAAI,MAAM,CAKzB;AAID,iBAAS,YAAY,IAAI,MAAM,CAE9B;AAED,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC"}