explico 0.7.0 → 0.11.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 +1409 -1
- package/README.md +60 -15
- package/dist/compiler/astro.d.ts +6 -1
- package/dist/compiler/cli.d.ts +54 -3
- package/dist/compiler/cli.js +80 -6
- package/dist/compiler/collections.d.ts +35 -2
- package/dist/compiler/collections.js +84 -8
- package/dist/compiler/course-config.d.ts +3 -194
- package/dist/compiler/course-config.js +78 -5
- package/dist/compiler/exports/standalone-html.d.ts +6 -1
- package/dist/compiler/knowledge-version.js +1 -1
- package/dist/compiler/lesson-derivation.d.ts +27 -10
- package/dist/compiler/lesson-derivation.js +23 -8
- package/dist/compiler/logging.d.ts +14 -1
- package/dist/compiler/logging.js +6 -2
- package/dist/compiler/manifest.d.ts +204 -31
- package/dist/compiler/manifest.js +270 -55
- package/dist/compiler/resolution-report.d.ts +6 -1
- package/dist/course-config-Dsnri9Tk.d.ts +464 -0
- package/dist/reference/base-accents.d.mts +26 -0
- package/dist/reference/base-accents.mjs +31 -0
- package/dist/reference/base-roman-labels.d.mts +2 -2
- package/dist/reference/base-roman-labels.mjs +2 -2
- package/dist/reference/consistency.d.ts +14 -2
- package/dist/reference/consistency.js +108 -4
- package/dist/reference/delimiter-size.d.ts +21 -11
- package/dist/reference/delimiter-size.js +15 -39
- package/dist/reference/diagrams-validate.d.ts +7 -2
- package/dist/reference/diagrams-validate.js +9 -1
- package/dist/reference/equations-validate.d.ts +8 -5
- package/dist/reference/equations-validate.js +1 -0
- package/dist/reference/equations.d.mts +69 -34
- package/dist/reference/equations.mjs +90 -44
- package/dist/reference/examples-validate.d.ts +31 -0
- package/dist/reference/examples-validate.js +48 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/figures-validate.js +4 -1
- package/dist/reference/folds-validate.d.ts +33 -0
- package/dist/reference/folds-validate.js +32 -0
- package/dist/reference/gate-abbreviations.d.ts +3 -1
- package/dist/reference/gate-abbreviations.js +3 -2
- package/dist/reference/gate-course-rules.d.ts +32 -0
- package/dist/reference/gate-course-rules.js +85 -0
- package/dist/reference/gate-heading-length.d.ts +5 -2
- package/dist/reference/gate-heading-length.js +47 -23
- package/dist/reference/gate-heading-structure.d.ts +41 -0
- package/dist/reference/gate-heading-structure.js +113 -0
- package/dist/reference/gate-math-punctuation.d.ts +71 -0
- package/dist/reference/gate-math-punctuation.js +251 -0
- package/dist/reference/gate-math.d.ts +44 -6
- package/dist/reference/gate-math.js +63 -10
- package/dist/reference/gate-part-pages.d.ts +50 -0
- package/dist/reference/gate-part-pages.js +118 -0
- package/dist/reference/gate-prose-notation.d.ts +32 -11
- package/dist/reference/gate-prose-notation.js +30 -8
- package/dist/reference/katex-delimiters.d.mts +15 -0
- package/dist/reference/katex-delimiters.mjs +138 -0
- package/dist/reference/katex-options.mjs +4 -0
- package/dist/reference/keyed-float-validate.d.ts +27 -10
- package/dist/reference/keyed-float-validate.js +15 -1
- package/dist/reference/keyed-jsx-floats.d.mts +11 -5
- package/dist/reference/keyed-jsx-floats.mjs +73 -20
- package/dist/reference/knowledge-checks-validate.d.ts +1 -1
- package/dist/reference/knowledge-checks.d.mts +3 -1
- package/dist/reference/knowledge-checks.mjs +9 -4
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-slot.d.ts +34 -0
- package/dist/reference/lab-math-slot.js +6 -0
- package/dist/reference/math-glyphs.d.mts +80 -4
- package/dist/reference/math-glyphs.mjs +588 -39
- package/dist/reference/page-notation.d.ts +6 -1
- package/dist/reference/raw-floats-validate.js +1 -1
- package/dist/reference/raw-floats.mjs +1 -1
- package/dist/reference/rehype-heading-anchors.d.mts +14 -0
- package/dist/reference/rehype-heading-anchors.mjs +116 -17
- package/dist/reference/rehype-table-header-labels.d.mts +6 -1
- package/dist/reference/rehype-table-header-labels.mjs +21 -3
- package/dist/reference/remark-asides.d.mts +3 -0
- package/dist/reference/remark-asides.mjs +180 -0
- package/dist/reference/remark-memo.d.mts +3 -1
- package/dist/reference/remark-memo.mjs +42 -11
- package/dist/reference/remark-notation.d.mts +60 -10
- package/dist/reference/remark-notation.mjs +387 -36
- package/dist/reference/render-lab-math.d.ts +4 -26
- package/dist/reference/render-lab-math.js +5 -5
- package/dist/reference/sections-validate.d.ts +27 -0
- package/dist/reference/sections-validate.js +41 -0
- package/dist/reference/sections.d.mts +97 -0
- package/dist/reference/sections.mjs +306 -0
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/types.d.ts +24 -1
- package/dist/reference/unit-words.d.ts +37 -0
- package/dist/reference/unit-words.js +170 -0
- package/dist/rules/catalog.d.ts +176 -0
- package/dist/rules/catalog.js +983 -0
- package/dist/rules/course-rules.d.ts +115 -0
- package/dist/rules/course-rules.js +292 -0
- package/dist/rules/course-rules.schema.json +138 -0
- package/dist/rules/in-effect.d.ts +53 -0
- package/dist/rules/in-effect.js +142 -0
- package/dist/rules/rules.schema.json +1072 -0
- package/dist/rules/settings.d.ts +3 -0
- package/dist/rules/settings.js +290 -0
- package/dist/rules/waivers.d.ts +53 -0
- package/dist/rules/waivers.js +132 -0
- package/dist/session/PreferenceStore.d.ts +5 -0
- package/dist/session/PreferenceStore.js +9 -0
- package/docs/VERSIONING.md +2 -2
- package/docs/authoring/README.md +232 -40
- package/docs/authoring/agents.md +55 -9
- package/docs/authoring/components.md +178 -22
- package/docs/authoring/migrating.md +1324 -2
- package/docs/authoring/notation.md +616 -344
- package/docs/authoring/prose.md +551 -0
- package/docs/authoring/retired.md +35 -0
- package/docs/authoring/structure-rules.md +422 -40
- package/docs/authoring/structure.md +445 -62
- package/docs/authoring/versioning.md +20 -28
- package/docs/authoring/visualizations.md +142 -20
- package/docs/katex-bracket-scaling.md +191 -0
- package/package.json +3 -2
- package/src/compiler/cli.ts +139 -6
- package/src/compiler/collections.ts +144 -10
- package/src/compiler/course-config.ts +273 -34
- package/src/compiler/knowledge-version.ts +1 -1
- package/src/compiler/lesson-derivation.ts +54 -15
- package/src/compiler/logging.ts +21 -4
- package/src/compiler/manifest.ts +573 -104
- package/src/components/BlockHeading.astro +113 -0
- package/src/components/CourseContents.astro +221 -0
- package/src/components/CurriculumMap.astro +5 -6
- package/src/components/FloatIndex.astro +200 -0
- package/src/components/HoverPanel.astro +431 -79
- package/src/components/PartBridge.astro +27 -0
- package/src/components/PartOverview.astro +401 -0
- package/src/components/PartScope.astro +27 -0
- package/src/components/abbreviation/AbbreviationLayer.astro +49 -51
- package/src/components/assessments/AssessmentRunner.tsx +8 -5
- package/src/components/assessments/AssessmentSet.astro +23 -26
- package/src/components/block-heading.ts +146 -0
- package/src/components/card-arrow.ts +243 -0
- package/src/components/card-drag.ts +631 -0
- package/src/components/card-jump.ts +45 -0
- package/src/components/card-manager.ts +1589 -0
- package/src/components/card-memory.ts +177 -0
- package/src/components/card-placement.ts +504 -0
- package/src/components/card-side.ts +336 -0
- package/src/components/card-travel.ts +197 -0
- package/src/components/citation/CitationLayer.astro +77 -76
- package/src/components/diagram/Diagram.astro +161 -316
- package/src/components/disclosure/course-disclosure.ts +24 -0
- package/src/components/disclosure/hover-preview.ts +122 -42
- package/src/components/disclosure/persisted-disclosure.ts +3 -3
- package/src/components/disclosure/print-as-shown.ts +252 -0
- package/src/components/examples/CompactExample.astro +3 -1
- package/src/components/examples/CompactExamples.astro +101 -94
- package/src/components/figure/Figure.astro +174 -274
- package/src/components/figure/FloatCaption.astro +87 -0
- package/src/components/figure/figure-state.ts +58 -0
- package/src/components/figure/figure-tools.ts +87 -0
- package/src/components/float-name.ts +101 -0
- package/src/components/fold/Fold.astro +125 -0
- package/src/components/fold/fold-id.ts +40 -0
- package/src/components/memo/Memo.astro +162 -231
- package/src/components/memo/ShortNote.astro +6 -6
- package/src/components/notation/NotationFormula.astro +5 -1
- package/src/components/notation/NotationGlossary.astro +24 -14
- package/src/components/notation/NotationLayer.astro +169 -162
- package/src/components/notation/NotationMath.astro +10 -1
- package/src/components/notation/render-notation-math.ts +111 -10
- package/src/components/reference/FloatRefLayer.astro +485 -423
- package/src/components/starlight/AboutPanel.astro +22 -6
- package/src/components/starlight/CollapsibleSections.astro +207 -93
- package/src/components/starlight/DiagramEnhancer.astro +15 -138
- package/src/components/starlight/HeadingAnchorEnhancer.astro +193 -1
- package/src/components/starlight/KeyedFloatEnhancer.astro +100 -9
- package/src/components/starlight/LayoutHeader.astro +298 -19
- package/src/components/starlight/LayoutPageSidebar.astro +99 -12
- package/src/components/starlight/LayoutPageTitle.astro +120 -0
- package/src/components/starlight/LayoutSidebar.astro +229 -11
- package/src/components/starlight/LessonExportActions.astro +53 -72
- package/src/components/starlight/LessonFooter.astro +26 -4
- package/src/components/starlight/section-parts.ts +15 -2
- package/src/components/starlight/section-summary.ts +181 -0
- package/src/components/table/Table.astro +95 -76
- package/src/components/table/TableOverflowExpander.astro +65 -28
- package/src/content-config.ts +40 -4
- package/src/reference/base-accents.mjs +31 -0
- package/src/reference/base-roman-labels.mjs +2 -2
- package/src/reference/consistency.ts +176 -5
- package/src/reference/delimiter-size.ts +40 -61
- package/src/reference/diagrams-validate.ts +17 -1
- package/src/reference/equations-validate.ts +10 -5
- package/src/reference/equations.mjs +90 -44
- package/src/reference/examples-validate.ts +97 -0
- package/src/reference/figures-validate.ts +6 -1
- package/src/reference/folds-validate.ts +65 -0
- package/src/reference/gate-abbreviations.ts +3 -2
- package/src/reference/gate-course-rules.ts +134 -0
- package/src/reference/gate-heading-length.ts +68 -37
- package/src/reference/gate-heading-structure.ts +193 -0
- package/src/reference/gate-math-punctuation.ts +381 -0
- package/src/reference/gate-math.ts +119 -12
- package/src/reference/gate-part-pages.ts +217 -0
- package/src/reference/gate-prose-notation.ts +74 -13
- package/src/reference/katex-delimiters.mjs +138 -0
- package/src/reference/katex-options.mjs +4 -0
- package/src/reference/keyed-float-validate.ts +45 -11
- package/src/reference/keyed-jsx-floats.mjs +73 -20
- package/src/reference/knowledge-checks-validate.ts +1 -1
- package/src/reference/knowledge-checks.mjs +9 -4
- package/src/reference/lab-math-slot.ts +36 -0
- package/src/reference/math-glyphs.mjs +588 -39
- package/src/reference/raw-floats-validate.ts +1 -1
- package/src/reference/raw-floats.mjs +1 -1
- package/src/reference/rehype-heading-anchors.mjs +116 -17
- package/src/reference/rehype-table-header-labels.mjs +21 -3
- package/src/reference/remark-asides.mjs +180 -0
- package/src/reference/remark-memo.mjs +42 -11
- package/src/reference/remark-notation.mjs +387 -36
- package/src/reference/render-lab-math.ts +17 -32
- package/src/reference/sections-validate.ts +81 -0
- package/src/reference/sections.mjs +306 -0
- package/src/reference/tables-validate.ts +2 -1
- package/src/reference/types.ts +24 -0
- package/src/reference/unit-words.ts +233 -0
- package/src/rules/catalog.ts +1298 -0
- package/src/rules/course-rules.ts +456 -0
- package/src/rules/in-effect.ts +235 -0
- package/src/rules/settings.ts +448 -0
- package/src/rules/waivers.ts +249 -0
- package/src/session/PreferenceStore.ts +15 -0
- package/src/styles/global.css +1471 -163
- package/src/styles/surfaces.css +182 -0
- package/src/components/hover-panel.ts +0 -339
- package/src/components/popup-stack.ts +0 -345
|
@@ -20,11 +20,23 @@
|
|
|
20
20
|
* Box sizes are a generous estimate (`reference/diagram-layout.ts`) unless a
|
|
21
21
|
* node gives an explicit `width`/`height` — there is no DOM at build time to
|
|
22
22
|
* measure a real render against.
|
|
23
|
+
*
|
|
24
|
+
* Named like every float (docs/plans/titles-and-containers.md Part 3): the
|
|
25
|
+
* long `caption` sits below the graph with its number, in the same caption
|
|
26
|
+
* line a `<Figure>` has (`../figure/FloatCaption.astro`), and an optional
|
|
27
|
+
* `short` caption heads the `[[dia-…]]` preview card. A diagram is always
|
|
28
|
+
* its graph and then that line (docs/plans/figures-and-short-captions.md,
|
|
29
|
+
* decision 1); the line ends with the widen button ↔, shown while the graph
|
|
30
|
+
* overflows its column (`../starlight/DiagramEnhancer.astro`). To let a
|
|
31
|
+
* reader fold a diagram away, wrap it in a `<Fold>` or put it in a
|
|
32
|
+
* collapsible section.
|
|
23
33
|
*/
|
|
24
34
|
import { estimateBoxSize, layoutDiagram } from '../../reference/diagram-layout';
|
|
25
35
|
import { renderNotationFormula } from '../notation/render-notation-math';
|
|
26
36
|
import type { SafeMathNode as SafeMathNodeType } from '../notation/render-notation-math';
|
|
27
37
|
import SafeMathNode from '../notation/SafeMathNode.astro';
|
|
38
|
+
import FloatCaption from '../figure/FloatCaption.astro';
|
|
39
|
+
import { DIAGRAM_NO_LONGER_FOLDS } from '../../reference/diagrams-validate';
|
|
28
40
|
import type { GlyphScopeEntry } from '../../reference/gloss';
|
|
29
41
|
import {
|
|
30
42
|
notationKeysInMathNodes,
|
|
@@ -50,8 +62,10 @@ export interface DiagramEdge {
|
|
|
50
62
|
export interface Props {
|
|
51
63
|
/** Unique on the page — namespaces the arrowhead marker id. */
|
|
52
64
|
id: string;
|
|
53
|
-
/**
|
|
54
|
-
|
|
65
|
+
/** The long caption, shown below the diagram with its number; also its accessible name. */
|
|
66
|
+
caption: string;
|
|
67
|
+
/** Optional short caption: heads the `[[dia-…]]` preview card; rule S1 measures it. */
|
|
68
|
+
short?: string;
|
|
55
69
|
nodes: readonly DiagramNode[];
|
|
56
70
|
edges: readonly DiagramEdge[];
|
|
57
71
|
/** Glyph scope `formula` resolves against — omit if no node uses `formula`. */
|
|
@@ -61,10 +75,6 @@ export interface Props {
|
|
|
61
75
|
number?: string;
|
|
62
76
|
/** Computed by `remark-notation.mjs` for a top-level lesson diagram. */
|
|
63
77
|
anchorId?: string;
|
|
64
|
-
/** Author-chosen state for a reader with nothing saved yet. Default: `true`. */
|
|
65
|
-
defaultOpen?: boolean;
|
|
66
|
-
/** Persist the reader's open/closed choice across visits. Default: `true`. */
|
|
67
|
-
rememberState?: boolean;
|
|
68
78
|
/**
|
|
69
79
|
* Emit a build warning when the laid-out SVG is wider than this many pixels.
|
|
70
80
|
* Set `false` only when horizontal overflow is deliberate. Default: `800`.
|
|
@@ -74,15 +84,14 @@ export interface Props {
|
|
|
74
84
|
|
|
75
85
|
const {
|
|
76
86
|
id,
|
|
77
|
-
|
|
87
|
+
caption,
|
|
88
|
+
short,
|
|
78
89
|
nodes,
|
|
79
90
|
edges,
|
|
80
91
|
scope = [],
|
|
81
92
|
direction = 'TB',
|
|
82
93
|
number,
|
|
83
94
|
anchorId,
|
|
84
|
-
defaultOpen = true,
|
|
85
|
-
rememberState = true,
|
|
86
95
|
warnAboveWidth = 800,
|
|
87
96
|
} = Astro.props;
|
|
88
97
|
|
|
@@ -90,6 +99,26 @@ const idPattern = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
|
90
99
|
if (!idPattern.test(id)) {
|
|
91
100
|
throw new Error(`Unsafe Diagram id: ${id}`);
|
|
92
101
|
}
|
|
102
|
+
for (const removed of ['label', 'title'] as const) {
|
|
103
|
+
if (removed in Astro.props) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`<Diagram id="${id}"> has no \`${removed}\` prop: a diagram is named by its \`caption\` (shown below it with its number) and an optional \`short\` caption.`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Also caught in the MDX by `dia-removed-prop`; this catches a diagram a
|
|
110
|
+
// wrapper component renders, whose props the MDX scan never sees.
|
|
111
|
+
for (const removed of ['defaultOpen', 'rememberState'] as const) {
|
|
112
|
+
if (removed in Astro.props) {
|
|
113
|
+
throw new Error(`<Diagram id="${id}"> has no \`${removed}\` prop: ${DIAGRAM_NO_LONGER_FOLDS}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (typeof caption !== 'string' || !caption.trim()) {
|
|
117
|
+
throw new Error(`Diagram "${id}" requires a non-empty \`caption\` prop.`);
|
|
118
|
+
}
|
|
119
|
+
if (short !== undefined && (typeof short !== 'string' || !short.trim())) {
|
|
120
|
+
throw new Error(`Diagram "${id}" \`short\` must be a non-empty string when given.`);
|
|
121
|
+
}
|
|
93
122
|
if (nodes.length === 0) {
|
|
94
123
|
throw new Error(`Diagram "${id}" has no nodes.`);
|
|
95
124
|
}
|
|
@@ -172,6 +201,7 @@ const markerId = `diagram-arrow-${id}`;
|
|
|
172
201
|
const legacyAnchorId = `diagram-${id}`;
|
|
173
202
|
const renderedAnchorId = anchorId ?? legacyAnchorId;
|
|
174
203
|
const viewportId = `${legacyAnchorId}-viewport`;
|
|
204
|
+
const captionTextId = `${legacyAnchorId}-caption`;
|
|
175
205
|
|
|
176
206
|
if (warnAboveWidth !== false && layout.width > warnAboveWidth) {
|
|
177
207
|
console.warn(
|
|
@@ -193,158 +223,140 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
193
223
|
<figure
|
|
194
224
|
class="diagram"
|
|
195
225
|
id={renderedAnchorId}
|
|
196
|
-
aria-labelledby={`${id}-caption`}
|
|
197
226
|
data-dia-number={number}
|
|
198
227
|
data-dia-key={number ? id : undefined}
|
|
228
|
+
data-dia-short={short}
|
|
199
229
|
data-diagram-width={layout.width}
|
|
200
230
|
data-diagram-expandable
|
|
201
231
|
>
|
|
202
|
-
<div class="
|
|
203
|
-
<
|
|
204
|
-
class="
|
|
205
|
-
|
|
206
|
-
data-remember-state={String(rememberState)}
|
|
207
|
-
data-state={defaultOpen ? 'open' : 'closed'}
|
|
208
|
-
open={defaultOpen}
|
|
232
|
+
<div class="diagram__body">
|
|
233
|
+
<div
|
|
234
|
+
class="diagram-stage"
|
|
235
|
+
id={renderedAnchorId === legacyAnchorId ? undefined : legacyAnchorId}
|
|
209
236
|
>
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
237
|
+
<div
|
|
238
|
+
id={viewportId}
|
|
239
|
+
class="diagram-scroll"
|
|
240
|
+
tabindex="0"
|
|
241
|
+
role="group"
|
|
242
|
+
aria-labelledby={captionTextId}
|
|
243
|
+
>
|
|
215
244
|
<div
|
|
216
|
-
class="diagram-
|
|
217
|
-
|
|
245
|
+
class="diagram-canvas"
|
|
246
|
+
style={`--diagram-print-ratio: ${layout.width} / ${layout.height}; --diagram-width: ${layout.width}; --diagram-height: ${layout.height}; width: ${layout.width}px; height: ${layout.height}px;`}
|
|
218
247
|
>
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
role="group"
|
|
224
|
-
aria-labelledby={`${id}-caption`}
|
|
248
|
+
<svg
|
|
249
|
+
viewBox={`0 0 ${layout.width} ${layout.height}`}
|
|
250
|
+
width="100%"
|
|
251
|
+
height="100%"
|
|
225
252
|
>
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
253
|
+
<defs>
|
|
254
|
+
<marker
|
|
255
|
+
id={markerId}
|
|
256
|
+
viewBox="0 0 10 10"
|
|
257
|
+
refX="9"
|
|
258
|
+
refY="5"
|
|
259
|
+
markerWidth="7"
|
|
260
|
+
markerHeight="7"
|
|
261
|
+
orient="auto-start-reverse"
|
|
234
262
|
>
|
|
235
|
-
<
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
263
|
+
<path
|
|
264
|
+
d="M 0 0 L 10 5 L 0 10 z"
|
|
265
|
+
class="diagram-arrowhead"
|
|
266
|
+
/>
|
|
267
|
+
</marker>
|
|
268
|
+
</defs>
|
|
269
|
+
|
|
270
|
+
{
|
|
271
|
+
layout.edges.map((edge) => (
|
|
272
|
+
<path
|
|
273
|
+
d={pathFrom(edge.points)}
|
|
274
|
+
class="diagram-edge"
|
|
275
|
+
marker-end={`url(#${markerId})`}
|
|
276
|
+
/>
|
|
277
|
+
))
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
{
|
|
281
|
+
layout.nodes.map((position) => {
|
|
282
|
+
const node = nodeById.get(position.id)!;
|
|
283
|
+
// Position each node with x/y attributes, never a
|
|
284
|
+
// `transform` on the group: WebKit (every iOS browser)
|
|
285
|
+
// paints a `foreignObject` descendant that gets its own
|
|
286
|
+
// render layer — every KaTeX `position: relative` span —
|
|
287
|
+
// without the ancestor transform, so formulas pile up at
|
|
288
|
+
// the SVG origin while their boxes stay put.
|
|
289
|
+
return (
|
|
290
|
+
<g class="diagram-node">
|
|
291
|
+
<rect
|
|
292
|
+
x={position.x}
|
|
293
|
+
y={position.y}
|
|
294
|
+
width={position.width}
|
|
295
|
+
height={position.height}
|
|
296
|
+
rx="8"
|
|
297
|
+
ry="8"
|
|
258
298
|
/>
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
class="diagram-node"
|
|
299
|
+
<foreignObject
|
|
300
|
+
x={position.x}
|
|
301
|
+
y={position.y}
|
|
302
|
+
width={position.width}
|
|
303
|
+
height={position.height}
|
|
304
|
+
>
|
|
305
|
+
<div
|
|
306
|
+
xmlns="http://www.w3.org/1999/xhtml"
|
|
307
|
+
class="diagram-node-content"
|
|
269
308
|
>
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
<span class="diagram-node-formula notation-math">
|
|
292
|
-
{node.mathNodes.map((mathNode) => (
|
|
293
|
-
<SafeMathNode node={mathNode} />
|
|
294
|
-
))}
|
|
295
|
-
</span>
|
|
296
|
-
)
|
|
297
|
-
}
|
|
298
|
-
</div>
|
|
299
|
-
</foreignObject>
|
|
300
|
-
</g>
|
|
301
|
-
);
|
|
302
|
-
})
|
|
303
|
-
}
|
|
304
|
-
</svg>
|
|
305
|
-
</div>
|
|
306
|
-
</div>
|
|
309
|
+
{
|
|
310
|
+
node.text && (
|
|
311
|
+
<span class="diagram-node-text">{node.text}</span>
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
{
|
|
315
|
+
node.mathNodes && (
|
|
316
|
+
<span class="diagram-node-formula notation-math">
|
|
317
|
+
{node.mathNodes.map((mathNode) => (
|
|
318
|
+
<SafeMathNode node={mathNode} />
|
|
319
|
+
))}
|
|
320
|
+
</span>
|
|
321
|
+
)
|
|
322
|
+
}
|
|
323
|
+
</div>
|
|
324
|
+
</foreignObject>
|
|
325
|
+
</g>
|
|
326
|
+
);
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
</svg>
|
|
307
330
|
</div>
|
|
308
331
|
</div>
|
|
309
|
-
</details>
|
|
310
|
-
|
|
311
|
-
<a
|
|
312
|
-
class="diagram__title-anchor"
|
|
313
|
-
href={`#${renderedAnchorId}`}
|
|
314
|
-
aria-label={`${number ? `Diagram ${number}: ` : ''}${label}`}
|
|
315
|
-
>
|
|
316
|
-
<svg
|
|
317
|
-
aria-hidden="true"
|
|
318
|
-
width="16"
|
|
319
|
-
height="16"
|
|
320
|
-
viewBox="0 0 24 24"
|
|
321
|
-
fill="currentColor"
|
|
322
|
-
><path
|
|
323
|
-
d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"
|
|
324
|
-
></path></svg
|
|
325
|
-
>
|
|
326
|
-
</a>
|
|
327
|
-
|
|
328
|
-
<div class="diagram-toolbar" data-diagram-toolbar hidden>
|
|
329
|
-
<button
|
|
330
|
-
type="button"
|
|
331
|
-
class="diagram-expand-button"
|
|
332
|
-
data-diagram-expand
|
|
333
|
-
aria-controls={viewportId}
|
|
334
|
-
aria-expanded="false"
|
|
335
|
-
title="Expand diagram horizontally"
|
|
336
|
-
>
|
|
337
|
-
<svg aria-hidden="true" viewBox="0 0 24 24">
|
|
338
|
-
<path class="diagram-expand-icon" d="M3 12h18M8 7l-5 5 5 5M16 7l5 5-5 5" />
|
|
339
|
-
<path
|
|
340
|
-
class="diagram-shrink-icon"
|
|
341
|
-
d="M3 12h7M7 9l3 3-3 3M21 12h-7M17 9l-3 3 3 3"
|
|
342
|
-
/>
|
|
343
|
-
</svg>
|
|
344
|
-
<span class="sr-only">Expand {label}</span>
|
|
345
|
-
</button>
|
|
346
332
|
</div>
|
|
347
333
|
</div>
|
|
334
|
+
|
|
335
|
+
<FloatCaption
|
|
336
|
+
kind="Diagram"
|
|
337
|
+
prefix="diagram"
|
|
338
|
+
caption={caption}
|
|
339
|
+
short={short}
|
|
340
|
+
anchorId={renderedAnchorId}
|
|
341
|
+
number={number}
|
|
342
|
+
textId={captionTextId}
|
|
343
|
+
>
|
|
344
|
+
<button
|
|
345
|
+
type="button"
|
|
346
|
+
class="float-tool diagram__widen"
|
|
347
|
+
data-diagram-expand
|
|
348
|
+
aria-controls={viewportId}
|
|
349
|
+
aria-expanded="false"
|
|
350
|
+
aria-label={`Expand ${number ? `Diagram ${number}` : 'this diagram'} horizontally`}
|
|
351
|
+
title="Expand diagram horizontally"
|
|
352
|
+
hidden
|
|
353
|
+
>
|
|
354
|
+
<svg aria-hidden="true" viewBox="0 0 24 24">
|
|
355
|
+
<path class="float-tool__widen" d="M3 12h18M8 7l-5 5 5 5M16 7l5 5-5 5" />
|
|
356
|
+
<path class="float-tool__narrow" d="M3 12h7M7 9l3 3-3 3M21 12h-7M17 9l-3 3 3 3" />
|
|
357
|
+
</svg>
|
|
358
|
+
</button>
|
|
359
|
+
</FloatCaption>
|
|
348
360
|
</figure>
|
|
349
361
|
|
|
350
362
|
<style>
|
|
@@ -356,112 +368,10 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
356
368
|
contain: inline-size;
|
|
357
369
|
}
|
|
358
370
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
.diagram__details {
|
|
364
|
-
border-inline-start: 0;
|
|
365
|
-
padding-inline-start: 0;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
.diagram__summary {
|
|
369
|
-
position: relative;
|
|
370
|
-
min-height: 1.75rem;
|
|
371
|
-
padding-inline-end: 4rem;
|
|
372
|
-
font-weight: 600;
|
|
373
|
-
cursor: pointer;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
.diagram__summary::before {
|
|
377
|
-
position: absolute;
|
|
378
|
-
top: 50%;
|
|
379
|
-
left: -1.35em;
|
|
380
|
-
margin: 0;
|
|
381
|
-
transform: translateY(-50%);
|
|
382
|
-
opacity: 0;
|
|
383
|
-
transition:
|
|
384
|
-
opacity 150ms ease 700ms,
|
|
385
|
-
transform 150ms ease;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
.diagram__details[data-state='open'] > .diagram__summary::before {
|
|
389
|
-
transform: translateY(-50%) rotateZ(90deg);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
.diagram__details[data-state='closed'] > .diagram__summary::before {
|
|
393
|
-
opacity: 1;
|
|
394
|
-
transition: none;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
.diagram__summary:hover::before,
|
|
398
|
-
.diagram__summary:focus-visible::before {
|
|
399
|
-
opacity: 1;
|
|
400
|
-
transition: opacity 100ms ease;
|
|
401
|
-
}
|
|
402
|
-
|
|
371
|
+
/* The caption line, its links and its widen button are styled once for
|
|
372
|
+
every float, in `global.css` (`.float-caption`, `.float-tool`). */
|
|
403
373
|
.diagram__body {
|
|
404
374
|
overflow: hidden;
|
|
405
|
-
transition: max-height 220ms ease;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
.diagram__number {
|
|
409
|
-
color: var(--sl-color-text-accent);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
.diagram__caption-text::before {
|
|
413
|
-
content: ' — ';
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
.diagram__summary > .diagram__caption-text:first-child::before {
|
|
417
|
-
content: none;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
.diagram__title-anchor {
|
|
421
|
-
position: absolute;
|
|
422
|
-
top: 0.1rem;
|
|
423
|
-
inset-inline-end: 0;
|
|
424
|
-
display: inline-flex;
|
|
425
|
-
width: 1.5rem;
|
|
426
|
-
height: 1.5rem;
|
|
427
|
-
align-items: center;
|
|
428
|
-
justify-content: center;
|
|
429
|
-
color: var(--sl-color-gray-3);
|
|
430
|
-
text-decoration: none;
|
|
431
|
-
opacity: 1;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
.diagram[data-diagram-overflow='true'] .diagram__title-anchor {
|
|
435
|
-
inset-inline-end: 2rem;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
.diagram__title-anchor svg {
|
|
439
|
-
width: 0.9rem;
|
|
440
|
-
height: 0.9rem;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
.diagram__title-anchor:hover,
|
|
444
|
-
.diagram__title-anchor:focus-visible {
|
|
445
|
-
color: var(--sl-color-text-accent);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
.diagram__title-anchor:focus-visible {
|
|
449
|
-
outline: 2px solid var(--sl-color-accent);
|
|
450
|
-
outline-offset: 0.1rem;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
@media (hover: hover) {
|
|
454
|
-
.diagram__title-anchor {
|
|
455
|
-
opacity: 0;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
.diagram__details:has(> .diagram__summary:hover) ~ .diagram__title-anchor,
|
|
459
|
-
.diagram__details:has(> .diagram__summary:focus-visible)
|
|
460
|
-
~ .diagram__title-anchor,
|
|
461
|
-
.diagram__title-anchor:hover,
|
|
462
|
-
.diagram__title-anchor:focus-visible {
|
|
463
|
-
opacity: 1;
|
|
464
|
-
}
|
|
465
375
|
}
|
|
466
376
|
|
|
467
377
|
.diagram-stage {
|
|
@@ -470,56 +380,6 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
470
380
|
overflow: hidden;
|
|
471
381
|
}
|
|
472
382
|
|
|
473
|
-
.diagram-toolbar {
|
|
474
|
-
position: absolute;
|
|
475
|
-
z-index: 2;
|
|
476
|
-
top: -0.25rem;
|
|
477
|
-
inset-inline-end: 0;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
.diagram-toolbar[hidden] {
|
|
481
|
-
display: none;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
.diagram-expand-button {
|
|
485
|
-
display: inline-flex;
|
|
486
|
-
width: 1.75rem;
|
|
487
|
-
height: 1.75rem;
|
|
488
|
-
margin: 0;
|
|
489
|
-
align-items: center;
|
|
490
|
-
justify-content: center;
|
|
491
|
-
color: var(--sl-color-gray-2);
|
|
492
|
-
border: 0;
|
|
493
|
-
border-radius: 0.25rem;
|
|
494
|
-
background: transparent;
|
|
495
|
-
cursor: pointer;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
.diagram-expand-button svg {
|
|
499
|
-
width: 1.1rem;
|
|
500
|
-
height: 1.1rem;
|
|
501
|
-
fill: none;
|
|
502
|
-
stroke: currentColor;
|
|
503
|
-
stroke-width: 1.8;
|
|
504
|
-
stroke-linecap: round;
|
|
505
|
-
stroke-linejoin: round;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
.diagram-expand-button[aria-expanded='false'] .diagram-shrink-icon,
|
|
509
|
-
.diagram-expand-button[aria-expanded='true'] .diagram-expand-icon {
|
|
510
|
-
display: none;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
.diagram-expand-button:hover {
|
|
514
|
-
color: var(--sl-color-text);
|
|
515
|
-
background: var(--sl-color-accent-low);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
.diagram-expand-button:focus-visible {
|
|
519
|
-
outline: 2px solid var(--sl-color-accent);
|
|
520
|
-
outline-offset: 1px;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
383
|
/* A wide graph scrolls inside its own box rather than shrinking to
|
|
524
384
|
illegibility — the same tradeoff `.notation-formula-math` makes for a
|
|
525
385
|
wide equation. `tabindex` on the scroller is the accessibility half of
|
|
@@ -595,29 +455,14 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
595
455
|
fill: var(--sl-color-gray-4);
|
|
596
456
|
}
|
|
597
457
|
|
|
458
|
+
/* A diagram prints its whole graph (`global.css` resets the scroll box
|
|
459
|
+
for print). */
|
|
598
460
|
@media print {
|
|
599
|
-
.diagram-toolbar,
|
|
600
|
-
.diagram__title-anchor,
|
|
601
|
-
.diagram__summary::before {
|
|
602
|
-
display: none;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
.diagram__number {
|
|
606
|
-
color: inherit;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
461
|
.diagram__body {
|
|
610
462
|
display: block !important;
|
|
611
463
|
max-height: none !important;
|
|
612
464
|
overflow: visible !important;
|
|
613
465
|
}
|
|
614
466
|
}
|
|
615
|
-
|
|
616
|
-
@media (prefers-reduced-motion: reduce) {
|
|
617
|
-
.diagram__summary::before,
|
|
618
|
-
.diagram__body {
|
|
619
|
-
transition: none;
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
467
|
}
|
|
623
468
|
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The course's collapse defaults at build time — `manifest.disclosure`, the
|
|
3
|
+
* `disclosure` block of the course settings with the engine defaults applied
|
|
4
|
+
* (`normalizeDisclosure` in `../../compiler/course-config`). A component
|
|
5
|
+
* reads its kind's first-visit state here instead of hardcoding one, and a
|
|
6
|
+
* per-instance prop (`defaultOpen`) still overrides it.
|
|
7
|
+
*
|
|
8
|
+
* Read once per build: every float on every page asks, and the manifest does
|
|
9
|
+
* not change under a running build (a content edit in dev restarts Astro).
|
|
10
|
+
*/
|
|
11
|
+
import {
|
|
12
|
+
DISCLOSURE_DEFAULTS,
|
|
13
|
+
type NormalizedDisclosure,
|
|
14
|
+
} from '../../compiler/course-config';
|
|
15
|
+
import { loadManifest } from '../../compiler/manifest';
|
|
16
|
+
|
|
17
|
+
let cached: Promise<NormalizedDisclosure> | undefined;
|
|
18
|
+
|
|
19
|
+
export function courseDisclosure(): Promise<NormalizedDisclosure> {
|
|
20
|
+
cached ??= loadManifest().then(
|
|
21
|
+
(manifest) => manifest.disclosure ?? DISCLOSURE_DEFAULTS,
|
|
22
|
+
);
|
|
23
|
+
return cached;
|
|
24
|
+
}
|