explico 0.8.0 → 0.11.1
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 +1257 -1
- package/README.md +60 -15
- package/dist/compiler/astro.d.ts +6 -1
- package/dist/compiler/cli.d.ts +46 -2
- package/dist/compiler/cli.js +70 -4
- package/dist/compiler/collections.d.ts +35 -2
- package/dist/compiler/collections.js +68 -5
- 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 +4 -1
- package/dist/compiler/logging.js +4 -1
- 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 +3 -2
- 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 +60 -31
- package/dist/reference/equations.mjs +83 -43
- 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 +1 -0
- 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 +45 -21
- 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 +22 -6
- package/dist/reference/gate-math.js +42 -8
- 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 +21 -11
- package/dist/reference/gate-prose-notation.js +25 -7
- package/dist/reference/katex-delimiters.mjs +20 -7
- 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 +572 -37
- 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 +4 -4
- 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 +17 -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 +5 -3
- 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 +1152 -2
- package/docs/authoring/notation.md +576 -322
- 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/package.json +2 -2
- package/src/compiler/cli.ts +116 -6
- package/src/compiler/collections.ts +111 -7
- 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 +8 -2
- 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 +3 -4
- package/src/components/notation/NotationLayer.astro +169 -162
- package/src/components/notation/NotationMath.astro +10 -1
- package/src/components/reference/FloatRefLayer.astro +485 -423
- package/src/components/starlight/AboutPanel.astro +5 -4
- 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 +3 -2
- package/src/reference/diagrams-validate.ts +17 -1
- package/src/reference/equations-validate.ts +10 -5
- package/src/reference/equations.mjs +83 -43
- 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 +1 -0
- package/src/reference/gate-course-rules.ts +134 -0
- package/src/reference/gate-heading-length.ts +66 -35
- package/src/reference/gate-heading-structure.ts +193 -0
- package/src/reference/gate-math-punctuation.ts +381 -0
- package/src/reference/gate-math.ts +69 -10
- package/src/reference/gate-part-pages.ts +217 -0
- package/src/reference/gate-prose-notation.ts +59 -12
- package/src/reference/katex-delimiters.mjs +20 -7
- 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 +572 -37
- 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 +16 -31
- 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 +17 -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 +1467 -163
- package/src/styles/surfaces.css +182 -0
- package/src/components/hover-panel.ts +0 -339
- package/src/components/popup-stack.ts +0 -345
|
@@ -42,16 +42,25 @@ export interface Props {
|
|
|
42
42
|
* links to reveal an explanation on hover.
|
|
43
43
|
*/
|
|
44
44
|
presentation?: 'full' | 'panel';
|
|
45
|
-
/** Author-chosen state for a reader with nothing saved yet. Default: `false` (closed) —
|
|
45
|
+
/** Author-chosen state for a reader with nothing saved yet. Default: `false` (closed) — from the course's `disclosure.notation` (`CourseConfig.disclosure`). */
|
|
46
46
|
defaultOpen?: boolean;
|
|
47
47
|
/** Persist the reader's open/closed choice across visits, per page. Default: `true`. */
|
|
48
48
|
rememberState?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Decorations this page says are not operators (`notation.suspend`, rule
|
|
51
|
+
* N22), shown at the top of the list so a reader who knows `'` as the
|
|
52
|
+
* derivative is told it means something else here.
|
|
53
|
+
*/
|
|
54
|
+
suspended?: readonly NotationSuspension[];
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
import HoverPanel from '../HoverPanel.astro';
|
|
51
58
|
import NotationMath from './NotationMath.astro';
|
|
52
59
|
import NotationFormula from './NotationFormula.astro';
|
|
53
60
|
import { stripNotationMarkers } from './render-notation-math';
|
|
61
|
+
import { operatorDisplayLatex } from '../../reference/math-glyphs.mjs';
|
|
54
62
|
import type { GlyphScopeEntry, ResolvedGloss } from '../../reference/gloss';
|
|
63
|
+
import type { NotationSuspension } from '../../reference/types';
|
|
55
64
|
|
|
56
65
|
const {
|
|
57
66
|
definitions,
|
|
@@ -61,6 +70,7 @@ const {
|
|
|
61
70
|
presentation = 'full',
|
|
62
71
|
defaultOpen = false,
|
|
63
72
|
rememberState = true,
|
|
73
|
+
suspended = [],
|
|
64
74
|
} = Astro.props;
|
|
65
75
|
|
|
66
76
|
const panelOnly = presentation === 'panel';
|
|
@@ -121,7 +131,7 @@ for (const gloss of glossItems) {
|
|
|
121
131
|
>
|
|
122
132
|
<div class="notation-list-titlebar">
|
|
123
133
|
<details
|
|
124
|
-
class="notation-list"
|
|
134
|
+
class="notation-list ex-tier-meta"
|
|
125
135
|
id={id}
|
|
126
136
|
hidden={panelOnly}
|
|
127
137
|
data-remember-state={String(rememberState)}
|
|
@@ -130,6 +140,28 @@ for (const gloss of glossItems) {
|
|
|
130
140
|
<summary>
|
|
131
141
|
{label} <span class="notation-count">({items.length})</span>
|
|
132
142
|
</summary>
|
|
143
|
+
{/* How the cards work, inside the panel: shown once the panel is
|
|
144
|
+
opened, not as three lines under every closed one. */}
|
|
145
|
+
{!panelOnly && (
|
|
146
|
+
<p class="notation-enhancement-help" data-notation-help hidden>
|
|
147
|
+
Point to a marked symbol or term, here or in the text, for a quick
|
|
148
|
+
explanation; a symbol inside an open card explains itself in a
|
|
149
|
+
card of its own. Click a symbol or term to keep its card open, and
|
|
150
|
+
click it again, use the card’s “×” or press Escape to close the
|
|
151
|
+
card.
|
|
152
|
+
</p>
|
|
153
|
+
)}
|
|
154
|
+
{!panelOnly && suspended.length > 0 && (
|
|
155
|
+
<ul class="notation-suspended" data-notation-suspended>
|
|
156
|
+
{suspended.map((item) => (
|
|
157
|
+
<li>
|
|
158
|
+
On this page,{' '}
|
|
159
|
+
<NotationMath latex={operatorDisplayLatex(item.operator)} /> is
|
|
160
|
+
not an operator.{item.reason ? ` ${item.reason}` : ''}
|
|
161
|
+
</li>
|
|
162
|
+
))}
|
|
163
|
+
</ul>
|
|
164
|
+
)}
|
|
133
165
|
<dl>
|
|
134
166
|
{items.map((definition) => (
|
|
135
167
|
<div
|
|
@@ -232,54 +264,44 @@ for (const gloss of glossItems) {
|
|
|
232
264
|
)}
|
|
233
265
|
</div>
|
|
234
266
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
<
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
<button
|
|
252
|
-
class="notation-popup-close"
|
|
253
|
-
type="button"
|
|
254
|
-
data-popup-close
|
|
255
|
-
aria-label="Close"
|
|
267
|
+
<HoverPanel
|
|
268
|
+
id={`${id}-card`}
|
|
269
|
+
label="Notation"
|
|
270
|
+
class="notation-popup"
|
|
271
|
+
data-notation-popup
|
|
272
|
+
>
|
|
273
|
+
<div class="notation-panel-heading" slot="heading">
|
|
274
|
+
<span class="notation-panel-symbol" data-slot-symbol></span>
|
|
275
|
+
<h3 data-slot-title></h3>
|
|
276
|
+
</div>
|
|
277
|
+
<div class="notation-panel-body">
|
|
278
|
+
<p data-slot-summary hidden></p>
|
|
279
|
+
<div data-slot-formula hidden></div>
|
|
280
|
+
<p class="notation-units" data-slot-units hidden></p>
|
|
281
|
+
<a data-slot-link hidden
|
|
282
|
+
>Go to the full definition<span aria-hidden="true" data-jump-arrow> →</span></a
|
|
256
283
|
>
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
<div class="notation-panel-body">
|
|
260
|
-
<header class="notation-panel-heading">
|
|
261
|
-
<span class="notation-panel-symbol" data-slot-symbol />
|
|
262
|
-
<h3 data-slot-title />
|
|
263
|
-
</header>
|
|
264
|
-
<p data-slot-summary hidden />
|
|
265
|
-
<div data-slot-formula hidden />
|
|
266
|
-
<p class="notation-units" data-slot-units hidden />
|
|
267
|
-
<a data-slot-link hidden>
|
|
268
|
-
Open the full definition
|
|
269
|
-
</a>
|
|
270
|
-
</div>
|
|
271
|
-
</aside>
|
|
272
|
-
</template>
|
|
284
|
+
</div>
|
|
285
|
+
</HoverPanel>
|
|
273
286
|
</section>
|
|
274
287
|
)
|
|
275
288
|
}
|
|
276
289
|
|
|
277
290
|
<script>
|
|
278
|
-
import {
|
|
291
|
+
import {
|
|
292
|
+
cloneCardShell,
|
|
293
|
+
isKept,
|
|
294
|
+
registerCardSource,
|
|
295
|
+
} from '../card-manager';
|
|
296
|
+
import { wireJumpArrow } from '../card-jump';
|
|
279
297
|
import { wirePersistedDetails } from '../disclosure/persisted-disclosure';
|
|
280
298
|
|
|
281
299
|
const triggerSelector = '[data-notation-key]';
|
|
282
300
|
|
|
301
|
+
function closestElement(node: EventTarget | null, selector: string) {
|
|
302
|
+
return node instanceof Element ? node.closest<HTMLElement>(selector) : null;
|
|
303
|
+
}
|
|
304
|
+
|
|
283
305
|
function setOptionalText(element: HTMLElement, value: string) {
|
|
284
306
|
element.textContent = value;
|
|
285
307
|
element.hidden = value.length === 0;
|
|
@@ -299,18 +321,19 @@ for (const gloss of glossItems) {
|
|
|
299
321
|
if (entries.size === 0) return;
|
|
300
322
|
|
|
301
323
|
const template = root.querySelector<HTMLTemplateElement>(
|
|
302
|
-
'[data-
|
|
324
|
+
'template[data-card-template]',
|
|
303
325
|
);
|
|
304
326
|
if (!template) return;
|
|
305
327
|
|
|
306
328
|
// Static triggers, computed once: markers embedded in prose or an
|
|
307
329
|
// equation, and the symbol glyphs in the "Notation used on this page"
|
|
308
330
|
// list. These get the always-on `.notation-trigger` cursor/hover
|
|
309
|
-
// treatment. Symbols that appear *inside a
|
|
310
|
-
// D15) are not in this list —
|
|
311
|
-
// exist — but they still work
|
|
312
|
-
// them live, and the shared
|
|
313
|
-
// `:global`, further down)
|
|
331
|
+
// treatment. Symbols that appear *inside a card* (a card's own formula,
|
|
332
|
+
// D15, or an equation a reference card previews) are not in this list —
|
|
333
|
+
// there's no bound on how many of those can exist — but they still work
|
|
334
|
+
// as triggers: `symbolFrom` below finds them live, and the shared
|
|
335
|
+
// `[data-notation-key]:hover` rule (declared `:global`, further down)
|
|
336
|
+
// already paints them the same way.
|
|
314
337
|
const externalTriggers = Array.from(
|
|
315
338
|
document.querySelectorAll<HTMLElement>(triggerSelector),
|
|
316
339
|
).filter(
|
|
@@ -327,14 +350,19 @@ for (const gloss of glossItems) {
|
|
|
327
350
|
for (const trigger of highlightTargets) {
|
|
328
351
|
trigger.classList.add('notation-trigger');
|
|
329
352
|
}
|
|
353
|
+
// C13: a `[[key]]` term's `title` is its no-JavaScript explanation; with
|
|
354
|
+
// the card here it would only be a second tooltip on top of it.
|
|
355
|
+
for (const term of externalTriggers) {
|
|
356
|
+
if (term.matches('a.notation-term')) term.removeAttribute('title');
|
|
357
|
+
}
|
|
330
358
|
const help = root.querySelector<HTMLElement>('[data-notation-help]');
|
|
331
359
|
if (help) help.hidden = false;
|
|
332
360
|
|
|
333
361
|
// The visible list's own symbol glyphs are the only keyboard path to
|
|
334
|
-
// pinning a card from this list
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
//
|
|
362
|
+
// pinning a card from this list — make them a real, labelled,
|
|
363
|
+
// Enter/Space-operable control rather than a mouse-only `<span>`.
|
|
364
|
+
// `symbolTriggers` (defined above) is already scoped to entries inside
|
|
365
|
+
// this list.
|
|
338
366
|
for (const trigger of symbolTriggers) {
|
|
339
367
|
const key = trigger.dataset.notationKey ?? '';
|
|
340
368
|
const entryLabel =
|
|
@@ -351,18 +379,9 @@ for (const gloss of glossItems) {
|
|
|
351
379
|
});
|
|
352
380
|
}
|
|
353
381
|
|
|
354
|
-
const keyFor = (element: HTMLElement | null) =>
|
|
355
|
-
element?.dataset.notationKey ?? element?.dataset.notationLink ?? null;
|
|
356
|
-
|
|
357
|
-
const staticLinkFrom = (node: EventTarget | null) => {
|
|
358
|
-
const candidate = closestElement(node, '[data-notation-link]');
|
|
359
|
-
return candidate && root.contains(candidate) ? candidate : null;
|
|
360
|
-
};
|
|
361
|
-
|
|
362
382
|
// A symbol trigger, wherever it lives: prose, the equation, the visible
|
|
363
|
-
// list, or — the D15 case
|
|
364
|
-
//
|
|
365
|
-
// live: a popup's content doesn't exist until the reader opens it.
|
|
383
|
+
// list, or — the D15 case — inside an open card. This has to be live: a
|
|
384
|
+
// card's content doesn't exist until the reader opens it.
|
|
366
385
|
const symbolFrom = (node: EventTarget | null) => {
|
|
367
386
|
const candidate = closestElement(node, triggerSelector);
|
|
368
387
|
if (!candidate || candidate.closest('.katex-mathml')) return null;
|
|
@@ -371,36 +390,27 @@ for (const gloss of glossItems) {
|
|
|
371
390
|
: null;
|
|
372
391
|
};
|
|
373
392
|
|
|
374
|
-
const triggerFrom = (node: EventTarget | null) =>
|
|
375
|
-
staticLinkFrom(node) ?? symbolFrom(node);
|
|
376
|
-
|
|
377
393
|
const labelOf = (entry: HTMLElement, key: string) =>
|
|
378
394
|
entry
|
|
379
395
|
.querySelector<HTMLElement>('[data-notation-link]')
|
|
380
396
|
?.textContent?.trim() ?? key;
|
|
381
397
|
|
|
382
|
-
const
|
|
398
|
+
const buildCard = (key: string) => {
|
|
383
399
|
const entry = entries.get(key);
|
|
384
400
|
if (!entry) return null;
|
|
385
401
|
|
|
386
|
-
const
|
|
387
|
-
const
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
const
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
);
|
|
394
|
-
const formulaHost = fragment.querySelector<HTMLElement>(
|
|
395
|
-
'[data-slot-formula]',
|
|
396
|
-
);
|
|
397
|
-
const units = fragment.querySelector<HTMLElement>('[data-slot-units]');
|
|
398
|
-
const link =
|
|
399
|
-
fragment.querySelector<HTMLAnchorElement>('[data-slot-link]');
|
|
402
|
+
const el = cloneCardShell(template);
|
|
403
|
+
const symbolHost = el?.querySelector<HTMLElement>('[data-slot-symbol]');
|
|
404
|
+
const title = el?.querySelector<HTMLElement>('[data-slot-title]');
|
|
405
|
+
const summary = el?.querySelector<HTMLElement>('[data-slot-summary]');
|
|
406
|
+
const formulaHost = el?.querySelector<HTMLElement>('[data-slot-formula]');
|
|
407
|
+
const units = el?.querySelector<HTMLElement>('[data-slot-units]');
|
|
408
|
+
const link = el?.querySelector<HTMLAnchorElement>('[data-slot-link]');
|
|
400
409
|
if (!el || !symbolHost || !title || !summary || !formulaHost || !units) {
|
|
401
410
|
return null;
|
|
402
411
|
}
|
|
403
412
|
|
|
413
|
+
el.dataset.popupKey = key;
|
|
404
414
|
el.setAttribute('aria-label', `Notation: ${labelOf(entry, key)}`);
|
|
405
415
|
|
|
406
416
|
const sourceSymbol = entry.querySelector<HTMLElement>('.notation-symbol');
|
|
@@ -431,30 +441,28 @@ for (const gloss of glossItems) {
|
|
|
431
441
|
?.textContent?.trim() ?? '',
|
|
432
442
|
);
|
|
433
443
|
|
|
434
|
-
// A gloss has no
|
|
444
|
+
// A gloss has no entry to go to. Its own card is the whole of it.
|
|
435
445
|
const href = entry.dataset.notationHref;
|
|
436
446
|
if (link) {
|
|
437
447
|
link.hidden = href === undefined;
|
|
438
|
-
if (href !== undefined)
|
|
448
|
+
if (href !== undefined) {
|
|
449
|
+
link.href = href;
|
|
450
|
+
wireJumpArrow(link);
|
|
451
|
+
}
|
|
439
452
|
}
|
|
440
453
|
|
|
441
454
|
return el;
|
|
442
455
|
};
|
|
443
456
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
groupId: 'notation',
|
|
454
|
-
triggerFrom,
|
|
455
|
-
keyFor,
|
|
456
|
-
createPopup,
|
|
457
|
-
onChange: (open, pinned) => {
|
|
457
|
+
// The card manager mounts every card in one layer on `<body>`, never in
|
|
458
|
+
// the article: an ancestor's stacking context once let the Starlight
|
|
459
|
+
// right sidebar eat a card's clicks.
|
|
460
|
+
registerCardSource({
|
|
461
|
+
layer: 'notation',
|
|
462
|
+
triggerFrom: symbolFrom,
|
|
463
|
+
itemFor: (trigger) => trigger.dataset.notationKey ?? null,
|
|
464
|
+
render: (key) => buildCard(key),
|
|
465
|
+
onChange: (open) => {
|
|
458
466
|
for (const trigger of highlightTargets) {
|
|
459
467
|
trigger.classList.toggle(
|
|
460
468
|
'is-notation-active',
|
|
@@ -462,10 +470,8 @@ for (const gloss of glossItems) {
|
|
|
462
470
|
);
|
|
463
471
|
}
|
|
464
472
|
for (const trigger of symbolTriggers) {
|
|
465
|
-
trigger.
|
|
466
|
-
|
|
467
|
-
String(pinned.has(trigger.dataset.notationKey ?? '')),
|
|
468
|
-
);
|
|
473
|
+
const mode = open.get(trigger.dataset.notationKey ?? '');
|
|
474
|
+
trigger.setAttribute('aria-pressed', String(!!mode && isKept(mode)));
|
|
469
475
|
}
|
|
470
476
|
},
|
|
471
477
|
});
|
|
@@ -560,7 +566,7 @@ for (const gloss of glossItems) {
|
|
|
560
566
|
// delegation needs.
|
|
561
567
|
document.addEventListener('mouseover', (event) => {
|
|
562
568
|
const origin = event.target instanceof Element ? event.target : null;
|
|
563
|
-
if (!origin || origin.getAttribute('title')
|
|
569
|
+
if (!origin || origin.getAttribute('title')?.startsWith('Copy LaTeX')) return;
|
|
564
570
|
if (
|
|
565
571
|
origin.closest(
|
|
566
572
|
'[data-notation-key], [data-notation-formula-copy], .notation-formula-number',
|
|
@@ -568,14 +574,20 @@ for (const gloss of glossItems) {
|
|
|
568
574
|
) {
|
|
569
575
|
return;
|
|
570
576
|
}
|
|
571
|
-
|
|
572
|
-
|
|
577
|
+
const formula = origin.closest<HTMLElement>('[data-notation-formula]');
|
|
578
|
+
if (!formula) return;
|
|
579
|
+
// "Copy LaTeX — ‹entry label›", the same title as the copy button.
|
|
580
|
+
origin.setAttribute('title', formula.dataset.copyTitle ?? 'Copy LaTeX');
|
|
581
|
+
origin.setAttribute('data-copy-hint', '');
|
|
573
582
|
});
|
|
574
583
|
|
|
575
584
|
document.addEventListener('mouseout', (event) => {
|
|
576
585
|
const origin = event.target instanceof Element ? event.target : null;
|
|
577
|
-
|
|
586
|
+
// Only a title this script added — the copy button's own static
|
|
587
|
+
// `title` must survive the pointer leaving it (or crossing onto its icon).
|
|
588
|
+
if (origin?.hasAttribute('data-copy-hint')) {
|
|
578
589
|
origin.removeAttribute('title');
|
|
590
|
+
origin.removeAttribute('data-copy-hint');
|
|
579
591
|
}
|
|
580
592
|
});
|
|
581
593
|
</script>
|
|
@@ -594,20 +606,16 @@ for (const gloss of glossItems) {
|
|
|
594
606
|
}
|
|
595
607
|
|
|
596
608
|
/* Positioning context for `.notation-list-anchor`, mirroring
|
|
597
|
-
`
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
it would there). */
|
|
609
|
+
`Memo.astro`'s frame — the anchor link is a DOM sibling of `<details>`,
|
|
610
|
+
not nested inside `<summary>` (a focusable `<a>` inside `<summary>`
|
|
611
|
+
trips axe's `nested-interactive` check). */
|
|
601
612
|
.notation-list-titlebar {
|
|
602
613
|
position: relative;
|
|
603
614
|
}
|
|
604
615
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
background: var(--sl-color-gray-7);
|
|
609
|
-
}
|
|
610
|
-
|
|
616
|
+
/* `.notation-list` itself has no box styles: the panel is page
|
|
617
|
+
logistics, and the meta tier (`ex-tier-meta`, `surfaces.css`) draws
|
|
618
|
+
its surface, border and radius. */
|
|
611
619
|
.notation-list > summary {
|
|
612
620
|
padding: 0.8rem 1rem;
|
|
613
621
|
padding-inline-end: 2.2rem;
|
|
@@ -671,6 +679,18 @@ for (const gloss of glossItems) {
|
|
|
671
679
|
padding: 0 1rem 1rem;
|
|
672
680
|
}
|
|
673
681
|
|
|
682
|
+
.notation-suspended {
|
|
683
|
+
margin: 0;
|
|
684
|
+
padding: 0 1rem 0.85rem;
|
|
685
|
+
list-style: none;
|
|
686
|
+
color: var(--sl-color-gray-2);
|
|
687
|
+
font-size: var(--sl-text-sm);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.notation-suspended li + li {
|
|
691
|
+
margin-top: 0.35rem;
|
|
692
|
+
}
|
|
693
|
+
|
|
674
694
|
.notation-entry {
|
|
675
695
|
display: grid;
|
|
676
696
|
grid-template-columns: minmax(9rem, 0.65fr) minmax(12rem, 1.35fr);
|
|
@@ -768,61 +788,21 @@ for (const gloss of glossItems) {
|
|
|
768
788
|
}
|
|
769
789
|
|
|
770
790
|
.notation-enhancement-help {
|
|
771
|
-
margin: 0
|
|
791
|
+
margin: 0 0 0.75rem;
|
|
792
|
+
padding: 0 1rem;
|
|
772
793
|
font-size: var(--sl-text-xs);
|
|
773
794
|
}
|
|
774
795
|
|
|
775
|
-
/* Each open explanation is its own
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
and a
|
|
781
|
-
.notation-popup {
|
|
782
|
-
position: fixed;
|
|
783
|
-
z-index: 100;
|
|
784
|
-
margin: 0;
|
|
785
|
-
width: min(23rem, calc(100vw - 1.5rem));
|
|
786
|
-
overflow: auto;
|
|
787
|
-
padding-block: 0.75rem;
|
|
788
|
-
padding-inline: 1rem 2.4rem;
|
|
789
|
-
border: 1px solid var(--sl-color-gray-5);
|
|
790
|
-
border-top: 0.25rem solid var(--sl-color-accent);
|
|
791
|
-
border-radius: 0.65rem;
|
|
792
|
-
color: var(--sl-color-text);
|
|
793
|
-
background: var(--sl-color-bg);
|
|
794
|
-
box-shadow: var(--sl-shadow-lg);
|
|
795
|
-
/* Relative to the surrounding prose's own font-size, not a fixed
|
|
796
|
-
Starlight step — the card is mounted on `<body>`, alongside the
|
|
797
|
-
article rather than nested inside it, so `%` still resolves against
|
|
798
|
-
the same base the article's paragraphs use. */
|
|
796
|
+
/* Each open explanation is its own card, cloned from the `HoverPanel`
|
|
797
|
+
shell above and mounted by the card manager (`card-manager.ts`) on
|
|
798
|
+
`<body>`. Relative to the surrounding prose's own font-size, not a
|
|
799
|
+
fixed Starlight step: `%` resolves against the same base the article's
|
|
800
|
+
paragraphs use. `.notation-panel-body` and its descendants below style
|
|
801
|
+
the fields common to both this static list and a card's content. */
|
|
802
|
+
.notation-popup.hover-panel {
|
|
799
803
|
font-size: 90%;
|
|
800
804
|
}
|
|
801
805
|
|
|
802
|
-
.notation-popup-close {
|
|
803
|
-
position: absolute;
|
|
804
|
-
top: 0.5rem;
|
|
805
|
-
right: 0.5rem;
|
|
806
|
-
width: 1.6rem;
|
|
807
|
-
height: 1.6rem;
|
|
808
|
-
display: flex;
|
|
809
|
-
align-items: center;
|
|
810
|
-
justify-content: center;
|
|
811
|
-
padding: 0;
|
|
812
|
-
border: 0;
|
|
813
|
-
border-radius: 0.35rem;
|
|
814
|
-
color: var(--sl-color-gray-3);
|
|
815
|
-
background: transparent;
|
|
816
|
-
font-size: 1.15rem;
|
|
817
|
-
line-height: 1;
|
|
818
|
-
cursor: pointer;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
.notation-popup-close:hover {
|
|
822
|
-
color: var(--sl-color-text);
|
|
823
|
-
background: var(--sl-color-gray-6);
|
|
824
|
-
}
|
|
825
|
-
|
|
826
806
|
/* Symbols inside a card's formula are click/hover-through triggers for
|
|
827
807
|
another card — the D15 case this whole file exists for. */
|
|
828
808
|
.notation-panel-body [data-slot-formula] :global([data-notation-key]) {
|
|
@@ -901,6 +881,33 @@ for (const gloss of glossItems) {
|
|
|
901
881
|
pointer-events: none;
|
|
902
882
|
}
|
|
903
883
|
|
|
884
|
+
/* An accent's glyph box (`\hat`, `\dot`, `\vec`, …) is a full line tall and
|
|
885
|
+
painted over the letter it decorates, so it took every hover on that
|
|
886
|
+
letter: under an operator entry (rule N22) `\dot{x}` showed the dot's
|
|
887
|
+
card wherever the reader pointed. The glyph box lets the pointer through,
|
|
888
|
+
and a strip across the top of the decorated form — where KaTeX puts the
|
|
889
|
+
accent's ink, since the vlist's height is the accent's top — is the
|
|
890
|
+
accent's hit area instead. It sits inside the decorated form's trigger
|
|
891
|
+
and outside the letter's, so the letter shows its card and the accent
|
|
892
|
+
shows the operator's. Measured over 14 accents on short, tall and
|
|
893
|
+
subscripted letters; rendering is pixel-identical. */
|
|
894
|
+
:global(.katex-html .accent-body) {
|
|
895
|
+
pointer-events: none;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
:global(.katex-html .accent > .vlist-t > .vlist-r > .vlist) {
|
|
899
|
+
position: relative;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
:global(.katex-html .accent > .vlist-t > .vlist-r > .vlist::after) {
|
|
903
|
+
content: '';
|
|
904
|
+
position: absolute;
|
|
905
|
+
inset-inline: -0.1em;
|
|
906
|
+
top: 0;
|
|
907
|
+
height: 0.25em;
|
|
908
|
+
pointer-events: auto;
|
|
909
|
+
}
|
|
910
|
+
|
|
904
911
|
:global(.katex-html [data-notation-key]) {
|
|
905
912
|
cursor: help;
|
|
906
913
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { renderNotationMath } from './render-notation-math';
|
|
3
3
|
import SafeMathNode from './SafeMathNode.astro';
|
|
4
|
+
import {
|
|
5
|
+
decorationOfEntry,
|
|
6
|
+
operatorDisplayLatex,
|
|
7
|
+
} from '../../reference/math-glyphs.mjs';
|
|
4
8
|
|
|
5
9
|
interface Props {
|
|
6
10
|
latex: string;
|
|
@@ -8,7 +12,12 @@ interface Props {
|
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
const { latex, class: className } = Astro.props;
|
|
11
|
-
|
|
15
|
+
// An operator entry (`\dot{}`, rule N22) is shown over a placeholder square;
|
|
16
|
+
// on its own the decoration is a speck.
|
|
17
|
+
const operator = decorationOfEntry(latex);
|
|
18
|
+
const nodes = renderNotationMath(
|
|
19
|
+
operator === undefined ? latex : operatorDisplayLatex(operator),
|
|
20
|
+
);
|
|
12
21
|
---
|
|
13
22
|
|
|
14
23
|
<span class:list={['notation-math', className]} data-notation-math>
|