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 +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +2 -6
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +42 -1
- package/dist/cli.js +0 -0
- package/dist/client/app.js +129 -9
- package/dist/renderer/blocks.d.ts.map +1 -1
- package/dist/renderer/blocks.js +33 -0
- package/dist/renderer/html-neo.d.ts +7 -0
- package/dist/renderer/html-neo.d.ts.map +1 -0
- package/dist/renderer/html-neo.js +173 -0
- package/dist/renderer/html.d.ts +3 -2
- package/dist/renderer/html.d.ts.map +1 -1
- package/dist/renderer/html.js +41 -18
- package/dist/renderer/index-neo.d.ts +4 -0
- package/dist/renderer/index-neo.d.ts.map +1 -0
- package/dist/renderer/index-neo.js +469 -0
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +186 -254
- package/dist/styles/theme-neo.css +1369 -0
- package/dist/styles/theme.css +368 -140
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/builder.ts +9 -16
- package/src/cli/init.ts +44 -1
- package/src/client/app.js +129 -9
- package/src/renderer/blocks.ts +33 -0
- package/src/renderer/html.ts +44 -17
- package/src/renderer/index.ts +186 -254
- package/src/styles/theme.css +368 -140
- package/src/types.ts +7 -0
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?:
|
|
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.
|
package/dist/builder.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"
|
|
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 ?? "
|
|
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 ?? "
|
|
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;
|
package/dist/cli/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAGA,wBAAsB,OAAO,
|
|
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
|
-
|
|
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
|
package/dist/client/app.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
335
|
+
uiBtns.forEach(btn => {
|
|
217
336
|
btn.addEventListener("click", () => {
|
|
218
|
-
const val = btn.dataset.
|
|
219
|
-
localStorage.setItem("bk-
|
|
220
|
-
|
|
221
|
-
root.setAttribute("data-
|
|
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,
|
|
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"}
|
package/dist/renderer/blocks.js
CHANGED
|
@@ -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 };
|
package/dist/renderer/html.d.ts
CHANGED
|
@@ -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
|
|
6
|
-
|
|
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,
|
|
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"}
|