explico 0.13.1 → 0.15.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 +990 -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 +100 -0
- package/dist/compiler/cli-main.js +433 -0
- package/dist/compiler/cli-reference.d.ts +50 -0
- package/dist/compiler/cli-reference.js +213 -0
- package/dist/compiler/cli-verbs.d.ts +45 -0
- package/dist/compiler/cli-verbs.js +224 -0
- package/dist/compiler/cli-verify.d.ts +51 -0
- package/dist/compiler/cli-verify.js +151 -0
- package/dist/compiler/cli.d.ts +408 -24
- package/dist/compiler/cli.js +1328 -8
- package/dist/compiler/collections.d.ts +88 -1
- package/dist/compiler/collections.js +170 -25
- package/dist/compiler/content-release.d.ts +49 -0
- package/dist/compiler/content-release.js +63 -0
- package/dist/compiler/content-schemas.d.ts +2 -2
- 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 +364 -58
- package/dist/compiler/page-versions.d.ts +184 -0
- package/dist/compiler/page-versions.js +217 -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 +82 -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 +6 -2
- package/dist/reference/diagram-fit.js +5 -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 +237 -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 +34 -10
- package/dist/rules/rules.schema.json +280 -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 +31 -9
- package/docs/authoring/agents.md +72 -18
- package/docs/authoring/cli-reference.json +2172 -0
- package/docs/authoring/cli.md +887 -0
- package/docs/authoring/components.md +15 -0
- package/docs/authoring/deck.md +612 -0
- package/docs/authoring/migrating.md +1195 -16
- package/docs/authoring/notation.md +49 -6
- package/docs/authoring/structure.md +80 -1
- package/docs/authoring/versioning.md +56 -3
- package/docs/authoring/visualizations.md +7 -2
- package/docs/course-agent/AGENTS.md +40 -0
- package/docs/course-agent/agents/rules-reviewer.md +33 -0
- package/docs/course-agent/skills/draft-lesson/SKILL.md +38 -0
- package/docs/course-agent/skills/migrate-course/SKILL.md +32 -0
- package/docs/course-agent/skills/release-content/SKILL.md +26 -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 +557 -0
- package/src/compiler/cli-reference.ts +285 -0
- package/src/compiler/cli-verbs.ts +270 -0
- package/src/compiler/cli-verify.ts +241 -0
- package/src/compiler/cli.ts +2119 -170
- package/src/compiler/collections.ts +284 -25
- package/src/compiler/content-release.ts +91 -0
- 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 +568 -63
- package/src/compiler/page-versions.ts +401 -0
- package/src/compiler/resolution-report.ts +38 -7
- package/src/compiler/validate-content.ts +215 -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 +137 -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-fit.ts +18 -4
- 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 +274 -4
- package/src/rules/course-rules.ts +21 -1
- package/src/rules/in-effect.ts +58 -11
- 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
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,993 @@ under **Breaking** below; a PATCH never breaks.
|
|
|
14
14
|
|
|
15
15
|
## [Unreleased]
|
|
16
16
|
|
|
17
|
+
## [0.15.0] - 2026-10-12
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Rule D11: a deck is flagged when its chapter changed after it did.**
|
|
22
|
+
`deck-stale`, an info diagnostic, names a lesson's own deck whose chapter's
|
|
23
|
+
rule C5 version is newer than the deck's — two files mean the chapter and
|
|
24
|
+
the deck can drift apart with nothing else to notice it. Scoped to a
|
|
25
|
+
lesson's own deck; a part's deck covers more than one chapter, so it has
|
|
26
|
+
none to compare against and is never flagged. `page-versions.ts` gains
|
|
27
|
+
`deckStaleDiagnostics`; the diagnostic joins `diagnostics.math` beside
|
|
28
|
+
D1–D10's frame codes. No manifest shape change.
|
|
29
|
+
- **`content help <verb> [--json]`: each verb's contract, machine-readable.**
|
|
30
|
+
`content help symbol` prints the verb's usage, what it is for, its flags,
|
|
31
|
+
what it writes, when it exits 1, and the shape of its `--json` as a tree of
|
|
32
|
+
named types; `--json` prints the same with a self-contained JSON Schema
|
|
33
|
+
(draft 2020-12). `content help --json` prints the whole reference. The verb
|
|
34
|
+
table is one source, `src/compiler/cli-verbs.ts` (`CONTENT_VERBS`, from which
|
|
35
|
+
`CONTENT_USAGE` is now derived, every line ending in `[--json]`);
|
|
36
|
+
`scripts/agent/gen-cli.mjs` reads the TypeScript report types with the
|
|
37
|
+
compiler API and writes `docs/authoring/cli-reference.json` and
|
|
38
|
+
`docs/authoring/cli.md`, both shipped, `--check` in verify and CI. New
|
|
39
|
+
module `explico/compiler/cli-reference` (`loadCliReference`, `verbHelp`,
|
|
40
|
+
`schemaOf`, `formatVerbHelp`, `cliReferenceMarkdown`, and
|
|
41
|
+
`jsonShapeErrors`, which checks a value against one of the schemas).
|
|
42
|
+
`cli-main` exports the named `--json` types its verbs print beside the
|
|
43
|
+
reports: `RulesJson`, `EditPlanJson`, `NewJson`, `ErrorJson`.
|
|
44
|
+
- **`content verify [--e2e] [--force]`: a course's one gate before handing
|
|
45
|
+
work back.** `validate:content` → `content check --changed` → `astro check`
|
|
46
|
+
(skipped, by name, when `@astrojs/check` is not installed) → the course's
|
|
47
|
+
`test` script → `astro build`, and with `--e2e` its `test:e2e` script (or
|
|
48
|
+
`playwright test`). Each step is its own process with its whole output in
|
|
49
|
+
`node_modules/.cache/explico/verify/<step>.log`; the run prints one line per
|
|
50
|
+
step, the tail of each failed step's log, and exits 1 on a failure. A pass
|
|
51
|
+
records the tree it left (git HEAD, the diff against it, the untracked
|
|
52
|
+
files), and a rerun on the same tree that asks for no more answers from the
|
|
53
|
+
record without running anything. New module `explico/compiler/cli-verify`
|
|
54
|
+
(`runVerify`, `VerifyReport`).
|
|
55
|
+
- `runContentCli` takes an optional fifth argument, a manifest already
|
|
56
|
+
compiled for the course, so a test running many verbs compiles once.
|
|
57
|
+
- **`content release [major|minor|patch] [--write]`: a content release in
|
|
58
|
+
every course.** `## [Unreleased]` in `content/CHANGELOG.md` becomes a dated
|
|
59
|
+
`## [x.y.z]` heading and `about.version` becomes `x.y.z` (rule C3), shown as
|
|
60
|
+
a diff and written with `--write`, like `move`, `rename` and `fix`; the bump
|
|
61
|
+
defaults to what the section's headings imply (rule C2), and the date is the
|
|
62
|
+
local one. It was the playground's own `scripts/release-content.ts`, which
|
|
63
|
+
the shipped `release-content` skill called as `pnpm release:content` in
|
|
64
|
+
courses that never had it. The playground's `release:content` script is now
|
|
65
|
+
`content release --write`. New module `explico/compiler/content-release`
|
|
66
|
+
(`releaseEdit`, `planContentRelease`); new error code `no-changelog`.
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- `content init-agent` says `new` or `differs from the engine's copy` for each
|
|
71
|
+
file, where a dry run used to say `installed`; after `--write` every edit
|
|
72
|
+
verb prints what to run next.
|
|
73
|
+
- `content status` lists at most six of the pages with unreleased changes and
|
|
74
|
+
counts the rest; `content context` says how many of a lesson's diagnostics
|
|
75
|
+
sit in its own file and how many in the shared cards it shows (the first is
|
|
76
|
+
what `diagnostics --lesson` lists).
|
|
77
|
+
- The shipped procedures (`docs/course-agent/`) survive a course's prettier:
|
|
78
|
+
no inline code span crosses a line break, which prettier re-indented out of
|
|
79
|
+
its list item. `gen-map --check` fails on one.
|
|
80
|
+
- `migrating.md`, 0.13.1 → 0.14.0, corrected where upgrading
|
|
81
|
+
credit-and-derivatives found it wrong: the patch goes before `pnpm add`
|
|
82
|
+
(pnpm refuses with `ERR_PNPM_UNUSED_PATCH`) and its entry may sit in
|
|
83
|
+
`pnpm-workspace.yaml`; pnpm 11's `minimumReleaseAgeExclude`; a course that
|
|
84
|
+
commits `build/resolution/` fails its first run after the upgrade; stale
|
|
85
|
+
`lint-ignore.yml` lines and a course's own tier guidance (step 20); the 404
|
|
86
|
+
page without a raw `<div>` (step 24); tests comparing sidebar and page
|
|
87
|
+
colours (step 25). Upgrading time-series added two more: pnpm can instead
|
|
88
|
+
stop with `ERR_PNPM_NO_MATURE_MATCHING_VERSION` (step 1), and the first
|
|
89
|
+
`content/versions.json` goes in before the upgrade's own changelog bullet,
|
|
90
|
+
or every page reads "not yet released" (step 10).
|
|
91
|
+
- `content fix` takes several lessons, or `--all`, as one plan: the lessons
|
|
92
|
+
with nothing to fix are counted, not listed. A course upgrading to 0.14.0
|
|
93
|
+
can have a thousand redundant `\explain` wraps (data-science-I: 1193).
|
|
94
|
+
- `content check` lists a lesson's errors and warnings line by line and
|
|
95
|
+
counts its info by code, with the command that lists them; `--json` is
|
|
96
|
+
unchanged.
|
|
97
|
+
- `definition-repeated` on a local entry whose glyph a shared card already
|
|
98
|
+
owns no longer says "move one copy to `content/notation/`": promoting it
|
|
99
|
+
would put two shared cards on one glyph. It says the entry is a reused
|
|
100
|
+
letter (rule N4) and how to acknowledge the copies; `content move` prints a
|
|
101
|
+
caution when the glyph is taken (time-series: 9 of its 34).
|
|
102
|
+
- `dia-too-wide` on `<CurriculumMap>`'s competency graph names the map's own
|
|
103
|
+
props (`graph="per-part"`, `direction`, `warnAboveWidth`) instead of a node
|
|
104
|
+
`width` and a shorter label, which the author does not write there.
|
|
105
|
+
- The rules-in-effect page says the course's `rules` and `courseRules` live
|
|
106
|
+
in `course.settings.json` or `course.config.ts`, not only the first.
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- `content move` wrote the new card a placeholder body ("Extend this body
|
|
111
|
+
with what a glossary reader needs."), which the glossary would publish, and
|
|
112
|
+
`domain: general` for a key without a prefix. The card now has no body, its
|
|
113
|
+
domain is the key's prefix when the course has that domain, else the one
|
|
114
|
+
most of the lesson's cards have; the plan says that the body is the
|
|
115
|
+
author's to write, and when the entry had no `label`.
|
|
116
|
+
- `validate:content`'s run log recorded each consistency warning
|
|
117
|
+
(`definition-repeated`, `glyph-unique-in-corpus`, …) at INFO and their
|
|
118
|
+
one-line digest as the only WARNING, so its `Run log: (… warning(s))` count
|
|
119
|
+
disagreed with `content status`. Each finding is recorded at WARNING now,
|
|
120
|
+
the digest at INFO.
|
|
121
|
+
- `ContextReport`'s `equations`, `tables`, `figures` and `diagrams` are typed
|
|
122
|
+
`ManifestLessonFloat[]`: `content context --json` always printed each
|
|
123
|
+
float's `short` and `caption`, which the type left out. The playground's
|
|
124
|
+
new `--json` contract test runs every read-only verb against the schemas and
|
|
125
|
+
caught it.
|
|
126
|
+
|
|
127
|
+
## [0.14.0] - 2026-10-11
|
|
128
|
+
|
|
129
|
+
### Breaking
|
|
130
|
+
|
|
131
|
+
- **A symbol no entry binds in a notation entry's body fails `validate:content`
|
|
132
|
+
(rule N4), and the build fails on an entry whose body did not render.** The
|
|
133
|
+
Markdown body of a `content/notation/*.md` entry was the one rendered-math
|
|
134
|
+
context no gate read. `remarkNotation` rejected an unbound `$w_3$` there, but
|
|
135
|
+
Astro's content layer only logs a render error (`[ERROR] [glob-loader]`) and
|
|
136
|
+
keeps the entry without its body, so `astro build` ended green and the
|
|
137
|
+
glossary showed the entry with no text. `gateContentMath` now resolves every
|
|
138
|
+
`$…$` / `$$…$$` and currency `$` in an entry's body (`unresolved-glyph`,
|
|
139
|
+
`invalid-latex`, `currency-dollar`, …, context `body`) at the file's own
|
|
140
|
+
line, against the table the render uses: every shared entry, built by the new
|
|
141
|
+
`registry-scope.mjs` for both. `NotationGlossary.astro` throws, naming the
|
|
142
|
+
files, when an entry with a body has none rendered, whatever the cause. No
|
|
143
|
+
diagnostic code is new. Measured on the three downstream courses and the
|
|
144
|
+
playground (109 body spans), nothing fails.
|
|
145
|
+
- **Each chapter and part page carries the knowledge version its content
|
|
146
|
+
last changed in (rule C5), kept in `content/versions.json`, which
|
|
147
|
+
`validate:content` writes and the course commits.** `MANIFEST_SCHEMA_VERSION`
|
|
148
|
+
is now v32. The course's version moves at every release, whatever the
|
|
149
|
+
release touched, so stamped on a chapter it said only "built after 0.4.0",
|
|
150
|
+
and in every PDF six times over, so a content release changed every LaTeX
|
|
151
|
+
cache key. Now a chapter's PDF, its source zip's README, its Markdown and
|
|
152
|
+
the `[?]` panel (a new "This page" row, `data-page-since`) say "unchanged
|
|
153
|
+
since version 0.2.0", the release its content last changed in, or "with
|
|
154
|
+
changes after version 0.4.0, not yet released" while `## [Unreleased]`
|
|
155
|
+
holds a change; a part's and the course's PDF and Markdown carry the newest
|
|
156
|
+
among their pages. A document unchanged since an earlier release keeps
|
|
157
|
+
that release's date (`SOURCE_DATE_EPOCH`, its figures' dates) and its
|
|
158
|
+
trailer `/ID`, so with `EXPLICO_LATEX_CACHE` a release recompiles only the
|
|
159
|
+
documents it changed. What counts as the page: its file, its `.checks.yml`
|
|
160
|
+
and assessments, the shared notation entries its text uses, the sources it
|
|
161
|
+
cites and its numbers. `content/versions.json` is a record like a lockfile:
|
|
162
|
+
`compileManifest` reads the committed one and works the next out
|
|
163
|
+
(`page-versions.ts`: a release takes every pending change; an unchanged
|
|
164
|
+
page keeps its version; a change waits while `## [Unreleased]` has
|
|
165
|
+
bullets), `validate:content` writes it on a developer's machine
|
|
166
|
+
(`syncPageVersions`) and in CI (`CI` set) fails with `page-versions-stale`
|
|
167
|
+
until the committed file is the one it would write — **so a course's first
|
|
168
|
+
build after upgrading needs one `pnpm validate:content` and a commit of
|
|
169
|
+
`content/versions.json`**. A file that is not such a record warns
|
|
170
|
+
`page-versions-invalid` and is rebuilt. The manifest gains
|
|
171
|
+
`lessons[].since`, `parts[].overview.since`, `about.knowledge.releases`
|
|
172
|
+
(every released entry with its date) and `about.knowledge.unreleased`, and
|
|
173
|
+
`pageVersions`; `content status` reports `pageVersions` (`tracked`,
|
|
174
|
+
`unreleased`), `content context` a lesson's `since`.
|
|
175
|
+
`explico.cls`: `\ExplicoSource`'s second argument and `\ExplicoTitlePage`'s
|
|
176
|
+
third are the phrase, printed as given ("From *Course*, unchanged since
|
|
177
|
+
version 0.2.0."; "Content unchanged since version 0.2.0"), where they were
|
|
178
|
+
a bare version. Rule off (`rules.C5.enabled: false`): nothing is read or
|
|
179
|
+
written, and every page carries the course's version as before.
|
|
180
|
+
|
|
181
|
+
- **The course asks each reader before it keeps their reading in their
|
|
182
|
+
browser, and keeps to the answer.** A small, non-blocking question at the
|
|
183
|
+
bottom of the window ("Remember your reading?", `ReadingMemoryNotice.astro`,
|
|
184
|
+
rendered by the header on every page) offers "Remember" and "Don't
|
|
185
|
+
remember", the same size and weight. Reading memory is what records what a
|
|
186
|
+
reader did across visits: the chapters they opened (the sidebar marks, and
|
|
187
|
+
the note under a changed page's title), the cards they keep open on a page
|
|
188
|
+
(`card-memory.ts`) and the course's last set of carried cards
|
|
189
|
+
(`card-carry.ts`). Until the reader says yes, and after a no, none of it
|
|
190
|
+
outlives the tab: no visit is recorded and no mark shown, and kept and
|
|
191
|
+
carried cards live in the tab's session storage, so Back, a reload and a
|
|
192
|
+
link still bring them back until the tab closes. **Kept and carried cards
|
|
193
|
+
therefore no longer come back after a browser restart, or in a new tab,
|
|
194
|
+
unless the reader said yes**; before, they always did. Settings a reader
|
|
195
|
+
chooses (theme, text size, panel layout, a folded section or part, the
|
|
196
|
+
"Carry cards" switch) are kept as before and need no answer. The answer is
|
|
197
|
+
kept per course (`explico-reading-memory:<base path>`) for 13 months, then
|
|
198
|
+
asked again; a no deletes the course's reading memory at once. The `[?]`
|
|
199
|
+
panel gains an "In this browser" section: a "Remember my reading" switch,
|
|
200
|
+
every copy of the panel in step, and "Forget what this course stored",
|
|
201
|
+
which deletes every key of the course (and the settings explico courses on
|
|
202
|
+
the site share, and Starlight's theme) and asks again. Nothing explico
|
|
203
|
+
stores is a cookie, and nothing leaves the browser. The new
|
|
204
|
+
`readingMemory` setting (`"ask"`, default, or `"off"`: never ask, never
|
|
205
|
+
keep reading memory, no marks) is in the manifest as `readingMemory`
|
|
206
|
+
(v32). `session/reading-memory.ts` holds the logic; `PreferenceStore`
|
|
207
|
+
gains an optional `keys()`.
|
|
208
|
+
|
|
209
|
+
### Added
|
|
210
|
+
|
|
211
|
+
- **The docs point at two downloadable courses.** The README, the shipped
|
|
212
|
+
agent guide, the rule index and the course `AGENTS.md` baseline link
|
|
213
|
+
https://danieltuzes.github.io/explico/start/, where the playground (at the
|
|
214
|
+
engine's latest release, standalone) and credit-and-derivatives are
|
|
215
|
+
downloadable at their newest version, with a machine-readable
|
|
216
|
+
`sources.json`; a `playground/…` path in the docs is a file of that
|
|
217
|
+
download.
|
|
218
|
+
- **The agent procedures ship to courses, and `content init-agent` installs
|
|
219
|
+
them.** `docs/course-agent/` (in the package) holds the `draft-lesson`,
|
|
220
|
+
`migrate-course` and `release-content` skills, the `rules-reviewer`
|
|
221
|
+
sub-agent and a baseline course `AGENTS.md` that points at the engine's
|
|
222
|
+
guide; `pnpm content init-agent [--write]` copies the skills and the agent
|
|
223
|
+
into the course's `.claude/` and writes the baseline only where the course
|
|
224
|
+
has no `AGENTS.md`. `content status` says whether the course's `AGENTS.md`
|
|
225
|
+
points at `docs/authoring/agents.md` and whether the procedures are
|
|
226
|
+
installed (`agentGuide` in the JSON). `docs/authoring/agents.md` replaces its
|
|
227
|
+
paragraph of verbs with a table: what you want to know, the verb, what it
|
|
228
|
+
prints.
|
|
229
|
+
- **The `content` CLI and `validate:content` ship in the engine.**
|
|
230
|
+
`runContentCli(courseConfig, argv?, io?)` (`explico/compiler/cli-main`) is
|
|
231
|
+
the whole router — every verb, the usage text (`CONTENT_USAGE`, printed by
|
|
232
|
+
`pnpm content help`), the flag parsing (`parseContentArgs`), the text output
|
|
233
|
+
and the exit code — and `runValidateContent(courseConfig)`
|
|
234
|
+
(`explico/compiler/validate-content`) the whole validate run. A course's
|
|
235
|
+
`scripts/content.ts` and `scripts/compile-manifest.ts` become three-line
|
|
236
|
+
shims, so a verb added to the engine reaches every course with the package;
|
|
237
|
+
the playground's two scripts are those shims.
|
|
238
|
+
- **The `appearance` setting: how the page tells its parts apart, and how a
|
|
239
|
+
deck's slides sit on it.** `zones` is `tonal` (the default: both sidebars
|
|
240
|
+
one step of Starlight's neutral grey, the header a step further, the
|
|
241
|
+
reading column unchanged), `accent-header` (the header a deep band of the
|
|
242
|
+
course accent in both themes, drawn on dark-theme colours, and the
|
|
243
|
+
dark-theme logo on it; its menus and the search dialog keep the page's
|
|
244
|
+
colours), `paper` (header and sidebars a desk, the reading column a sheet
|
|
245
|
+
on it whose edge casts a soft shadow, a step lighter than the desk in the
|
|
246
|
+
dark theme) or `none` (Starlight's colours). `slides` is `lifted` (the
|
|
247
|
+
default: an edge and a drop shadow, and in the dark theme a sheet a step
|
|
248
|
+
lighter than the page), `edge` (the edge and shadow on the page's colour)
|
|
249
|
+
or `sorter` (the deck on a tinted well). `LayoutHeader.astro` writes the
|
|
250
|
+
choice on `[data-explico-zones]` / `[data-explico-slides]`, and the new
|
|
251
|
+
`src/styles/zones.css` and `deck.css` select it with `:root:has(…)`, so it
|
|
252
|
+
is right in the first painted frame; each style is a set of `--ex-zone-*`
|
|
253
|
+
/ `--deck-stage-*` tokens per theme that a course can retune. Screen only:
|
|
254
|
+
print, Present mode and a figure captured for the exports are unchanged.
|
|
255
|
+
`normalizeAppearance` validates it; the manifest carries it as
|
|
256
|
+
`appearance`, and the manifest schema is now v37.
|
|
257
|
+
- **Released courses now receive copy-ready 404-page instructions** in the
|
|
258
|
+
README, the structure guide and the current migration section: add
|
|
259
|
+
`content/docs/404.mdx` as a splash page, use Astro's `BASE_URL` to get home
|
|
260
|
+
from any missing path, and set Astro's `site` origin so Starlight can emit its
|
|
261
|
+
sitemap without a warning. The playground turns the missing URL into a
|
|
262
|
+
trajectory that misses its plotted page and exercises an actually missing
|
|
263
|
+
route.
|
|
264
|
+
- **The contents list and a part's page show each lesson's slides**, when the
|
|
265
|
+
course has a deck. A slides column ends every row of `<CourseContents>` and
|
|
266
|
+
of `<PartOverview>`'s reading list: a lesson's own deck is a tile on its
|
|
267
|
+
title line, and a part's deck is one bar along the chapters it covers, from
|
|
268
|
+
the first covered title to the last, each cell a link to that chapter's
|
|
269
|
+
section of the deck, named and described as the sidebar names it ("Slides:
|
|
270
|
+
Velocity Under Constant Acceleration" / "Slides 17–25 of the part's
|
|
271
|
+
slides"). A part's deck that skips a chapter breaks into runs; one that
|
|
272
|
+
covers a chapter with its own deck runs in a second column. Each title
|
|
273
|
+
starts with the glyph of what it opens (a chapter's sheet, a slides-only
|
|
274
|
+
lesson's frame), a part's heading with Overview's two sheets
|
|
275
|
+
(`--explico-part-glyph`, `global.css`), and the contents list's counts gain
|
|
276
|
+
the decks ("4 slide decks") and a key to the glyphs. A slides-only lesson's
|
|
277
|
+
tile is out of the tab order and hidden from assistive technology: its
|
|
278
|
+
title opens the same page. A course with no deck renders both lists as
|
|
279
|
+
before; `slides={false}` on either component turns it all off. The cells
|
|
280
|
+
come from `deck-lane.ts` (`deckLanes`, `laneLink`).
|
|
281
|
+
- **The glossary lists page-bound meanings.** Under its index, "On one page
|
|
282
|
+
only" lists every `notation.local` entry (linking to its lesson) and every
|
|
283
|
+
gloss (linking to the card whose formula names it), so a reader who looks a
|
|
284
|
+
letter up always finds it and sees which meanings are course-wide and which
|
|
285
|
+
are page-bound; the cards themselves stay the shared entries.
|
|
286
|
+
- **`content move`, `content rename` and `content fix`: the refactors as
|
|
287
|
+
verbs, dry-run by default.** `move <lesson>:<key> [--to <key>]` turns a
|
|
288
|
+
`notation.local` entry into a shared card written from the entry's own
|
|
289
|
+
fields, removes the copy from every lesson that declares the key (reporting
|
|
290
|
+
a copy that differed) and, with a new key, rewrites every `[[key]]` and
|
|
291
|
+
`\explain{key}`; `rename <old> <new>` renames a shared card and everything
|
|
292
|
+
that names it, `seeAlso` and `lint-ignore.yml` included; `fix <lesson>`
|
|
293
|
+
unwraps every `\explain` the gate reports as redundant. Each prints its
|
|
294
|
+
plan as a unified diff and changes nothing without `--write`. `planMove`,
|
|
295
|
+
`planRename`, `planFix`, `renderEditPlan`, `applyEditPlan`,
|
|
296
|
+
`removeLocalItem`, `rewriteKeyReferences` and `sharedCardFromLocal` are
|
|
297
|
+
exported from `explico/compiler/cli`.
|
|
298
|
+
- **`definition-repeated` (warning), `meaning-repeated` (info) and
|
|
299
|
+
`explain-redundant` (info), under rule N4.** One local key declared in two
|
|
300
|
+
lessons, saying whether the copies agree and that moving one copy to
|
|
301
|
+
`content/notation/<key>.md` keeps every `[[key]]` working; one symbol and
|
|
302
|
+
name defined at two sites in any tier (a local card and a gloss, two
|
|
303
|
+
glosses, a local card beside the shared card that already says it); and an
|
|
304
|
+
`\explain{key}{…}` in page math whose bare symbol already resolves to the
|
|
305
|
+
same card with nothing left over. The first two come from `consistency.ts`
|
|
306
|
+
(`checkDefinitionRepeated`, `checkMeaningRepeated`), the third from the
|
|
307
|
+
completeness gate, located at the span; `explainCalls` and
|
|
308
|
+
`redundantExplainWraps` are exported from `explico/reference/gate-math`.
|
|
309
|
+
- **`content equation "<latex>" [--lesson <id>]` resolves one expression the
|
|
310
|
+
way the gate will.** Against the lesson's scope (its `notation.local` and
|
|
311
|
+
the shared cards it introduces, with its suspended decorations) or, with no
|
|
312
|
+
lesson, against every shared card as a notation entry's body is; prints
|
|
313
|
+
each glyph's card, redundant `\explain` wraps, unresolved glyphs with where
|
|
314
|
+
they are defined, and exits 1 when the build would refuse the span. A few
|
|
315
|
+
lines, while drafting. `contentEquation` and `formatEquationReport` are
|
|
316
|
+
exported from `explico/compiler/cli`.
|
|
317
|
+
- **`content migrate [--from <v>] [--to <v>]` prints the migration an
|
|
318
|
+
upgrade needs.** The guide's `## <from> → <to>` sections from the version
|
|
319
|
+
`package.json` pins at HEAD to the one installed (either end overridable),
|
|
320
|
+
oldest first, each section whole; a `0.4.x` range on the left matches its
|
|
321
|
+
patch versions, `Unreleased` is allowed on the right, and a hole in the
|
|
322
|
+
chain is an error that names the version no section continues from. One
|
|
323
|
+
or two sections instead of the forty-thousand-token file. `content status`
|
|
324
|
+
sizes that migration among the agent surfaces when the pin and the install
|
|
325
|
+
differ. `contentMigrate`, `parseMigrationSections`, `selectMigrationPath`,
|
|
326
|
+
`installedEngineVersion`, `pinnedEngineVersion` and `formatMigrateReport`
|
|
327
|
+
are exported from `explico/compiler/cli`.
|
|
328
|
+
- **`content bindings <lesson>` shows what a lesson's math binds before a
|
|
329
|
+
build.** Span by span: each glyph and its card with how it resolved
|
|
330
|
+
(`canonical`, `family`, `derived`, `base`, `operator`, or an explicit
|
|
331
|
+
wrap), every `\explain{key}{…}` whose bare symbol resolves to the same card
|
|
332
|
+
(a redundant wrap), and every unresolved glyph with where `content symbol`
|
|
333
|
+
finds it defined; the counts first. The same resolver and scope the
|
|
334
|
+
completeness gate uses. `contentBindings`, `spanBindings` and
|
|
335
|
+
`formatBindingsReport` are exported from `explico/compiler/cli`.
|
|
336
|
+
- **`content rule <ID>` prints one rule whole.** The catalog entry as this
|
|
337
|
+
course has it (kind, elements, enforcement, editions, on or off, waivable,
|
|
338
|
+
codes, settings in effect, summary) and the rule page's own section sliced
|
|
339
|
+
by heading, example included, about half a thousand tokens where opening
|
|
340
|
+
the page costs twenty thousand; an invariant by its slug, a retired rule
|
|
341
|
+
with its date and successor, an unknown ID lists the rules in effect and
|
|
342
|
+
exits 1. `contentRule`, `formatRuleReport`, `ruleSection` and
|
|
343
|
+
`authoringDocsDir` are exported from `explico/compiler/cli`.
|
|
344
|
+
- **A lesson can have a deck: its slide edition, `<lesson>.deck.mdx`**
|
|
345
|
+
(`docs/authoring/deck.md`). A deck sits beside its chapter, served at
|
|
346
|
+
`/<part>/<lesson>/slides/` and listed under the chapter in the sidebar, or
|
|
347
|
+
alone, as a slides-first lesson at the lesson's own URL. `##` opens a section
|
|
348
|
+
(a divider frame), `###` is a frame whose heading is its title,
|
|
349
|
+
`<Pause />` is a step, `<Notes>` holds the speaker notes and
|
|
350
|
+
`<Recall ref="eq-…" />` (`fig-`, `tab-`, `dia-`) shows the chapter's float with
|
|
351
|
+
the chapter's number; none needs an `import`. The engine writes the title
|
|
352
|
+
frame, the outcomes frame (`deck.outcomesFrame`) and the references frame, and
|
|
353
|
+
a legend line on each frame naming the symbols it introduces. A deck shows its
|
|
354
|
+
lesson's symbols: its math binds in the chapter's scope, its notation bundle
|
|
355
|
+
holds the chapter's, and a lab recalled onto it reads the lesson's scope
|
|
356
|
+
(`labMathScope`). Its own figures, tables and diagrams are unnumbered and an
|
|
357
|
+
equation it labels numbers (1), (2) within it; `Figure`, `Table` and
|
|
358
|
+
`Diagram` read that from the manifest (`components/deck/deck-context.ts`), so a
|
|
359
|
+
course's wrapper forwards nothing new. Area **D** joins the rule set: rule D1
|
|
360
|
+
(sections of frames, locked), rule D2 (a frame fits its canvas), rule D3 (a
|
|
361
|
+
frame makes one claim), rule D4 (notes on a frame with text), rule D5 (a frame
|
|
362
|
+
title fits one line), rule D6 (at most `maxSteps` steps, each adding), rule D7
|
|
363
|
+
(one picture per frame), rule D8 (recall, never retype), rule D9 (at most
|
|
364
|
+
`maxNewSymbols` new symbols) and rule D10 (generated title and outcomes
|
|
365
|
+
frames), with the new invariant `decks` (`deck-frontmatter`,
|
|
366
|
+
`deck-outside-part`, `recall-unresolved`, `pause-invalid`). A catalog entry
|
|
367
|
+
now says which edition of a lesson it is about (`editions`): V7, V8, S1, S6 and
|
|
368
|
+
S7 are about a chapter's page, and a `D` rule says the same of a frame, so a
|
|
369
|
+
course's own `X` rule may name its edition too. `build/rules-in-effect.md` is
|
|
370
|
+
the chapter's page, as before; a course with a deck also gets
|
|
371
|
+
`build/rules-in-effect-deck.md` (`content rules --edition deck`).
|
|
372
|
+
`content new deck <lesson>` drafts a deck from the chapter. The course setting
|
|
373
|
+
`deck` sets the canvas (`aspectRatio`: `16:9`, `16:10` or `4:3`), the legend
|
|
374
|
+
line, who sees the notes, the outcomes frame and the handout PDF.
|
|
375
|
+
`MANIFEST_SCHEMA_VERSION` is now v33 (additive): `decks`, `deck` and
|
|
376
|
+
`lessons[].editions`. `explico` depends on `github-slugger` 2.0.0 (the id
|
|
377
|
+
Astro gives a deck's page). On a chapter, Next and Previous still step
|
|
378
|
+
from chapter to chapter, past a chapter's slides row; on a deck's page they
|
|
379
|
+
step from deck to deck, a part's and a slides-first lesson's included, each
|
|
380
|
+
named "Slides: *title*" (`deckNeighbours` in `deck-context.ts`). The
|
|
381
|
+
glossary names a chapter once, not its deck as a second page, and a deck's
|
|
382
|
+
"On this page" names each frame by its title as it reads, math included.
|
|
383
|
+
- **A deck's page presents.** It reads as a study page, every frame on a
|
|
384
|
+
canvas of fixed size (`deck.aspectRatio`: 800×450, 720×450 or 600×450 CSS
|
|
385
|
+
pixels) scaled to the column, each in its final step with its notes under it.
|
|
386
|
+
Its Present button shows one frame at a time, full screen: → ↓ Space PageDown
|
|
387
|
+
step, ← ↑ PageUp Backspace step back, Home and End, a number and Enter jump,
|
|
388
|
+
`F` full screen, `N` the notes beside the frame, `P` a presenter window (the
|
|
389
|
+
frame, the next, the notes, a clock, kept in step through a
|
|
390
|
+
`BroadcastChannel`), `B` a black screen, Esc leaves; the address is
|
|
391
|
+
`#slide-N`. A step can drive a lab (`<Pause control="Launch angle" from="15"
|
|
392
|
+
to="75" seconds="5" />` moves its control), light a symbol up
|
|
393
|
+
(`highlight="key"`), and a frame titled `### … [morph]` morphs from the one
|
|
394
|
+
before through View Transitions. A figure on a frame scales its tools down
|
|
395
|
+
and narrows its picture to fit, to no less than 60 %. After the build, each deck page is
|
|
396
|
+
laid out in the course's Chromium and a frame that still runs past its canvas
|
|
397
|
+
fails the build: `frame-overflow` (rule D2; a warning without a browser,
|
|
398
|
+
an error in CI). The deck offers "Continue at slide N", for the tab and,
|
|
399
|
+
with the reader's yes to reading memory, on later visits
|
|
400
|
+
(`explico:decks:<base>`, `docs/privacy.md`). Print gives one frame per
|
|
401
|
+
page.
|
|
402
|
+
- **A deck downloads as slides, a handout, LaTeX, offline HTML and Marp
|
|
403
|
+
Markdown.** With `lessonExports.latex`, each deck compiles in beamer with
|
|
404
|
+
explico's theme: `downloads/<lesson>-slides.pdf`, one page per step, every
|
|
405
|
+
symbol on a frame linked to its entry on the notation frames that close the
|
|
406
|
+
deck; `downloads/<lesson>-slides-notes.pdf`, each frame in its final state
|
|
407
|
+
followed by its notes and its check's answers (with `deck.handoutPdf`, and
|
|
408
|
+
`deck.notes` not `off`); and their source, `downloads/<lesson>-slides-latex.zip`
|
|
409
|
+
(`main.tex`, `handout.tex`, `deck.tex`, `beamerthemeexplico.sty`). The build
|
|
410
|
+
fails when the PDF numbers a frame differently from the page, and warns when
|
|
411
|
+
a frame runs over its slide on paper. `explico.cls` now loads
|
|
412
|
+
`explico-common.sty` (fonts, colours, figures, diagrams, notation markers),
|
|
413
|
+
which the theme shares; a chapter's and a book's LaTeX folder carry it.
|
|
414
|
+
Beamer cannot write a tagged PDF, so a deck's PDFs are untagged. With
|
|
415
|
+
`standaloneHtml`, `downloads/<lesson>-slides.html` presents offline; with
|
|
416
|
+
`markdown`, `downloads/<lesson>-slides-markdown.zip` holds the deck in Marp's
|
|
417
|
+
dialect. The Download menu has a row for the deck on its page and its
|
|
418
|
+
chapter's (`deck` scope, a `handout` column). A part's and the course's book
|
|
419
|
+
keep a slides-first lesson's place with a short chapter (its outcomes and a
|
|
420
|
+
link to its slides), so later chapters keep their numbers. `decks[].since`
|
|
421
|
+
dates a deck (rule C5): its PDFs' date, title frame and cache key. The CI
|
|
422
|
+
package list (`texlive-packages.txt`) adds `beamer` and `translator`.
|
|
423
|
+
- **Every diagnostic line names its rule and page.** Text output reads
|
|
424
|
+
`info consistency:weak-local [N4 · notation.md#n4]: …`, and the JSON carries
|
|
425
|
+
`doc` next to `rule`, so finding what a code answers to needs no second
|
|
426
|
+
step. `formatCliDiagnostic` and `ownerTag` are exported from
|
|
427
|
+
`explico/compiler/cli`; the playground wrapper prints through them.
|
|
428
|
+
- **`content status` sizes the agent surfaces.** One line with the estimated
|
|
429
|
+
tokens of `AGENTS.md` (the course's, and the repository's one level up) and
|
|
430
|
+
of the rules-in-effect page (`agentSurfaces` in the JSON): a budget to
|
|
431
|
+
watch.
|
|
432
|
+
- **A page that changed since the reader last opened it says so under its
|
|
433
|
+
title**: "This page changed since you last opened it.", with a "What
|
|
434
|
+
changed" link to the course's `changelogHref` when it has one, and the
|
|
435
|
+
sidebar's accent dot beside it. It shows once, on the visit that finds the
|
|
436
|
+
change, only with the reader's yes to reading memory, and not with
|
|
437
|
+
`sidebarMarks.changed` off. `LayoutPageTitle.astro` renders it hidden on
|
|
438
|
+
every chapter and part page; the sidebar's script shows it.
|
|
439
|
+
- **[`docs/privacy.md`](docs/privacy.md)**, shipped in the package: every key
|
|
440
|
+
an explico site keeps in a reader's browser, when it is written, which of
|
|
441
|
+
them need the reader's yes, and what a course's own privacy notice should
|
|
442
|
+
add (its host, anything it loads from another site).
|
|
443
|
+
- **`content symbol <latex | key>` says where a symbol is already defined.**
|
|
444
|
+
The shared card, every `notation.local` entry with its lesson and every
|
|
445
|
+
gloss with its card, matched on the latex as written, a shared card's
|
|
446
|
+
`aliases` or the key, then the entries whose notation contains it as a
|
|
447
|
+
glyph (`v` in `v_0`), each with label, units, the first sentence of its
|
|
448
|
+
meaning and, for a shared card, the lessons that bind it. One call before
|
|
449
|
+
declaring a symbol, so an author references what exists instead of copying
|
|
450
|
+
it. Read-only; `--json` for the full report. `contentSymbol` and
|
|
451
|
+
`formatSymbolReport` are exported from `explico/compiler/cli`; a course
|
|
452
|
+
adds the verb to its `scripts/content.ts`.
|
|
453
|
+
- **`<CurriculumMap>` takes `graph`, `direction` and `warnAboveWidth`.** A
|
|
454
|
+
course with many competencies got a `dia-too-wide` warning (rule V8) on the
|
|
455
|
+
map's one competency graph and could not act on it. `graph="per-part"` draws
|
|
456
|
+
one diagram per part (`competency-graph-<part dir>`), each with the
|
|
457
|
+
competencies its lessons teach first and the earlier ones they build on as
|
|
458
|
+
boxes labelled with their part, and a last group for competencies no lesson
|
|
459
|
+
teaches; `direction` and `warnAboveWidth` reach every competency diagram.
|
|
460
|
+
The default, `graph="whole"`, renders exactly what it did.
|
|
461
|
+
- **The sidebar marks, for each reader, the chapters and part pages they
|
|
462
|
+
have not opened yet and those that changed since they last opened them.**
|
|
463
|
+
A quiet ring for "not opened yet", an accent dot for "changed since you
|
|
464
|
+
last opened it". A labelled row carries its mark in the panel's margin just
|
|
465
|
+
past the row's end, so a title keeps its width; a compact part's tile
|
|
466
|
+
carries it on its corner, and the tile's tooltip names it under the title;
|
|
467
|
+
a closed part (the phone's menu) carries its strongest mark after its
|
|
468
|
+
label; and with the panel folded away, its restore control carries a
|
|
469
|
+
change. A line under the chapter list says what the marks mean and offers
|
|
470
|
+
"Mark all as seen". "Changed" compares the page's rule C5 hash (the
|
|
471
|
+
current one, `pending ?? source`, cut to 12 hex digits) with the one the
|
|
472
|
+
reader saw, so an unreleased change on the live site counts and a release
|
|
473
|
+
that only stamps a version on a page does not. What a reader has seen is
|
|
474
|
+
view state kept in their browser through the `PreferenceStore`, under
|
|
475
|
+
`explico-page-marks:<base path>`, so courses that share an origin keep
|
|
476
|
+
their own; it is reading memory (above), so it is recorded, and marks
|
|
477
|
+
shown, only after the reader's yes; without storage nothing is marked. Each marked link names its
|
|
478
|
+
mark as its description (`aria-describedby`). The new `sidebarMarks`
|
|
479
|
+
setting (`unopened`, `changed`, both on by default) turns either off; the
|
|
480
|
+
manifest carries it as `sidebarMarks` (v32). `page-marks.ts` holds the
|
|
481
|
+
logic, `LayoutSidebar.astro` the wiring, `global.css` the marks.
|
|
482
|
+
- **`withNoneSeen` and `DECK_LESSON_CLASS`.** `page-marks.ts` names both
|
|
483
|
+
resets of a reader's record: `withNoneSeen()`, the record with no page
|
|
484
|
+
seen ("Mark all as unseen", below under Changed), beside `withAllSeen`.
|
|
485
|
+
`lesson-derivation.ts` exports `DECK_LESSON_CLASS` (`explico-deck-lesson`),
|
|
486
|
+
the class of a slides-first lesson's sidebar item, beside `DECK_ROW_CLASS`,
|
|
487
|
+
and `sidebarLessonSlug(item)`, the lesson a sidebar item lists (a chapter's
|
|
488
|
+
slug, or a slides-first lesson's item), which the manifest's chapter
|
|
489
|
+
numbering reads. `buildSidebar` takes `slidesFirst`, the lessons whose only
|
|
490
|
+
edition is a deck.
|
|
491
|
+
- **`sidebarEditions`, and two controls in the sidebar's foot that switch
|
|
492
|
+
it.** A lesson with a chapter and a deck is one sidebar row (below, under
|
|
493
|
+
Changed); the setting says which edition the row opens, `lead: "chapter"`
|
|
494
|
+
(default) or `"slides"`, and whether it lists the other, `other: "listed"`
|
|
495
|
+
(default) or `"hidden"` (`normalizeSidebarEditions`,
|
|
496
|
+
`SIDEBAR_EDITIONS_DEFAULTS` in `course-config.ts`; any other value fails
|
|
497
|
+
the build, naming the field). Each reader switches both under the chapter
|
|
498
|
+
list: "Lessons open as" Chapter or Slides, a pair of radios drawn as one
|
|
499
|
+
control, and "List the other edition too", a checkbox. Their choice is a
|
|
500
|
+
setting, like a compact part, kept in their browser whatever they answered
|
|
501
|
+
about reading memory, under `explico-sidebar-editions` (one key for the
|
|
502
|
+
courses on a site, listed in `docs/privacy.md`, reset by "Forget what this
|
|
503
|
+
course stored" with the other shared settings), and kept field by field, so
|
|
504
|
+
a field they never set follows the course's default. A course without a
|
|
505
|
+
deck shows no controls. The manifest carries the setting as
|
|
506
|
+
`sidebarEditions`, and `MANIFEST_SCHEMA_VERSION` is now v34.
|
|
507
|
+
`sidebar-editions.ts` holds the logic, `LayoutSidebar.astro` the wiring.
|
|
508
|
+
- **A deck's page shows which slides Present mode has shown the reader, and
|
|
509
|
+
presents from any of them** (`docs/plans/deck-navigation/`, phase 3, and
|
|
510
|
+
the "Seen slides and glyphs" decisions). Each frame Present mode shows, at
|
|
511
|
+
any step, in the room's window or the presenter's, is kept as it was. A
|
|
512
|
+
line above each frame, outside its canvas and in the page's own type
|
|
513
|
+
(`.deck-frame__line`), says "Slide N" and "Shown", "Not shown yet" (the
|
|
514
|
+
sidebar's ring) or "Changed since shown" (its dot), and ends on a button:
|
|
515
|
+
"Continue here", filled and always shown, on the frame to continue at;
|
|
516
|
+
"Present from here" on every other (`button.deck-frame__present`, named
|
|
517
|
+
"Present from here, slide N"), shown while the pointer is on the frame or
|
|
518
|
+
the keyboard's focus is in it, with an accent ring round the frame, and
|
|
519
|
+
always, as its icon, on a screen without hover. Under the title, the slide
|
|
520
|
+
map (`nav.deck-map`) shows every frame as a numbered square linking to it:
|
|
521
|
+
filled once shown, outlined before, dotted when changed since, the frame to
|
|
522
|
+
continue at ringed and the one in view underlined (`aria-current`). It
|
|
523
|
+
stays under the header while the deck scrolls (`data-stuck`), and a frame
|
|
524
|
+
a link lands on keeps its line clear of it (`--deck-map-height`). A deck
|
|
525
|
+
too long for the map's line keeps its first and last frames, the frames
|
|
526
|
+
before and after the one to continue at and round the one in view, as many
|
|
527
|
+
as the line has room for, with a gap for each run left out that links to
|
|
528
|
+
the frame in its middle (`components/deck/deck-map.ts`: `slideMap`,
|
|
529
|
+
`slideMapKeeping`). "Not shown yet" and "Changed since shown" are the
|
|
530
|
+
sidebar's two marks, which `sidebarMarks` turns off here too; with
|
|
531
|
+
`unopened` off, no frame says "Shown" either. Each frame names its state as
|
|
532
|
+
its description (`aria-describedby`). A line under Present counts them
|
|
533
|
+
("14 slides not shown yet", "2 slides changed since shown") and offers
|
|
534
|
+
"Mark all as seen" and "Mark all as unseen" for the deck, with a
|
|
535
|
+
`role="status"` line that says what a button did. Every frame of
|
|
536
|
+
`decks[].frames` carries `id`, 12 hex digits of a SHA-256 over what it
|
|
537
|
+
shows (an authored frame's source, notes included, and the chapter's
|
|
538
|
+
number for each float it recalls; the title frame's title, course and
|
|
539
|
+
authors, not its version; the outcomes frame's outcomes; the references
|
|
540
|
+
frame's sources), stamped on the frame as `data-frame-id`, so a frame moved
|
|
541
|
+
by one added before it is still the frame the reader saw.
|
|
542
|
+
`MANIFEST_SCHEMA_VERSION` is now v35. `buildDecks` takes `course` (the
|
|
543
|
+
title frame's course and authors) and each lesson's `outcomes`. The record
|
|
544
|
+
under `explico:decks:<base>` is now `{ "v": 2, "decks": { slug: { at,
|
|
545
|
+
step, seen } } }`: the frame and the step Present mode stopped at, and the
|
|
546
|
+
frames it showed; a version 1 record (`{ slug: frame }`) reads as one with
|
|
547
|
+
no frame seen. "Continue at slide N" presents from the frame the reader
|
|
548
|
+
stopped at, unless they were shown its every step, then from the frame
|
|
549
|
+
after it, following that frame to its number now when frames were added
|
|
550
|
+
before it. Before the reader answers the reading-memory question, the
|
|
551
|
+
frames shown are kept, and marked, for the tab alone, as kept cards are;
|
|
552
|
+
"Remember" keeps them for later visits (`mergeDeckMemory`), and "Don't
|
|
553
|
+
remember" clears them, keeps only where each deck stopped for the tab, and
|
|
554
|
+
records no frame after. With `readingMemory: "off"` no frame is recorded and
|
|
555
|
+
nothing is marked. The question itself now names the slides it keeps. The
|
|
556
|
+
resume button, the lines, the map and the marks' line are the reader's own
|
|
557
|
+
(`data-explico-export-chrome`): Present mode, print and a downloaded deck
|
|
558
|
+
show none of them. `session/deck-memory.ts` holds the logic
|
|
559
|
+
(`decodeDeckMemory`, `encodeDeckMemory`, `withPosition`, `withShown`,
|
|
560
|
+
`withAllSeen`, `withNoneSeen`, `withEveryDeckSeen`, `withEveryDeckUnseen`,
|
|
561
|
+
`mergeDeckMemory`, `frameMark`, `resumeAt`, `DECK_MEMORY_EVENT`),
|
|
562
|
+
`deck-controller.ts` the wiring.
|
|
563
|
+
- **A part can have a deck: `<part>/index.deck.mdx`, served at
|
|
564
|
+
`/<part>/slides/`** (`docs/authoring/deck.md`, "A deck for a part";
|
|
565
|
+
`docs/plans/deck-navigation/`, phase 4). It sits beside the part's page,
|
|
566
|
+
sets only `title` and `description`, and each `##` section may name the
|
|
567
|
+
chapter it covers, `## Title [chapter: <name>]`, the marker stripped from
|
|
568
|
+
the divider. A chapter may run over several sections in a row, each naming
|
|
569
|
+
it, as a chapter's own deck does; the first one's divider is the chapter's
|
|
570
|
+
address in the deck (`#slide-N`). Its symbols bind in the scope of the part's chapters, a key
|
|
571
|
+
two of them define binding to the first in reading order; `<Recall ref>`
|
|
572
|
+
shows a covered chapter's float with that chapter's number, linked to it,
|
|
573
|
+
the section's own chapter first; `[[eq-…]]`, `[[fig-…]]` and `[[sec-…]]`
|
|
574
|
+
fall back to the one covered chapter that has the key; `<AssessmentSet />`
|
|
575
|
+
asks the checks of its section's chapter (the engine passes `lesson`, a new
|
|
576
|
+
prop); the outcomes frame lists every covered chapter's competencies; the
|
|
577
|
+
title frame falls back to the part's label. In the sidebar it is a row of
|
|
578
|
+
its own right after the part's Overview, `explico-deck-row
|
|
579
|
+
explico-part-deck`, the deck's glyph before "Slides" and a tile of its own in a
|
|
580
|
+
compact part; a chapter it covers that has no deck of its own carries
|
|
581
|
+
`data-deck-href`, and the sidebar's script makes that address the
|
|
582
|
+
chapter's other edition, "Slides: *title*", unmarked (`data-deck-section`):
|
|
583
|
+
a lesson's own deck wins. "Slides for this chapter" goes to that section
|
|
584
|
+
when the chapter has no deck; the part's page offers "Slides for this
|
|
585
|
+
part" and the deck's page "Open the part". It downloads as every deck does,
|
|
586
|
+
named after its part (`downloads/motion-slides.pdf`, `-notes.pdf`,
|
|
587
|
+
`-latex.zip`, `-markdown.zip`, `.html`), on its page, on its part's and,
|
|
588
|
+
as "Its slides", on each chapter it covers that has no deck of its own;
|
|
589
|
+
`deckFileStem` takes the owner's slug, and `deckOwnerSlug`, `deckSaveName`
|
|
590
|
+
(`exports/export-pages.ts`) and `deckCheckItems` (`latex/document.ts`) name
|
|
591
|
+
and fill it. Its page has a version of its own (rule C5), which counts the
|
|
592
|
+
number, captions and equation each recalled float has in its chapter. The
|
|
593
|
+
`decks` invariant gains `deck-chapter-unknown`, `deck-chapter-repeated` (a
|
|
594
|
+
chapter named again after a section of another chapter or of the deck's
|
|
595
|
+
own), `deck-chapter-outside-part`, `deck-marker-misplaced`,
|
|
596
|
+
`deck-check-no-chapter` and `deck-route-taken`. `content new deck <part>`
|
|
597
|
+
drafts it from the part's chapters (a section per chapter in track order, a
|
|
598
|
+
frame per section, a `<Recall>` per numbered float), and `content check`
|
|
599
|
+
takes a deck's page, `<part>/slides` or `<part>/<lesson>/slides`
|
|
600
|
+
(`findCheckTarget`). `MANIFEST_SCHEMA_VERSION` is now v36: `decks[]` gains
|
|
601
|
+
`part`, `covers` (every deck; empty on a lesson's), `recalledFrom` and
|
|
602
|
+
`frames[].chapter`, and `lessonId` is absent on a part's deck. In the
|
|
603
|
+
engine, `DeckFile` is `LessonDeckFile | PartDeckFile` (`scope`, `partDir`),
|
|
604
|
+
`NotationLessonInput.scopeLessonIds` lists the lessons a deck's page binds
|
|
605
|
+
in (`resolvePageReferenceId`, `pageScopeLessonIds` in
|
|
606
|
+
`reference/references.ts`; `scopeLessonsOf` in `page-notation.ts`), and
|
|
607
|
+
`lesson-derivation.ts` gains `isPartDeckSlug`, `partDeckDir`,
|
|
608
|
+
`partDeckRouteSlug`, `partDeckPageId` and `PART_DECK_CLASS`. A course with
|
|
609
|
+
no part's deck sees no change but the manifest's shape.
|
|
610
|
+
- **`EXPLICO_LATEX_CACHE=<directory>` reuses a compiled PDF whose source did
|
|
611
|
+
not change.** The LaTeX export recompiled every document on every build:
|
|
612
|
+
43 LuaLaTeX compiles, 685 s on a two-core CI runner, for a course of 37
|
|
613
|
+
chapters. With the variable set, `latex/cache.ts` keys each document by a
|
|
614
|
+
SHA-256 over every file of its folder, the engine, the TeX installation
|
|
615
|
+
(`texFingerprint`: the engine's and latexmk's banners, the LaTeX kernel's
|
|
616
|
+
date), the epoch and `EXPLICO_LATEX_CACHE_SALT`, and keeps its PDF, `.aux`
|
|
617
|
+
and log. A reused document is checked like a compiled one: its numbers
|
|
618
|
+
against the website's, its log for characters no font set. A failed
|
|
619
|
+
compile stores nothing, an entry that does not read back whole is a miss,
|
|
620
|
+
and entries unused for a week are deleted. The summary line says
|
|
621
|
+
"7 compiled, 36 reused from …". Unset, the build is unchanged. With rule
|
|
622
|
+
C5 (above) a document's version line and date are its own, so a content
|
|
623
|
+
release, too, recompiles only the documents it changed.
|
|
624
|
+
- **`pnpm check:dist-imports`, run by `prepack`.** It parses every module in
|
|
625
|
+
`dist/` and fails on a relative import whose target the package does not
|
|
626
|
+
ship. The repository never loads `dist/`, so such a gap (below) passes the
|
|
627
|
+
build, the playground and the tests.
|
|
628
|
+
|
|
629
|
+
- **[`docs/diagram-scaling.md`](docs/diagram-scaling.md)**, shipped in the
|
|
630
|
+
package like `docs/katex-bracket-scaling.md`: how a diagram follows the
|
|
631
|
+
phone's text size (below, under Changed), why it is scaled through the HTML
|
|
632
|
+
canvas and never the SVG, the rules for changing it, and what to check on a
|
|
633
|
+
real iPhone, which the end-to-end suite (Chromium) cannot.
|
|
634
|
+
|
|
635
|
+
### Changed
|
|
636
|
+
|
|
637
|
+
- **The header, the two sidebars and the reading column are told apart by
|
|
638
|
+
colour, and every slide on a deck's page has a visible edge and a drop
|
|
639
|
+
shadow** (`appearance`, above, at its defaults). Before, the light theme
|
|
640
|
+
drew all three columns white, and the dark theme gave the header and the
|
|
641
|
+
course sidebar one colour and the contents sidebar the article's. A dark
|
|
642
|
+
slide had no visible edge: its border was `hairline-shade`, which in the
|
|
643
|
+
dark theme is the page's own colour, and its shadow was black on
|
|
644
|
+
near-black. The part holding the open page is tinted with the sidebar's
|
|
645
|
+
own accent tint (`--ex-zone-rail-accent`), a step darker than
|
|
646
|
+
`accent-low`, so it differs from the grey by lightness as well as hue.
|
|
647
|
+
The course's title in the header is its accent a step toward the text
|
|
648
|
+
colour (`--ex-zone-title`), which keeps it at 4.5:1 on the tinted header.
|
|
649
|
+
`"zones": "none"` keeps the old frame.
|
|
650
|
+
- **A part's deck shares the part's row with its Overview.** It was a row of
|
|
651
|
+
its own under the Overview, listed whatever the sidebar's two controls
|
|
652
|
+
said, with a chapter's deck glyph and the tooltip "Slides". The sidebar's
|
|
653
|
+
script now makes the two one row, as a lesson's chapter and deck are, and
|
|
654
|
+
it follows "Lessons open as" and "List the other edition too" the same way,
|
|
655
|
+
Overview standing for the chapter: "Overview" with the deck as the icon at
|
|
656
|
+
its end, or "Slides for this part" with Overview's two sheets there, or
|
|
657
|
+
one of them alone (an unlisted one still shows while it is the open page).
|
|
658
|
+
In a part with no Overview the deck keeps a row of its own, unlisted only
|
|
659
|
+
while chapters lead with the other edition unlisted. Both links keep their
|
|
660
|
+
glyph in every state, and a compact part joins their tiles, both in the
|
|
661
|
+
accent. The deck's glyph is two frames, its own in front with an outlined
|
|
662
|
+
frame behind (`--explico-part-deck-glyph`, `deck.css`). Its tooltip names
|
|
663
|
+
the part, then on a quieter second line its chapters and slides ("Slides
|
|
664
|
+
for this part: Motion in the plane" / "Chapters 1–2 · 26 slides"), and a
|
|
665
|
+
chapter's section of it names its slides ("Slides 17–25 of the part's
|
|
666
|
+
slides"); the second line is the link's `aria-description` and a
|
|
667
|
+
`small.layout-edition-detail` in its name's span, shown only where the
|
|
668
|
+
span is a tooltip. `buildSidebar` adds `data-part` and `data-part-edition`
|
|
669
|
+
to the Overview's item and the deck's, `data-title` and `data-chapters`
|
|
670
|
+
(the covered chapters' ordinals, `1–2`, `1, 3`) to the deck's, and the new
|
|
671
|
+
`withPartDeckFrames` adds, once `buildDecks` has run, `data-frames` to the
|
|
672
|
+
deck's item and `data-deck-range` to each chapter that links into its
|
|
673
|
+
section (its frames, `2–16`). `sidebar-editions.ts` gains `partRow`,
|
|
674
|
+
`partEditionLabel`, `partDeckDetail`, `sectionDetail`,
|
|
675
|
+
`PART_EDITION_ATTRIBUTE`, `PART_ROW_CLASSES` and `EDITION_DETAIL_CLASS`;
|
|
676
|
+
`lesson-derivation.ts` gains `numberList`. Without scripts the sidebar is as
|
|
677
|
+
before. No schema bump: the attributes are additive.
|
|
678
|
+
- **A formula's "Symbols" list names every symbol the formula names.** The
|
|
679
|
+
cards an entry's `formula` wraps with `\explain{key}{…}` are listed with its
|
|
680
|
+
glosses, in formula order, each card linked to its own entry on the
|
|
681
|
+
glossary page (`cards` on `<NotationFormula>`; `data-notation-card` marks
|
|
682
|
+
one); the list used to show the glosses alone, so a formula read as
|
|
683
|
+
half-explained without hover and in the exports.
|
|
684
|
+
- **Rule N4's lints follow the tier model: a letter is declared once.**
|
|
685
|
+
`glyph-unique-in-corpus` now warns only when two *shared* cards claim one
|
|
686
|
+
glyph; a `notation.local` entry or a gloss that reuses a letter is the
|
|
687
|
+
declared exception and is never reported, so the acknowledgements courses
|
|
688
|
+
wrote for every reused index letter can go. N4's summary and its page say
|
|
689
|
+
which tier a symbol takes in one question — is this letter already
|
|
690
|
+
defined? — and `content symbol` answers it.
|
|
691
|
+
- **`content diagnostics` counts by default and lists on request.** The text
|
|
692
|
+
output is a severity line, then counts by code (with each code's rule and
|
|
693
|
+
page) and by file, most frequent first and the file list capped at 25;
|
|
694
|
+
`--all` lists every line as before, and `--code <code>`, `--lesson <id>` or
|
|
695
|
+
`--changed` list a part. The JSON report is the same shape it was, filtered
|
|
696
|
+
when a flag is given. `summarizeDiagnostics`, `filterDiagnostics` and
|
|
697
|
+
`formatDiagnosticsSummary` are exported from `explico/compiler/cli`.
|
|
698
|
+
- **`validate:content` passes on its first run.** It still rewrites
|
|
699
|
+
`build/resolution/*`, but it fails only on a report git tracks that it had
|
|
700
|
+
to rewrite (the committed-report contract a course that tracks `build/`
|
|
701
|
+
relies on) and lists the rest as refreshed (`refreshed` on
|
|
702
|
+
`syncResolutionReports`' result). A course whose `build/` is git-ignored no
|
|
703
|
+
longer fails and asks for a commit of files git ignores; a "run it twice"
|
|
704
|
+
instruction can go. `scripts/agent/verify` runs it once.
|
|
705
|
+
- **The LaTeX export starts the longest documents first**: the course, then
|
|
706
|
+
the parts, then the chapters, the largest folder first within each. The
|
|
707
|
+
course took longest and started last, so it ran alone at the end while the
|
|
708
|
+
other cores had nothing left to do. Output is unchanged.
|
|
709
|
+
- **The README and the wiring errors show `markdown.processor: unified({ … })`.**
|
|
710
|
+
Astro 7.3 deprecates the flat `markdown.remarkPlugins` / `rehypePlugins`
|
|
711
|
+
lists. `assertRemarkPluginsWired` still reads both surfaces; only its
|
|
712
|
+
messages and the README sketch name the processor form.
|
|
713
|
+
`docs/authoring/migrating.md` has the step to move a course's lists.
|
|
714
|
+
- **The Download button's tooltip names what its menu offers.** It said
|
|
715
|
+
"Download this page" everywhere, but the menu lists the scopes that contain
|
|
716
|
+
the page: this chapter, this part and the whole course on a chapter; this
|
|
717
|
+
part and the whole course on a part's page; the whole course on any other
|
|
718
|
+
page, which has no download of its own. The `title` now reads "Download this
|
|
719
|
+
chapter, this part or the whole course", "Download this part or the whole
|
|
720
|
+
course" or "Download the whole course", in the menu's own words. The
|
|
721
|
+
accessible name is still "Download this page", so a browser test that finds
|
|
722
|
+
the button by role and name keeps working.
|
|
723
|
+
|
|
724
|
+
- **The text size on touch screens runs from 50% to 100% in five geometric
|
|
725
|
+
steps**: 50, 59, 71, 84 and 100%, each 2^(1/4) (about 1.19) times the one
|
|
726
|
+
below, listed smallest first. It was 100, 90, 80 and 70%. `global.css` has
|
|
727
|
+
one `:root[data-text-size='…']` rule per step and
|
|
728
|
+
`TextSizeControl.astro` builds the list. A size the earlier release saved
|
|
729
|
+
(90, 80 or 70) is ignored: the page opens at 100% until the reader picks a
|
|
730
|
+
new one. `<html>` now also carries `--explico-text-scale`, the choice as a
|
|
731
|
+
number from 0.5 to 1, for what is drawn in px.
|
|
732
|
+
|
|
733
|
+
- **A diagram follows the text size as a whole**, boxes and text together, so
|
|
734
|
+
a wide diagram can be made to fit a phone: the phone menu's 50% takes a
|
|
735
|
+
687 px diagram to 344 px. It is scaled the way print already scales it:
|
|
736
|
+
the SVG stays at its build-time size (WebKit does not scale a
|
|
737
|
+
`foreignObject`'s HTML with the `viewBox`) and the HTML canvas around it
|
|
738
|
+
takes a `transform`. `Diagram.astro` therefore has a new
|
|
739
|
+
`div.diagram-frame` between `.diagram-scroll` and `.diagram-canvas`; it
|
|
740
|
+
holds `--diagram-width` and `--diagram-height` (the canvas inherits them)
|
|
741
|
+
and takes the scaled size, which is what the scroller measures, so the
|
|
742
|
+
widen button ↔ appears or goes with the size
|
|
743
|
+
(`DiagramEnhancer.astro` watches the frame). Course CSS or tests that
|
|
744
|
+
select `.diagram-scroll > .diagram-canvas` as a child must use a
|
|
745
|
+
descendant selector. Only a diagram in the lesson (also when expanded)
|
|
746
|
+
scales; one in a preview card keeps its size and the card its 12 px text.
|
|
747
|
+
With no size chosen, and on a screen with hover, nothing changes.
|
|
748
|
+
|
|
749
|
+
- **The sidebar draws a chapter, a part and a deck differently.** A compact
|
|
750
|
+
part's chapter tile is one sheet with lines of text on it (it was two
|
|
751
|
+
plain sheets, as the part's Overview tile still is). A deck is a filled
|
|
752
|
+
slide frame with a play mark cut out of it, on its "Slides" row and its
|
|
753
|
+
tile; a slides-first lesson's row carries it before its title, as the
|
|
754
|
+
Overview row carries its sheets, and its tile shows it in place of a
|
|
755
|
+
sheet. The manifest's `sidebar` lists a slides-first lesson as
|
|
756
|
+
`{ slug, attrs: { class: "explico-deck-lesson" } }` rather than its bare
|
|
757
|
+
slug, so `deck.css` can find it; it keeps its place and its chapter
|
|
758
|
+
number. The chapter's and the deck's glyphs are one SVG mask each over
|
|
759
|
+
the link's own colour (`--explico-chapter-glyph` in `global.css`,
|
|
760
|
+
`--explico-deck-glyph` in `deck.css`), the part's two sheets a border and
|
|
761
|
+
a shadow, so each takes the link's colour hovered, open or covered; the
|
|
762
|
+
Overview's second sheet now follows the tile's fill in those states.
|
|
763
|
+
- **A chapter's tile and its deck's tile touch**, one pair in a compact
|
|
764
|
+
part: square where they meet, with one line between them that lights with
|
|
765
|
+
whichever tile is hovered, and accent around the open page's tile. The
|
|
766
|
+
sidebar's script makes the two one row (below), and `li[data-editions="pair"]`
|
|
767
|
+
joins them; without the script, `:has()` does, and a browser without it
|
|
768
|
+
keeps the gap.
|
|
769
|
+
- **A lesson is one row in the sidebar.** A lesson with a chapter and a deck
|
|
770
|
+
was two rows, the chapter and a "Slides" row under it. It is one row now:
|
|
771
|
+
the row opens the lead edition under the lesson's title, and the other
|
|
772
|
+
edition is an icon at the row's end, as `»` ends a part's header, or, in a
|
|
773
|
+
compact part, the second of two joined tiles, the lead first
|
|
774
|
+
(`docs/plans/deck-navigation/`, phase 2). The icon's accessible name,
|
|
775
|
+
and its tooltip, is "Slides: *title*" or "Chapter: *title*", so a browser
|
|
776
|
+
test that finds a sidebar link by a lesson's title without `exact: true`
|
|
777
|
+
now finds two. A lesson with one edition carries its glyph before its title
|
|
778
|
+
only when that edition does not lead: a slides-first lesson while chapters
|
|
779
|
+
lead, as before, and a chapter-only lesson while slides lead
|
|
780
|
+
(`explico-chapter-lesson`, a sheet). A hidden edition is listed while it is
|
|
781
|
+
the open page. The row's own link carries its mark at the row's end, as
|
|
782
|
+
before; the icon carries its own on its corner
|
|
783
|
+
(`a.layout-edition-other[data-page-mark]`, drawn by `i.layout-edition-mark`),
|
|
784
|
+
and the progress rail counts rows, the row holding the open page being the
|
|
785
|
+
reader's place. The two controls (above, under Added) and the marks' line
|
|
786
|
+
share the panel's foot, `.explico-sidebar-foot`, which draws the separator
|
|
787
|
+
the line drew. Without scripts the sidebar is what the compiler emits: each
|
|
788
|
+
chapter, then its "Slides" row. In the manifest's `sidebar`, every item of
|
|
789
|
+
a lesson names its edition, lesson and title (`data-edition`,
|
|
790
|
+
`data-lesson`, `data-title` in `attrs`), so a chapter is `{ slug, attrs }`
|
|
791
|
+
where it was a bare slug; `sidebarLessonSlug` reads an item's lesson as its
|
|
792
|
+
`data-lesson` when that is its own `slug`, and `buildSidebar` takes
|
|
793
|
+
`titleOf`, the lesson titles.
|
|
794
|
+
- **Pointing at a part's `»` lights its Overview row**, or its compact tile,
|
|
795
|
+
as a pointer on the row would: both open the part's page. Keyboard focus
|
|
796
|
+
on `»` counts.
|
|
797
|
+
- **The marks' line stays, and offers "Mark all as unseen" beside "Mark all
|
|
798
|
+
as seen".** The line under the chapter list is there whenever the reader's
|
|
799
|
+
record is kept, with a mark on screen or none, so either reset can be
|
|
800
|
+
undone; "Mark all as unseen" forgets every page but the open one, which is
|
|
801
|
+
open. What a button did is said in a `role="status"` line inside it
|
|
802
|
+
("Every page is marked as seen." / "… as not opened yet."), where
|
|
803
|
+
"Mark all as seen" used to replace the line with that sentence and leave
|
|
804
|
+
no way back. A button with nothing to change is `aria-disabled`: it keeps
|
|
805
|
+
its place, and focus.
|
|
806
|
+
- **The sidebar's "Mark all as seen" and "Mark all as unseen" cover every
|
|
807
|
+
deck's frames too** (D9 of `docs/plans/deck-navigation/`), so a deck's
|
|
808
|
+
page shows them all seen, or none, at once and on its next load. In a
|
|
809
|
+
course with a deck, the status they leave says so: "Every page and slide
|
|
810
|
+
is marked as seen." and "Every page is marked as not opened yet, and every
|
|
811
|
+
slide as not shown yet." The marks' payload (`PageMarksPayload.decks`)
|
|
812
|
+
carries each deck's frame ids, and a button is in use while a deck's frame
|
|
813
|
+
has something to change, as a page does. A deck's page now holds a
|
|
814
|
+
"Present from here, slide N" button in every frame's line, so a browser
|
|
815
|
+
test that finds the deck's Present button by name adds `exact: true`.
|
|
816
|
+
|
|
817
|
+
### Fixed
|
|
818
|
+
|
|
819
|
+
- **A hovered row in either sidebar shows its fill in the dark theme.** The
|
|
820
|
+
fill was `--sl-color-gray-6`, which is the dark course sidebar's own
|
|
821
|
+
colour, so a hovered chapter or part there changed only its text colour.
|
|
822
|
+
The fill is now each sidebar's colour with 10 % ink mixed in
|
|
823
|
+
(`--ex-row-hover`), whatever colour the sidebar is.
|
|
824
|
+
- **A single-language course no longer warns that Starlight's `i18n`
|
|
825
|
+
collection is missing or empty.** `explico/content-config` now exports the
|
|
826
|
+
collection with Starlight's schema and an empty English in-memory fallback;
|
|
827
|
+
authored JSON or YAML translations under `content/i18n/` replace it. The
|
|
828
|
+
playground also declares its canonical Astro `site`, clearing the sitemap
|
|
829
|
+
warning alongside its new `404.mdx`.
|
|
830
|
+
- **With a part's deck open, the chapter on screen lights its slides in the
|
|
831
|
+
sidebar, and the rail follows it.** Opened at a chapter's section
|
|
832
|
+
(`/motion/slides/#slide-17`) only the part's deck was lit, not the
|
|
833
|
+
chapter's slides icon that opened it, and the rail stopped at the part's
|
|
834
|
+
row. Each frame of a covered section now carries its chapter
|
|
835
|
+
(`data-chapter`, from `frameChapters` in `file.data.explicoDeck`), and the
|
|
836
|
+
deck's page tells the sidebar the chapter of the frame in view on the
|
|
837
|
+
study page, or shown in Present mode and the presenter
|
|
838
|
+
(`DECK_FRAME_EVENT`, `explico:deck-frame`, with `{ deck, chapter }`, and
|
|
839
|
+
`data-deck-chapter` on `<html>`). The sidebar lights that chapter's section
|
|
840
|
+
link with `aria-current="location"`, as the open page lights its own, and
|
|
841
|
+
the rail covers every row before it; the title and outcomes frames, which
|
|
842
|
+
belong to no chapter, light none.
|
|
843
|
+
- **"Continue at slide N" is offered whenever a reader left a deck past its
|
|
844
|
+
first frame, and presents from there.** Present mode writes `#slide-N`
|
|
845
|
+
into the address so a slide can be shared, and the offer was made only on
|
|
846
|
+
a page opened without one, once: after Esc, and after a reload of that
|
|
847
|
+
address, it was missing. `refreshResume` in `deck-controller.ts` now
|
|
848
|
+
renders it as the page opens and again whenever Present mode ends,
|
|
849
|
+
whatever the address says: a button (`data-deck-resume`) beside Present,
|
|
850
|
+
where it was a link to the frame, that presents from the frame to continue
|
|
851
|
+
at (above). Once the reader was shown all of the last frame it reads
|
|
852
|
+
"Present again" and presents from the first.
|
|
853
|
+
It is the reader's own (`data-explico-export-chrome`), so a deck's
|
|
854
|
+
standalone HTML and Markdown never carry it. A link to `#slide-N` still
|
|
855
|
+
opens the study page at that frame.
|
|
856
|
+
- **Opening a page no longer writes its sections' state to the browser.**
|
|
857
|
+
`wirePersistedDetails` meant to save only a section the reader folded or
|
|
858
|
+
opened, but restoring a section's default state fired a `toggle` of its
|
|
859
|
+
own, which it saved too: every page with collapsible sections left one
|
|
860
|
+
`disclosure:<path>:<section>` entry per section on a mere visit, a list of
|
|
861
|
+
the pages a reader opened. Only a state the reader moved a section to is
|
|
862
|
+
saved now.
|
|
863
|
+
- **A notation entry's body honours `fixedIndex` (rule N23).** Its glyph table
|
|
864
|
+
dropped the flag that a lesson's keeps, so in the glossary `r_2` took the
|
|
865
|
+
card of the family `r_m` although `m` was marked `fixedIndex: true`. The
|
|
866
|
+
entry's body and a lesson now agree; the error names the card that fixed the
|
|
867
|
+
index. The render's message for an entry's body no longer suggests
|
|
868
|
+
`notation.local`, which an entry does not have.
|
|
869
|
+
- **`astro build` reports a notation entry's error at the file's own line.**
|
|
870
|
+
Astro's glob loader renders an entry from its body alone, so the line in
|
|
871
|
+
`entry.md:1:43` (the message, and the loader's `Failed to parse Markdown file`
|
|
872
|
+
header) counted from the end of the frontmatter. `remark-notation.mjs` now
|
|
873
|
+
finds where the body sits in the file (`source-lines.mjs`, read only while a
|
|
874
|
+
failure or warning is reported) and moves the location, so the build and
|
|
875
|
+
`validate:content` agree. A lesson is compiled whole and was already right.
|
|
876
|
+
- **An unresolved-glyph error quotes the math it is in** (`… "w", in $w_3$.`),
|
|
877
|
+
in `astro build` and in `validate:content`, so a symbol can be searched for
|
|
878
|
+
whatever the line says. The sentence before `Introduce the symbol …` gains
|
|
879
|
+
`, in $…$`; a test matching the text up to the token is unaffected.
|
|
880
|
+
- **The published package loads again.** 0.13.0 and 0.13.1 shipped
|
|
881
|
+
`dist/compiler/exports/{latex,markdown}/serialize.js` importing
|
|
882
|
+
`dist/components/float-name.js`, which no one built, so `astro build`,
|
|
883
|
+
`astro dev` and `astro check` stopped with "Unable to load your Astro
|
|
884
|
+
config". `float-name.ts` (no Astro, no DOM beyond the `Element` that
|
|
885
|
+
`floatOf` takes) moved from `src/components/` to `src/reference/`, which
|
|
886
|
+
tsup compiles. It was never a documented author-facing export; a course
|
|
887
|
+
that patched the module in (`patches/explico@0.13.1.patch`) deletes the
|
|
888
|
+
patch.
|
|
889
|
+
- **`migrating.md`'s 0.13.0 → 0.13.1 section said the manifest schema stays
|
|
890
|
+
v29.** It is v31.
|
|
891
|
+
- **A figure no longer fails on `e`, `\pi`, `i` or `d`.** `renderLabMath`
|
|
892
|
+
leaves a plain base-library atom without a card, as a lesson's math does, but
|
|
893
|
+
`assertFigureSymbolsBound` / `unboundFigureSymbols` (`figure-symbols.ts`)
|
|
894
|
+
then failed the build on it ("figure symbols without a notation card"). The
|
|
895
|
+
check now exempts the same library (`isBaseLibraryGlyph`,
|
|
896
|
+
`base-library.mjs`), in a power too (`e^{i\pi}`). An index (`e_i`, rule N23),
|
|
897
|
+
a decorated (`\hat{e}`, rule N22) or a styled (`\mathbf{e}`) letter is
|
|
898
|
+
another symbol and is still reported.
|
|
899
|
+
- **The build reports every page with a figure symbol that has no card, or a
|
|
900
|
+
notation trigger with no popup entry, at once.** `astro:build:done` threw on
|
|
901
|
+
the first page and never reached the later ones or the exports. It now checks
|
|
902
|
+
all pages and throws once with the whole list (`assertNoUnboundFigureSymbols`
|
|
903
|
+
is new in `figure-symbols.ts`; `assertFigureSymbolsBound` is unchanged). The
|
|
904
|
+
standalone, part, course and LaTeX exports still wait for a clean check.
|
|
905
|
+
- **`lab-katex-direct` is reported per lesson.** A helper that imports `katex`
|
|
906
|
+
was reported once, against the first lesson that reached it, so
|
|
907
|
+
`content check <lesson>` could not tell whether another lesson was clean. It
|
|
908
|
+
is now reported once for each lesson whose imports reach it, with that
|
|
909
|
+
lesson's own chain, and a lesson that reaches none is clean. The code and
|
|
910
|
+
severity are unchanged. `validate:content` prints one error per lesson while
|
|
911
|
+
several share a helper.
|
|
912
|
+
- **A card only a lab template uses now reaches the page.** The package serves
|
|
913
|
+
`explico/reference/*` from `dist/`, but `LessonFooter.astro` imports the
|
|
914
|
+
TypeScript source of `page-notation`, so the two copies had separate
|
|
915
|
+
registries. A key bound by `labMathScope` or `renderLabMath` in a template
|
|
916
|
+
(and a derived N23 card it registered) was never in the card payload, and the
|
|
917
|
+
hover opened nothing. The registries now live on `globalThis` under
|
|
918
|
+
`Symbol.for('explico.reference.page-notation')`, one per process.
|
|
919
|
+
- **Rule N23 no longer asks for the set of a letter that is not an index.**
|
|
920
|
+
`index-range` named `b` in `\nabla_{b_n}` (the base of the carded symbol
|
|
921
|
+
`b_n`, whose own index `n` is checked in its own right) and `g` in
|
|
922
|
+
`\mathbb{E}_{Z \sim g}` (a density in a condition), and asked for a `range`
|
|
923
|
+
on the card of `b_n` as "the set of the running index b". A letter that sits
|
|
924
|
+
inside a larger symbol with a card of its own, and every letter of a
|
|
925
|
+
subscript slot that holds a relation (`\sim`, `=`, `\in`, …), is no longer a
|
|
926
|
+
running index. A letter with a card of its own, and one inside an author's
|
|
927
|
+
`\explain`, is checked as before.
|
|
928
|
+
- **A family whose index is juxtaposed letters now reaches its instances.** The
|
|
929
|
+
entry `x_{ij}` (`K_{ij}`, `r_{ik}`) gave its card to the exact form only, so
|
|
930
|
+
`x_{i1}`, `x_{12}` and `K_{ji}` failed rule N4 as unresolved and the message
|
|
931
|
+
said the entry "explains its own instances only". A slot of two or more
|
|
932
|
+
lowercase letters is now a double index: the family matches a run of as many
|
|
933
|
+
letters and digits (`x_{i1}`, `x_{12}`, `x_{ji}`), as `x_{i,j}` always did,
|
|
934
|
+
and never `x_i`, `x_{ijk}` or `x_{i+1}`. A page that has both `x_{ij}` and
|
|
935
|
+
`x_k` as entries now fails `ambiguous-base-fallback` on `x_{12}`, which both
|
|
936
|
+
fit; wrap that instance in `\explain`.
|
|
937
|
+
- **An `\explain` inside a family instance's index no longer unbinds the
|
|
938
|
+
family.** `\beta_{\explain{count}{K}}` and `x_{\explain{iter}{k}}` left the
|
|
939
|
+
base unresolved, because the match was dropped for enclosing the author's
|
|
940
|
+
wrap. A symbol that holds an `\explain` in its own subscript now keeps its
|
|
941
|
+
card, and the two wraps nest: `\explain{beta-j}{\beta_{\explain{count}{K}}}`.
|
|
942
|
+
A match that only straddles a wrap's braces is still dropped.
|
|
943
|
+
- **A wrapped family instance is not re-bound inside.** On a page with the
|
|
944
|
+
family `\sigma_k` and a plain `\sigma`, `\explain{component-sd}{\sigma_1}`
|
|
945
|
+
became `\explain{component-sd}{\explain{population-sd}{\sigma}_1}`, so hovering
|
|
946
|
+
the σ opened the population standard deviation. The wrap names the indexed
|
|
947
|
+
symbol, so its base takes no other entry's card; this holds under a power
|
|
948
|
+
(`\sigma_1^2`), for a two-letter family and for a font-styled base. A wrap
|
|
949
|
+
around a symbol whose key has another base still binds the glyphs inside.
|
|
950
|
+
- **An active prose link no longer falls below AA contrast.** 0.13.1 blended
|
|
951
|
+
the highlight of every active notation target (`mix-blend-mode: multiply`
|
|
952
|
+
in the light theme, `screen` in the dark one), but the blend exists for a
|
|
953
|
+
symbol in math, whose KaTeX boxes paint over the glyph to their left. On a
|
|
954
|
+
prose term link (`a.notation-term`), `multiply` darkened the tint over a
|
|
955
|
+
glossary row's panel and the engine's own link colour dropped from 4.75:1
|
|
956
|
+
to 4.4:1, which axe reports as `color-contrast`. The blend is now scoped to
|
|
957
|
+
`.katex-html`; a prose link keeps the opaque tint it had before 0.13.1. A
|
|
958
|
+
course that added `a.notation-term.is-notation-active { color: … }` to pass
|
|
959
|
+
axe deletes it.
|
|
960
|
+
- **`unresolved-glyph` names the card that fixed a family's index.** Marking
|
|
961
|
+
the card of `m` `fixedIndex: true` turns the family `r_m` into a single
|
|
962
|
+
symbol (rule N23), so `r_2` stops being its instance. The error then blamed
|
|
963
|
+
"a bare r" and offered `\explain{periodic-rate}{r}`, which is the wrong
|
|
964
|
+
repair. For a subscripted symbol that a family would have explained, it now
|
|
965
|
+
says "`r_2` would be an instance of `periodic-rate`, but `m` is marked
|
|
966
|
+
`fixedIndex` on `compounding-frequency`", and to give that card a `range`
|
|
967
|
+
if `m` runs over a set. The same holds for an entry that carries
|
|
968
|
+
`fixedIndex` itself, and for an index entry that fixes the subscript. A
|
|
969
|
+
truly bare `r` keeps its message. The error `astro build` throws for the
|
|
970
|
+
same symbol says it too. `index-range`'s offer of `fixedIndex: true` now
|
|
971
|
+
says that a family indexed by that letter then explains none of its
|
|
972
|
+
instances. `resolveMathGlyphs` returns `instance` and `fixedLenders` on such
|
|
973
|
+
an unresolved item, and `math-glyphs.mjs` exports `fixedLenderMessage`.
|
|
974
|
+
|
|
975
|
+
- **The `[?]` About panel opens on screen in the phone menu.** The menu's
|
|
976
|
+
copy of the butto
|
|
977
|
+
### Removed
|
|
978
|
+
|
|
979
|
+
- **`gloss-wants-promoting`.** It fired on three identical glosses and never
|
|
980
|
+
did in any course; `meaning-repeated` reports the same copy at two. A
|
|
981
|
+
`lint-ignore.yml` line for it can be deleted.
|
|
982
|
+
n starts its row, and the panel hung from the button's end,
|
|
983
|
+
so it ran off the screen's start edge and past the end of the menu. Below
|
|
984
|
+
50rem it is now a sheet fixed under the header, centred, at most 21rem
|
|
985
|
+
wide.
|
|
986
|
+
|
|
987
|
+
- **The `[?]` button is round in the phone menu.** The sidebar's rules for a
|
|
988
|
+
part's header (`.layout-navigation-content summary`) are unlayered and
|
|
989
|
+
reached it, making it a rounded square with the `?` at its start; they now
|
|
990
|
+
skip `.about-toggle`.
|
|
991
|
+
|
|
992
|
+
- **A hover peek no longer overwrites a collapsed section's saved state.** A
|
|
993
|
+
collapsed section peeks (its content floats open) when the pointer is on its
|
|
994
|
+
title, and a peek has to set `details.open = true` to render, which fired the
|
|
995
|
+
native `toggle` that `wirePersistedDetails` saves as "open". A reader who
|
|
996
|
+
collapsed a section and reloaded with the pointer still on its title (the
|
|
997
|
+
browser sends the pointer's `pointerenter` after the reload) found it open
|
|
998
|
+
from then on: `open` was stored over `closed`. A peek now carries
|
|
999
|
+
`data-explico-temporary-open`, which `persisted-disclosure.ts` already skips,
|
|
1000
|
+
from its first `open = true` until the `toggle` its closing fires; a click
|
|
1001
|
+
that commits the peek removes it. `CollapsibleSections.astro`'s module
|
|
1002
|
+
comment already said a peek "never persists anything".
|
|
1003
|
+
|
|
17
1004
|
## [0.13.1] - 2026-10-07
|
|
18
1005
|
|
|
19
1006
|
### Fixed
|
|
@@ -3446,7 +4433,9 @@ under **Breaking** below; a PATCH never breaks.
|
|
|
3446
4433
|
system with its completeness gate, the curriculum-graph validator, the
|
|
3447
4434
|
Astro/Starlight UI, the LMS / session / analytics seams, and the `content` CLI.
|
|
3448
4435
|
|
|
3449
|
-
[Unreleased]: https://github.com/danieltuzes/explico/compare/v0.
|
|
4436
|
+
[Unreleased]: https://github.com/danieltuzes/explico/compare/v0.15.0...HEAD
|
|
4437
|
+
[0.15.0]: https://github.com/danieltuzes/explico/compare/v0.14.0...v0.15.0
|
|
4438
|
+
[0.14.0]: https://github.com/danieltuzes/explico/compare/v0.13.1...v0.14.0
|
|
3450
4439
|
[0.13.1]: https://github.com/danieltuzes/explico/compare/v0.13.0...v0.13.1
|
|
3451
4440
|
[0.13.0]: https://github.com/danieltuzes/explico/compare/v0.12.0...v0.13.0
|
|
3452
4441
|
[0.12.0]: https://github.com/danieltuzes/explico/compare/v0.11.1...v0.12.0
|