explico 0.11.1 → 0.13.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 +1292 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +11 -4
- package/dist/compiler/astro.js +48 -15
- package/dist/compiler/cli.d.ts +27 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +33 -2
- package/dist/compiler/collections.js +91 -19
- package/dist/compiler/content-schema.d.ts +31 -0
- package/dist/compiler/content-schema.js +82 -0
- package/dist/compiler/content-schemas.d.ts +422 -0
- package/dist/compiler/content-schemas.js +229 -0
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +30 -2
- package/dist/compiler/exports/combined-html.d.ts +97 -0
- package/dist/compiler/exports/combined-html.js +492 -0
- package/dist/compiler/exports/download-index.d.ts +9 -0
- package/dist/compiler/exports/download-index.js +33 -0
- package/dist/compiler/exports/export-chapters.d.ts +98 -0
- package/dist/compiler/exports/export-chapters.js +164 -0
- package/dist/compiler/exports/export-pages.d.ts +48 -0
- package/dist/compiler/exports/export-pages.js +22 -0
- package/dist/compiler/exports/html-tree.d.ts +22 -0
- package/dist/compiler/exports/html-tree.js +47 -0
- package/dist/compiler/exports/latex/capture.d.ts +106 -0
- package/dist/compiler/exports/latex/capture.js +435 -0
- package/dist/compiler/exports/latex/compile.d.ts +73 -0
- package/dist/compiler/exports/latex/compile.js +115 -0
- package/dist/compiler/exports/latex/document.d.ts +102 -0
- package/dist/compiler/exports/latex/document.js +349 -0
- package/dist/compiler/exports/latex/explico.cls +415 -0
- package/dist/compiler/exports/latex/numbering.d.ts +18 -0
- package/dist/compiler/exports/latex/numbering.js +57 -0
- package/dist/compiler/exports/latex/serialize.d.ts +112 -0
- package/dist/compiler/exports/latex/serialize.js +606 -0
- package/dist/compiler/exports/latex-export.d.ts +44 -0
- package/dist/compiler/exports/latex-export.js +169 -0
- package/dist/compiler/exports/markdown/serialize.d.ts +51 -0
- package/dist/compiler/exports/markdown/serialize.js +527 -0
- package/dist/compiler/exports/markdown-export.d.ts +39 -0
- package/dist/compiler/exports/markdown-export.js +240 -0
- package/dist/compiler/exports/standalone-html.d.ts +15 -5
- package/dist/compiler/exports/standalone-html.js +23 -51
- package/dist/compiler/exports/static-tree.d.ts +253 -0
- package/dist/compiler/exports/static-tree.js +625 -0
- package/dist/compiler/exports/zip.d.ts +16 -0
- package/dist/compiler/exports/zip.js +72 -0
- package/dist/compiler/lesson-derivation.d.ts +8 -2
- package/dist/compiler/lesson-derivation.js +6 -7
- package/dist/compiler/manifest.d.ts +115 -8
- package/dist/compiler/manifest.js +221 -39
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +3 -1
- package/dist/{course-config-Dsnri9Tk.d.ts → course-config-rRtME5UV.d.ts} +56 -13
- package/dist/curriculum/validation.d.ts +9 -3
- package/dist/curriculum/validation.js +35 -17
- package/dist/reference/base-abbreviations.d.mts +2 -2
- package/dist/reference/base-abbreviations.mjs +2 -2
- package/dist/reference/base-operators.d.mts +8 -2
- package/dist/reference/base-operators.mjs +8 -10
- package/dist/reference/base-roman-labels.d.mts +4 -3
- package/dist/reference/base-roman-labels.mjs +4 -3
- package/dist/reference/citation-format.d.mts +35 -0
- package/dist/reference/citation-format.mjs +74 -0
- package/dist/reference/consistency.d.ts +5 -9
- package/dist/reference/consistency.js +34 -38
- package/dist/reference/curriculum-alignment.js +3 -24
- package/dist/reference/derived-entries.d.ts +45 -0
- package/dist/reference/derived-entries.js +50 -0
- package/dist/reference/derived-notation.d.mts +125 -0
- package/dist/reference/derived-notation.mjs +121 -0
- package/dist/reference/diagram-fit.d.ts +45 -0
- package/dist/reference/diagram-fit.js +54 -0
- package/dist/reference/diagram-layout.d.ts +59 -10
- package/dist/reference/diagram-layout.js +85 -24
- package/dist/reference/diagrams-validate.d.ts +1 -1
- package/dist/reference/equations-validate.d.ts +1 -1
- package/dist/reference/equations-validate.js +26 -1
- package/dist/reference/equations.d.mts +27 -0
- package/dist/reference/equations.mjs +120 -22
- package/dist/reference/examples-validate.d.ts +1 -1
- package/dist/reference/figure-fit.d.ts +70 -0
- package/dist/reference/figure-fit.js +60 -0
- package/dist/reference/figure-pictures.d.ts +27 -0
- package/dist/reference/figure-pictures.js +49 -0
- package/dist/reference/figure-symbols.d.ts +32 -0
- package/dist/reference/figure-symbols.js +55 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-abbreviations.js +1 -1
- package/dist/reference/gate-course-rules.d.ts +4 -3
- package/dist/reference/gate-course-rules.js +9 -4
- package/dist/reference/gate-heading-length.d.ts +2 -0
- package/dist/reference/gate-heading-length.js +7 -5
- package/dist/reference/gate-heading-structure.js +26 -0
- package/dist/reference/gate-indices.d.ts +35 -0
- package/dist/reference/gate-indices.js +299 -0
- package/dist/reference/gate-math.d.ts +32 -2
- package/dist/reference/gate-math.js +68 -12
- package/dist/reference/gate-mdx-expression.d.ts +17 -0
- package/dist/reference/gate-mdx-expression.js +29 -0
- package/dist/reference/gate-non-chapter-pages.d.ts +39 -0
- package/dist/reference/gate-non-chapter-pages.js +156 -0
- package/dist/reference/gate-part-pages.d.ts +4 -2
- package/dist/reference/gate-part-pages.js +2 -1
- package/dist/reference/gate-prop-text.d.ts +28 -0
- package/dist/reference/gate-prop-text.js +106 -0
- package/dist/reference/gate-prose-notation.d.ts +3 -1
- package/dist/reference/gate-prose-notation.js +4 -2
- package/dist/reference/gate-retired-keys.d.ts +35 -0
- package/dist/reference/gate-retired-keys.js +58 -0
- package/dist/reference/gloss.d.ts +2 -0
- package/dist/reference/katex-measure.d.ts +17 -0
- package/dist/reference/katex-measure.js +223 -0
- package/dist/reference/keyed-float-validate.js +12 -0
- package/dist/reference/keyed-jsx-floats.d.mts +2 -2
- package/dist/reference/keyed-jsx-floats.mjs +11 -14
- package/dist/reference/lab-katex-validate.d.ts +43 -0
- package/dist/reference/lab-katex-validate.js +96 -0
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- package/dist/reference/lint-ignore.js +1 -1
- package/dist/reference/math-glyphs.d.mts +94 -2
- package/dist/reference/math-glyphs.mjs +851 -46
- package/dist/reference/mixed-content.d.ts +8 -3
- package/dist/reference/mixed-content.js +4 -2
- package/dist/reference/page-notation.d.ts +39 -7
- package/dist/reference/page-notation.js +62 -10
- package/dist/reference/raw-floats.mjs +37 -13
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +115 -11
- package/dist/reference/rehype-fail-katex-errors.d.mts +9 -0
- package/dist/reference/rehype-fail-katex-errors.mjs +19 -0
- package/dist/reference/rehype-heading-anchors.mjs +11 -1
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/remark-notation.mjs +275 -23
- package/dist/reference/render-lab-math.d.ts +13 -2
- package/dist/reference/render-lab-math.js +18 -6
- package/dist/reference/sections-validate.d.ts +28 -3
- package/dist/reference/sections-validate.js +31 -4
- package/dist/reference/sections.d.mts +24 -6
- package/dist/reference/sections.mjs +92 -17
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/tables-validate.js +24 -1
- package/dist/reference/text-measure.d.ts +10 -0
- package/dist/reference/text-measure.js +41 -0
- package/dist/reference/text-widths.d.ts +10 -0
- package/dist/reference/text-widths.js +1238 -0
- package/dist/reference/types.d.ts +64 -8
- package/dist/rules/catalog.js +223 -32
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +100 -27
- package/dist/rules/settings.d.ts +1 -1
- package/dist/rules/settings.js +7 -0
- package/dist/session/PreferenceStore.d.ts +18 -1
- package/dist/session/PreferenceStore.js +29 -1
- package/docs/authoring/README.md +33 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +115 -10
- package/docs/authoring/migrating.md +878 -0
- package/docs/authoring/notation.md +285 -30
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +84 -45
- package/docs/authoring/structure.md +67 -2
- package/docs/authoring/visualizations.md +167 -25
- package/package.json +12 -7
- package/src/compiler/astro.ts +72 -21
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +158 -27
- package/src/compiler/content-schema.ts +108 -0
- package/src/compiler/content-schemas.ts +391 -0
- package/src/compiler/course-config.ts +86 -15
- package/src/compiler/exports/combined-html.ts +669 -0
- package/src/compiler/exports/download-index.ts +36 -0
- package/src/compiler/exports/export-chapters.ts +233 -0
- package/src/compiler/exports/export-pages.ts +44 -0
- package/src/compiler/exports/html-tree.ts +62 -0
- package/src/compiler/exports/latex/capture.ts +651 -0
- package/src/compiler/exports/latex/compile.ts +168 -0
- package/src/compiler/exports/latex/document.ts +479 -0
- package/src/compiler/exports/latex/explico.cls +415 -0
- package/src/compiler/exports/latex/numbering.ts +74 -0
- package/src/compiler/exports/latex/serialize.ts +787 -0
- package/src/compiler/exports/latex/texlive-packages.txt +76 -0
- package/src/compiler/exports/latex-export.ts +255 -0
- package/src/compiler/exports/markdown/serialize.ts +632 -0
- package/src/compiler/exports/markdown-export.ts +329 -0
- package/src/compiler/exports/standalone-html.ts +39 -70
- package/src/compiler/exports/static-tree.ts +944 -0
- package/src/compiler/exports/zip.ts +88 -0
- package/src/compiler/lesson-derivation.ts +13 -8
- package/src/compiler/manifest.ts +387 -40
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/CourseContents.astro +6 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +18 -9
- package/src/components/abbreviation/AbbreviationGlossary.astro +6 -2
- package/src/components/abbreviation/AbbreviationLayer.astro +21 -12
- package/src/components/assessments/AssessmentRunner.tsx +7 -1
- package/src/components/assessments/AssessmentSet.astro +14 -1
- package/src/components/block-heading.ts +38 -0
- package/src/components/card-arrow.ts +18 -4
- package/src/components/card-carry.ts +406 -0
- package/src/components/card-drag.ts +1 -30
- package/src/components/card-fetch.ts +87 -0
- package/src/components/card-manager.ts +1222 -38
- package/src/components/card-memory.ts +5 -1
- package/src/components/card-placement.ts +211 -13
- package/src/components/card-side.ts +281 -31
- package/src/components/citation/CitationLayer.astro +45 -40
- package/src/components/diagram/Diagram.astro +123 -44
- package/src/components/disclosure/print-as-shown.ts +42 -6
- package/src/components/figure/Figure.astro +17 -1
- package/src/components/figure/FloatCaption.astro +4 -17
- package/src/components/figure/figure-state.ts +26 -17
- package/src/components/float-toolbar.ts +274 -0
- package/src/components/memo/Memo.astro +21 -10
- package/src/components/memo/ShortNote.astro +4 -0
- package/src/components/notation/NotationGlossary.astro +22 -17
- package/src/components/notation/NotationLayer.astro +300 -79
- package/src/components/notation/NotationMath.astro +8 -1
- package/src/components/notation/render-notation-math.ts +51 -5
- package/src/components/readable-text.ts +25 -0
- package/src/components/reference/FloatRefLayer.astro +162 -89
- package/src/components/starlight/HeadingAnchorEnhancer.astro +13 -8
- package/src/components/starlight/KeyedFloatEnhancer.astro +28 -9
- package/src/components/starlight/LayoutPageSidebar.astro +17 -3
- package/src/components/starlight/LayoutSocialIcons.astro +79 -29
- package/src/components/starlight/LessonExportActions.astro +384 -310
- package/src/components/starlight/LessonFooter.astro +66 -8
- package/src/components/starlight/PrintController.astro +28 -0
- package/src/components/starlight/TextSizeControl.astro +137 -0
- package/src/components/starlight/print-controller.ts +380 -0
- package/src/components/starlight/section-summary.ts +13 -5
- package/src/components/table/Table.astro +14 -22
- package/src/components/table/table-truncation.ts +15 -0
- package/src/content-config.ts +20 -312
- package/src/curriculum/validation.ts +72 -24
- package/src/reference/base-abbreviations.mjs +2 -2
- package/src/reference/base-operators.mjs +8 -10
- package/src/reference/base-roman-labels.mjs +4 -3
- package/src/reference/citation-format.mjs +74 -0
- package/src/reference/consistency.ts +47 -61
- package/src/reference/curriculum-alignment.ts +4 -41
- package/src/reference/derived-entries.ts +68 -0
- package/src/reference/derived-notation.mjs +121 -0
- package/src/reference/diagram-fit.ts +104 -0
- package/src/reference/diagram-layout.ts +182 -51
- package/src/reference/diagrams-validate.ts +2 -1
- package/src/reference/equations-validate.ts +41 -2
- package/src/reference/equations.mjs +120 -22
- package/src/reference/examples-validate.ts +1 -0
- package/src/reference/figure-fit.ts +139 -0
- package/src/reference/figure-pictures.ts +96 -0
- package/src/reference/figure-symbols.ts +117 -0
- package/src/reference/figures-validate.ts +2 -1
- package/src/reference/gate-abbreviations.ts +1 -1
- package/src/reference/gate-course-rules.ts +22 -7
- package/src/reference/gate-heading-length.ts +25 -7
- package/src/reference/gate-heading-structure.ts +40 -1
- package/src/reference/gate-indices.ts +470 -0
- package/src/reference/gate-math.ts +102 -13
- package/src/reference/gate-mdx-expression.ts +45 -0
- package/src/reference/gate-non-chapter-pages.ts +241 -0
- package/src/reference/gate-part-pages.ts +1 -1
- package/src/reference/gate-prop-text.ts +145 -0
- package/src/reference/gate-prose-notation.ts +19 -5
- package/src/reference/gate-retired-keys.ts +101 -0
- package/src/reference/gloss.ts +2 -0
- package/src/reference/katex-measure.ts +384 -0
- package/src/reference/keyed-float-validate.ts +22 -0
- package/src/reference/keyed-jsx-floats.mjs +11 -14
- package/src/reference/lab-katex-validate.ts +156 -0
- package/src/reference/lab-math-scope.ts +15 -1
- package/src/reference/lint-ignore.ts +4 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +114 -14
- package/src/reference/raw-floats.mjs +37 -13
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +170 -9
- package/src/reference/rehype-fail-katex-errors.mjs +19 -0
- package/src/reference/rehype-heading-anchors.mjs +11 -1
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/remark-notation.mjs +275 -23
- package/src/reference/render-lab-math.ts +40 -5
- package/src/reference/sections-validate.ts +67 -3
- package/src/reference/sections.mjs +92 -17
- package/src/reference/tables-validate.ts +40 -2
- package/src/reference/text-measure.ts +63 -0
- package/src/reference/text-widths.ts +133 -0
- package/src/reference/types.ts +75 -8
- package/src/rules/catalog.ts +241 -31
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +322 -83
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* quick look at the source without leaving the reader's place.
|
|
7
7
|
*
|
|
8
8
|
* It reads everything it shows from the page's own static markup — the
|
|
9
|
-
* marker's `data-*` and the
|
|
10
|
-
* page serializes a second copy of the source database. Opening, pinning,
|
|
9
|
+
* marker's `data-*` and the reference-list item it links to (`#cite-n`) —
|
|
10
|
+
* so no page serializes a second copy of the source database. Opening, pinning,
|
|
11
11
|
* Escape and placement come from the card manager (`../card-manager.ts`); a
|
|
12
12
|
* card per source, several at once.
|
|
13
13
|
*/
|
|
@@ -21,12 +21,11 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
21
21
|
</p>
|
|
22
22
|
<div class="citation-panel-body">
|
|
23
23
|
<p class="citation-panel-locator" data-panel-locator hidden></p>
|
|
24
|
-
<p class="citation-panel-status" data-panel-status hidden></p>
|
|
25
24
|
<p class="citation-panel-links">
|
|
26
|
-
<a class="citation-panel-link" data-panel-link hidden
|
|
25
|
+
<a class="citation-panel-link hover-panel-action" data-panel-link hidden
|
|
27
26
|
>Go to the source<span aria-hidden="true" data-jump-arrow> ↗</span></a
|
|
28
27
|
>
|
|
29
|
-
<a class="citation-panel-jump" data-panel-jump
|
|
28
|
+
<a class="citation-panel-jump hover-panel-action" data-panel-jump
|
|
30
29
|
>Go to the reference list<span aria-hidden="true" data-jump-arrow> ↓</span></a
|
|
31
30
|
>
|
|
32
31
|
</p>
|
|
@@ -35,6 +34,7 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
35
34
|
|
|
36
35
|
<script>
|
|
37
36
|
import { cloneCardShell, registerCardSource } from '../card-manager';
|
|
37
|
+
import { fetchDoc, hrefFrom } from '../card-fetch';
|
|
38
38
|
import { wireJumpArrow } from '../card-jump';
|
|
39
39
|
import { referenceLabelFromText } from '../../reference/citation-format.mjs';
|
|
40
40
|
|
|
@@ -49,10 +49,11 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
49
49
|
|
|
50
50
|
function setup() {
|
|
51
51
|
const template = document.getElementById('citation-panel');
|
|
52
|
+
// Every page registers, with markers or none: a citation's card carried
|
|
53
|
+
// in from another page is built here (rule K5).
|
|
52
54
|
if (
|
|
53
55
|
!(template instanceof HTMLTemplateElement) ||
|
|
54
|
-
template.dataset.cardSourceReady === 'true'
|
|
55
|
-
!document.querySelector('a.citation-ref[data-citation-id]')
|
|
56
|
+
template.dataset.cardSourceReady === 'true'
|
|
56
57
|
) {
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
@@ -66,27 +67,34 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
66
67
|
return candidate && !candidate.closest('[data-card-foreign]') ? candidate : null;
|
|
67
68
|
};
|
|
68
69
|
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
// The reference-list item a marker links to (`#cite-n`). Followed, not
|
|
71
|
+
// built from the number: a downloaded part or course holds one list per
|
|
72
|
+
// chapter, each numbered from 1, with the chapter in its items' ids.
|
|
73
|
+
const itemIdOf = (marker: HTMLElement) => {
|
|
74
|
+
const href = marker.getAttribute('href') ?? '';
|
|
75
|
+
return href.startsWith('#') && href.length > 1 ? decodeURIComponent(href.slice(1)) : null;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Fill a card from the marker plus its reference-list item — never from
|
|
79
|
+
// a serialized source table. On another page (K5), both come from the
|
|
80
|
+
// page the card was opened on, and its links go there.
|
|
81
|
+
const render = (itemId: string, marker: HTMLElement, from?: Document, page?: string) => {
|
|
82
|
+
const item = (from ?? document).getElementById(itemId);
|
|
83
|
+
const number = marker.dataset.citationNumber ?? '';
|
|
73
84
|
const el = cloneCardShell(template);
|
|
74
85
|
if (!item || !el) return null;
|
|
75
86
|
const field = (name: string) => el.querySelector<HTMLElement>(`[data-panel-${name}]`);
|
|
76
87
|
const markerEl = field('marker');
|
|
77
88
|
const label = field('label');
|
|
78
89
|
const locator = field('locator');
|
|
79
|
-
const status = field('status');
|
|
80
90
|
const link = el.querySelector<HTMLAnchorElement>('[data-panel-link]');
|
|
81
91
|
const jump = el.querySelector<HTMLAnchorElement>('[data-panel-jump]');
|
|
82
|
-
if (!markerEl || !label || !locator || !
|
|
92
|
+
if (!markerEl || !label || !locator || !link || !jump) return null;
|
|
83
93
|
|
|
84
94
|
// The reference list is a tight list, so the `<li>` has no `<p>`
|
|
85
|
-
// wrapper: clone it and drop the trailing link
|
|
86
|
-
const line =
|
|
87
|
-
for (const extra of line.querySelectorAll(
|
|
88
|
-
'.citation-url, .citation-status, .citation-backref',
|
|
89
|
-
)) {
|
|
95
|
+
// wrapper: clone it and drop the trailing link chrome.
|
|
96
|
+
const line = document.importNode(item, true);
|
|
97
|
+
for (const extra of line.querySelectorAll('.citation-url, .citation-backref')) {
|
|
90
98
|
extra.remove();
|
|
91
99
|
}
|
|
92
100
|
const referenceText = line.textContent ?? '';
|
|
@@ -97,11 +105,6 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
97
105
|
setText(locator, loc);
|
|
98
106
|
el.setAttribute('aria-label', `Source citation ${number}`);
|
|
99
107
|
|
|
100
|
-
const sourceStatus = item
|
|
101
|
-
.querySelector('.citation-status')
|
|
102
|
-
?.textContent?.trim();
|
|
103
|
-
setText(status, sourceStatus ? `Source record: ${sourceStatus}` : '');
|
|
104
|
-
|
|
105
108
|
const sourceUrl = item.querySelector<HTMLAnchorElement>('a.citation-url');
|
|
106
109
|
if (sourceUrl) {
|
|
107
110
|
link.href = sourceUrl.href;
|
|
@@ -109,19 +112,34 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
109
112
|
link.hidden = false;
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
const jumpTo = marker.getAttribute('href') ?? '#references';
|
|
116
|
+
jump.href = page ? hrefFrom(jumpTo, page) : jumpTo;
|
|
113
117
|
wireJumpArrow(jump);
|
|
114
118
|
return el;
|
|
115
119
|
};
|
|
116
120
|
|
|
121
|
+
/** A reference-list item names its source only on its own page. */
|
|
122
|
+
const idOf = (item: string) => item.split('@')[0] ?? item;
|
|
123
|
+
|
|
117
124
|
registerCardSource({
|
|
118
125
|
layer: 'citation',
|
|
119
126
|
triggerFrom: markerFrom,
|
|
120
127
|
itemFor: (marker) => {
|
|
121
|
-
const
|
|
122
|
-
return
|
|
128
|
+
const id = itemIdOf(marker);
|
|
129
|
+
return id && marker.dataset.citationNumber && document.getElementById(id) ? id : null;
|
|
123
130
|
},
|
|
124
|
-
render,
|
|
131
|
+
render: (id, marker) => render(id, marker),
|
|
132
|
+
// K5: on another page, `[3]` is that page's third source.
|
|
133
|
+
awayItem: (id, page) => `${idOf(id)}@${page}`,
|
|
134
|
+
build: (id, page) =>
|
|
135
|
+
fetchDoc(page).then((doc) => {
|
|
136
|
+
const marker = [
|
|
137
|
+
...doc.querySelectorAll<HTMLElement>('a.citation-ref[data-citation-number]'),
|
|
138
|
+
].find((candidate) => itemIdOf(candidate) === idOf(id));
|
|
139
|
+
const el = marker ? render(idOf(id), marker, doc, page) : null;
|
|
140
|
+
el?.setAttribute('data-card-foreign', '');
|
|
141
|
+
return el;
|
|
142
|
+
}),
|
|
125
143
|
});
|
|
126
144
|
}
|
|
127
145
|
|
|
@@ -155,21 +173,8 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
155
173
|
color: var(--sl-color-gray-2);
|
|
156
174
|
}
|
|
157
175
|
|
|
158
|
-
.citation-panel-status {
|
|
159
|
-
color: var(--sl-color-gray-3);
|
|
160
|
-
font-size: var(--sl-text-xs);
|
|
161
|
-
text-transform: lowercase;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
176
|
.citation-panel-body .citation-panel-links {
|
|
165
177
|
margin: 0;
|
|
166
178
|
}
|
|
167
|
-
|
|
168
|
-
.citation-panel-link,
|
|
169
|
-
.citation-panel-jump {
|
|
170
|
-
display: inline-block;
|
|
171
|
-
margin-inline-end: 0.9rem;
|
|
172
|
-
font-size: var(--sl-text-xs);
|
|
173
|
-
}
|
|
174
179
|
}
|
|
175
180
|
</style>
|
|
@@ -17,9 +17,20 @@
|
|
|
17
17
|
* client script**: `NotationLayer`'s trigger scan already queries the whole
|
|
18
18
|
* document, not just its own subtree.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Each box is sized from what it holds (`nodeBoxSize` in
|
|
21
|
+
* `reference/diagram-layout.ts`): the label measured in DejaVu Sans, the
|
|
22
|
+
* widest common system font, and wrapped to a line count that sets the
|
|
23
|
+
* height, and the formula measured from KaTeX's own layout tree
|
|
24
|
+
* (`reference/katex-measure.ts`). A node's `width` or `height` overrides
|
|
25
|
+
* either; with only a `width`, the label wraps inside it and the height
|
|
26
|
+
* follows. A diagram wider than the lesson column first wraps its labels
|
|
27
|
+
* narrower until it fits (`fitDiagramLayout`).
|
|
28
|
+
*
|
|
29
|
+
* One that still does not fit (rule V8, `rules.V8.columnWidth`, or the
|
|
30
|
+
* diagram's own `warnAboveWidth`) is marked `data-diagram-too-wide`; the
|
|
31
|
+
* build reports it as a `dia-too-wide` warning with the lesson file and this
|
|
32
|
+
* id (`reference/diagram-fit.ts`), and `astro dev` prints the same warning as
|
|
33
|
+
* it renders.
|
|
23
34
|
*
|
|
24
35
|
* Named like every float (docs/plans/titles-and-containers.md Part 3): the
|
|
25
36
|
* long `caption` sits below the graph with its number, in the same caption
|
|
@@ -31,7 +42,10 @@
|
|
|
31
42
|
* reader fold a diagram away, wrap it in a `<Fold>` or put it in a
|
|
32
43
|
* collapsible section.
|
|
33
44
|
*/
|
|
34
|
-
import {
|
|
45
|
+
import { fitDiagramLayout, FORMULA_FONT_PX } from '../../reference/diagram-layout';
|
|
46
|
+
import { measureFormula } from '../../reference/katex-measure';
|
|
47
|
+
import { diagramTooWideMessage, diagramWidthLimit } from '../../reference/diagram-fit';
|
|
48
|
+
import { loadManifest } from '../../compiler/manifest';
|
|
35
49
|
import { renderNotationFormula } from '../notation/render-notation-math';
|
|
36
50
|
import type { SafeMathNode as SafeMathNodeType } from '../notation/render-notation-math';
|
|
37
51
|
import SafeMathNode from '../notation/SafeMathNode.astro';
|
|
@@ -40,8 +54,11 @@ import { DIAGRAM_NO_LONGER_FOLDS } from '../../reference/diagrams-validate';
|
|
|
40
54
|
import type { GlyphScopeEntry } from '../../reference/gloss';
|
|
41
55
|
import {
|
|
42
56
|
notationKeysInMathNodes,
|
|
57
|
+
registerPageDerivedNotation,
|
|
43
58
|
registerPageNotationDependencies,
|
|
44
59
|
} from '../../reference/page-notation';
|
|
60
|
+
import { indexFindings } from '../../reference/gate-indices';
|
|
61
|
+
import type { DerivedUse } from '../../reference/types';
|
|
45
62
|
|
|
46
63
|
export interface DiagramNode {
|
|
47
64
|
readonly id: string;
|
|
@@ -49,8 +66,9 @@ export interface DiagramNode {
|
|
|
49
66
|
readonly text?: string;
|
|
50
67
|
/** Raw LaTeX, resolved against `scope` before rendering. */
|
|
51
68
|
readonly formula?: string;
|
|
52
|
-
/**
|
|
69
|
+
/** The box's width in px; the label wraps inside it and the height follows. */
|
|
53
70
|
readonly width?: number;
|
|
71
|
+
/** The box's height in px. */
|
|
54
72
|
readonly height?: number;
|
|
55
73
|
}
|
|
56
74
|
|
|
@@ -76,8 +94,9 @@ export interface Props {
|
|
|
76
94
|
/** Computed by `remark-notation.mjs` for a top-level lesson diagram. */
|
|
77
95
|
anchorId?: string;
|
|
78
96
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
97
|
+
* The widest this diagram may lay out, in px, before the build warns
|
|
98
|
+
* (`dia-too-wide`, rule V8). Default: the course's `rules.V8.columnWidth`,
|
|
99
|
+
* the lesson column. Set `false` only when horizontal overflow is deliberate.
|
|
81
100
|
*/
|
|
82
101
|
warnAboveWidth?: number | false;
|
|
83
102
|
}
|
|
@@ -92,7 +111,7 @@ const {
|
|
|
92
111
|
direction = 'TB',
|
|
93
112
|
number,
|
|
94
113
|
anchorId,
|
|
95
|
-
warnAboveWidth
|
|
114
|
+
warnAboveWidth,
|
|
96
115
|
} = Astro.props;
|
|
97
116
|
|
|
98
117
|
const idPattern = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
@@ -128,6 +147,7 @@ if ((number && !anchorId) || (!number && anchorId)) {
|
|
|
128
147
|
);
|
|
129
148
|
}
|
|
130
149
|
if (
|
|
150
|
+
warnAboveWidth !== undefined &&
|
|
131
151
|
warnAboveWidth !== false &&
|
|
132
152
|
(!Number.isFinite(warnAboveWidth) || warnAboveWidth <= 0)
|
|
133
153
|
) {
|
|
@@ -136,26 +156,47 @@ if (
|
|
|
136
156
|
|
|
137
157
|
interface RenderedNode extends DiagramNode {
|
|
138
158
|
readonly mathNodes?: readonly SafeMathNodeType[];
|
|
159
|
+
/** The LaTeX `mathNodes` were rendered from, glyphs bound. */
|
|
160
|
+
readonly boundFormula?: string;
|
|
139
161
|
}
|
|
140
162
|
|
|
163
|
+
// The course's rule settings; a page rendered without a manifest (a
|
|
164
|
+
// component test) checks against the defaults.
|
|
165
|
+
const rules = await loadManifest().then(
|
|
166
|
+
(manifest) => manifest.rules,
|
|
167
|
+
() => undefined,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Rule N23: a diagram's formula is page math, so its indexed symbols take
|
|
171
|
+
// derived cards like the lesson's, and are held to the rule.
|
|
172
|
+
const derivedUses: DerivedUse[] = [];
|
|
141
173
|
const rendered: RenderedNode[] = nodes.map((node) => {
|
|
142
174
|
if (!node.text && !node.formula) {
|
|
143
175
|
throw new Error(`Diagram "${id}" node "${node.id}" has neither text nor formula.`);
|
|
144
176
|
}
|
|
145
177
|
if (!node.formula) return { ...node };
|
|
146
178
|
|
|
147
|
-
const {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
179
|
+
const {
|
|
180
|
+
nodes: mathNodes,
|
|
181
|
+
latex,
|
|
182
|
+
unresolved,
|
|
183
|
+
degraded,
|
|
184
|
+
reason,
|
|
185
|
+
derived,
|
|
186
|
+
indices,
|
|
187
|
+
} = renderNotationFormula(node.formula, scope, { derive: true });
|
|
151
188
|
if (degraded) {
|
|
189
|
+
// The resolver says what went wrong; an empty `scope` is the usual cause
|
|
190
|
+
// when the diagram is written straight into MDX, where nothing passes it.
|
|
191
|
+
const emptyScope =
|
|
192
|
+
scope.length === 0
|
|
193
|
+
? ' The diagram has no `scope`, so no symbol can resolve: pass the page\'s ' +
|
|
194
|
+
'notation scope (`labMathScope`), as a wrapper component does.'
|
|
195
|
+
: '';
|
|
152
196
|
throw new Error(
|
|
153
197
|
`Diagram "${id}" node "${node.id}" formula "${node.formula}" could not be ` +
|
|
154
|
-
`bound to the notation scope: the LaTeX did not parse
|
|
155
|
-
`
|
|
156
|
-
`\\explain{key}{latex}, or brace a subscripted base (write {v_0}^{2}, not ` +
|
|
157
|
-
`v_0^{2}), so every glyph resolves — a diagram formula is never allowed to ` +
|
|
158
|
-
`render as silent, unexplained math.`,
|
|
198
|
+
`bound to the notation scope: ${(reason ?? 'the LaTeX did not parse').replace(/\.$/, '')}.${emptyScope} ` +
|
|
199
|
+
`A diagram formula is never allowed to render as silent, unexplained math.`,
|
|
159
200
|
);
|
|
160
201
|
}
|
|
161
202
|
if (unresolved.length > 0) {
|
|
@@ -166,33 +207,55 @@ const rendered: RenderedNode[] = nodes.map((node) => {
|
|
|
166
207
|
`or pass it in the diagram's scope.`,
|
|
167
208
|
);
|
|
168
209
|
}
|
|
169
|
-
|
|
210
|
+
const findings = rules?.disabled.includes('N23') ? [] : indexFindings(indices);
|
|
211
|
+
if (findings.length > 0) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`Diagram "${id}" node "${node.id}" formula "${node.formula}" has an index no card ` +
|
|
214
|
+
`explains (rule N23): ${findings.join('; ')}.`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
derivedUses.push(...derived);
|
|
218
|
+
return { ...node, mathNodes, boundFormula: latex };
|
|
170
219
|
});
|
|
171
220
|
|
|
221
|
+
const derivedKeys = new Set(derivedUses.map((use) => use.key));
|
|
222
|
+
registerPageDerivedNotation(Astro.locals, derivedUses, `Diagram "${id}"`);
|
|
172
223
|
for (const node of rendered) {
|
|
173
224
|
if (!node.mathNodes) continue;
|
|
174
225
|
registerPageNotationDependencies(
|
|
175
226
|
Astro.locals,
|
|
176
|
-
|
|
227
|
+
// A derived card is no definition: it ships through its own registry.
|
|
228
|
+
notationKeysInMathNodes(node.mathNodes).filter((key) => !derivedKeys.has(key)),
|
|
177
229
|
`Diagram "${id}" node "${node.id}" formula "${node.formula}"`,
|
|
178
230
|
);
|
|
179
231
|
}
|
|
180
232
|
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
233
|
+
for (const node of rendered) {
|
|
234
|
+
for (const side of ['width', 'height'] as const) {
|
|
235
|
+
const value = node[side];
|
|
236
|
+
if (value !== undefined && !(Number.isFinite(value) && value > 0)) {
|
|
237
|
+
throw new Error(`Diagram "${id}" node "${node.id}" needs a positive \`${side}\`.`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Rule V8's settings, from the course's rules above.
|
|
243
|
+
const widthLimit = diagramWidthLimit(warnAboveWidth, rules);
|
|
244
|
+
|
|
245
|
+
const { layout } = fitDiagramLayout(
|
|
246
|
+
rendered.map((node) => ({
|
|
247
|
+
id: node.id,
|
|
248
|
+
content: {
|
|
249
|
+
...(node.text ? { text: node.text } : {}),
|
|
250
|
+
...(node.boundFormula
|
|
251
|
+
? { formula: measureFormula(node.boundFormula, FORMULA_FONT_PX) }
|
|
252
|
+
: {}),
|
|
253
|
+
},
|
|
254
|
+
...(node.width !== undefined ? { width: node.width } : {}),
|
|
255
|
+
...(node.height !== undefined ? { height: node.height } : {}),
|
|
256
|
+
})),
|
|
194
257
|
edges.map((edge) => ({ from: edge.from, to: edge.to })),
|
|
195
|
-
{ direction },
|
|
258
|
+
{ direction, ...(widthLimit !== undefined ? { fitWidth: widthLimit } : {}) },
|
|
196
259
|
);
|
|
197
260
|
|
|
198
261
|
const nodeById = new Map(rendered.map((node) => [node.id, node]));
|
|
@@ -203,13 +266,13 @@ const renderedAnchorId = anchorId ?? legacyAnchorId;
|
|
|
203
266
|
const viewportId = `${legacyAnchorId}-viewport`;
|
|
204
267
|
const captionTextId = `${legacyAnchorId}-caption`;
|
|
205
268
|
|
|
206
|
-
|
|
269
|
+
const tooWide = widthLimit !== undefined && layout.width > widthLimit;
|
|
270
|
+
if (tooWide && import.meta.env.DEV) {
|
|
271
|
+
const entry = (Astro.locals as { starlightRoute?: { entry?: { filePath?: string; id?: string } } })
|
|
272
|
+
.starlightRoute?.entry;
|
|
207
273
|
console.warn(
|
|
208
|
-
`[
|
|
209
|
-
|
|
210
|
-
`by readers, but consider recreating the graph with direction="TB", shorter ` +
|
|
211
|
-
`labels, or explicit node sizes. Set warnAboveWidth={false} only when the ` +
|
|
212
|
-
`horizontal overflow is intentional.`,
|
|
274
|
+
`[dia-too-wide] ${entry?.filePath ?? entry?.id ?? Astro.url.pathname}: ` +
|
|
275
|
+
diagramTooWideMessage(id, layout.width, widthLimit),
|
|
213
276
|
);
|
|
214
277
|
}
|
|
215
278
|
|
|
@@ -227,6 +290,7 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
227
290
|
data-dia-key={number ? id : undefined}
|
|
228
291
|
data-dia-short={short}
|
|
229
292
|
data-diagram-width={layout.width}
|
|
293
|
+
data-diagram-too-wide={tooWide ? widthLimit : undefined}
|
|
230
294
|
data-diagram-expandable
|
|
231
295
|
>
|
|
232
296
|
<div class="diagram__body">
|
|
@@ -426,23 +490,38 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
426
490
|
stroke-width: 1;
|
|
427
491
|
}
|
|
428
492
|
|
|
493
|
+
/* `NODE_FONT_PX` and the insets in `reference/diagram-layout.ts` size each
|
|
494
|
+
box from these values; change them together. The size is in px, not
|
|
495
|
+
rem: the boxes are measured at build time for 13.6px text, so text that
|
|
496
|
+
followed a reader's larger default font size (20px, Chrome's "Large")
|
|
497
|
+
outgrew its box and was cut off. Scaling the whole drawing instead is no
|
|
498
|
+
way out — WebKit on iOS scales the SVG but not the HTML in a
|
|
499
|
+
`foreignObject`. Browser zoom still enlarges it with everything else. */
|
|
429
500
|
.diagram-node-content {
|
|
430
501
|
display: flex;
|
|
431
502
|
height: 100%;
|
|
432
503
|
flex-direction: column;
|
|
433
504
|
align-items: center;
|
|
434
505
|
justify-content: center;
|
|
435
|
-
gap:
|
|
436
|
-
padding:
|
|
506
|
+
gap: 2.4px;
|
|
507
|
+
padding: 3.2px 8px;
|
|
437
508
|
color: var(--sl-color-text);
|
|
438
509
|
font-family: var(--sl-font);
|
|
439
|
-
font-size:
|
|
510
|
+
font-size: 13.6px;
|
|
440
511
|
line-height: 1.25;
|
|
441
512
|
text-align: center;
|
|
442
513
|
}
|
|
443
514
|
|
|
444
|
-
|
|
445
|
-
|
|
515
|
+
/* The box was sized for its label wrapped evenly; a narrower font
|
|
516
|
+
balances it the same way rather than leaving one word alone. */
|
|
517
|
+
.diagram-node-text {
|
|
518
|
+
text-wrap: balance;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/* The box is as wide as the formula on one line (`nodeBoxSize`); KaTeX's
|
|
522
|
+
inline math would otherwise break after a `+` or `=` and outgrow it. */
|
|
523
|
+
.diagram-node-formula {
|
|
524
|
+
white-space: nowrap;
|
|
446
525
|
}
|
|
447
526
|
|
|
448
527
|
.diagram-edge {
|
|
@@ -16,6 +16,15 @@
|
|
|
16
16
|
* never prints, open or folded, and is left exactly as it is: no note, not
|
|
17
17
|
* opened for an export.
|
|
18
18
|
*
|
|
19
|
+
* A note never goes inside an Astro island. An island still waiting to
|
|
20
|
+
* hydrate (`client:visible` — every knowledge check) that starts while the
|
|
21
|
+
* page is prepared for print would find a node its framework never rendered
|
|
22
|
+
* and throw away its server render (React's error #418); a hydrated one's
|
|
23
|
+
* markup is its framework's to own either way. A closed disclosure inside
|
|
24
|
+
* an island gets its note after the outermost island instead, once per
|
|
25
|
+
* target URL: the folded questions of one check all point at the check's
|
|
26
|
+
* own anchor, so one note after the check says it for all of them.
|
|
27
|
+
*
|
|
19
28
|
* Two callers share this module:
|
|
20
29
|
* - `LessonExportActions.astro`, the print controller a course gets with
|
|
21
30
|
* `lessonExports.print`: `'as-shown'` for its print button and the
|
|
@@ -90,6 +99,15 @@ function anchorIdFor(element: Element): string | undefined {
|
|
|
90
99
|
return undefined;
|
|
91
100
|
}
|
|
92
101
|
|
|
102
|
+
/** The outermost `<astro-island>` around an element, if any. */
|
|
103
|
+
function outermostIsland(element: Element): Element | null {
|
|
104
|
+
let island: Element | null = null;
|
|
105
|
+
for (let node = element.parentElement; node; node = node.parentElement) {
|
|
106
|
+
if (node.tagName === 'ASTRO-ISLAND') island = node;
|
|
107
|
+
}
|
|
108
|
+
return island;
|
|
109
|
+
}
|
|
110
|
+
|
|
93
111
|
function createNote(href: string): HTMLElement {
|
|
94
112
|
const note = document.createElement('div');
|
|
95
113
|
note.className = COLLAPSED_NOTE_CLASS;
|
|
@@ -152,20 +170,38 @@ export function prepareDisclosures(
|
|
|
152
170
|
const insideClosed = (element: Element) =>
|
|
153
171
|
!!element.parentElement?.closest('details:not([open])');
|
|
154
172
|
|
|
173
|
+
// The notes already placed after each island: the last one, which the
|
|
174
|
+
// next follows, and the URLs they name.
|
|
175
|
+
const afterIsland = new Map<Element, { last: Element; hrefs: Set<string> }>();
|
|
176
|
+
const place = (element: Element, where: 'before' | 'after') => {
|
|
177
|
+
const href = options.noteHref(anchorIdFor(element));
|
|
178
|
+
const island = outermostIsland(element);
|
|
179
|
+
if (!island) {
|
|
180
|
+
const note = createNote(href);
|
|
181
|
+
element[where](note);
|
|
182
|
+
notes.push(note);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const placed = afterIsland.get(island) ?? { last: island, hrefs: new Set<string>() };
|
|
186
|
+
if (placed.hrefs.has(href)) return;
|
|
187
|
+
const note = createNote(href);
|
|
188
|
+
placed.last.after(note);
|
|
189
|
+
placed.last = note;
|
|
190
|
+
placed.hrefs.add(href);
|
|
191
|
+
afterIsland.set(island, placed);
|
|
192
|
+
notes.push(note);
|
|
193
|
+
};
|
|
194
|
+
|
|
155
195
|
for (const details of main.querySelectorAll('details:not([open]):not([data-print-omit])')) {
|
|
156
196
|
if (insideClosed(details)) continue;
|
|
157
|
-
|
|
158
|
-
details.after(note);
|
|
159
|
-
notes.push(note);
|
|
197
|
+
place(details, 'after');
|
|
160
198
|
}
|
|
161
199
|
// Disclosures built on `hidden` rather than `<details>`.
|
|
162
200
|
for (const element of main.querySelectorAll(
|
|
163
201
|
':is(.short-note, .assessment-panel)[hidden]',
|
|
164
202
|
)) {
|
|
165
203
|
if (insideClosed(element)) continue;
|
|
166
|
-
|
|
167
|
-
element.before(note);
|
|
168
|
-
notes.push(note);
|
|
204
|
+
place(element, 'before');
|
|
169
205
|
}
|
|
170
206
|
}
|
|
171
207
|
|
|
@@ -84,7 +84,7 @@ if (short !== undefined && (typeof short !== 'string' || !short.trim())) {
|
|
|
84
84
|
}
|
|
85
85
|
if (!number || !anchorId) {
|
|
86
86
|
throw new Error(
|
|
87
|
-
|
|
87
|
+
`Figure is missing its computed \`number\`/\`anchorId\`. remark-notation numbers a <Figure> only on a lesson page, at its top level or in a <Memo>, <ShortNote> or <Fold>: elsewhere (a worked example) show the content without <Figure>, and on a page that is not a chapter (rule S10) link the chapter's figure. At a lesson's top level, this page is not running remark-notation with the manifest's \`figures\` (see astro.config.mjs).`,
|
|
88
88
|
);
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -176,8 +176,13 @@ const name = `Figure ${number}`;
|
|
|
176
176
|
Q8). A figure that should read as set apart goes in a `### … [card]`
|
|
177
177
|
section. The caption line is styled once for every float, in
|
|
178
178
|
`global.css` (`.float-caption`). */
|
|
179
|
+
/* A wide picture scrolls sideways. `overflow-x: auto` alone computes
|
|
180
|
+
`overflow-y` to `auto` too, and a body with no fixed height overflows
|
|
181
|
+
vertically only by rounding (a fractional height at a browser zoom),
|
|
182
|
+
which drew a one-pixel vertical scrollbar beside the figure. */
|
|
179
183
|
.keyed-figure__body {
|
|
180
184
|
overflow-x: auto;
|
|
185
|
+
overflow-y: hidden;
|
|
181
186
|
}
|
|
182
187
|
|
|
183
188
|
/* A lab's tools: a tray of their own after the caption line — a thin
|
|
@@ -258,6 +263,17 @@ const name = `Figure ${number}`;
|
|
|
258
263
|
.keyed-figure__tools-stub {
|
|
259
264
|
display: none !important;
|
|
260
265
|
}
|
|
266
|
+
|
|
267
|
+
/* A lab the reader never scrolled to has not drawn yet. The Print button
|
|
268
|
+
and Ctrl+P load it first; the browser's own File → Print cannot wait,
|
|
269
|
+
so the empty box says how to print the figure. */
|
|
270
|
+
.keyed-figure__body:has(astro-island[ssr])::after {
|
|
271
|
+
content: 'Interactive figure not loaded: print with the page’s Print button or Ctrl+P to include it.';
|
|
272
|
+
display: block;
|
|
273
|
+
font-size: 0.85em;
|
|
274
|
+
font-style: italic;
|
|
275
|
+
padding: 0.5rem 0;
|
|
276
|
+
}
|
|
261
277
|
}
|
|
262
278
|
</style>
|
|
263
279
|
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* (docs/plans/figures-and-short-captions.md, decisions 1 and 4). One
|
|
5
5
|
* anatomy, below the picture, the LaTeX figure convention:
|
|
6
6
|
*
|
|
7
|
-
* Figure 2.2.1
|
|
7
|
+
* Figure 2.2.1 **‹short›.** ‹caption› ‹live end› [buttons]
|
|
8
8
|
*
|
|
9
|
-
* The number links to the float
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* The number links to the float; hovering or focusing it shows its toolbar,
|
|
10
|
+
* whose Copy link copies that link (`float-toolbar.ts`). The caption is the
|
|
11
|
+
* float's one long caption. A float
|
|
12
12
|
* with a short caption opens the caption with it as a bold title,
|
|
13
13
|
* `b.float-caption__title` (decision 9.1), outside `.float-caption__text`, so
|
|
14
14
|
* a reader of the long caption (a preview card, a fold's bar) still reads
|
|
@@ -65,19 +65,6 @@ const tools = Astro.slots.has('default') ? (await Astro.slots.render('default'))
|
|
|
65
65
|
</a>
|
|
66
66
|
)
|
|
67
67
|
}
|
|
68
|
-
<a
|
|
69
|
-
class="float-caption__anchor"
|
|
70
|
-
href={`#${anchorId}`}
|
|
71
|
-
aria-label={`Copy the link to ${name}`}
|
|
72
|
-
title="Copy link"
|
|
73
|
-
data-copy-link={name}
|
|
74
|
-
>
|
|
75
|
-
<svg aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="currentColor"
|
|
76
|
-
><path
|
|
77
|
-
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"
|
|
78
|
-
></path></svg
|
|
79
|
-
>
|
|
80
|
-
</a>
|
|
81
68
|
{short && <b class="float-caption__title">{captionTitle(short)}</b>}{short && ' '}<span
|
|
82
69
|
class:list={['float-caption__text', `${prefix}__caption-text`]}
|
|
83
70
|
id={textId}
|