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
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
|
|
4
|
-
import type { Manifest, ManifestLesson, ManifestPart } from '../../manifest';
|
|
4
|
+
import type { Manifest, ManifestDeck, ManifestLesson, ManifestPart } from '../../manifest';
|
|
5
|
+
import { newestSince, versionPhrase } from '../../page-versions';
|
|
5
6
|
import type { Block, StaticPage } from '../static-tree';
|
|
6
7
|
import {
|
|
7
8
|
escapeText,
|
|
9
|
+
escapeUrl,
|
|
10
|
+
labelOf,
|
|
8
11
|
serializeAbbreviationAppendix,
|
|
9
12
|
serializeChapter,
|
|
10
13
|
serializeNotationAppendix,
|
|
@@ -30,6 +33,11 @@ export function explicoClass(): string {
|
|
|
30
33
|
return readFileSync(new URL('./explico.cls', import.meta.url), 'utf8');
|
|
31
34
|
}
|
|
32
35
|
|
|
36
|
+
/** `explico-common.sty`: what the book class and the deck theme share. */
|
|
37
|
+
export function explicoCommon(): string {
|
|
38
|
+
return readFileSync(new URL('./explico-common.sty', import.meta.url), 'utf8');
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
function twoDigits(value: number): string {
|
|
34
42
|
return String(value).padStart(2, '0');
|
|
35
43
|
}
|
|
@@ -59,6 +67,26 @@ export function checkItems(manifest: Pick<Manifest, 'assessmentContent'>, lesson
|
|
|
59
67
|
return items;
|
|
60
68
|
}
|
|
61
69
|
|
|
70
|
+
/**
|
|
71
|
+
* The items a deck's question frames ask: its lesson's checks, or on a
|
|
72
|
+
* part's deck those of each chapter it covers, as its frames show them
|
|
73
|
+
* (an assessment two chapters share, as the first one does).
|
|
74
|
+
*/
|
|
75
|
+
export function deckCheckItems(
|
|
76
|
+
manifest: Pick<Manifest, 'assessmentContent'>,
|
|
77
|
+
deck: Pick<ManifestDeck, 'lessonId' | 'covers'>,
|
|
78
|
+
): Map<string, CheckItem[]> {
|
|
79
|
+
const lessonIds =
|
|
80
|
+
deck.lessonId !== undefined ? [deck.lessonId] : deck.covers.map((cover) => cover.chapter.replace(/\//g, '.'));
|
|
81
|
+
const items = new Map<string, CheckItem[]>();
|
|
82
|
+
for (const id of lessonIds) {
|
|
83
|
+
for (const [assessment, list] of checkItems(manifest, { id })) {
|
|
84
|
+
if (!items.has(assessment)) items.set(assessment, list);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return items;
|
|
88
|
+
}
|
|
89
|
+
|
|
62
90
|
/**
|
|
63
91
|
* The seed comes first: tagpdf names its "user" structure namespace with
|
|
64
92
|
* `\int_rand:n` digits as it loads, and TeX seeds its random numbers from
|
|
@@ -85,16 +113,31 @@ const DOCUMENT_METADATA = [
|
|
|
85
113
|
|
|
86
114
|
/**
|
|
87
115
|
* The PDF's file identifier (its trailer `/ID`), which the engines derive
|
|
88
|
-
* from the output file's path unless told: fixed from the course,
|
|
89
|
-
* content
|
|
116
|
+
* from the output file's path unless told: fixed from the course, the
|
|
117
|
+
* version the document's content is at (rule C5) and the document, so every
|
|
118
|
+
* compile of a source agrees, and a release that left the document alone
|
|
119
|
+
* leaves its identifier.
|
|
90
120
|
*/
|
|
91
|
-
export function trailerId(manifest: Pick<Manifest, 'about'>, document: string): string {
|
|
121
|
+
export function trailerId(manifest: Pick<Manifest, 'about'>, document: string, since: string | null): string {
|
|
92
122
|
return createHash('md5')
|
|
93
|
-
.update(`${manifest.about.material.name}\n${manifest.about.knowledge.version}\n${document}`)
|
|
123
|
+
.update(`${manifest.about.material.name}\n${versionPhrase(since, manifest.about.knowledge.version)}\n${document}`)
|
|
94
124
|
.digest('hex')
|
|
95
125
|
.toUpperCase();
|
|
96
126
|
}
|
|
97
127
|
|
|
128
|
+
/**
|
|
129
|
+
* The version a book's content is at: the newest among its chapters and
|
|
130
|
+
* part pages, `null` when any has a change not yet released.
|
|
131
|
+
*/
|
|
132
|
+
export function bookSince(parts: readonly BookPart[]): string | null {
|
|
133
|
+
return newestSince(
|
|
134
|
+
parts.flatMap(({ part, chapters }) => [
|
|
135
|
+
...(part.overview ? [part.overview.since] : []),
|
|
136
|
+
...chapters.map(({ lesson }) => lesson.since),
|
|
137
|
+
]),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
98
141
|
function trailerIdLine(id: string): string {
|
|
99
142
|
return `\\ifdefined\\directlua\\pdfvariable trailerid {[<${id}><${id}>]}\\else\\pdftrailerid{${id}}\\fi`;
|
|
100
143
|
}
|
|
@@ -116,7 +159,7 @@ function mainTex(
|
|
|
116
159
|
...DOCUMENT_METADATA,
|
|
117
160
|
`\\documentclass[${paper}]{explico}`,
|
|
118
161
|
'% The same identifier for every compile of this source.',
|
|
119
|
-
trailerIdLine(trailerId(manifest, lesson.slug)),
|
|
162
|
+
trailerIdLine(trailerId(manifest, lesson.slug, lesson.since)),
|
|
120
163
|
...(numbering.floats === 'part' ? ['\\ExplicoFloatsByPart'] : []),
|
|
121
164
|
`\\ExplicoSectionDepth{${numbering.sections.show ? numbering.sections.depth : 1}}`,
|
|
122
165
|
`\\hypersetup{pdftitle={${escapeText(lesson.title)}},pdfauthor={${escapeText(
|
|
@@ -146,7 +189,7 @@ function readme(manifest: Manifest, lesson: ManifestLesson, url: string | undefi
|
|
|
146
189
|
`# ${lesson.title}`,
|
|
147
190
|
'',
|
|
148
191
|
`The LaTeX source of a chapter of *${course}*` +
|
|
149
|
-
` (
|
|
192
|
+
` (${versionPhrase(lesson.since, manifest.about.knowledge.version)}).` +
|
|
150
193
|
(url ? ` Interactive version: ${url}` : ''),
|
|
151
194
|
'',
|
|
152
195
|
'## Build',
|
|
@@ -166,6 +209,8 @@ function readme(manifest: Manifest, lesson: ManifestLesson, url: string | undefi
|
|
|
166
209
|
'- `main.tex` — the document: class options, then the chapter.',
|
|
167
210
|
'- `explico.cls` — explico\'s book class: layout, numbering, and the',
|
|
168
211
|
' environments the chapter uses (memos, notes, worked examples, checks).',
|
|
212
|
+
'- `explico-common.sty` — what the class shares with explico\'s slides: fonts,',
|
|
213
|
+
' colours, figures, diagrams and the notation markers.',
|
|
169
214
|
`- \`${chapterPath(manifest, lesson)}\` — the chapter.`,
|
|
170
215
|
'- `figures/` — the chapter\'s figures, as vector PDF where the website draws them.',
|
|
171
216
|
'',
|
|
@@ -199,7 +244,7 @@ export function chapterSource(input: ChapterSourceInput): SourceFile[] {
|
|
|
199
244
|
checkItems: checkItems(manifest, lesson),
|
|
200
245
|
source: {
|
|
201
246
|
course: manifest.about.material.name,
|
|
202
|
-
|
|
247
|
+
since: versionPhrase(lesson.since, manifest.about.knowledge.version),
|
|
203
248
|
...(url ? { url } : {}),
|
|
204
249
|
},
|
|
205
250
|
});
|
|
@@ -208,6 +253,7 @@ export function chapterSource(input: ChapterSourceInput): SourceFile[] {
|
|
|
208
253
|
{ path: 'latexmkrc', content: LATEXMKRC },
|
|
209
254
|
{ path: 'main.tex', content: mainTex(manifest, lesson, file) },
|
|
210
255
|
{ path: 'explico.cls', content: explicoClass() },
|
|
256
|
+
{ path: 'explico-common.sty', content: explicoCommon() },
|
|
211
257
|
{ path: file, content: chapter },
|
|
212
258
|
...[...input.pictures.values()].map((picture) => ({ path: picture.path, content: picture.content })),
|
|
213
259
|
]);
|
|
@@ -229,15 +275,19 @@ const MATH_GREEK = /[αβγδεθλμπρστφωΓΔΘΛΠΣΦΩ]/gu;
|
|
|
229
275
|
* fallback fonts under LuaLaTeX, which costs every compile that does not
|
|
230
276
|
* need them about two seconds.
|
|
231
277
|
*/
|
|
278
|
+
/**
|
|
279
|
+
* Whether a document's LaTeX holds a character of another script, so its
|
|
280
|
+
* class (or a deck's theme) should load the fallback fonts. A Greek letter on
|
|
281
|
+
* its own is a symbol set as math; a Greek word (`\ExplicoGreekWord`), an
|
|
282
|
+
* accented letter or another script needs a text font.
|
|
283
|
+
*/
|
|
284
|
+
export function needsScripts(tex: string): boolean {
|
|
285
|
+
return tex.includes('\\ExplicoGreekWord{') || OTHER_SCRIPTS.test(tex.replace(MATH_GREEK, ''));
|
|
286
|
+
}
|
|
287
|
+
|
|
232
288
|
function withScripts(files: SourceFile[]): SourceFile[] {
|
|
233
|
-
// A Greek letter on its own is a symbol the class sets as math; a Greek
|
|
234
|
-
// word (`\ExplicoGreekWord`), an accented letter or another script needs a
|
|
235
|
-
// text font.
|
|
236
289
|
const needed = files.some(
|
|
237
|
-
(file) =>
|
|
238
|
-
file.path.endsWith('.tex') &&
|
|
239
|
-
typeof file.content === 'string' &&
|
|
240
|
-
(file.content.includes('\\ExplicoGreekWord{') || OTHER_SCRIPTS.test(file.content.replace(MATH_GREEK, ''))),
|
|
290
|
+
(file) => file.path.endsWith('.tex') && typeof file.content === 'string' && needsScripts(file.content),
|
|
241
291
|
);
|
|
242
292
|
if (!needed) return files;
|
|
243
293
|
return files.map((file) =>
|
|
@@ -254,11 +304,42 @@ export interface BookChapter {
|
|
|
254
304
|
readonly pictures: ReadonlyMap<string, { readonly path: string; readonly content: Uint8Array }>;
|
|
255
305
|
}
|
|
256
306
|
|
|
307
|
+
/**
|
|
308
|
+
* A lesson of a book's part that has no chapter, only slides (a slides-first
|
|
309
|
+
* lesson, docs/authoring/deck.md): the book keeps its place and its number
|
|
310
|
+
* with a short chapter that points at the slides.
|
|
311
|
+
*/
|
|
312
|
+
export interface BookSlidesLesson {
|
|
313
|
+
readonly lesson: ManifestLesson;
|
|
314
|
+
/** The deck's PDF and interactive version, when the course publishes them. */
|
|
315
|
+
readonly slidesUrl?: string;
|
|
316
|
+
readonly outcomes: readonly string[];
|
|
317
|
+
}
|
|
318
|
+
|
|
257
319
|
/** A part of a book: its own page, when it has one, and its chapters in order. */
|
|
258
320
|
export interface BookPart {
|
|
259
321
|
readonly part: ManifestPart;
|
|
260
322
|
readonly overview?: StaticPage;
|
|
261
323
|
readonly chapters: readonly BookChapter[];
|
|
324
|
+
/** Its slides-first lessons, placed among the chapters by their chapter number. */
|
|
325
|
+
readonly slides?: readonly BookSlidesLesson[];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** A slides-first lesson's place in a book: its title, outcomes and where its slides are. */
|
|
329
|
+
function slidesChapter(entry: BookSlidesLesson): string {
|
|
330
|
+
// As many checks as the website numbers for it (manifest part offsets).
|
|
331
|
+
const checks = entry.lesson.assessments.length;
|
|
332
|
+
return [
|
|
333
|
+
`\\chapter{${escapeText(entry.lesson.title)}}\\label{${labelOf(entry.lesson.slug, '_top')}}`,
|
|
334
|
+
`This lesson is taught as slides${entry.slidesUrl ? `: \\url{${escapeUrl(entry.slidesUrl)}}` : ''}.` +
|
|
335
|
+
(checks > 0 ? ` Its knowledge check${checks === 1 ? ' is' : 's are'} on its slides.` : ''),
|
|
336
|
+
...(entry.outcomes.length > 0
|
|
337
|
+
? ['', 'After it, you can:', '\\begin{itemize}', ...entry.outcomes.map((outcome) => `\\item ${escapeText(outcome)}`), '\\end{itemize}']
|
|
338
|
+
: []),
|
|
339
|
+
// Its checks keep their numbers, so the chapters after it keep theirs.
|
|
340
|
+
...(checks > 0 ? [`\\addtocounter{explicocheck}{${checks}}`] : []),
|
|
341
|
+
'',
|
|
342
|
+
].join('\n');
|
|
262
343
|
}
|
|
263
344
|
|
|
264
345
|
export interface BookSourceInput {
|
|
@@ -335,7 +416,7 @@ function bookMainTex(input: BookSourceInput, inputs: readonly string[], appendic
|
|
|
335
416
|
...DOCUMENT_METADATA,
|
|
336
417
|
`\\documentclass[${paper}]{explico}`,
|
|
337
418
|
'% The same identifier for every compile of this source.',
|
|
338
|
-
trailerIdLine(trailerId(manifest, input.document)),
|
|
419
|
+
trailerIdLine(trailerId(manifest, input.document, bookSince(input.parts))),
|
|
339
420
|
...(numbering.floats === 'part' ? ['\\ExplicoFloatsByPart'] : []),
|
|
340
421
|
`\\ExplicoSectionDepth{${numbering.sections.show ? numbering.sections.depth : 1}}`,
|
|
341
422
|
'% The contents list parts, chapters and sections.',
|
|
@@ -346,7 +427,7 @@ function bookMainTex(input: BookSourceInput, inputs: readonly string[], appendic
|
|
|
346
427
|
'\\begin{document}',
|
|
347
428
|
'\\frontmatter',
|
|
348
429
|
`\\ExplicoTitlePage{${escapeText(input.title)}}{${escapeText(input.subtitle ?? '')}}{${escapeText(
|
|
349
|
-
manifest.about.knowledge.version,
|
|
430
|
+
versionPhrase(bookSince(input.parts), manifest.about.knowledge.version),
|
|
350
431
|
)}}{${escapeText(authors.join(', '))}}{${url ? url.replace(/[\\{}]/gu, '').replace(/[%#]/gu, (char) => `\\${char}`) : ''}}`,
|
|
351
432
|
'% The contents and lists in black, as a book sets them; links in the text keep their colour.',
|
|
352
433
|
'\\begingroup\\hypersetup{linkcolor=black}',
|
|
@@ -368,7 +449,7 @@ function bookReadme(input: BookSourceInput): string {
|
|
|
368
449
|
`# ${input.title}`,
|
|
369
450
|
'',
|
|
370
451
|
`The LaTeX source of ${input.subtitle ? `${input.subtitle.replace(/^Part/u, 'part')}` : `*${manifest.about.material.name}*`}` +
|
|
371
|
-
` (
|
|
452
|
+
` (${versionPhrase(bookSince(input.parts), manifest.about.knowledge.version)}).` +
|
|
372
453
|
(url ? ` Interactive version: ${url}` : ''),
|
|
373
454
|
'',
|
|
374
455
|
'## Build',
|
|
@@ -389,6 +470,8 @@ function bookReadme(input: BookSourceInput): string {
|
|
|
389
470
|
' diagrams, then each part and its chapters, then the appendices.',
|
|
390
471
|
"- `explico.cls` — explico's book class: layout, numbering, and the",
|
|
391
472
|
' environments the chapters use (memos, notes, worked examples, checks).',
|
|
473
|
+
"- `explico-common.sty` — what the class shares with explico's slides: fonts,",
|
|
474
|
+
' colours, figures, diagrams and the notation markers.',
|
|
392
475
|
"- `parts/NN-<part>.tex` — a part's opening page and text;",
|
|
393
476
|
' `parts/NN-<part>/MM-<chapter>.tex` — its chapters.',
|
|
394
477
|
'- `backmatter/` — the notation and abbreviation appendices.',
|
|
@@ -410,7 +493,6 @@ export function bookSource(input: BookSourceInput): SourceFile[] {
|
|
|
410
493
|
const { manifest, parts } = input;
|
|
411
494
|
const canonicalBaseUrl = manifest.lessonExports.canonicalBaseUrl;
|
|
412
495
|
const course = manifest.about.material.name;
|
|
413
|
-
const version = manifest.about.knowledge.version;
|
|
414
496
|
const documentRoutes = new Set(
|
|
415
497
|
parts.flatMap(({ overview, chapters }) => [
|
|
416
498
|
...(overview ? [overview.route] : []),
|
|
@@ -422,7 +504,7 @@ export function bookSource(input: BookSourceInput): SourceFile[] {
|
|
|
422
504
|
const common = { documentRoutes, canonicalBaseUrl, inBook: true, notationTargets } as const;
|
|
423
505
|
const files: SourceFile[] = [];
|
|
424
506
|
const inputs: string[] = [];
|
|
425
|
-
for (const { part, overview, chapters } of parts) {
|
|
507
|
+
for (const { part, overview, chapters, slides = [] } of parts) {
|
|
426
508
|
const partFile = `parts/${twoDigits(part.ordinal)}-${part.dir}.tex`;
|
|
427
509
|
files.push({
|
|
428
510
|
path: partFile,
|
|
@@ -431,7 +513,18 @@ export function bookSource(input: BookSourceInput): SourceFile[] {
|
|
|
431
513
|
: `\\ExplicoPart{${part.ordinal}}{${escapeText(part.label)}}\n`,
|
|
432
514
|
});
|
|
433
515
|
inputs.push(partFile);
|
|
516
|
+
// A slides-first lesson keeps its chapter number with a short chapter of its own.
|
|
517
|
+
const pending = [...slides].sort((a, b) => a.lesson.chapter - b.lesson.chapter);
|
|
518
|
+
const writeSlides = (before: number) => {
|
|
519
|
+
while (pending.length > 0 && pending[0]!.lesson.chapter < before) {
|
|
520
|
+
const entry = pending.shift()!;
|
|
521
|
+
const file = chapterPath(manifest, entry.lesson);
|
|
522
|
+
files.push({ path: file, content: slidesChapter(entry) });
|
|
523
|
+
inputs.push(file);
|
|
524
|
+
}
|
|
525
|
+
};
|
|
434
526
|
for (const { lesson, page, pictures } of chapters) {
|
|
527
|
+
writeSlides(lesson.chapter);
|
|
435
528
|
const file = chapterPath(manifest, lesson);
|
|
436
529
|
const url = canonicalBaseUrl ? `${canonicalBaseUrl}${lesson.slug}/` : undefined;
|
|
437
530
|
files.push({
|
|
@@ -441,12 +534,14 @@ export function bookSource(input: BookSourceInput): SourceFile[] {
|
|
|
441
534
|
page,
|
|
442
535
|
pictures: new Map([...pictures].map(([anchor, picture]) => [anchor, picture.path])),
|
|
443
536
|
checkItems: checkItems(manifest, lesson),
|
|
444
|
-
|
|
537
|
+
// In a book the line is the URL alone; the title page carries the version.
|
|
538
|
+
source: { course, ...(url ? { url } : {}) },
|
|
445
539
|
}),
|
|
446
540
|
});
|
|
447
541
|
inputs.push(file);
|
|
448
542
|
files.push(...[...pictures.values()].map((picture) => ({ path: picture.path, content: picture.content })));
|
|
449
543
|
}
|
|
544
|
+
writeSlides(Number.POSITIVE_INFINITY);
|
|
450
545
|
}
|
|
451
546
|
const appendices: string[] = [];
|
|
452
547
|
const notation = serializeNotationAppendix(appendixNotation(manifest, parts), {
|
|
@@ -474,6 +569,7 @@ export function bookSource(input: BookSourceInput): SourceFile[] {
|
|
|
474
569
|
{ path: 'latexmkrc', content: LATEXMKRC },
|
|
475
570
|
{ path: 'main.tex', content: bookMainTex(input, inputs, appendices) },
|
|
476
571
|
{ path: 'explico.cls', content: explicoClass() },
|
|
572
|
+
{ path: 'explico-common.sty', content: explicoCommon() },
|
|
477
573
|
...files,
|
|
478
574
|
]);
|
|
479
575
|
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
%% explico-common.sty — what every LaTeX document explico writes shares: its
|
|
2
|
+
%% book class (`explico.cls`) and its deck theme (`beamerthemeexplico.sty`).
|
|
3
|
+
%%
|
|
4
|
+
%% The engine, the fonts and the Unicode characters, the colours, the
|
|
5
|
+
%% figures and tables, the TikZ styles of a diagram, the box style, the
|
|
6
|
+
%% notation markers (\explain, \slot) and the cross-references. Edit it
|
|
7
|
+
%% freely in a download.
|
|
8
|
+
\NeedsTeXFormat{LaTeX2e}
|
|
9
|
+
\ProvidesPackage{explico-common}[2026/10/10 explico shared definitions]
|
|
10
|
+
|
|
11
|
+
%% `scripts`: the document holds Greek, Cyrillic, CJK or emoji (the exporter
|
|
12
|
+
%% sets it when it does), so LuaLaTeX loads the fallback fonts below.
|
|
13
|
+
\newif\ifexplico@scripts
|
|
14
|
+
\DeclareOption{scripts}{\explico@scriptstrue}
|
|
15
|
+
\ProcessOptions\relax
|
|
16
|
+
|
|
17
|
+
%% --- Engine and fonts ------------------------------------------------------
|
|
18
|
+
\RequirePackage{iftex}
|
|
19
|
+
\RequirePackage{amsmath,amssymb,mathtools}
|
|
20
|
+
%% Rule N17's engine half, as on the website (src/reference/katex-delimiters.mjs):
|
|
21
|
+
%% a negative \delimitershortfall makes every \left...\right pair strictly taller
|
|
22
|
+
%% than its content, so a nest grows outward at each level. TeX's default (5pt)
|
|
23
|
+
%% lets nested pairs round to the same glyph.
|
|
24
|
+
\delimitershortfall=-1pt
|
|
25
|
+
%% Whether a text font sets Greek; if none does, a Greek letter in prose is
|
|
26
|
+
%% set as its math symbol (below, with the other Unicode characters).
|
|
27
|
+
\newif\ifexplico@greek
|
|
28
|
+
\ifPDFTeX
|
|
29
|
+
\RequirePackage[T1]{fontenc}
|
|
30
|
+
\RequirePackage{lmodern}
|
|
31
|
+
\RequirePackage{textcomp}
|
|
32
|
+
\RequirePackage{bm}
|
|
33
|
+
%% A character no pdfTeX font sets (accented Greek, Chinese, an emoji) stays
|
|
34
|
+
%% blank instead of stopping the compile, and the log says so in LuaLaTeX's
|
|
35
|
+
%% words, which the export turns into its warning about blank characters.
|
|
36
|
+
\def\UTFviii@undefined@err#1{%
|
|
37
|
+
\typeout{Missing character: There is no
|
|
38
|
+
\expandafter\UTFviii@splitcsname\string#1\relax\space in font pdftex!}}
|
|
39
|
+
\else
|
|
40
|
+
%% Latin Modern for text and math. unicode-math is also what lets a tagged
|
|
41
|
+
%% PDF carry MathML for every formula (luamml needs it); bm does not work
|
|
42
|
+
%% with it, so \bm becomes \boldsymbol.
|
|
43
|
+
\RequirePackage{unicode-math}
|
|
44
|
+
\providecommand{\bm}{\boldsymbol}
|
|
45
|
+
%% Latin Modern has no Greek, Cyrillic, Chinese, Japanese, Korean or emoji.
|
|
46
|
+
%% With `scripts`, prose in those scripts comes from fallback fonts: for each
|
|
47
|
+
%% script, the first of the fonts below this machine has (CMU Serif, from
|
|
48
|
+
%% TeX Live's cm-unicode, matches Latin Modern). A script none of them
|
|
49
|
+
%% covers stays blank, and the export warns about it.
|
|
50
|
+
\ifexplico@scripts
|
|
51
|
+
\def\explico@fallbacks{}
|
|
52
|
+
\def\explico@fallback#1#2{%
|
|
53
|
+
\let\explico@found\@empty
|
|
54
|
+
\@for\explico@candidate:=#1\do{%
|
|
55
|
+
\ifx\explico@found\@empty
|
|
56
|
+
\IfFontExistsTF{\explico@candidate}{%
|
|
57
|
+
\edef\explico@fallbacks{\explico@fallbacks"\explico@candidate:mode=harf;",}%
|
|
58
|
+
\let\explico@found\explico@candidate}{}%
|
|
59
|
+
\fi}%
|
|
60
|
+
\ifx\explico@found\@empty\else#2\fi}
|
|
61
|
+
\explico@fallback{CMU Serif,Noto Serif,DejaVu Serif,FreeSerif}{\explico@greektrue}
|
|
62
|
+
\explico@fallback{Noto Serif CJK SC,Noto Sans CJK SC,FandolSong,Source Han Serif SC}{}
|
|
63
|
+
\explico@fallback{Noto Color Emoji,Twemoji Mozilla,Symbola}{}
|
|
64
|
+
\ifx\explico@fallbacks\@empty\else
|
|
65
|
+
\directlua{luaotfload.add_fallback("explico", {\explico@fallbacks})}%
|
|
66
|
+
\setmainfont{Latin Modern Roman}[RawFeature={fallback=explico}]%
|
|
67
|
+
\fi
|
|
68
|
+
\fi
|
|
69
|
+
\fi
|
|
70
|
+
\RequirePackage{microtype}
|
|
71
|
+
|
|
72
|
+
%% --- Page and colour --------------------------------------------------------
|
|
73
|
+
\RequirePackage{xcolor}
|
|
74
|
+
\definecolor{explicoaccent}{HTML}{12775C}
|
|
75
|
+
\definecolor{explicoframe}{HTML}{9DB8AD}
|
|
76
|
+
\definecolor{explicoback}{HTML}{F3F8F6}
|
|
77
|
+
\definecolor{explicoasidecaution}{HTML}{B5651D}
|
|
78
|
+
\definecolor{explicoasidecautionback}{HTML}{FBF3EA}
|
|
79
|
+
\definecolor{explicorule}{HTML}{8A9A93}
|
|
80
|
+
|
|
81
|
+
%% --- Floats, tables and captions -------------------------------------------
|
|
82
|
+
\RequirePackage{graphicx}
|
|
83
|
+
\RequirePackage{array,booktabs,tabularx}
|
|
84
|
+
\RequirePackage[export]{adjustbox}
|
|
85
|
+
%% explico's short caption, run in bold before the long one.
|
|
86
|
+
\newcommand*{\ExplicoCaptionTitle}[1]{\textbf{#1}}
|
|
87
|
+
|
|
88
|
+
%% --- Diagrams ---------------------------------------------------------------
|
|
89
|
+
\RequirePackage{tikz}
|
|
90
|
+
\usetikzlibrary{arrows.meta}
|
|
91
|
+
\tikzset{
|
|
92
|
+
explico diagram node/.style={
|
|
93
|
+
draw=explicorule, fill=explicoback, rounded corners=3pt, line width=0.5pt,
|
|
94
|
+
align=center, inner sep=3pt, font=\small,
|
|
95
|
+
},
|
|
96
|
+
explico diagram edge/.style={
|
|
97
|
+
draw=explicorule, line width=0.6pt, -{Stealth[length=5pt,width=4pt]},
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
%% --- Boxes: memos, notes, asides, worked examples, checks ------------------
|
|
102
|
+
\RequirePackage[most]{tcolorbox}
|
|
103
|
+
\tcbset{
|
|
104
|
+
explico/.style={
|
|
105
|
+
enhanced, breakable, colback=explicoback, colframe=explicoframe,
|
|
106
|
+
boxrule=0.5pt, arc=2pt, left=6pt, right=6pt, top=4pt, bottom=4pt,
|
|
107
|
+
fonttitle=\bfseries\small, coltitle=black, colbacktitle=explicoback!60!white,
|
|
108
|
+
titlerule=0.4pt, before skip=10pt plus 2pt, after skip=10pt plus 2pt,
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
%% --- Unicode in text that the default fonts lack ---------------------------
|
|
113
|
+
\RequirePackage{newunicodechar}
|
|
114
|
+
\newunicodechar{°}{\ifmmode^\circ\else\textdegree\fi}
|
|
115
|
+
\newunicodechar{−}{\ensuremath{-}}
|
|
116
|
+
\newunicodechar{×}{\ensuremath{\times}}
|
|
117
|
+
\newunicodechar{±}{\ensuremath{\pm}}
|
|
118
|
+
\newunicodechar{≤}{\ensuremath{\le}}
|
|
119
|
+
\newunicodechar{≥}{\ensuremath{\ge}}
|
|
120
|
+
\newunicodechar{≈}{\ensuremath{\approx}}
|
|
121
|
+
\newunicodechar{≠}{\ensuremath{\neq}}
|
|
122
|
+
\newunicodechar{→}{\ensuremath{\rightarrow}}
|
|
123
|
+
\newunicodechar{←}{\ensuremath{\leftarrow}}
|
|
124
|
+
\newunicodechar{↑}{\ensuremath{\uparrow}}
|
|
125
|
+
\newunicodechar{↓}{\ensuremath{\downarrow}}
|
|
126
|
+
\newunicodechar{⟨}{\ensuremath{\langle}}
|
|
127
|
+
\newunicodechar{⟩}{\ensuremath{\rangle}}
|
|
128
|
+
\newunicodechar{⋮}{\ensuremath{\vdots}}
|
|
129
|
+
\newunicodechar{√}{\ensuremath{\surd}}
|
|
130
|
+
\newunicodechar{∞}{\ensuremath{\infty}}
|
|
131
|
+
\newunicodechar{′}{\ensuremath{'}}
|
|
132
|
+
\newunicodechar{𝒩}{\ensuremath{\mathcal{N}}}
|
|
133
|
+
\newunicodechar{①}{\textcircled{\scriptsize 1}}
|
|
134
|
+
\newunicodechar{②}{\textcircled{\scriptsize 2}}
|
|
135
|
+
\newunicodechar{③}{\textcircled{\scriptsize 3}}
|
|
136
|
+
\newunicodechar{④}{\textcircled{\scriptsize 4}}
|
|
137
|
+
\newunicodechar{⑤}{\textcircled{\scriptsize 5}}
|
|
138
|
+
\newunicodechar{₀}{\textsubscript{0}}
|
|
139
|
+
\newunicodechar{₁}{\textsubscript{1}}
|
|
140
|
+
\newunicodechar{₂}{\textsubscript{2}}
|
|
141
|
+
\newunicodechar{₃}{\textsubscript{3}}
|
|
142
|
+
\newunicodechar{¹}{\textsuperscript{1}}
|
|
143
|
+
\newunicodechar{²}{\textsuperscript{2}}
|
|
144
|
+
\newunicodechar{³}{\textsuperscript{3}}
|
|
145
|
+
%% A Greek letter on its own is a symbol (the polar coordinates ρ and φ in a
|
|
146
|
+
%% caption, which holds no math): it is set as its math symbol. Inside a Greek
|
|
147
|
+
%% word, which the exporter marks \ExplicoGreekWord{…}, it is a letter, set
|
|
148
|
+
%% from the text font's Greek where one is loaded (`scripts`).
|
|
149
|
+
\newif\ifexplico@word
|
|
150
|
+
\DeclareRobustCommand{\ExplicoGreekWord}[1]{{\explico@wordtrue#1}}
|
|
151
|
+
%% Protected, as \ensuremath is: the text of an equation is expanded for its
|
|
152
|
+
%% tagging (alt text, MathML), and an expandable body breaks it there.
|
|
153
|
+
\protected\def\explico@greekletter#1#2{%
|
|
154
|
+
\ifmmode#2\else
|
|
155
|
+
\ifexplico@word
|
|
156
|
+
\ifexplico@greek\char#1\relax\else\ensuremath{#2}\fi
|
|
157
|
+
\else\ensuremath{#2}\fi
|
|
158
|
+
\fi}
|
|
159
|
+
\newunicodechar{α}{\explico@greekletter{"03B1}{\alpha}}
|
|
160
|
+
\newunicodechar{β}{\explico@greekletter{"03B2}{\beta}}
|
|
161
|
+
\newunicodechar{γ}{\explico@greekletter{"03B3}{\gamma}}
|
|
162
|
+
\newunicodechar{δ}{\explico@greekletter{"03B4}{\delta}}
|
|
163
|
+
\newunicodechar{ε}{\explico@greekletter{"03B5}{\varepsilon}}
|
|
164
|
+
\newunicodechar{θ}{\explico@greekletter{"03B8}{\theta}}
|
|
165
|
+
\newunicodechar{λ}{\explico@greekletter{"03BB}{\lambda}}
|
|
166
|
+
\newunicodechar{μ}{\explico@greekletter{"03BC}{\mu}}
|
|
167
|
+
\newunicodechar{π}{\explico@greekletter{"03C0}{\pi}}
|
|
168
|
+
\newunicodechar{ρ}{\explico@greekletter{"03C1}{\rho}}
|
|
169
|
+
\newunicodechar{σ}{\explico@greekletter{"03C3}{\sigma}}
|
|
170
|
+
\newunicodechar{τ}{\explico@greekletter{"03C4}{\tau}}
|
|
171
|
+
\newunicodechar{φ}{\explico@greekletter{"03C6}{\varphi}}
|
|
172
|
+
\newunicodechar{ω}{\explico@greekletter{"03C9}{\omega}}
|
|
173
|
+
\newunicodechar{Γ}{\explico@greekletter{"0393}{\Gamma}}
|
|
174
|
+
\newunicodechar{Δ}{\explico@greekletter{"0394}{\Delta}}
|
|
175
|
+
\newunicodechar{Θ}{\explico@greekletter{"0398}{\Theta}}
|
|
176
|
+
\newunicodechar{Λ}{\explico@greekletter{"039B}{\Lambda}}
|
|
177
|
+
\newunicodechar{Π}{\explico@greekletter{"03A0}{\Pi}}
|
|
178
|
+
\newunicodechar{Σ}{\explico@greekletter{"03A3}{\Sigma}}
|
|
179
|
+
\newunicodechar{Φ}{\explico@greekletter{"03A6}{\Phi}}
|
|
180
|
+
\newunicodechar{Ω}{\explico@greekletter{"03A9}{\Omega}}
|
|
181
|
+
|
|
182
|
+
%% --- Notation ---------------------------------------------------------------
|
|
183
|
+
%% \explain{key}{tex} and \slot{key}{tex} are explico's markers in math: the
|
|
184
|
+
%% website opens a card for the key; on paper they print their content.
|
|
185
|
+
\providecommand{\explain}[2]{#2}
|
|
186
|
+
\providecommand{\slot}[2]{#2}
|
|
187
|
+
%% \ExplicoNotation{target}{tex}: a formula's symbol that links to its notation entry
|
|
188
|
+
%% (the serializer writes it only where the book has that entry).
|
|
189
|
+
\providecommand{\ExplicoNotation}[2]{\hyperlink{#1}{#2}}
|
|
190
|
+
%% A term in prose with a notation card on the website.
|
|
191
|
+
\newcommand{\ExplicoTerm}[2]{#2}
|
|
192
|
+
|
|
193
|
+
%% --- Cross-references ---------------------------------------------------------
|
|
194
|
+
%% #1 label, #2 text before the number, #3 text after it.
|
|
195
|
+
\newcommand{\ExplicoRef}[3]{\hyperref[#1]{#2\ref*{#1}#3}}
|
|
196
|
+
\newcommand{\ExplicoEqRef}[1]{\hyperref[#1]{(\ref*{#1})}}
|
|
197
|
+
|
|
198
|
+
\endinput
|