mr-md 1.0.2 → 1.0.4

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
@@ -149,6 +149,8 @@ export declare class ChapterBuilder {
149
149
  private _rawOptions;
150
150
  constructor(title: string, options?: BuildOptions, callerDir?: string);
151
151
  slug(slug: string): this;
152
+ /** @internal Used by CourseBuilder to push down shared config */
153
+ _inheritOptions(parentOpts: BuildOptions, parentRawOpts?: BuildOptions): void;
152
154
  description(text: string): this;
153
155
  status(status: "completed" | "active" | "locked"): this;
154
156
  lesson(lessonBuilder: LessonBuilder): this;
@@ -167,4 +169,16 @@ export declare class ChapterBuilder {
167
169
  * .build();
168
170
  */
169
171
  export declare function chapter(title: string, options?: BuildOptions): ChapterBuilder;
172
+ export declare class CourseBuilder {
173
+ private meta;
174
+ private chapterBuilders;
175
+ private options;
176
+ private _rawOptions;
177
+ constructor(title: string, options?: BuildOptions, callerDir?: string);
178
+ slug(slug: string): this;
179
+ description(text: string): this;
180
+ chapter(chapterBuilder: ChapterBuilder): this;
181
+ build(): string;
182
+ }
183
+ export declare function course(title: string, options?: BuildOptions): CourseBuilder;
170
184
  //# sourceMappingURL=builder.d.ts.map
@@ -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,6 +1,6 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
- import { render, renderChapter } from "./renderer/index.js";
3
+ import { render, renderChapter, renderCourse } from "./renderer/index.js";
4
4
  function getCallerDir() {
5
5
  const err = new Error();
6
6
  const stack = err.stack?.split("\n");
@@ -109,17 +109,16 @@ export class LessonBuilder {
109
109
  /** @internal Used by ChapterBuilder to push down shared config */
110
110
  _inheritOptions(parentOpts, parentRawOpts) {
111
111
  this.options = {
112
- outDir: this._rawOptions.outDir ?? (parentRawOpts?.outDir || parentOpts.outDir) ?? this.options.outDir,
113
- contentBase: this._rawOptions.contentBase ??
114
- parentRawOpts?.contentBase ??
115
- this.options.contentBase,
112
+ ...this.options,
113
+ outDir: this._rawOptions.outDir ?? parentOpts.outDir ?? this.options.outDir,
114
+ contentBase: this._rawOptions.contentBase ?? this.options.contentBase,
116
115
  theme: this._rawOptions.theme ?? parentOpts.theme ?? this.options.theme,
117
116
  palette: this._rawOptions.palette ?? parentOpts.palette ?? this.options.palette,
118
117
  strict: this._rawOptions.strict ?? parentOpts.strict ?? this.options.strict,
119
118
  preset: {
119
+ ...this.options.preset,
120
120
  ...parentOpts.preset,
121
121
  ...this._rawOptions.preset,
122
- ...this.options.preset,
123
122
  },
124
123
  };
125
124
  }
@@ -512,6 +511,25 @@ export class ChapterBuilder {
512
511
  this.meta.slug = slug;
513
512
  return this;
514
513
  }
514
+ /** @internal Used by CourseBuilder to push down shared config */
515
+ _inheritOptions(parentOpts, parentRawOpts) {
516
+ this.options = {
517
+ ...this.options,
518
+ outDir: this._rawOptions.outDir ?? parentOpts.outDir ?? this.options.outDir,
519
+ contentBase: this._rawOptions.contentBase ?? this.options.contentBase,
520
+ theme: this._rawOptions.theme ?? parentOpts.theme ?? this.options.theme,
521
+ palette: this._rawOptions.palette ?? parentOpts.palette ?? this.options.palette,
522
+ strict: this._rawOptions.strict ?? parentOpts.strict ?? this.options.strict,
523
+ preset: {
524
+ ...this.options.preset,
525
+ ...parentOpts.preset,
526
+ ...this._rawOptions.preset,
527
+ },
528
+ };
529
+ for (const lb of this.lessonBuilders) {
530
+ lb._inheritOptions(this.options, this._rawOptions);
531
+ }
532
+ }
515
533
  description(text) {
516
534
  this.meta.description = text;
517
535
  return this;
@@ -580,3 +598,67 @@ export class ChapterBuilder {
580
598
  export function chapter(title, options = {}) {
581
599
  return new ChapterBuilder(title, options, getCallerDir());
582
600
  }
601
+ // ─── CourseBuilder ──────────────────────────────────────────────────────────
602
+ export class CourseBuilder {
603
+ meta;
604
+ chapterBuilders = [];
605
+ options;
606
+ _rawOptions;
607
+ constructor(title, options = {}, callerDir) {
608
+ this._rawOptions = options;
609
+ let slug = title
610
+ .toLowerCase()
611
+ .replace(/[^a-z0-9]+/g, "-")
612
+ .replace(/(^-|-$)/g, "");
613
+ if (!slug)
614
+ slug = "course";
615
+ this.meta = { title, slug };
616
+ this.options = {
617
+ outDir: options.outDir ?? "./out",
618
+ contentBase: options.contentBase ?? callerDir ?? ".",
619
+ theme: options.theme ?? "auto",
620
+ palette: options.palette ?? "ink",
621
+ strict: options.strict ?? true,
622
+ preset: {
623
+ layout: "lesson",
624
+ density: "comfortable",
625
+ tone: "scholarly",
626
+ ...options.preset,
627
+ },
628
+ ...options,
629
+ };
630
+ }
631
+ slug(slug) {
632
+ this.meta.slug = slug;
633
+ return this;
634
+ }
635
+ description(text) {
636
+ this.meta.description = text;
637
+ return this;
638
+ }
639
+ chapter(chapterBuilder) {
640
+ chapterBuilder._inheritOptions(this.options, this._rawOptions);
641
+ this.chapterBuilders.push(chapterBuilder);
642
+ return this;
643
+ }
644
+ build() {
645
+ const chapters = [];
646
+ for (const cb of this.chapterBuilders) {
647
+ cb.build();
648
+ chapters.push(cb.toJSON());
649
+ }
650
+ const courseData = { meta: this.meta, chapters };
651
+ const html = renderCourse(courseData, this.options);
652
+ const outDir = path.resolve(this.options.outDir);
653
+ if (!fs.existsSync(outDir))
654
+ fs.mkdirSync(outDir, { recursive: true });
655
+ const outPath = path.join(outDir, `${this.meta.slug}.html`);
656
+ fs.writeFileSync(outPath, html, "utf-8");
657
+ const relPath = path.relative(process.cwd(), outPath);
658
+ console.log(` ✓ Built course (${this.chapterBuilders.length} chapters) → ${relPath}`);
659
+ return outPath;
660
+ }
661
+ }
662
+ export function course(title, options = {}) {
663
+ return new CourseBuilder(title, options, getCallerDir());
664
+ }
@@ -1,5 +1,5 @@
1
1
  function bkSimDoc(js, props, loop, dependencies) {
2
- const scriptTags = (dependencies || []).map(url => '<script src="' + url.replace(/"/g, '&quot;') + '"></' + 'script>').join("\\n");
2
+ const scriptTags = (dependencies || []).map(url => '<script src="' + url.replace(/"/g, '&quot;') + '"></' + 'script>').join("\n");
3
3
  return (
4
4
  "<!DOCTYPE html><html><head>" +
5
5
  scriptTags +
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { ChapterBuilder, chapter, LessonBuilder, lesson } from "./builder.js";
1
+ export { ChapterBuilder, chapter, CourseBuilder, course, LessonBuilder, lesson } from "./builder.js";
2
2
  export { render } from "./renderer/index.js";
3
3
  export type { AnimationBlock, AnimationOptions, Block, BlockAccent, BlockType, BuildOptions, CalloutBlock, CodeBlock, ColumnItem, ColumnsBlock, ColumnsOptions, HeadingBlock, LatexBlock, LatexOptions, Lesson, LessonMeta, LessonPreset, MarkdownBlock, MediaBlock, MediaKind, MediaOptions, QuizBlock, QuizFile, QuizQuestion, SectionBlock, SimulationBlock, SimulationControl, SimulationOptions, YouTubeBlock, YouTubeOptions, } from "./types.js";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EACX,cAAc,EACd,gBAAgB,EAChB,KAAK,EACL,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,MAAM,EACN,UAAU,EACV,YAAY,EACZ,aAAa,EACb,UAAU,EACV,SAAS,EACT,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,cAAc,GACd,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACrG,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EACX,cAAc,EACd,gBAAgB,EAChB,KAAK,EACL,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,MAAM,EACN,UAAU,EACV,YAAY,EACZ,aAAa,EACb,UAAU,EACV,SAAS,EACT,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,cAAc,GACd,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { ChapterBuilder, chapter, LessonBuilder, lesson } from "./builder.js";
1
+ export { ChapterBuilder, chapter, CourseBuilder, course, LessonBuilder, lesson } from "./builder.js";
2
2
  export { render } from "./renderer/index.js";
@@ -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,CA0QxC;AAuID,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,CA2QxC;AAuID,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC"}
@@ -37,8 +37,8 @@ function renderBlockInner(block, idx, options) {
37
37
  switch (block.type) {
38
38
  case "heading": {
39
39
  const md = resolveContent(block.src, options, "md");
40
- const { html, title } = mdToHtml(md);
41
- const label = block.title || title || (typeof block.src === "string" && !block.src.includes(".md") ? block.src : "Heading");
40
+ const { html, title, headings } = mdToHtml(md);
41
+ const label = block.title || title || headings[0]?.text || (typeof block.src === "string" && !block.src.includes(".md") ? block.src.replace(/^#+\s*/, '') : "Heading");
42
42
  const id = `heading-${idx}`;
43
43
  return {
44
44
  html: `<section id="${id}" class="bk-section bk-heading">${html}</section>`,
@@ -57,8 +57,8 @@ function renderBlockInner(block, idx, options) {
57
57
  }
58
58
  case "section": {
59
59
  const md = resolveContent(block.src, options, "md");
60
- const { html, title } = mdToHtml(md);
61
- const label = block.label || title || (typeof block.src === "string" && !block.src.includes(".md") ? block.src : "Section");
60
+ const { html, title, headings } = mdToHtml(md);
61
+ const label = block.label || title || headings[0]?.text || (typeof block.src === "string" && !block.src.includes(".md") ? block.src.replace(/^#+\s*/, '') : "Section");
62
62
  const id = `section-${idx}`;
63
63
  return {
64
64
  html: `<section id="${id}" class="bk-section bk-subsection">${html}</section>`,
@@ -210,7 +210,8 @@ function renderBlockInner(block, idx, options) {
210
210
  if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
211
211
  throw new Error("Quiz file not found or invalid JSON format");
212
212
  }
213
- quiz = JSON.parse(trimmed);
213
+ const parsed = JSON.parse(trimmed);
214
+ quiz = Array.isArray(parsed) ? { questions: parsed } : parsed;
214
215
  }
215
216
  catch (e) {
216
217
  const msg = e instanceof Error ? e.message : String(e);
@@ -265,7 +266,7 @@ function renderQuestion(q, quizId, qi) {
265
266
  }
266
267
  // Wraps a JS string in a minimal iframe document
267
268
  function iframeDoc(js, props, loop, dependencies) {
268
- const scriptTags = (dependencies ?? []).map((url) => `<script src="${escAttr(url)}"></script>`).join("\\n");
269
+ const scriptTags = (dependencies ?? []).map((url) => `<script src="${escAttr(url)}"></script>`).join("\n");
269
270
  const doc = `<!DOCTYPE html><html><head>
270
271
  ${scriptTags}
271
272
  <style>
@@ -1,4 +1,5 @@
1
- import type { BuildOptions, Chapter, Lesson } from "../types.js";
1
+ import type { BuildOptions, Chapter, Course, Lesson } from "../types.js";
2
2
  export declare function render(lesson: Lesson, opts?: BuildOptions): string;
3
3
  export declare function renderChapter(chapter: Chapter, opts?: BuildOptions): string;
4
+ export declare function renderCourse(course: Course, opts?: BuildOptions): string;
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAOjE,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,MAAM,CAatE;AAID,wBAAgB,aAAa,CAC5B,OAAO,EAAE,OAAO,EAChB,IAAI,GAAE,YAAiB,GACrB,MAAM,CAqXR"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAOzE,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,MAAM,CAatE;AAID,wBAAgB,aAAa,CAC5B,OAAO,EAAE,OAAO,EAChB,IAAI,GAAE,YAAiB,GACrB,MAAM,CAqXR;AAID,wBAAgB,YAAY,CAC3B,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,YAAiB,GACrB,MAAM,CAqXR"}
@@ -379,3 +379,369 @@ ${clientScript()}
379
379
  </body>
380
380
  </html>`;
381
381
  }
382
+ // ─── Course Rendering ────────────────────────────────────────────────────────
383
+ export function renderCourse(course, opts = {}) {
384
+ const theme = opts.theme ?? "auto";
385
+ const schemeAttr = theme === "auto" ? "" : `data-theme="${theme}"`;
386
+ const preset = opts.preset ?? {};
387
+ const layout = preset.layout ?? "lesson";
388
+ const density = preset.density ?? "comfortable";
389
+ const tone = preset.tone ?? "scholarly";
390
+ const palette = opts.palette ?? "ink";
391
+ const navHtml = course.chapters
392
+ .map((c) => `<a href="${escAttr(c.meta.slug)}.html" class="bk-nav-item bk-nav-chapter">${escHtml(c.meta.title)}</a>`)
393
+ .join("\n");
394
+ const timelineHtml = `
395
+ <div class="bk-chapter-timeline-wrapper">
396
+ <div class="bk-chapter-timeline">
397
+ ${course.chapters
398
+ .map((chapter, idx) => `
399
+ <a href="${escAttr(chapter.meta.slug)}.html" class="bk-timeline-card bk-status-${chapter.meta.status ?? "unread"}">
400
+ <div class="bk-timeline-node"></div>
401
+ <div class="bk-timeline-content">
402
+ <h3 class="bk-timeline-title" style="view-transition-name: title-${escAttr(chapter.meta.slug)}">${escHtml(chapter.meta.title)}</h3>
403
+ ${chapter.meta.description ? `<p class="bk-timeline-desc">${escHtml(chapter.meta.description)}</p>` : ""}
404
+ <span class="bk-timeline-action">${chapter.meta.status === "completed" ? "Review" : "Start Chapter"} <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="M5 12h14m-7-7 7 7-7 7"/></svg></span>
405
+ </div>
406
+ </a>
407
+ `)
408
+ .join("")}
409
+ </div>
410
+ </div>
411
+ <script>
412
+ if (!CSS.supports('(animation-timeline: view()) and (animation-range: entry)')) {
413
+ const observer = new IntersectionObserver(
414
+ (entries) => {
415
+ for (const entry of entries) {
416
+ if (entry.isIntersecting) {
417
+ entry.target.classList.add('js-visible');
418
+ entry.target.classList.remove('js-hidden');
419
+ observer.unobserve(entry.target);
420
+ }
421
+ }
422
+ },
423
+ { threshold: 0.1 }
424
+ );
425
+ document.querySelectorAll('.bk-timeline-card').forEach((el) => {
426
+ el.classList.add('js-hidden');
427
+ observer.observe(el);
428
+ });
429
+ }
430
+ </script>`;
431
+ const chapterStyles = `
432
+ .bk-chapter-timeline-wrapper {
433
+ position: relative;
434
+ width: 100%;
435
+ padding: 1rem 0;
436
+ z-index: 1;
437
+ }
438
+
439
+ .bk-chapter-timeline {
440
+ display: flex;
441
+ flex-direction: column;
442
+ gap: 3rem;
443
+ padding: 3rem 0;
444
+ position: relative;
445
+ max-width: 800px;
446
+ margin: 0 auto;
447
+ }
448
+
449
+ /* Minimalist vertical connecting line */
450
+ .bk-chapter-timeline::before {
451
+ content: '';
452
+ position: absolute;
453
+ left: 20px;
454
+ top: 3rem;
455
+ bottom: 3rem;
456
+ width: 1px;
457
+ background: var(--line);
458
+ z-index: 0;
459
+ transform: translateX(-50%);
460
+ }
461
+
462
+ .bk-timeline-card {
463
+ display: flex;
464
+ align-items: stretch;
465
+ gap: 2rem;
466
+ text-decoration: none !important;
467
+ border: none !important;
468
+ color: inherit;
469
+ position: relative;
470
+ z-index: 1;
471
+ opacity: 1;
472
+ transform: none;
473
+ }
474
+
475
+ /* Subtle scroll-driven animations */
476
+ @media (prefers-reduced-motion: no-preference) {
477
+ @supports ((animation-timeline: view()) and (animation-range: entry)) {
478
+ .bk-timeline-card {
479
+ animation-name: slide-fade-in;
480
+ animation-fill-mode: both;
481
+ animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
482
+ animation-timeline: view(block);
483
+ animation-range: entry 5% cover 20%;
484
+ }
485
+ @keyframes slide-fade-in {
486
+ 0% { opacity: 0; transform: translateY(20px); }
487
+ 100% { opacity: 1; transform: translateY(0); }
488
+ }
489
+ }
490
+ }
491
+
492
+ /* Fallback for browsers without animation-timeline support */
493
+ .bk-timeline-card.js-hidden {
494
+ opacity: 0;
495
+ transform: translateY(20px);
496
+ }
497
+ .bk-timeline-card.js-visible {
498
+ opacity: 1;
499
+ transform: translateY(0);
500
+ transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1), transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
501
+ }
502
+
503
+ .bk-timeline-node {
504
+ width: 40px;
505
+ height: 40px;
506
+ border-radius: 50%;
507
+ background: var(--paper);
508
+ border: 1px solid var(--accent);
509
+ display: flex;
510
+ align-items: center;
511
+ justify-content: center;
512
+ flex-shrink: 0;
513
+ transition: all 0.3s ease;
514
+ position: relative;
515
+ box-shadow: 0 2px 4px rgba(0,0,0,0.02);
516
+ }
517
+ .bk-timeline-node::after {
518
+ content: '';
519
+ width: 10px;
520
+ height: 10px;
521
+ border-radius: 50%;
522
+ background: var(--accent);
523
+ transition: all 0.3s ease;
524
+ }
525
+ .bk-timeline-card:hover .bk-timeline-node {
526
+ background: var(--accent);
527
+ }
528
+ .bk-timeline-card:hover .bk-timeline-node::after {
529
+ background: var(--paper);
530
+ }
531
+
532
+ .bk-timeline-content {
533
+ background: var(--paper);
534
+ padding: 2rem;
535
+ border-radius: 12px;
536
+ border: 1px solid var(--line);
537
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.02);
538
+ flex: 1;
539
+ transition: all 0.3s ease;
540
+ display: flex;
541
+ flex-direction: column;
542
+ justify-content: center;
543
+ position: relative;
544
+ }
545
+ .bk-timeline-card:hover .bk-timeline-content {
546
+ border-color: color-mix(in srgb, var(--accent) 30%, var(--line));
547
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.04);
548
+ transform: translateY(-2px);
549
+ }
550
+
551
+ .bk-timeline-title {
552
+ margin: 0 0 0.5rem 0;
553
+ font-family: var(--font-display);
554
+ font-size: 1.6rem;
555
+ color: var(--ink);
556
+ width: fit-content;
557
+ transition: color 0.2s ease;
558
+ }
559
+ .bk-timeline-card:hover .bk-timeline-title {
560
+ color: var(--accent);
561
+ }
562
+
563
+ .bk-timeline-desc {
564
+ margin: 0 0 1.5rem 0;
565
+ color: var(--muted);
566
+ line-height: 1.6;
567
+ font-size: 1.05rem;
568
+ }
569
+
570
+ .bk-timeline-action {
571
+ font-weight: 500;
572
+ color: var(--accent);
573
+ display: inline-flex;
574
+ align-items: center;
575
+ gap: 0.4rem;
576
+ font-size: 0.95rem;
577
+ align-self: flex-start;
578
+ transition: all 0.2s ease;
579
+ border-bottom: 1px solid transparent;
580
+ }
581
+ .bk-timeline-card:hover .bk-timeline-action {
582
+ gap: 0.6rem;
583
+ border-bottom-color: var(--accent);
584
+ }
585
+
586
+ .bk-status-unread .bk-timeline-node {
587
+ border: 1px solid var(--line-strong);
588
+ }
589
+ .bk-status-unread .bk-timeline-node::after {
590
+ background: var(--line-strong);
591
+ transform: scale(0.8);
592
+ }
593
+ .bk-status-unread .bk-timeline-content {
594
+ background: transparent;
595
+ box-shadow: none;
596
+ border: 1px solid transparent;
597
+ }
598
+ .bk-status-unread .bk-timeline-title {
599
+ color: var(--muted);
600
+ }
601
+ .bk-status-unread .bk-timeline-desc {
602
+ color: color-mix(in srgb, var(--muted) 80%, transparent);
603
+ }
604
+ .bk-status-unread .bk-timeline-action {
605
+ color: var(--muted);
606
+ }
607
+ .bk-status-unread:hover .bk-timeline-node {
608
+ border-color: var(--ink);
609
+ background: var(--paper);
610
+ }
611
+ .bk-status-unread:hover .bk-timeline-node::after {
612
+ background: var(--ink);
613
+ transform: scale(1);
614
+ }
615
+ .bk-status-unread:hover .bk-timeline-content {
616
+ background: var(--paper);
617
+ border-color: var(--line);
618
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.02);
619
+ }
620
+ .bk-status-unread:hover .bk-timeline-title {
621
+ color: var(--ink);
622
+ }
623
+ .bk-status-unread:hover .bk-timeline-action {
624
+ color: var(--ink);
625
+ border-bottom-color: var(--ink);
626
+ }
627
+
628
+ @media (prefers-color-scheme: dark) {
629
+ .bk-timeline-content {
630
+ background: var(--panel);
631
+ }
632
+ .bk-status-unread .bk-timeline-content {
633
+ background: transparent;
634
+ }
635
+ .bk-status-unread:hover .bk-timeline-content {
636
+ background: var(--panel);
637
+ }
638
+ }
639
+
640
+ @media (max-width: 600px) {
641
+ .bk-chapter-timeline::before {
642
+ left: 16px;
643
+ }
644
+ .bk-timeline-card {
645
+ gap: 1.5rem;
646
+ }
647
+ .bk-timeline-node {
648
+ width: 32px;
649
+ height: 32px;
650
+ }
651
+ .bk-timeline-node::after {
652
+ width: 8px;
653
+ height: 8px;
654
+ }
655
+ .bk-timeline-content {
656
+ padding: 1.5rem;
657
+ border-radius: 10px;
658
+ }
659
+ .bk-timeline-title {
660
+ font-size: 1.4rem;
661
+ }
662
+ }
663
+ `;
664
+ return `<!DOCTYPE html>
665
+ <html lang="en" data-palette="${palette}" ${schemeAttr}>
666
+ <head>
667
+ <meta charset="UTF-8">
668
+ <meta name="viewport" content="width=device-width, initial-scale=1">
669
+ <title>${escHtml(course.meta.title)}</title>
670
+ ${course.meta.description ? `<meta name="description" content="${escHtml(course.meta.description)}">` : ""}
671
+ ${opts.head ?? ""}
672
+ <style>
673
+ ${opts.font ? `:root { --font-sans: ${opts.font}, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }` : ""}
674
+ ${pageCSS()}
675
+ ${chapterStyles}
676
+ </style>
677
+ </head>
678
+ <body class="bk-layout-${layout} bk-density-${density} bk-tone-${tone}">
679
+ <div class="bk-shell">
680
+ <aside class="bk-sidebar">
681
+ <div class="bk-sidebar-inner">
682
+ <div class="bk-sidebar-header">
683
+ <div style="margin-top: 8px;"></div>
684
+ <div class="bk-sidebar-title">${escHtml(course.meta.title)}</div>
685
+ </div>
686
+ <nav class="bk-nav">${navHtml}</nav>
687
+ <div class="bk-sidebar-footer">
688
+ <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">
689
+ <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>
690
+ <span class="bk-sr-only">Display settings</span>
691
+ </button>
692
+ <div class="bk-theme-panel" id="bk-theme-panel" aria-label="Display settings" hidden>
693
+ <div class="bk-theme-row">
694
+ <span>Theme</span>
695
+ <div class="bk-segmented-control" id="bk-theme-icons">
696
+ <button type="button" class="bk-segment-btn ${theme === "light" ? "active" : ""}" data-theme="light" title="Light" aria-label="Light theme">
697
+ <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>
698
+ </button>
699
+ <button type="button" class="bk-segment-btn ${theme === "dark" ? "active" : ""}" data-theme="dark" title="Dark" aria-label="Dark theme">
700
+ <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>
701
+ </button>
702
+ <button type="button" class="bk-segment-btn ${theme === "auto" ? "active" : ""}" data-theme="auto" title="System" aria-label="System theme">
703
+ <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>
704
+ </button>
705
+ </div>
706
+ </div>
707
+ <div class="bk-theme-row">
708
+ <span>Palette</span>
709
+ <div class="bk-segmented-control" id="bk-palette-icons">
710
+ <button type="button" class="bk-segment-btn ${palette === "ink" ? "active" : ""}" data-palette="ink" title="Ink" aria-label="Ink palette">
711
+ <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>
712
+ </button>
713
+ <button type="button" class="bk-segment-btn ${palette === "field" ? "active" : ""}" data-palette="field" title="Field" aria-label="Field palette">
714
+ <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 12"></path></svg>
715
+ </button>
716
+ <button type="button" class="bk-segment-btn ${palette === "ember" ? "active" : ""}" data-palette="ember" title="Ember" aria-label="Ember palette">
717
+ <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>
718
+ </button>
719
+ </div>
720
+ </div>
721
+ </div>
722
+ </div>
723
+ </div>
724
+ </aside>
725
+ <button class="bk-sidebar-collapse-floating" id="bk-sidebar-collapse" aria-label="Collapse sidebar">
726
+ <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>
727
+ </button>
728
+ <main class="bk-main">
729
+ <button class="bk-sidebar-expand" id="bk-sidebar-expand" type="button" aria-label="Expand sidebar">
730
+ <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>
731
+ </button>
732
+ <article class="bk-content" style="max-width: 1000px; margin: 0 auto;">
733
+ <header class="bk-hero" style="border-bottom: none;">
734
+ <p class="bk-eyebrow">Course</p>
735
+ <h1>${escHtml(course.meta.title)}</h1>
736
+ ${course.meta.description ? `<p class="bk-deck">${escHtml(course.meta.description)}</p>` : ""}
737
+ </header>
738
+ ${timelineHtml}
739
+ </article>
740
+ </main>
741
+ </div>
742
+ <script>
743
+ ${clientScript()}
744
+ </script>
745
+ </body>
746
+ </html>`;
747
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/renderer/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,OAAO;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;CACrC;AAID,iBAAS,cAAc,CACtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,YAAY,EACrB,YAAY,GAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,MAAe,GAClD,MAAM,CAmCR;AAED,iBAAS,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAwCnE;AAED,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/renderer/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,OAAO;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;CACrC;AAID,iBAAS,cAAc,CACtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,YAAY,EACrB,YAAY,GAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,MAAe,GAClD,MAAM,CA0CR;AAED,iBAAS,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAgDnE;AAED,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC"}