explico 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +879 -1
- package/README.md +200 -30
- package/dist/compiler/astro.d.ts +15 -2
- package/dist/compiler/astro.js +40 -11
- package/dist/compiler/cli-main.d.ts +43 -0
- package/dist/compiler/cli-main.js +392 -0
- package/dist/compiler/cli.d.ts +424 -9
- package/dist/compiler/cli.js +1289 -8
- package/dist/compiler/collections.d.ts +88 -1
- package/dist/compiler/collections.js +170 -25
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +105 -1
- package/dist/compiler/decks.d.ts +161 -0
- package/dist/compiler/decks.js +235 -0
- package/dist/compiler/exports/combined-html.d.ts +5 -1
- package/dist/compiler/exports/deck-fit.d.ts +55 -0
- package/dist/compiler/exports/deck-fit.js +90 -0
- package/dist/compiler/exports/export-chapters.d.ts +37 -6
- package/dist/compiler/exports/export-chapters.js +64 -5
- package/dist/compiler/exports/export-pages.d.ts +30 -3
- package/dist/compiler/exports/export-pages.js +24 -1
- package/dist/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/dist/compiler/exports/latex/cache.d.ts +78 -0
- package/dist/compiler/exports/latex/cache.js +129 -0
- package/dist/compiler/exports/latex/capture.d.ts +10 -1
- package/dist/compiler/exports/latex/capture.js +3 -1
- package/dist/compiler/exports/latex/compile.d.ts +13 -2
- package/dist/compiler/exports/latex/compile.js +12 -1
- package/dist/compiler/exports/latex/deck.d.ts +92 -0
- package/dist/compiler/exports/latex/deck.js +349 -0
- package/dist/compiler/exports/latex/document.d.ts +51 -6
- package/dist/compiler/exports/latex/document.js +71 -12
- package/dist/compiler/exports/latex/explico-common.sty +198 -0
- package/dist/compiler/exports/latex/explico.cls +13 -183
- package/dist/compiler/exports/latex/serialize.d.ts +60 -4
- package/dist/compiler/exports/latex/serialize.js +4 -2
- package/dist/compiler/exports/latex-export.d.ts +24 -2
- package/dist/compiler/exports/latex-export.js +107 -26
- package/dist/compiler/exports/markdown/serialize.d.ts +24 -4
- package/dist/compiler/exports/markdown/serialize.js +85 -8
- package/dist/compiler/exports/markdown-export.d.ts +6 -1
- package/dist/compiler/exports/markdown-export.js +50 -11
- package/dist/compiler/exports/standalone-html.d.ts +10 -5
- package/dist/compiler/exports/standalone-html.js +3 -3
- package/dist/compiler/exports/static-tree.d.ts +38 -1
- package/dist/compiler/exports/static-tree.js +120 -4
- package/dist/compiler/knowledge-version.d.ts +26 -2
- package/dist/compiler/knowledge-version.js +27 -17
- package/dist/compiler/lesson-derivation.d.ts +143 -6
- package/dist/compiler/lesson-derivation.js +145 -13
- package/dist/compiler/manifest.d.ts +133 -4
- package/dist/compiler/manifest.js +359 -58
- package/dist/compiler/page-versions.d.ts +160 -0
- package/dist/compiler/page-versions.js +198 -0
- package/dist/compiler/render-diagnostics.d.ts +5 -1
- package/dist/compiler/resolution-report.d.ts +24 -6
- package/dist/compiler/resolution-report.js +22 -4
- package/dist/compiler/validate-content.d.ts +7 -0
- package/dist/compiler/validate-content.js +160 -0
- package/dist/{course-config-rRtME5UV.d.ts → course-config-BLtIdkei.d.ts} +164 -1
- package/dist/curriculum/competency-graph.d.ts +54 -0
- package/dist/curriculum/competency-graph.js +41 -0
- package/dist/reference/base-library.d.mts +8 -0
- package/dist/reference/base-library.mjs +19 -0
- package/dist/reference/consistency.d.ts +8 -4
- package/dist/reference/consistency.js +76 -26
- package/dist/reference/deck-remark.d.mts +123 -0
- package/dist/reference/deck-remark.mjs +600 -0
- package/dist/reference/deck-source.d.ts +107 -0
- package/dist/reference/deck-source.js +140 -0
- package/dist/reference/decks-validate.d.ts +133 -0
- package/dist/reference/decks-validate.js +359 -0
- package/dist/reference/derived-entries.d.ts +5 -1
- package/dist/reference/diagram-fit.d.ts +1 -1
- package/dist/reference/figure-symbols.d.ts +23 -6
- package/dist/reference/figure-symbols.js +51 -15
- package/dist/reference/float-name.d.ts +43 -0
- package/dist/reference/float-name.js +58 -0
- package/dist/reference/folds-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-indices.js +5 -4
- package/dist/reference/gate-math.d.ts +29 -2
- package/dist/reference/gate-math.js +99 -18
- package/dist/reference/gate-part-pages.d.ts +1 -1
- package/dist/reference/lab-katex-validate.d.ts +10 -6
- package/dist/reference/lab-katex-validate.js +17 -9
- package/dist/reference/lab-math-scope.js +29 -4
- package/dist/reference/math-glyphs.d.mts +25 -0
- package/dist/reference/math-glyphs.mjs +189 -25
- package/dist/reference/page-notation.d.ts +22 -3
- package/dist/reference/page-notation.js +32 -10
- package/dist/reference/references.d.ts +14 -1
- package/dist/reference/references.js +13 -0
- package/dist/reference/registry-scope.d.mts +33 -0
- package/dist/reference/registry-scope.mjs +34 -0
- package/dist/reference/registry.js +29 -10
- package/dist/reference/rehype-deck.d.mts +6 -0
- package/dist/reference/rehype-deck.mjs +286 -0
- package/dist/reference/rehype-heading-anchors.d.mts +20 -0
- package/dist/reference/rehype-heading-anchors.mjs +48 -6
- package/dist/reference/remark-notation.mjs +249 -40
- package/dist/reference/source-lines.d.mts +12 -0
- package/dist/reference/source-lines.mjs +65 -0
- package/dist/reference/types.d.ts +28 -0
- package/dist/rules/catalog.d.ts +21 -4
- package/dist/rules/catalog.js +221 -2
- package/dist/rules/course-rules.d.ts +5 -1
- package/dist/rules/course-rules.js +17 -3
- package/dist/rules/course-rules.schema.json +12 -0
- package/dist/rules/in-effect.d.ts +13 -3
- package/dist/rules/in-effect.js +30 -7
- package/dist/rules/rules.schema.json +259 -1
- package/dist/rules/settings.d.ts +1 -1
- package/dist/session/PreferenceStore.d.ts +6 -0
- package/dist/session/PreferenceStore.js +18 -1
- package/dist/session/deck-memory.d.ts +116 -0
- package/dist/session/deck-memory.js +143 -0
- package/dist/session/reading-memory.d.ts +96 -0
- package/dist/session/reading-memory.js +133 -0
- package/docs/VERSIONING.md +21 -18
- package/docs/authoring/README.md +29 -9
- package/docs/authoring/agents.md +63 -16
- package/docs/authoring/components.md +15 -0
- package/docs/authoring/deck.md +588 -0
- package/docs/authoring/migrating.md +1045 -16
- package/docs/authoring/notation.md +49 -6
- package/docs/authoring/structure.md +80 -1
- package/docs/authoring/versioning.md +54 -2
- package/docs/authoring/visualizations.md +7 -2
- package/docs/course-agent/AGENTS.md +37 -0
- package/docs/course-agent/agents/rules-reviewer.md +33 -0
- package/docs/course-agent/skills/draft-lesson/SKILL.md +37 -0
- package/docs/course-agent/skills/migrate-course/SKILL.md +31 -0
- package/docs/course-agent/skills/release-content/SKILL.md +24 -0
- package/docs/diagram-scaling.md +148 -0
- package/docs/privacy.md +59 -0
- package/package.json +8 -2
- package/src/compiler/astro.ts +60 -21
- package/src/compiler/cli-main.ts +469 -0
- package/src/compiler/cli.ts +1905 -16
- package/src/compiler/collections.ts +284 -25
- package/src/compiler/course-config.ts +267 -0
- package/src/compiler/decks.ts +455 -0
- package/src/compiler/exports/deck-fit.ts +127 -0
- package/src/compiler/exports/export-chapters.ts +105 -6
- package/src/compiler/exports/export-pages.ts +46 -2
- package/src/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/src/compiler/exports/latex/cache.ts +183 -0
- package/src/compiler/exports/latex/capture.ts +5 -2
- package/src/compiler/exports/latex/compile.ts +18 -0
- package/src/compiler/exports/latex/deck.ts +419 -0
- package/src/compiler/exports/latex/document.ts +117 -21
- package/src/compiler/exports/latex/explico-common.sty +198 -0
- package/src/compiler/exports/latex/explico.cls +13 -183
- package/src/compiler/exports/latex/serialize.ts +25 -21
- package/src/compiler/exports/latex/texlive-packages.txt +6 -2
- package/src/compiler/exports/latex-export.ts +187 -45
- package/src/compiler/exports/markdown/serialize.ts +118 -9
- package/src/compiler/exports/markdown-export.ts +56 -11
- package/src/compiler/exports/standalone-html.ts +8 -7
- package/src/compiler/exports/static-tree.ts +175 -3
- package/src/compiler/knowledge-version.ts +56 -21
- package/src/compiler/lesson-derivation.ts +282 -16
- package/src/compiler/manifest.ts +558 -63
- package/src/compiler/page-versions.ts +359 -0
- package/src/compiler/resolution-report.ts +38 -7
- package/src/compiler/validate-content.ts +212 -0
- package/src/components/CourseContents.astro +124 -6
- package/src/components/CurriculumMap.astro +49 -1
- package/src/components/FloatIndex.astro +1 -1
- package/src/components/PartOverview.astro +51 -5
- package/src/components/assessments/AssessmentSet.astro +41 -15
- package/src/components/block-heading.ts +15 -6
- package/src/components/card-carry.ts +7 -4
- package/src/components/card-manager.ts +14 -2
- package/src/components/card-memory.ts +13 -9
- package/src/components/deck/DeckEnhancer.astro +13 -0
- package/src/components/deck/deck-context.ts +104 -0
- package/src/components/deck/deck-controller.ts +1287 -0
- package/src/components/deck/deck-map.ts +91 -0
- package/src/components/deck-lane.ts +163 -0
- package/src/components/diagram/Diagram.astro +131 -86
- package/src/components/disclosure/persisted-disclosure.ts +9 -1
- package/src/components/figure/Figure.astro +7 -2
- package/src/components/figure/FloatCaption.astro +5 -3
- package/src/components/fold/Fold.astro +2 -2
- package/src/components/notation/NotationFormula.astro +81 -11
- package/src/components/notation/NotationGlossary.astro +132 -1
- package/src/components/notation/NotationLayer.astro +15 -7
- package/src/components/starlight/AboutPanel.astro +186 -3
- package/src/components/starlight/CollapsibleSections.astro +24 -3
- package/src/components/starlight/DiagramEnhancer.astro +5 -1
- package/src/components/starlight/HeadingAnchorEnhancer.astro +1 -1
- package/src/components/starlight/LayoutHeader.astro +17 -0
- package/src/components/starlight/LayoutPageTitle.astro +110 -0
- package/src/components/starlight/LayoutSidebar.astro +807 -21
- package/src/components/starlight/LayoutSocialIcons.astro +62 -6
- package/src/components/starlight/LessonExportActions.astro +27 -9
- package/src/components/starlight/LessonFooter.astro +59 -0
- package/src/components/starlight/ReadingMemoryNotice.astro +114 -0
- package/src/components/starlight/TextSizeControl.astro +24 -13
- package/src/components/starlight/page-marks.ts +139 -0
- package/src/components/starlight/section-summary.ts +1 -1
- package/src/components/starlight/sidebar-editions.ts +245 -0
- package/src/components/table/Table.astro +15 -7
- package/src/content-config.ts +87 -1
- package/src/curriculum/competency-graph.ts +95 -0
- package/src/reference/base-library.mjs +19 -0
- package/src/reference/consistency.ts +126 -39
- package/src/reference/deck-remark.mjs +600 -0
- package/src/reference/deck-source.ts +273 -0
- package/src/reference/decks-validate.ts +604 -0
- package/src/reference/diagram-layout.ts +3 -1
- package/src/reference/figure-symbols.ts +108 -31
- package/src/reference/folds-validate.ts +1 -1
- package/src/reference/gate-indices.ts +5 -3
- package/src/reference/gate-math.ts +169 -25
- package/src/reference/lab-katex-validate.ts +30 -15
- package/src/reference/lab-math-scope.ts +34 -3
- package/src/reference/math-glyphs.mjs +189 -25
- package/src/reference/page-notation.ts +69 -15
- package/src/reference/references.ts +28 -0
- package/src/reference/registry-scope.mjs +34 -0
- package/src/reference/registry.ts +41 -11
- package/src/reference/rehype-deck.mjs +286 -0
- package/src/reference/rehype-heading-anchors.mjs +48 -6
- package/src/reference/remark-notation.mjs +249 -40
- package/src/reference/source-lines.mjs +65 -0
- package/src/reference/types.ts +28 -0
- package/src/rules/catalog.ts +257 -4
- package/src/rules/course-rules.ts +21 -1
- package/src/rules/in-effect.ts +54 -8
- package/src/session/PreferenceStore.ts +23 -0
- package/src/session/deck-memory.ts +263 -0
- package/src/session/reading-memory.ts +243 -0
- package/src/styles/deck.css +1150 -0
- package/src/styles/global.css +958 -27
- package/src/styles/zones.css +277 -0
- /package/src/{components → reference}/float-name.ts +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Manifest, ManifestDeck } from '../../manifest.js';
|
|
2
|
+
import { StaticDeck, NotationEntry } from '../static-tree.js';
|
|
3
|
+
import { ChapterContext } from './serialize.js';
|
|
4
|
+
import { SourceFile } from './document.js';
|
|
5
|
+
import '../../../curriculum/validation.js';
|
|
6
|
+
import '../../../reference/consistency.js';
|
|
7
|
+
import '../../../course-config-BLtIdkei.js';
|
|
8
|
+
import '../../../rules/catalog.js';
|
|
9
|
+
import '../../../rules/course-rules.js';
|
|
10
|
+
import '../../collections.js';
|
|
11
|
+
import '../../../reference/types.js';
|
|
12
|
+
import '../../../reference/gate-retired-keys.js';
|
|
13
|
+
import '../../../reference/lint-ignore.js';
|
|
14
|
+
import '../../../reference/equations-validate.js';
|
|
15
|
+
import '../../../reference/tables-validate.js';
|
|
16
|
+
import '../../../reference/keyed-float-validate.js';
|
|
17
|
+
import '../../../reference/figures-validate.js';
|
|
18
|
+
import '../../../reference/diagrams-validate.js';
|
|
19
|
+
import '../../../reference/examples-validate.js';
|
|
20
|
+
import '../../../reference/folds-validate.js';
|
|
21
|
+
import '../../../reference/knowledge-checks-validate.js';
|
|
22
|
+
import '../../../reference/raw-floats-validate.js';
|
|
23
|
+
import '../../../reference/lab-katex-validate.js';
|
|
24
|
+
import '../../../reference/gate-math.js';
|
|
25
|
+
import '../../../reference/mixed-content.js';
|
|
26
|
+
import '../../../reference/gloss.js';
|
|
27
|
+
import '../../../rules/waivers.js';
|
|
28
|
+
import '../../knowledge-version.js';
|
|
29
|
+
import '../../page-versions.js';
|
|
30
|
+
import '../../decks.js';
|
|
31
|
+
import '../../../reference/decks-validate.js';
|
|
32
|
+
import '../../../reference/deck-source.js';
|
|
33
|
+
import '../../lesson-derivation.js';
|
|
34
|
+
import '../html-tree.js';
|
|
35
|
+
import 'parse5';
|
|
36
|
+
|
|
37
|
+
/** `beamerthemeexplico.sty`, read next to this module. */
|
|
38
|
+
declare function deckTheme(): string;
|
|
39
|
+
/**
|
|
40
|
+
* The notation keys a deck's LaTeX names, in order of first use: in a
|
|
41
|
+
* formula (`\explain{key}{…}`) or in prose (`\ExplicoTerm{key}{…}`).
|
|
42
|
+
*/
|
|
43
|
+
declare function deckNotationKeys(tex: string): string[];
|
|
44
|
+
/**
|
|
45
|
+
* The symbols a deck's frames use, in order of first use, from its page's
|
|
46
|
+
* notation list: its appendix in every download.
|
|
47
|
+
*/
|
|
48
|
+
declare function deckSymbols(context: Omit<ChapterContext, 'page'> & {
|
|
49
|
+
readonly deck: StaticDeck;
|
|
50
|
+
}): NotationEntry[];
|
|
51
|
+
interface DeckSerialization {
|
|
52
|
+
/** `deck.tex`: every frame, in order. */
|
|
53
|
+
readonly tex: string;
|
|
54
|
+
/** The line of `deck.tex` each frame ends on, by frame number: a paper overflow names its frame by it. */
|
|
55
|
+
readonly frameEnds: ReadonlyMap<number, number>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The frames of a deck in beamer, then the notation appendix of the symbols
|
|
59
|
+
* they use (`appendix`, each linked from its uses through `notationTargets`).
|
|
60
|
+
*/
|
|
61
|
+
declare function serializeDeck(context: Omit<ChapterContext, 'page'> & {
|
|
62
|
+
readonly deck: StaticDeck;
|
|
63
|
+
readonly appendix?: readonly NotationEntry[];
|
|
64
|
+
}): DeckSerialization;
|
|
65
|
+
interface DeckSourceInput {
|
|
66
|
+
readonly manifest: Manifest;
|
|
67
|
+
readonly deck: ManifestDeck;
|
|
68
|
+
readonly page: StaticDeck;
|
|
69
|
+
readonly checkItems: ChapterContext['checkItems'];
|
|
70
|
+
readonly pictures: ReadonlyMap<string, {
|
|
71
|
+
readonly path: string;
|
|
72
|
+
readonly content: Uint8Array;
|
|
73
|
+
}>;
|
|
74
|
+
readonly scripts?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/** A deck's LaTeX folder, and where each of its frames ends in `deck.tex`. */
|
|
77
|
+
declare function deckSource(input: DeckSourceInput): {
|
|
78
|
+
files: SourceFile[];
|
|
79
|
+
frameEnds: ReadonlyMap<number, number>;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* The frames LaTeX numbered differently from the deck page: each frame's
|
|
83
|
+
* `\label{frame:N}` must carry frame number N.
|
|
84
|
+
*/
|
|
85
|
+
declare function deckNumberingProblems(aux: string, frames: number): string[];
|
|
86
|
+
/** The frames a beamer log says run over their slide, by `deck.tex` line: `{ frame, points }`. */
|
|
87
|
+
declare function deckOverflows(log: string, frameEnds: ReadonlyMap<number, number>): {
|
|
88
|
+
frame: number;
|
|
89
|
+
points: number;
|
|
90
|
+
}[];
|
|
91
|
+
|
|
92
|
+
export { type DeckSerialization, type DeckSourceInput, deckNotationKeys, deckNumberingProblems, deckOverflows, deckSource, deckSymbols, deckTheme, serializeDeck };
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { escapeText, ChapterWriter, labelOf, linkExplains } from "./serialize.js";
|
|
3
|
+
import { versionPhrase } from "../../page-versions.js";
|
|
4
|
+
import { explicoCommon, needsScripts, trailerId } from "./document.js";
|
|
5
|
+
function deckTheme() {
|
|
6
|
+
return readFileSync(new URL("./beamerthemeexplico.sty", import.meta.url), "utf8");
|
|
7
|
+
}
|
|
8
|
+
const ASPECT = { "16:9": "169", "16:10": "1610", "4:3": "43" };
|
|
9
|
+
function deckPage(deck) {
|
|
10
|
+
return {
|
|
11
|
+
slug: deck.slug,
|
|
12
|
+
route: deck.route,
|
|
13
|
+
title: deck.title,
|
|
14
|
+
blocks: deck.frames.flatMap((frame) => [...frame.segments.flatMap((segment) => segment.blocks), ...frame.notes]),
|
|
15
|
+
notation: [],
|
|
16
|
+
notationRemarks: []
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
class DeckWriter extends ChapterWriter {
|
|
20
|
+
inline(inline) {
|
|
21
|
+
if (inline.kind === "cite") return `[${escapeText(inline.number)}]`;
|
|
22
|
+
return super.inline(inline);
|
|
23
|
+
}
|
|
24
|
+
/** A float's caption on a frame: its number (the chapter's, when recalled), its short and long caption. */
|
|
25
|
+
deckCaption(kind, block, extra = []) {
|
|
26
|
+
const number = block.number ? `${kind}~${escapeText(block.number)}` : "";
|
|
27
|
+
const short = block.short?.trim() ? escapeText(block.short.trim().replace(/\.$/u, "")) : "";
|
|
28
|
+
const long = [this.plain(block.caption), this.plain(extra)].filter(Boolean).join(" ");
|
|
29
|
+
return `\\ExplicoDeckCaption{${number}}{${short}}{${long}}`;
|
|
30
|
+
}
|
|
31
|
+
block(block, inBox = false) {
|
|
32
|
+
switch (block.kind) {
|
|
33
|
+
case "heading":
|
|
34
|
+
return `\\par\\textbf{${this.plain(block.children)}}\\par`;
|
|
35
|
+
case "equation":
|
|
36
|
+
return `\\begin{equation*}
|
|
37
|
+
${this.math(block.tex)}
|
|
38
|
+
\\tag{${escapeText(block.number)}}
|
|
39
|
+
\\end{equation*}`;
|
|
40
|
+
case "list": {
|
|
41
|
+
const environment = block.ordered ? "enumerate" : "itemize";
|
|
42
|
+
const items = block.items.map((item, index) => {
|
|
43
|
+
const step = block.itemSteps?.[index] ?? 1;
|
|
44
|
+
return `\\item${step > 1 ? `<${step}->` : ""} ${this.blocks(item, inBox)}`;
|
|
45
|
+
});
|
|
46
|
+
return `\\begin{${environment}}
|
|
47
|
+
${items.join("\n")}
|
|
48
|
+
\\end{${environment}}`;
|
|
49
|
+
}
|
|
50
|
+
case "figure": {
|
|
51
|
+
const alt = block.alt ?? [block.short, ...block.caption.map((inline) => "value" in inline ? inline.value : "")].filter(Boolean).join(" ");
|
|
52
|
+
const picture = this.picture(block.anchor, block.picture, alt).replace("max height=0.6\\textheight", "max height=0.62\\textheight");
|
|
53
|
+
return `\\begin{center}
|
|
54
|
+
${picture}
|
|
55
|
+
${this.deckCaption("Figure", block, block.live)}
|
|
56
|
+
\\end{center}`;
|
|
57
|
+
}
|
|
58
|
+
case "diagram":
|
|
59
|
+
return [
|
|
60
|
+
"\\begin{center}",
|
|
61
|
+
"\\begin{adjustbox}{max width=\\linewidth,max height=0.62\\textheight}",
|
|
62
|
+
this.unlinkedWhile(() => this.picture(block.anchor, { kind: "diagram", geometry: block.geometry }, "")),
|
|
63
|
+
"\\end{adjustbox}",
|
|
64
|
+
this.deckCaption("Diagram", block),
|
|
65
|
+
"\\end{center}"
|
|
66
|
+
].join("\n");
|
|
67
|
+
case "table": {
|
|
68
|
+
const tabular = this.table({ ...block, number: "" }, true);
|
|
69
|
+
return `\\begin{center}
|
|
70
|
+
${this.deckCaption("Table", block)}
|
|
71
|
+
\\smallskip
|
|
72
|
+
${tabular}
|
|
73
|
+
\\end{center}`;
|
|
74
|
+
}
|
|
75
|
+
case "memo":
|
|
76
|
+
return [`\\begin{block}{${this.plain(block.title)}}`, this.blocks(block.children, true), "\\end{block}"].join("\n");
|
|
77
|
+
case "note":
|
|
78
|
+
return [`\\begin{block}{${escapeText(block.title)}}`, this.blocks(block.children, true), "\\end{block}"].join("\n");
|
|
79
|
+
case "aside": {
|
|
80
|
+
const environment = block.variant === "caution" || block.variant === "danger" ? "alertblock" : "block";
|
|
81
|
+
return [`\\begin{${environment}}{${this.plain(block.title)}}`, this.blocks(block.children, true), `\\end{${environment}}`].join("\n");
|
|
82
|
+
}
|
|
83
|
+
case "examples":
|
|
84
|
+
return block.items.map((item) => [`\\begin{block}{${this.plain(item.title)}}`, this.blocks(item.children, true), "\\end{block}"].join("\n")).join("\n");
|
|
85
|
+
case "check": {
|
|
86
|
+
const items = this.context.checkItems.get(block.assessmentId) ?? [];
|
|
87
|
+
const questions = items.map((item) => {
|
|
88
|
+
const options = item.type === "single-choice" && item.options && item.options.length > 0 ? `
|
|
89
|
+
\\begin{enumerate}
|
|
90
|
+
${item.options.map((option) => `\\item[(${String.fromCharCode(97 + item.options.indexOf(option))})] ${this.optionLabel(option)}`).join("\n")}
|
|
91
|
+
\\end{enumerate}` : "";
|
|
92
|
+
return `\\item ${this.segments(item.promptSegments)}${options}`;
|
|
93
|
+
});
|
|
94
|
+
return [
|
|
95
|
+
`\\par{\\usebeamercolor[fg]{structure}\\textbf{Knowledge check ${escapeText(block.number)}}}\\enspace ${this.plain(block.title)}\\par`,
|
|
96
|
+
...questions.length > 0 ? ["\\begin{enumerate}", ...questions, "\\end{enumerate}"] : []
|
|
97
|
+
].join("\n");
|
|
98
|
+
}
|
|
99
|
+
default:
|
|
100
|
+
return super.block(block, inBox);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** A check's answers, for the frame's notes. */
|
|
104
|
+
checkAnswers(block) {
|
|
105
|
+
const items = this.context.checkItems.get(block.assessmentId) ?? [];
|
|
106
|
+
return items.map((item) => {
|
|
107
|
+
if (item.type === "single-choice" && item.options) {
|
|
108
|
+
const index = item.options.findIndex((option) => option.id === item.correctOptionId);
|
|
109
|
+
const answer = index === -1 ? "" : `(${String.fromCharCode(97 + index)}) ${this.optionLabel(item.options[index])}. `;
|
|
110
|
+
return `Answer: ${answer}${this.segments(item.explanationSegments)}`;
|
|
111
|
+
}
|
|
112
|
+
if (item.type === "numeric" && item.answer) {
|
|
113
|
+
return `Answer: $${item.answer.value}$ (within $\\pm${item.answer.tolerance}$). ${this.segments(item.explanationSegments)}`;
|
|
114
|
+
}
|
|
115
|
+
return this.segments(item.explanationSegments);
|
|
116
|
+
}).join("\\par ");
|
|
117
|
+
}
|
|
118
|
+
frameTitle(frame) {
|
|
119
|
+
return this.plain(frame.title);
|
|
120
|
+
}
|
|
121
|
+
/** A legend line's symbol, linked to its appendix entry. */
|
|
122
|
+
legendSymbol(tex) {
|
|
123
|
+
return this.math(tex);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The notation appendix: each symbol the deck uses, by first use, with its
|
|
127
|
+
* name, what it is, its units and its defining formula, as the chapter's
|
|
128
|
+
* notation lists it. It breaks over as many frames as it needs.
|
|
129
|
+
*/
|
|
130
|
+
notationFrames(entries) {
|
|
131
|
+
if (entries.length === 0) return "";
|
|
132
|
+
const targets = new Set(entries.map((entry) => entry.key));
|
|
133
|
+
const items = entries.map((entry) => {
|
|
134
|
+
const formula = entry.formulaTex ? linkExplains(entry.formulaTex, (named) => named !== entry.key && targets.has(named) ? labelOf("notation", named) : void 0) : void 0;
|
|
135
|
+
const parts = [
|
|
136
|
+
`\\textbf{${this.inlines(entry.label)}}.`,
|
|
137
|
+
this.inlines(entry.summary),
|
|
138
|
+
...entry.units ? [`\\emph{Units:} ${this.inlines(entry.units)}.`] : [],
|
|
139
|
+
...formula ? [`$${formula}$`] : []
|
|
140
|
+
];
|
|
141
|
+
return `\\item[{${entry.symbolTex ? `$${entry.symbolTex}$` : ""}}]\\hypertarget{${labelOf("notation", entry.key)}}{}${parts.join(" ")}`;
|
|
142
|
+
});
|
|
143
|
+
return [
|
|
144
|
+
"\\appendix",
|
|
145
|
+
"\\section{Notation}",
|
|
146
|
+
"\\begin{frame}[allowframebreaks,t]{Notation}",
|
|
147
|
+
"\\small",
|
|
148
|
+
"\\begin{description}",
|
|
149
|
+
...items,
|
|
150
|
+
"\\end{description}",
|
|
151
|
+
"\\end{frame}"
|
|
152
|
+
].join("\n");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function deckNotationKeys(tex) {
|
|
156
|
+
const keys = /* @__PURE__ */ new Set();
|
|
157
|
+
for (const match of tex.matchAll(/\\(?:explain|ExplicoTerm)\{([^{}]+)\}\{/gu)) keys.add(match[1]);
|
|
158
|
+
return [...keys];
|
|
159
|
+
}
|
|
160
|
+
function deckSymbols(context) {
|
|
161
|
+
const byKey = new Map(context.deck.notation.map((entry) => [entry.key, entry]));
|
|
162
|
+
return deckNotationKeys(serializeDeck(context).tex).flatMap((key) => {
|
|
163
|
+
const entry = byKey.get(key);
|
|
164
|
+
return entry ? [entry] : [];
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function checksOf(blocks) {
|
|
168
|
+
const out = [];
|
|
169
|
+
for (const block of blocks) {
|
|
170
|
+
if (block.kind === "check") out.push(block);
|
|
171
|
+
if ("children" in block && Array.isArray(block.children) && block.kind !== "paragraph" && block.kind !== "heading") {
|
|
172
|
+
out.push(...checksOf(block.children));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
function hasCode(blocks) {
|
|
178
|
+
return blocks.some(
|
|
179
|
+
(block) => block.kind === "code" || "children" in block && Array.isArray(block.children) && block.kind !== "paragraph" && block.kind !== "heading" && hasCode(block.children)
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
function serializeDeck(context) {
|
|
183
|
+
const writer = new DeckWriter({ ...context, page: deckPage(context.deck) });
|
|
184
|
+
const lines = [];
|
|
185
|
+
const frameEnds = /* @__PURE__ */ new Map();
|
|
186
|
+
const push = (text) => lines.push(...text.split("\n"));
|
|
187
|
+
push(`\\ExplicoDeckFrames{${context.deck.frames.length}}`);
|
|
188
|
+
lines.push("");
|
|
189
|
+
for (const frame of context.deck.frames) {
|
|
190
|
+
const label = `\\label{frame:${frame.number}}`;
|
|
191
|
+
if (frame.kind === "title") {
|
|
192
|
+
push(`\\begin{frame}[plain]${label}
|
|
193
|
+
\\titlepage
|
|
194
|
+
\\end{frame}`);
|
|
195
|
+
} else if (frame.kind === "section") {
|
|
196
|
+
push(`\\section{${writer.frameTitle(frame)}}
|
|
197
|
+
\\begin{frame}${label}
|
|
198
|
+
\\ExplicoSectionPage
|
|
199
|
+
\\end{frame}`);
|
|
200
|
+
} else {
|
|
201
|
+
const blocks = frame.segments.flatMap((segment) => segment.blocks);
|
|
202
|
+
const options = hasCode(blocks) ? "[fragile]" : "";
|
|
203
|
+
const body = frame.segments.map((segment) => {
|
|
204
|
+
const content = writer.blocks(segment.blocks);
|
|
205
|
+
return segment.step > 1 ? `\\begin{uncoverenv}<${segment.step}->
|
|
206
|
+
${content}
|
|
207
|
+
\\end{uncoverenv}` : content;
|
|
208
|
+
});
|
|
209
|
+
const legend = frame.legend.filter((item) => item.tex);
|
|
210
|
+
const answers = checksOf(blocks).map((check) => writer.checkAnswers(check)).filter(Boolean);
|
|
211
|
+
const notes = [writer.blocks(frame.notes), ...answers].filter((text) => text.trim().length > 0);
|
|
212
|
+
push(
|
|
213
|
+
[
|
|
214
|
+
`\\begin{frame}${options}{${writer.frameTitle(frame)}}${label}`,
|
|
215
|
+
...body,
|
|
216
|
+
...legend.length > 0 ? [`\\ExplicoLegend{${legend.map((item) => `$${writer.legendSymbol(item.tex)}$~${escapeText(item.label.map((inline) => "value" in inline ? inline.value : "").join(""))}`).join("\\quad ")}}`] : [],
|
|
217
|
+
...notes.length > 0 ? [`\\note{${notes.join("\n\n")}}`] : [],
|
|
218
|
+
"\\end{frame}"
|
|
219
|
+
].join("\n")
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
frameEnds.set(frame.number, lines.length);
|
|
223
|
+
lines.push("");
|
|
224
|
+
}
|
|
225
|
+
const appendix = writer.notationFrames(context.appendix ?? []);
|
|
226
|
+
if (appendix) push(`${appendix}
|
|
227
|
+
`);
|
|
228
|
+
return { tex: `${lines.join("\n")}
|
|
229
|
+
`, frameEnds };
|
|
230
|
+
}
|
|
231
|
+
const LATEXMKRC = [
|
|
232
|
+
"# LuaLaTeX by default; `latexmk -pdf` uses pdfLaTeX instead.",
|
|
233
|
+
"$pdf_mode = 4;",
|
|
234
|
+
"$postscript_mode = $dvi_mode = 0;",
|
|
235
|
+
"# luaotfload rewrites its font caches as fonts are looked up; they are not",
|
|
236
|
+
"# this document's sources, so a rewrite is no reason to run again.",
|
|
237
|
+
"$hash_calc_ignore_pattern{'luc'} = '^';",
|
|
238
|
+
""
|
|
239
|
+
].join("\n");
|
|
240
|
+
function deckMain(manifest, deck, handout, scripts) {
|
|
241
|
+
const ratio = ASPECT[manifest.deck?.aspectRatio ?? "16:9"] ?? "169";
|
|
242
|
+
const course = manifest.about.material.name;
|
|
243
|
+
const authors = (manifest.about.authors ?? []).map((author) => author.name).filter(Boolean).join(", ");
|
|
244
|
+
const version = versionPhrase(deck.since, manifest.about.knowledge.version);
|
|
245
|
+
const document = `${deck.slug}${handout ? "#handout" : ""}`;
|
|
246
|
+
const trailer = trailerId(manifest, document, deck.since);
|
|
247
|
+
return [
|
|
248
|
+
`% The deck's ${handout ? "handout: each slide followed by its notes" : "slides"}. Compile with \`latexmk${handout ? " handout.tex" : ""}\` (LuaLaTeX, see latexmkrc).`,
|
|
249
|
+
"% A fixed seed for TeX's random numbers: the same source gives the same PDF.",
|
|
250
|
+
"\\ExplSyntaxOn \\sys_gset_rand_seed:n { 1 } \\ExplSyntaxOff",
|
|
251
|
+
// usepdftitle=false: the title below is the PDF's, not beamer's "title - subtitle".
|
|
252
|
+
`\\documentclass[aspectratio=${ratio},11pt,usepdftitle=false${handout ? ",handout" : ""}]{beamer}`,
|
|
253
|
+
`\\usetheme${scripts ? "[scripts]" : ""}{explico}`,
|
|
254
|
+
...handout ? ["\\setbeameroption{show notes}"] : [],
|
|
255
|
+
`\\ifdefined\\directlua\\pdfvariable trailerid {[<${trailer}><${trailer}>]}\\else\\pdftrailerid{${trailer}}\\fi`,
|
|
256
|
+
`\\title{${escapeText(deck.title)}}`,
|
|
257
|
+
`\\subtitle{${escapeText(course)}}`,
|
|
258
|
+
`\\author{${escapeText(authors || course)}}`,
|
|
259
|
+
`\\date{Content ${escapeText(version)}}`,
|
|
260
|
+
`\\hypersetup{pdftitle={${escapeText(deck.title)}},pdfauthor={${escapeText(authors || course)}},pdfsubject={${escapeText(course)}}}`,
|
|
261
|
+
"\\begin{document}",
|
|
262
|
+
"\\input{deck}",
|
|
263
|
+
"\\end{document}",
|
|
264
|
+
""
|
|
265
|
+
].join("\n");
|
|
266
|
+
}
|
|
267
|
+
function deckReadme(manifest, deck, url) {
|
|
268
|
+
const course = manifest.about.material.name;
|
|
269
|
+
return [
|
|
270
|
+
`# ${deck.title} \u2014 slides`,
|
|
271
|
+
"",
|
|
272
|
+
`The LaTeX source of a deck of *${course}*, ${versionPhrase(deck.since, manifest.about.knowledge.version)}.` + (url ? ` Its interactive version: ${url}` : ""),
|
|
273
|
+
"",
|
|
274
|
+
"- `main.tex` \u2014 the slides: `latexmk` builds `main.pdf`.",
|
|
275
|
+
"- `handout.tex` \u2014 each slide followed by its speaker notes: `latexmk handout.tex`.",
|
|
276
|
+
"- `deck.tex` \u2014 the frames, which both read.",
|
|
277
|
+
"- `beamerthemeexplico.sty` \u2014 explico's beamer theme: the legend line, the frame number, the progress bar.",
|
|
278
|
+
"- `explico-common.sty` \u2014 what the theme shares with explico's book class: fonts, colours, figures,",
|
|
279
|
+
" diagrams and the notation markers.",
|
|
280
|
+
"- `figures/` \u2014 the deck's figures, as vector PDF where the website draws them.",
|
|
281
|
+
"- `latexmkrc` \u2014 LuaLaTeX by default; `latexmk -pdf` uses pdfLaTeX.",
|
|
282
|
+
"",
|
|
283
|
+
"Beamer cannot write a tagged PDF: these PDFs are not accessible to a screen reader. The deck's",
|
|
284
|
+
"web page and its chapter's PDF are.",
|
|
285
|
+
""
|
|
286
|
+
].join("\n");
|
|
287
|
+
}
|
|
288
|
+
function deckSource(input) {
|
|
289
|
+
const { manifest, deck, page } = input;
|
|
290
|
+
const base = manifest.lessonExports.canonicalBaseUrl;
|
|
291
|
+
const url = base ? `${base}${deck.slug}/` : void 0;
|
|
292
|
+
const context = {
|
|
293
|
+
deck: page,
|
|
294
|
+
documentRoutes: /* @__PURE__ */ new Set([page.route]),
|
|
295
|
+
...base ? { canonicalBaseUrl: base } : {},
|
|
296
|
+
pictures: new Map([...input.pictures].map(([anchor, picture]) => [anchor, picture.path])),
|
|
297
|
+
checkItems: input.checkItems
|
|
298
|
+
};
|
|
299
|
+
const appendix = deckSymbols(context);
|
|
300
|
+
const serialized = serializeDeck({
|
|
301
|
+
...context,
|
|
302
|
+
appendix,
|
|
303
|
+
notationTargets: new Set(appendix.map((entry) => entry.key))
|
|
304
|
+
});
|
|
305
|
+
const scripts = input.scripts ?? needsScripts(serialized.tex);
|
|
306
|
+
const files = [
|
|
307
|
+
{ path: "main.tex", content: deckMain(manifest, deck, false, scripts) },
|
|
308
|
+
{ path: "handout.tex", content: deckMain(manifest, deck, true, scripts) },
|
|
309
|
+
{ path: "deck.tex", content: serialized.tex },
|
|
310
|
+
{ path: "beamerthemeexplico.sty", content: deckTheme() },
|
|
311
|
+
{ path: "explico-common.sty", content: explicoCommon() },
|
|
312
|
+
{ path: "latexmkrc", content: LATEXMKRC },
|
|
313
|
+
{ path: "README.md", content: deckReadme(manifest, deck, url) },
|
|
314
|
+
...[...input.pictures.values()].map((picture) => ({ path: picture.path, content: picture.content }))
|
|
315
|
+
];
|
|
316
|
+
return { files, frameEnds: serialized.frameEnds };
|
|
317
|
+
}
|
|
318
|
+
function deckNumberingProblems(aux, frames) {
|
|
319
|
+
const numbers = /* @__PURE__ */ new Map();
|
|
320
|
+
for (const match of aux.matchAll(/\\newlabel\{frame:(\d+)\}\{\{(\d+)\}/gu)) {
|
|
321
|
+
numbers.set(Number(match[1]), Number(match[2]));
|
|
322
|
+
}
|
|
323
|
+
const problems = [];
|
|
324
|
+
for (let frame = 1; frame <= frames; frame += 1) {
|
|
325
|
+
const printed = numbers.get(frame);
|
|
326
|
+
if (printed === void 0) problems.push(`slide ${frame} has no frame in the PDF`);
|
|
327
|
+
else if (printed !== frame) problems.push(`slide ${frame} is frame ${printed} in the PDF`);
|
|
328
|
+
}
|
|
329
|
+
return problems;
|
|
330
|
+
}
|
|
331
|
+
function deckOverflows(log, frameEnds) {
|
|
332
|
+
const ends = [...frameEnds].sort((a, b) => a[1] - b[1]);
|
|
333
|
+
const found = /* @__PURE__ */ new Map();
|
|
334
|
+
for (const match of log.matchAll(/Overfull \\vbox \(([\d.]+)pt too high\) detected at line (\d+)/gu)) {
|
|
335
|
+
const line = Number(match[2]);
|
|
336
|
+
const frame = ends.find(([, end]) => line <= end + 1)?.[0];
|
|
337
|
+
if (frame !== void 0) found.set(frame, Math.max(found.get(frame) ?? 0, Number(match[1])));
|
|
338
|
+
}
|
|
339
|
+
return [...found].map(([frame, points]) => ({ frame, points: Math.round(points) })).sort((a, b) => a.frame - b.frame);
|
|
340
|
+
}
|
|
341
|
+
export {
|
|
342
|
+
deckNotationKeys,
|
|
343
|
+
deckNumberingProblems,
|
|
344
|
+
deckOverflows,
|
|
345
|
+
deckSource,
|
|
346
|
+
deckSymbols,
|
|
347
|
+
deckTheme,
|
|
348
|
+
serializeDeck
|
|
349
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ManifestLesson, ManifestPart, Manifest } from '../../manifest.js';
|
|
1
|
+
import { ManifestLesson, ManifestPart, Manifest, ManifestDeck } from '../../manifest.js';
|
|
2
2
|
import { StaticPage } from '../static-tree.js';
|
|
3
3
|
import { CheckItem } from './serialize.js';
|
|
4
4
|
import '../../../curriculum/validation.js';
|
|
5
5
|
import '../../../reference/consistency.js';
|
|
6
|
-
import '../../../course-config-
|
|
6
|
+
import '../../../course-config-BLtIdkei.js';
|
|
7
7
|
import '../../../rules/catalog.js';
|
|
8
8
|
import '../../../rules/course-rules.js';
|
|
9
9
|
import '../../collections.js';
|
|
@@ -25,6 +25,10 @@ import '../../../reference/mixed-content.js';
|
|
|
25
25
|
import '../../../reference/gloss.js';
|
|
26
26
|
import '../../../rules/waivers.js';
|
|
27
27
|
import '../../knowledge-version.js';
|
|
28
|
+
import '../../page-versions.js';
|
|
29
|
+
import '../../decks.js';
|
|
30
|
+
import '../../../reference/decks-validate.js';
|
|
31
|
+
import '../../../reference/deck-source.js';
|
|
28
32
|
import '../../lesson-derivation.js';
|
|
29
33
|
import '../html-tree.js';
|
|
30
34
|
import 'parse5';
|
|
@@ -41,18 +45,33 @@ interface SourceFile {
|
|
|
41
45
|
}
|
|
42
46
|
/** explico's class, shipped next to this module (copied into `dist/` by `copy-assets`). */
|
|
43
47
|
declare function explicoClass(): string;
|
|
48
|
+
/** `explico-common.sty`: what the book class and the deck theme share. */
|
|
49
|
+
declare function explicoCommon(): string;
|
|
44
50
|
/** `parts/02-projectiles/02-optimal-launch-angle.tex` for chapter 2.2. */
|
|
45
51
|
declare function chapterPath(manifest: Pick<Manifest, 'parts'>, lesson: ManifestLesson): string;
|
|
46
52
|
/** The folder name a chapter's download unzips to. */
|
|
47
53
|
declare function chapterFolderName(lesson: ManifestLesson): string;
|
|
48
54
|
/** A chapter's check answers, by assessment id, in authored order. */
|
|
49
55
|
declare function checkItems(manifest: Pick<Manifest, 'assessmentContent'>, lesson: Pick<ManifestLesson, 'id'>): Map<string, CheckItem[]>;
|
|
56
|
+
/**
|
|
57
|
+
* The items a deck's question frames ask: its lesson's checks, or on a
|
|
58
|
+
* part's deck those of each chapter it covers, as its frames show them
|
|
59
|
+
* (an assessment two chapters share, as the first one does).
|
|
60
|
+
*/
|
|
61
|
+
declare function deckCheckItems(manifest: Pick<Manifest, 'assessmentContent'>, deck: Pick<ManifestDeck, 'lessonId' | 'covers'>): Map<string, CheckItem[]>;
|
|
50
62
|
/**
|
|
51
63
|
* The PDF's file identifier (its trailer `/ID`), which the engines derive
|
|
52
|
-
* from the output file's path unless told: fixed from the course,
|
|
53
|
-
* content
|
|
64
|
+
* from the output file's path unless told: fixed from the course, the
|
|
65
|
+
* version the document's content is at (rule C5) and the document, so every
|
|
66
|
+
* compile of a source agrees, and a release that left the document alone
|
|
67
|
+
* leaves its identifier.
|
|
68
|
+
*/
|
|
69
|
+
declare function trailerId(manifest: Pick<Manifest, 'about'>, document: string, since: string | null): string;
|
|
70
|
+
/**
|
|
71
|
+
* The version a book's content is at: the newest among its chapters and
|
|
72
|
+
* part pages, `null` when any has a change not yet released.
|
|
54
73
|
*/
|
|
55
|
-
declare function
|
|
74
|
+
declare function bookSince(parts: readonly BookPart[]): string | null;
|
|
56
75
|
interface ChapterSourceInput {
|
|
57
76
|
readonly manifest: Manifest;
|
|
58
77
|
readonly lesson: ManifestLesson;
|
|
@@ -67,6 +86,19 @@ interface ChapterSourceInput {
|
|
|
67
86
|
}
|
|
68
87
|
/** Every file of one chapter's LaTeX folder. */
|
|
69
88
|
declare function chapterSource(input: ChapterSourceInput): SourceFile[];
|
|
89
|
+
/**
|
|
90
|
+
* The document's files, with the class option `scripts` on `main.tex` when a
|
|
91
|
+
* `.tex` file holds a character of another script: the class then loads its
|
|
92
|
+
* fallback fonts under LuaLaTeX, which costs every compile that does not
|
|
93
|
+
* need them about two seconds.
|
|
94
|
+
*/
|
|
95
|
+
/**
|
|
96
|
+
* Whether a document's LaTeX holds a character of another script, so its
|
|
97
|
+
* class (or a deck's theme) should load the fallback fonts. A Greek letter on
|
|
98
|
+
* its own is a symbol set as math; a Greek word (`\ExplicoGreekWord`), an
|
|
99
|
+
* accented letter or another script needs a text font.
|
|
100
|
+
*/
|
|
101
|
+
declare function needsScripts(tex: string): boolean;
|
|
70
102
|
/** A chapter of a book, with its figure files. */
|
|
71
103
|
interface BookChapter {
|
|
72
104
|
readonly lesson: ManifestLesson;
|
|
@@ -76,11 +108,24 @@ interface BookChapter {
|
|
|
76
108
|
readonly content: Uint8Array;
|
|
77
109
|
}>;
|
|
78
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* A lesson of a book's part that has no chapter, only slides (a slides-first
|
|
113
|
+
* lesson, docs/authoring/deck.md): the book keeps its place and its number
|
|
114
|
+
* with a short chapter that points at the slides.
|
|
115
|
+
*/
|
|
116
|
+
interface BookSlidesLesson {
|
|
117
|
+
readonly lesson: ManifestLesson;
|
|
118
|
+
/** The deck's PDF and interactive version, when the course publishes them. */
|
|
119
|
+
readonly slidesUrl?: string;
|
|
120
|
+
readonly outcomes: readonly string[];
|
|
121
|
+
}
|
|
79
122
|
/** A part of a book: its own page, when it has one, and its chapters in order. */
|
|
80
123
|
interface BookPart {
|
|
81
124
|
readonly part: ManifestPart;
|
|
82
125
|
readonly overview?: StaticPage;
|
|
83
126
|
readonly chapters: readonly BookChapter[];
|
|
127
|
+
/** Its slides-first lessons, placed among the chapters by their chapter number. */
|
|
128
|
+
readonly slides?: readonly BookSlidesLesson[];
|
|
84
129
|
}
|
|
85
130
|
interface BookSourceInput {
|
|
86
131
|
readonly manifest: Manifest;
|
|
@@ -99,4 +144,4 @@ interface BookSourceInput {
|
|
|
99
144
|
*/
|
|
100
145
|
declare function bookSource(input: BookSourceInput): SourceFile[];
|
|
101
146
|
|
|
102
|
-
export { type BookChapter, type BookPart, type BookSourceInput, type ChapterSourceInput, type SourceFile, bookSource, chapterFolderName, chapterPath, chapterSource, checkItems, explicoClass, trailerId };
|
|
147
|
+
export { type BookChapter, type BookPart, type BookSlidesLesson, type BookSourceInput, type ChapterSourceInput, type SourceFile, bookSince, bookSource, chapterFolderName, chapterPath, chapterSource, checkItems, deckCheckItems, explicoClass, explicoCommon, needsScripts, trailerId };
|