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
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
stripNotationMarkers,
|
|
11
11
|
} from '../../reference/math-glyphs.mjs';
|
|
12
12
|
import type { GlyphScopeEntry } from '../../reference/gloss';
|
|
13
|
+
import type { DerivedUse, IndexedSymbol } from '../../reference/types';
|
|
13
14
|
|
|
14
15
|
interface HastText {
|
|
15
16
|
type: 'text';
|
|
@@ -284,14 +285,27 @@ function sanitizeNode(node: HastNode): SafeMathNode {
|
|
|
284
285
|
throw new Error(`Unexpected KaTeX node: ${node.type}.`);
|
|
285
286
|
}
|
|
286
287
|
|
|
288
|
+
const properties = safeProperties(node);
|
|
287
289
|
return Object.freeze({
|
|
288
290
|
type: 'element',
|
|
289
291
|
tagName: node.tagName,
|
|
290
|
-
|
|
292
|
+
// KaTeX writes each formula twice, as MathML (with its LaTeX in an
|
|
293
|
+
// `<annotation>`) for assistive technology and as visible glyphs; the
|
|
294
|
+
// site search indexes the glyphs alone (`withSearchOnce`).
|
|
295
|
+
properties: withSearchOnce(properties),
|
|
291
296
|
children: Object.freeze(node.children.map(sanitizeNode)),
|
|
292
297
|
});
|
|
293
298
|
}
|
|
294
299
|
|
|
300
|
+
/** `data-pagefind-ignore` on KaTeX's MathML copy of a formula. */
|
|
301
|
+
function withSearchOnce(
|
|
302
|
+
properties: Readonly<Record<string, string>>,
|
|
303
|
+
): Readonly<Record<string, string>> {
|
|
304
|
+
return properties.class?.split(' ').includes('katex-mathml')
|
|
305
|
+
? Object.freeze({ ...properties, 'data-pagefind-ignore': '' })
|
|
306
|
+
: properties;
|
|
307
|
+
}
|
|
308
|
+
|
|
295
309
|
// Re-exported so existing imports of `stripNotationMarkers` from this module
|
|
296
310
|
// (the notation popup card's "Copy LaTeX" button) keep working. The
|
|
297
311
|
// implementation lives in `math-glyphs.mjs` because `remark-notation.mjs`
|
|
@@ -388,19 +402,34 @@ export function renderNotationMath(latex: string): readonly SafeMathNode[] {
|
|
|
388
402
|
export function renderNotationFormula(
|
|
389
403
|
formula: string,
|
|
390
404
|
scope: readonly GlyphScopeEntry[],
|
|
405
|
+
{ derive = false }: { readonly derive?: boolean } = {},
|
|
391
406
|
): {
|
|
392
407
|
readonly nodes: readonly SafeMathNode[];
|
|
408
|
+
/** The LaTeX `nodes` were rendered from: `formula` with its glyphs bound, or as written. */
|
|
409
|
+
readonly latex: string;
|
|
393
410
|
readonly unresolved: readonly string[];
|
|
394
411
|
readonly degraded: boolean;
|
|
412
|
+
/** Why the formula could not be bound, when `degraded`: the resolver's own message. */
|
|
413
|
+
readonly reason?: string;
|
|
414
|
+
/** With `derive` (page math, rule N23): the derived cards the formula uses. */
|
|
415
|
+
readonly derived: readonly DerivedUse[];
|
|
416
|
+
/** How each symbol with a subscript is explained (rule N23). */
|
|
417
|
+
readonly indices: readonly IndexedSymbol[];
|
|
395
418
|
} {
|
|
396
419
|
let bound = formula;
|
|
397
420
|
let unresolved: string[] = [];
|
|
398
421
|
let degraded = false;
|
|
422
|
+
let reason: string | undefined;
|
|
423
|
+
let derived: DerivedUse[] = [];
|
|
424
|
+
let indices: IndexedSymbol[] = [];
|
|
399
425
|
try {
|
|
400
|
-
const result = resolveMathGlyphs(formula, [...scope]);
|
|
426
|
+
const result = resolveMathGlyphs(formula, [...scope], { derive });
|
|
401
427
|
bound = result.latex;
|
|
402
428
|
unresolved = result.unresolved.map(({ token }: { token: string }) => token);
|
|
429
|
+
derived = result.derived;
|
|
430
|
+
indices = result.indices;
|
|
403
431
|
} catch (error) {
|
|
432
|
+
reason = error instanceof Error ? error.message : String(error);
|
|
404
433
|
// N13 (a nonlinear function with no parenthesized argument) is a hard,
|
|
405
434
|
// no-exceptions rule like N9 — never degrade it to inert math, so both
|
|
406
435
|
// `Diagram` (which turns `degraded` into a build error anyway, but with
|
|
@@ -417,11 +446,28 @@ export function renderNotationFormula(
|
|
|
417
446
|
degraded = true;
|
|
418
447
|
}
|
|
419
448
|
|
|
449
|
+
const why = reason === undefined ? {} : { reason };
|
|
420
450
|
try {
|
|
421
|
-
return {
|
|
422
|
-
|
|
451
|
+
return {
|
|
452
|
+
nodes: renderNotationMath(bound),
|
|
453
|
+
latex: bound,
|
|
454
|
+
unresolved,
|
|
455
|
+
degraded,
|
|
456
|
+
...why,
|
|
457
|
+
derived,
|
|
458
|
+
indices,
|
|
459
|
+
};
|
|
460
|
+
} catch (error) {
|
|
423
461
|
// A marker that KaTeX or the sanitizer rejects must not cost the reader
|
|
424
462
|
// the equation itself.
|
|
425
|
-
return {
|
|
463
|
+
return {
|
|
464
|
+
nodes: renderNotationMath(formula),
|
|
465
|
+
latex: formula,
|
|
466
|
+
unresolved,
|
|
467
|
+
degraded: true,
|
|
468
|
+
reason: reason ?? (error instanceof Error ? error.message : String(error)),
|
|
469
|
+
derived: [],
|
|
470
|
+
indices: [],
|
|
471
|
+
};
|
|
426
472
|
}
|
|
427
473
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An element's text as a reader sees it. KaTeX writes each formula three ways
|
|
3
|
+
* — MathML, its LaTeX `<annotation>` and its `aria-hidden` glyphs — so a
|
|
4
|
+
* heading's `textContent` reads `R\explain{motion.range}{R}R`; this reads the
|
|
5
|
+
* formula once, from its MathML, as `rehype-heading-anchors.mjs` does for the
|
|
6
|
+
* heading link's label.
|
|
7
|
+
*/
|
|
8
|
+
export function readableText(element: Element): string {
|
|
9
|
+
let text = '';
|
|
10
|
+
const walk = (node: Node): void => {
|
|
11
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
12
|
+
text += node.textContent ?? '';
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
16
|
+
const child = node as Element;
|
|
17
|
+
if (child.localName === 'annotation' || child.classList.contains('katex-html')) return;
|
|
18
|
+
child.childNodes.forEach(walk);
|
|
19
|
+
};
|
|
20
|
+
walk(element);
|
|
21
|
+
return text
|
|
22
|
+
.replace(/[-]/g, '')
|
|
23
|
+
.replace(/\s+/g, ' ')
|
|
24
|
+
.trim();
|
|
25
|
+
}
|
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
* - otherwise a card floats near the reference showing its number,
|
|
23
23
|
* caption (table/figure), content, and a "Go to …" link, whose arrow
|
|
24
24
|
* says where it lands (`../card-jump.ts`): ↑ / ↓ on this page, → with the
|
|
25
|
-
* lesson's name on another one.
|
|
25
|
+
* lesson's name on another one. The float's number heads the card's
|
|
26
|
+
* title, "Equation (1.1.3)", "Figure 2.1.1", and the link then says only
|
|
27
|
+
* "Go to the figure". A figure's picture is 80% of its width in the
|
|
28
|
+
* article. A click on the
|
|
26
29
|
* reference pins the card, a second one closes it (the card manager's
|
|
27
30
|
* contract, `../card-manager.ts`); the card's own links navigate.
|
|
28
31
|
*
|
|
@@ -60,7 +63,8 @@
|
|
|
60
63
|
*
|
|
61
64
|
* One card per referenced float, several at once; the card manager places
|
|
62
65
|
* them clear of every other open card, and a symbol inside a card opens its
|
|
63
|
-
* notation card as a child of it
|
|
66
|
+
* notation card as a child of it — in a card from another page, as that
|
|
67
|
+
* page explains it (`markForeign`), even a symbol this page never uses.
|
|
64
68
|
*/
|
|
65
69
|
import HoverPanel from '../HoverPanel.astro';
|
|
66
70
|
---
|
|
@@ -68,23 +72,30 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
68
72
|
<HoverPanel id="float-ref-panel" label="Reference preview" data-float-ref-panel>
|
|
69
73
|
<p class="float-ref-panel-title" slot="heading">
|
|
70
74
|
<span class="float-ref-panel-kind" data-panel-kind></span>
|
|
75
|
+
<a class="float-ref-panel-number" data-panel-number></a>
|
|
71
76
|
<span class="float-ref-panel-heading" data-panel-heading hidden></span>
|
|
72
77
|
</p>
|
|
73
78
|
<div class="float-ref-panel-body">
|
|
74
|
-
<div class="float-ref-panel-
|
|
75
|
-
<div class="float-ref-panel-content" data-panel-content></div>
|
|
76
|
-
<a class="float-ref-panel-number" data-panel-number></a>
|
|
77
|
-
</div>
|
|
79
|
+
<div class="float-ref-panel-content" data-panel-content></div>
|
|
78
80
|
<p class="float-ref-panel-caption" data-panel-caption></p>
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
<p class="float-ref-panel-links">
|
|
82
|
+
<a class="float-ref-panel-jump hover-panel-action" data-panel-jump
|
|
83
|
+
>Go to <span data-panel-jump-label></span
|
|
84
|
+
><span aria-hidden="true" data-jump-arrow> →</span></a
|
|
85
|
+
>
|
|
86
|
+
</p>
|
|
83
87
|
</div>
|
|
84
88
|
</HoverPanel>
|
|
85
89
|
|
|
86
90
|
<script>
|
|
87
91
|
import { cloneCardShell, isKept, registerCardSource } from '../card-manager';
|
|
92
|
+
import {
|
|
93
|
+
ensureKatexStylesheet,
|
|
94
|
+
fetchDoc,
|
|
95
|
+
isThisPage,
|
|
96
|
+
markForeign,
|
|
97
|
+
pageTitleOf,
|
|
98
|
+
} from '../card-fetch';
|
|
88
99
|
import { wireJumpArrow } from '../card-jump';
|
|
89
100
|
|
|
90
101
|
interface KindConfig {
|
|
@@ -120,6 +131,7 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
120
131
|
// equation, not a hover preview of it — same principle as the table
|
|
121
132
|
// preview below never offering its live pagination/expand controls.
|
|
122
133
|
clone.querySelector('.keyed-equation__controls')?.remove();
|
|
134
|
+
clone.querySelector('[data-eq-copy]')?.remove();
|
|
123
135
|
return clone;
|
|
124
136
|
}
|
|
125
137
|
|
|
@@ -234,8 +246,8 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
234
246
|
* decision 12). The body is the picture alone — a lab's tools sit in a tray
|
|
235
247
|
* outside it. A hydrated island in it (a lab's plot) becomes plain markup,
|
|
236
248
|
* so it never hydrates a second time inside the card: its plot is copied as
|
|
237
|
-
* drawn
|
|
238
|
-
*
|
|
249
|
+
* drawn, or, before the island has drawn and on a fetched page, the
|
|
250
|
+
* picture the build drew (rule V3). A picture with nothing drawn at all
|
|
239
251
|
* gives no copy, and the card shows the caption alone.
|
|
240
252
|
*/
|
|
241
253
|
function cloneFigureBody(target: HTMLElement): HTMLElement | null {
|
|
@@ -248,7 +260,21 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
248
260
|
still.append(...island.childNodes);
|
|
249
261
|
island.replaceWith(still);
|
|
250
262
|
}
|
|
251
|
-
clone.querySelectorAll('script, template
|
|
263
|
+
clone.querySelectorAll('script, template').forEach((node) => node.remove());
|
|
264
|
+
// What an island was given as children sits in an `<astro-slot>`: a
|
|
265
|
+
// lab's build-time picture, the one a fetched page or a figure not yet
|
|
266
|
+
// drawn has (rule V3). Keep it, without the wrapper, unless the island
|
|
267
|
+
// has already drawn its own picture beside it.
|
|
268
|
+
for (const slot of clone.querySelectorAll('astro-slot, astro-static-slot')) {
|
|
269
|
+
const drawnBeside = Array.from(slot.parentElement?.children ?? []).some(
|
|
270
|
+
(sibling) =>
|
|
271
|
+
sibling !== slot &&
|
|
272
|
+
!sibling.matches('astro-slot, astro-static-slot') &&
|
|
273
|
+
sibling.querySelector('svg, img, picture, canvas, video') !== null,
|
|
274
|
+
);
|
|
275
|
+
if (drawnBeside) slot.remove();
|
|
276
|
+
else slot.replaceWith(...Array.from(slot.childNodes));
|
|
277
|
+
}
|
|
252
278
|
const drawn = clone.querySelector('svg, img, picture, canvas, video, table');
|
|
253
279
|
if (islands.length > 0 && !drawn) return null;
|
|
254
280
|
for (const control of clone.querySelectorAll<HTMLElement>('input, select, textarea, button')) {
|
|
@@ -259,6 +285,35 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
259
285
|
return clone;
|
|
260
286
|
}
|
|
261
287
|
|
|
288
|
+
/**
|
|
289
|
+
* A figure's picture in a card is 80% of its width in the article. On this
|
|
290
|
+
* page that width is measured on the figure. A fetched page has no layout,
|
|
291
|
+
* so its copy is laid out unseen in this page's article, where every
|
|
292
|
+
* lesson's figures take the same width, and measured there.
|
|
293
|
+
*/
|
|
294
|
+
const FIGURE_CARD_SCALE = 0.8;
|
|
295
|
+
const PICTURE = ':is(svg:not(.katex *), img, canvas, video)';
|
|
296
|
+
|
|
297
|
+
function figureCardWidth(target: HTMLElement, clone: HTMLElement): number | null {
|
|
298
|
+
let width = 0;
|
|
299
|
+
if (target.ownerDocument === document) {
|
|
300
|
+
width =
|
|
301
|
+
target.querySelector(`.keyed-figure__body ${PICTURE}`)?.getBoundingClientRect().width ?? 0;
|
|
302
|
+
}
|
|
303
|
+
if (!(width > 0)) {
|
|
304
|
+
const article = document.querySelector<HTMLElement>('.main-pane .sl-markdown-content');
|
|
305
|
+
if (article) {
|
|
306
|
+
const probe = document.createElement('div');
|
|
307
|
+
probe.style.cssText = 'height:0;overflow:hidden;visibility:hidden';
|
|
308
|
+
probe.append(clone);
|
|
309
|
+
article.append(probe);
|
|
310
|
+
width = clone.querySelector(PICTURE)?.getBoundingClientRect().width ?? 0;
|
|
311
|
+
probe.remove();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return width > 0 ? Math.round(width * FIGURE_CARD_SCALE) : null;
|
|
315
|
+
}
|
|
316
|
+
|
|
262
317
|
/** A copy with no ids, so a preview never collides with the page. */
|
|
263
318
|
function importWithoutIds(node: Node): Node {
|
|
264
319
|
const clone = document.importNode(node, true);
|
|
@@ -359,6 +414,11 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
359
414
|
fillContent(target, contentEl) {
|
|
360
415
|
const previewable = target.dataset.figPreviewable !== 'false';
|
|
361
416
|
const clone = previewable ? cloneFigureBody(target) : null;
|
|
417
|
+
const width = clone ? figureCardWidth(target, clone) : null;
|
|
418
|
+
if (clone && width) {
|
|
419
|
+
clone.style.width = `${width}px`;
|
|
420
|
+
clone.style.maxWidth = '100%';
|
|
421
|
+
}
|
|
362
422
|
contentEl.replaceChildren(...(clone ? [clone] : []));
|
|
363
423
|
},
|
|
364
424
|
captionFor(target) {
|
|
@@ -469,9 +529,35 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
469
529
|
return node instanceof Element ? node.closest<HTMLElement>(selector) : null;
|
|
470
530
|
}
|
|
471
531
|
|
|
532
|
+
/**
|
|
533
|
+
* A reference's kind, or the kind of a float whose own number this is (the
|
|
534
|
+
* number's toolbar hangs the float's card from it, `float-toolbar.ts`).
|
|
535
|
+
*/
|
|
472
536
|
function kindOf(trigger: HTMLElement): KindConfig | undefined {
|
|
473
|
-
return Object.values(KINDS).find(
|
|
474
|
-
|
|
537
|
+
return Object.values(KINDS).find(
|
|
538
|
+
(kind) =>
|
|
539
|
+
trigger.classList.contains(kind.triggerClass) ||
|
|
540
|
+
(kind.numberClass !== '' && trigger.classList.contains(kind.numberClass)),
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/** The kind an anchor names: by its prefix, else a section's heading. */
|
|
545
|
+
function kindOfId(id: string): KindConfig {
|
|
546
|
+
return (
|
|
547
|
+
Object.values(KINDS).find(
|
|
548
|
+
(kind) => kind.hrefPrefix !== '#' && id.startsWith(kind.hrefPrefix.slice(1)),
|
|
549
|
+
) ?? KINDS.section
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/** A float's own number on this page, for `item` (`eq-range`, `fig-…`). */
|
|
554
|
+
function ownNumber(item: string): HTMLElement | null {
|
|
555
|
+
const kind = Object.values(KINDS).find(
|
|
556
|
+
(candidate) => candidate.numberClass !== '' && item.startsWith(candidate.hrefPrefix.slice(1)),
|
|
557
|
+
);
|
|
558
|
+
if (!kind) return null;
|
|
559
|
+
return (
|
|
560
|
+
document.getElementById(item)?.querySelector<HTMLElement>(`a.${kind.numberClass}`) ?? null
|
|
475
561
|
);
|
|
476
562
|
}
|
|
477
563
|
|
|
@@ -494,61 +580,23 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
494
580
|
return { page: href.slice(0, hash), id };
|
|
495
581
|
}
|
|
496
582
|
|
|
497
|
-
/**
|
|
498
|
-
* Parsed target pages, keyed by path. A cross-page preview fetches the
|
|
499
|
-
* referenced lesson once and reuses it for every later hover on this page.
|
|
500
|
-
* A failed fetch drops its entry so a later hover can retry.
|
|
501
|
-
*/
|
|
502
|
-
const pageCache = new Map<string, Promise<Document>>();
|
|
503
|
-
|
|
504
583
|
/** A standalone lesson deliberately has no other course pages to fetch. */
|
|
505
584
|
const standalone = document.documentElement.hasAttribute(
|
|
506
585
|
'data-explico-standalone',
|
|
507
586
|
);
|
|
508
587
|
|
|
509
|
-
function fetchDoc(page: string): Promise<Document> {
|
|
510
|
-
let pending = pageCache.get(page);
|
|
511
|
-
if (!pending) {
|
|
512
|
-
pending = fetch(page, { credentials: 'same-origin' })
|
|
513
|
-
.then((response) => {
|
|
514
|
-
if (!response.ok) throw new Error(`${response.status} for ${page}`);
|
|
515
|
-
return response.text();
|
|
516
|
-
})
|
|
517
|
-
.then((html) => new DOMParser().parseFromString(html, 'text/html'))
|
|
518
|
-
.catch((error) => {
|
|
519
|
-
pageCache.delete(page);
|
|
520
|
-
throw error;
|
|
521
|
-
});
|
|
522
|
-
pageCache.set(page, pending);
|
|
523
|
-
}
|
|
524
|
-
return pending;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* A cloned equation preview needs KaTeX's stylesheet to render. Every page
|
|
529
|
-
* that *authors* math already loads it; this only matters for a page whose
|
|
530
|
-
* sole math is a cross-page reference, so copy the `<link>` from the fetched
|
|
531
|
-
* document when this one has none.
|
|
532
|
-
*/
|
|
533
|
-
function ensureKatexStylesheet(sourceDoc: Document): void {
|
|
534
|
-
const selector = 'link[rel="stylesheet"][href*="katex"]';
|
|
535
|
-
if (document.querySelector(selector)) return;
|
|
536
|
-
const link = sourceDoc.querySelector<HTMLLinkElement>(selector);
|
|
537
|
-
if (link) document.head.appendChild(document.importNode(link, true));
|
|
538
|
-
}
|
|
539
|
-
|
|
540
588
|
const capitalized = (text: string) =>
|
|
541
589
|
`${text.charAt(0).toUpperCase()}${text.slice(1)}`;
|
|
542
590
|
|
|
543
|
-
/** The number link's text: `(2.1)
|
|
591
|
+
/** The number link's text: `Equation (2.1)`, `Table 2.1`, `§ 1.1.2`, …; empty hides it. */
|
|
544
592
|
function numberText(kind: KindConfig, number: string): string {
|
|
545
593
|
if (kind.numberLabel) return kind.numberLabel(number);
|
|
546
594
|
return kind.jumpLabel === 'equation'
|
|
547
|
-
? `(${number})`
|
|
595
|
+
? `Equation (${number})`
|
|
548
596
|
: `${capitalized(kind.jumpLabel)} ${number}`;
|
|
549
597
|
}
|
|
550
598
|
|
|
551
|
-
/** What the card
|
|
599
|
+
/** What the card previews, for its label (C15): `equation (1.4)`, `table 2.1`, `the section`. */
|
|
552
600
|
function goToLabel(kind: KindConfig, number: string): string {
|
|
553
601
|
if (!number) return `the ${kind.jumpLabel}`;
|
|
554
602
|
return kind.jumpLabel === 'equation'
|
|
@@ -584,8 +632,9 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
584
632
|
return targetFor(trigger, kind) || crossPageHref(trigger, kind) ? trigger : null;
|
|
585
633
|
};
|
|
586
634
|
|
|
587
|
-
|
|
588
|
-
|
|
635
|
+
// Every page registers, with references or none: its floats' numbers
|
|
636
|
+
// pin and dock their own cards (`float-toolbar.ts`), and a card carried
|
|
637
|
+
// in from another page is built here (rule K5).
|
|
589
638
|
shell.dataset.cardSourceReady = 'true';
|
|
590
639
|
|
|
591
640
|
/**
|
|
@@ -680,19 +729,26 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
680
729
|
|
|
681
730
|
const number = target.dataset[kind.numberDataKey] ?? '';
|
|
682
731
|
const href = trigger.getAttribute('href') ?? '';
|
|
683
|
-
const
|
|
732
|
+
const named = goToLabel(kind, number);
|
|
684
733
|
kindEl.textContent = capitalized(kind.jumpLabel);
|
|
685
734
|
headingEl.textContent = kind.shortDataKey
|
|
686
735
|
? (target.dataset[kind.shortDataKey] ?? '')
|
|
687
736
|
: '';
|
|
688
737
|
headingEl.hidden = headingEl.textContent.length === 0;
|
|
689
|
-
// The
|
|
690
|
-
//
|
|
738
|
+
// The float is named by its number in the card's title, "Equation
|
|
739
|
+
// (2.1)", "Figure 2.1", in place of its kind, so the link below need
|
|
740
|
+
// not repeat it. The number is itself a link to the float.
|
|
691
741
|
numberEl.textContent = numberText(kind, number);
|
|
692
742
|
numberEl.hidden = numberEl.textContent.length === 0;
|
|
693
743
|
numberEl.href = href;
|
|
694
744
|
numberEl.title = `Go to the ${kind.jumpLabel}`;
|
|
745
|
+
kindEl.hidden = !numberEl.hidden;
|
|
746
|
+
const goTo = `the ${kind.jumpLabel}`;
|
|
695
747
|
kind.fillContent(target, contentEl);
|
|
748
|
+
el.toggleAttribute(
|
|
749
|
+
'data-panel-picture',
|
|
750
|
+
kind.jumpLabel === 'figure' && !!contentEl.querySelector('svg, img, picture, canvas, video'),
|
|
751
|
+
);
|
|
696
752
|
// A term cloned from another page still carries its no-JS tooltip.
|
|
697
753
|
for (const term of contentEl.querySelectorAll('a.notation-term[title]')) {
|
|
698
754
|
term.removeAttribute('title');
|
|
@@ -702,7 +758,7 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
702
758
|
jumpLabelEl.textContent = lesson ? `${goTo} in ${lesson}` : goTo;
|
|
703
759
|
jumpEl.href = href;
|
|
704
760
|
wireJumpArrow(jumpEl);
|
|
705
|
-
el.setAttribute('aria-label', `Preview of ${
|
|
761
|
+
el.setAttribute('aria-label', `Preview of ${named}`);
|
|
706
762
|
return el;
|
|
707
763
|
};
|
|
708
764
|
|
|
@@ -734,9 +790,8 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
734
790
|
const target = sourceDoc.getElementById(crossPage.id);
|
|
735
791
|
if (!target) return null;
|
|
736
792
|
ensureKatexStylesheet(sourceDoc);
|
|
737
|
-
const
|
|
738
|
-
|
|
739
|
-
el?.setAttribute('data-card-foreign', '');
|
|
793
|
+
const el = buildCard(trigger, target, kind, pageTitleOf(sourceDoc));
|
|
794
|
+
if (el) markForeign(el, sourceDoc, crossPage.page);
|
|
740
795
|
return el;
|
|
741
796
|
});
|
|
742
797
|
};
|
|
@@ -761,6 +816,27 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
761
816
|
return !!target && !isFullyVisible(target);
|
|
762
817
|
},
|
|
763
818
|
render,
|
|
819
|
+
ownAnchor: ownNumber,
|
|
820
|
+
// K5: `eq-range` names this page's equation; elsewhere it is
|
|
821
|
+
// `/its/page/#eq-range`, the name a cross-page reference gives it.
|
|
822
|
+
awayItem: (item, page) => (item.includes('#') ? item : `${page}#${item}`),
|
|
823
|
+
build: (item, page) => {
|
|
824
|
+
const hash = item.indexOf('#');
|
|
825
|
+
const targetPage = hash === -1 ? page : item.slice(0, hash);
|
|
826
|
+
const id = hash === -1 ? item : item.slice(hash + 1);
|
|
827
|
+
const kind = kindOfId(id);
|
|
828
|
+
return fetchDoc(targetPage).then((sourceDoc) => {
|
|
829
|
+
const target = sourceDoc.getElementById(id);
|
|
830
|
+
if (!target) return null;
|
|
831
|
+
ensureKatexStylesheet(sourceDoc);
|
|
832
|
+
const here = isThisPage(targetPage);
|
|
833
|
+
const link = document.createElement('a');
|
|
834
|
+
link.setAttribute('href', here ? `#${id}` : `${targetPage}#${id}`);
|
|
835
|
+
const el = buildCard(link, target, kind, here ? undefined : pageTitleOf(sourceDoc));
|
|
836
|
+
if (el && !here) markForeign(el, sourceDoc, targetPage);
|
|
837
|
+
return el;
|
|
838
|
+
});
|
|
839
|
+
},
|
|
764
840
|
onChange: (open) => {
|
|
765
841
|
for (const [item, bar] of foldMarks) {
|
|
766
842
|
if (open.has(item)) continue;
|
|
@@ -825,23 +901,11 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
825
901
|
gap: 0.6rem;
|
|
826
902
|
}
|
|
827
903
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
min-width: 0;
|
|
831
|
-
/* Center, not baseline: a tall equation's own baseline sits wherever
|
|
832
|
-
its glyphs put it, which for a fraction or multi-row expression can
|
|
833
|
-
be well above center — baseline-aligning the number to that point
|
|
834
|
-
would leave it looking pinned near the top of the card, seemingly
|
|
835
|
-
above the equation, instead of beside it. */
|
|
836
|
-
align-items: center;
|
|
837
|
-
justify-content: space-between;
|
|
838
|
-
gap: 0.75rem;
|
|
839
|
-
}
|
|
840
|
-
|
|
904
|
+
/* A float's number in the title, in place of its kind: "Equation
|
|
905
|
+
(1.1.3)", "Figure 2.1.1". */
|
|
841
906
|
.float-ref-panel-number {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
color: var(--sl-color-gray-3);
|
|
907
|
+
color: var(--sl-color-gray-2);
|
|
908
|
+
font-size: var(--sl-text-xs);
|
|
845
909
|
font-weight: 600;
|
|
846
910
|
font-variant-numeric: tabular-nums;
|
|
847
911
|
text-decoration: none;
|
|
@@ -857,7 +921,6 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
857
921
|
`viewBox` alone, or a table in its scroll clip, has no width of its
|
|
858
922
|
own to give a card that sizes itself to its content. */
|
|
859
923
|
.float-ref-panel-content {
|
|
860
|
-
flex: 1 1 auto;
|
|
861
924
|
min-width: 0;
|
|
862
925
|
overflow-x: auto;
|
|
863
926
|
/* `overflow-x: auto` alone makes the block axis compute to `auto` too
|
|
@@ -877,10 +940,6 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
877
940
|
min-inline-size: min(22rem, 70vw);
|
|
878
941
|
}
|
|
879
942
|
|
|
880
|
-
.float-ref-panel-content :global(.katex-display) {
|
|
881
|
-
margin-block: 0;
|
|
882
|
-
}
|
|
883
|
-
|
|
884
943
|
.float-ref-panel-content :global(table) {
|
|
885
944
|
margin: 0;
|
|
886
945
|
/* 60% of the real table's own font-size (`global.css`'s
|
|
@@ -920,6 +979,12 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
920
979
|
font-size: var(--sl-text-xs);
|
|
921
980
|
}
|
|
922
981
|
|
|
982
|
+
/* A figure card is as wide as its picture: the caption wraps under it
|
|
983
|
+
rather than widening the card to fit its own line. */
|
|
984
|
+
:global(.hover-panel[data-panel-picture]) .float-ref-panel-caption {
|
|
985
|
+
contain: inline-size;
|
|
986
|
+
}
|
|
987
|
+
|
|
923
988
|
.float-ref-panel-heading {
|
|
924
989
|
font-weight: 600;
|
|
925
990
|
font-size: var(--sl-text-sm);
|
|
@@ -943,9 +1008,17 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
943
1008
|
font-size: var(--sl-text-sm);
|
|
944
1009
|
}
|
|
945
1010
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1011
|
+
/* The card's links in one row: "Go to …", and a kept card's "Opened
|
|
1012
|
+
at …" beside it (rule K7, `card-manager.ts`). */
|
|
1013
|
+
.float-ref-panel-links {
|
|
1014
|
+
margin: 0;
|
|
949
1015
|
}
|
|
950
1016
|
}
|
|
1017
|
+
|
|
1018
|
+
/* Outside the layer: `katex.css` is unlayered, and its
|
|
1019
|
+
`.katex-display { margin: 1em 0 }` beats any layered rule, so inside
|
|
1020
|
+
`@layer` this left the equation 1em of air above and below. */
|
|
1021
|
+
.float-ref-panel-content :global(.katex-display) {
|
|
1022
|
+
margin-block: 0;
|
|
1023
|
+
}
|
|
951
1024
|
</style>
|
|
@@ -23,11 +23,12 @@
|
|
|
23
23
|
* still navigates, so the hash and the highlight below follow as before;
|
|
24
24
|
* a clipboard that is missing or refuses leaves exactly that navigation.
|
|
25
25
|
* On hover the icon says "Copy link", a title this script sets, since
|
|
26
|
-
* only with it does a click copy. A float's
|
|
27
|
-
*
|
|
28
|
-
* named by its number and short caption — "Link copied ·
|
|
29
|
-
* Projectile trajectory explorer", pasted as "Figure
|
|
30
|
-
* trajectory explorer"; its landing is
|
|
26
|
+
* only with it does a click copy. A float's Copy link, in the toolbar
|
|
27
|
+
* its number shows (`a[data-copy-link]`, `float-toolbar.ts`), copies the
|
|
28
|
+
* same way, named by its number and short caption — "Link copied ·
|
|
29
|
+
* Figure 2.2.1 · Projectile trajectory explorer", pasted as "Figure
|
|
30
|
+
* 2.2.1, Projectile trajectory explorer"; its landing is
|
|
31
|
+
* `KeyedFloatEnhancer`'s;
|
|
31
32
|
* - a smooth, header-aware scroll on an in-page jump;
|
|
32
33
|
* - a brief highlight of the section body (the heading's following siblings up
|
|
33
34
|
* to the next heading of equal or higher rank), so a deep link lands the
|
|
@@ -57,6 +58,7 @@
|
|
|
57
58
|
import { HEADINGS, sectionParts } from './section-parts';
|
|
58
59
|
import { animatedScrollIntoView } from '../scroll-animation';
|
|
59
60
|
import { floatOf } from '../float-name';
|
|
61
|
+
import { readableText } from '../readable-text';
|
|
60
62
|
|
|
61
63
|
(() => {
|
|
62
64
|
const root = document.querySelector('.sl-markdown-content');
|
|
@@ -161,15 +163,18 @@
|
|
|
161
163
|
const titled = heading.querySelector('.block-heading__title') ?? heading;
|
|
162
164
|
return {
|
|
163
165
|
label,
|
|
164
|
-
title: short || (titled
|
|
166
|
+
title: short || readableText(titled),
|
|
165
167
|
};
|
|
166
168
|
};
|
|
167
169
|
|
|
170
|
+
// A float's copy link (its number's toolbar, `float-toolbar.ts`): named
|
|
171
|
+
// by its number, then its short caption, an equation's `\caption{}` too.
|
|
168
172
|
const floatName = (link: HTMLElement): LinkName => {
|
|
169
173
|
const root = link.closest('figure');
|
|
174
|
+
const equation = link.closest<HTMLElement>('.keyed-equation');
|
|
170
175
|
return {
|
|
171
176
|
label: link.dataset.copyLink ?? '',
|
|
172
|
-
title: (root && floatOf(root)?.short) || '',
|
|
177
|
+
title: (root && floatOf(root)?.short) || equation?.dataset.eqShort || '',
|
|
173
178
|
};
|
|
174
179
|
};
|
|
175
180
|
|
|
@@ -258,7 +263,7 @@
|
|
|
258
263
|
root.addEventListener('click', (event) => {
|
|
259
264
|
const origin = event.target instanceof Element ? event.target : null;
|
|
260
265
|
|
|
261
|
-
// A float's
|
|
266
|
+
// A float's copy link: copy, confirm, and let the click navigate.
|
|
262
267
|
const floatLink = origin?.closest<HTMLElement>('a[data-copy-link]');
|
|
263
268
|
const floatHref = floatLink?.getAttribute('href') || '';
|
|
264
269
|
if (floatLink && floatHref.startsWith('#')) {
|