explico 0.3.0 → 0.5.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 +344 -1
- package/README.md +117 -3
- package/dist/compiler/astro.d.ts +38 -0
- package/dist/compiler/astro.js +258 -0
- package/dist/compiler/cli.d.ts +13 -0
- package/dist/compiler/cli.js +32 -12
- package/dist/compiler/collections.d.ts +3 -2
- package/dist/compiler/collections.js +28 -1
- package/dist/compiler/course-config.d.ts +86 -4
- package/dist/compiler/course-config.js +39 -0
- package/dist/compiler/exports/standalone-html.d.ts +34 -0
- package/dist/compiler/exports/standalone-html.js +803 -0
- package/dist/compiler/lesson-derivation.d.ts +1 -1
- package/dist/compiler/lesson-derivation.js +2 -2
- package/dist/compiler/manifest.d.ts +112 -7
- package/dist/compiler/manifest.js +205 -40
- package/dist/compiler/resolution-report.d.ts +4 -0
- package/dist/reference/base-abbreviations.d.mts +30 -0
- package/dist/reference/base-abbreviations.mjs +60 -0
- package/dist/reference/base-operators.d.mts +15 -0
- package/dist/reference/base-operators.mjs +40 -0
- package/dist/reference/base-roman-labels.d.mts +35 -0
- package/dist/reference/base-roman-labels.mjs +43 -0
- package/dist/reference/consistency.d.ts +8 -2
- package/dist/reference/consistency.js +50 -3
- package/dist/reference/diagrams-validate.d.ts +21 -0
- package/dist/reference/diagrams-validate.js +13 -0
- package/dist/reference/equations-validate.d.ts +8 -3
- package/dist/reference/equations-validate.js +1 -1
- package/dist/reference/equations.d.mts +66 -35
- package/dist/reference/equations.mjs +142 -40
- package/dist/reference/gate-abbreviations.d.ts +17 -0
- package/dist/reference/gate-abbreviations.js +64 -0
- package/dist/reference/gate-math.d.ts +28 -5
- package/dist/reference/gate-math.js +5 -2
- package/dist/reference/gate-prose-notation.d.ts +60 -0
- package/dist/reference/gate-prose-notation.js +125 -0
- package/dist/reference/keyed-float-validate.d.ts +14 -8
- package/dist/reference/keyed-float-validate.js +1 -1
- package/dist/reference/keyed-jsx-floats.d.mts +24 -21
- package/dist/reference/keyed-jsx-floats.mjs +90 -41
- package/dist/reference/knowledge-checks-validate.d.ts +35 -0
- package/dist/reference/knowledge-checks-validate.js +78 -0
- package/dist/reference/knowledge-checks.d.mts +25 -0
- package/dist/reference/knowledge-checks.mjs +45 -0
- package/dist/reference/lab-math-scope.d.ts +9 -1
- package/dist/reference/lab-math-scope.js +32 -4
- package/dist/reference/math-glyphs.d.mts +30 -0
- package/dist/reference/math-glyphs.mjs +367 -0
- package/dist/reference/mdx-attributes.d.mts +13 -0
- package/dist/reference/mdx-attributes.mjs +38 -0
- package/dist/reference/mixed-content.d.ts +17 -0
- package/dist/reference/mixed-content.js +29 -0
- package/dist/reference/page-notation.d.ts +52 -0
- package/dist/reference/page-notation.js +171 -0
- package/dist/reference/raw-floats-validate.d.ts +18 -0
- package/dist/reference/raw-floats-validate.js +53 -0
- package/dist/reference/raw-floats.d.mts +18 -0
- package/dist/reference/raw-floats.mjs +129 -0
- package/dist/reference/rehype-heading-anchors.d.mts +1 -1
- package/dist/reference/rehype-heading-anchors.mjs +107 -1
- package/dist/reference/rehype-table-header-labels.d.mts +26 -0
- package/dist/reference/rehype-table-header-labels.mjs +152 -0
- package/dist/reference/remark-abbreviations.d.mts +7 -0
- package/dist/reference/remark-abbreviations.mjs +174 -0
- package/dist/reference/remark-memo.d.mts +16 -0
- package/dist/reference/remark-memo.mjs +339 -0
- package/dist/reference/remark-notation.d.mts +102 -5
- package/dist/reference/remark-notation.mjs +506 -50
- package/dist/reference/remark-short-note.d.mts +4 -0
- package/dist/reference/remark-short-note.mjs +237 -0
- package/dist/reference/types.d.ts +16 -1
- package/dist/reference/units-vocab.js +4 -0
- package/docs/VERSIONING.md +33 -4
- package/docs/authoring/README.md +12 -0
- package/docs/authoring/agents.md +17 -2
- package/docs/authoring/components.md +135 -0
- package/docs/authoring/migrating.md +154 -7
- package/docs/authoring/notation.md +568 -8
- package/docs/authoring/structure.md +251 -0
- package/docs/authoring/visualizations.md +36 -3
- package/package.json +5 -2
- package/src/compiler/astro.ts +332 -0
- package/src/compiler/cli.ts +33 -10
- package/src/compiler/collections.ts +45 -4
- package/src/compiler/course-config.ts +131 -3
- package/src/compiler/exports/standalone-html.ts +963 -0
- package/src/compiler/lesson-derivation.ts +2 -2
- package/src/compiler/manifest.ts +367 -49
- package/src/components/HoverPanel.astro +45 -4
- package/src/components/abbreviation/AbbreviationGlossary.astro +70 -0
- package/src/components/abbreviation/AbbreviationLayer.astro +127 -0
- package/src/components/assessments/AssessmentRunner.tsx +52 -17
- package/src/components/assessments/AssessmentSet.astro +98 -14
- package/src/components/assessments/RenderedContent.tsx +55 -0
- package/src/components/assessments/assessment-randomization.ts +16 -0
- package/src/components/diagram/Diagram.astro +444 -83
- package/src/components/disclosure/hover-preview.ts +202 -0
- package/src/components/disclosure/persisted-disclosure.ts +66 -0
- package/src/components/examples/CompactExamples.astro +2 -0
- package/src/components/figure/Figure.astro +279 -10
- package/src/components/memo/Memo.astro +453 -0
- package/src/components/memo/ShortNote.astro +223 -0
- package/src/components/notation/NotationFormula.astro +18 -1
- package/src/components/notation/NotationLayer.astro +116 -8
- package/src/components/notation/render-notation-math.ts +39 -2
- package/src/components/notation/safe-math-to-react.ts +50 -0
- package/src/components/reference/FloatRefLayer.astro +233 -15
- package/src/components/starlight/CollapsibleSections.astro +461 -0
- package/src/components/starlight/DiagramEnhancer.astro +385 -0
- package/src/components/starlight/HeadingAnchorEnhancer.astro +5 -17
- package/src/components/starlight/KeyedFloatEnhancer.astro +81 -3
- package/src/components/starlight/LayoutHeader.astro +50 -0
- package/src/components/starlight/LayoutSidebar.astro +62 -1
- package/src/components/starlight/LayoutSocialIcons.astro +41 -2
- package/src/components/starlight/LessonExportActions.astro +436 -0
- package/src/components/starlight/LessonFooter.astro +38 -2
- package/src/components/starlight/section-parts.ts +31 -0
- package/src/components/table/Table.astro +296 -9
- package/src/components/table/TableOverflowExpander.astro +489 -0
- package/src/content-config.ts +20 -0
- package/src/reference/base-abbreviations.mjs +60 -0
- package/src/reference/base-operators.mjs +40 -0
- package/src/reference/base-roman-labels.mjs +43 -0
- package/src/reference/consistency.ts +73 -2
- package/src/reference/diagrams-validate.ts +40 -0
- package/src/reference/equations-validate.ts +6 -4
- package/src/reference/equations.mjs +142 -40
- package/src/reference/gate-abbreviations.ts +128 -0
- package/src/reference/gate-math.ts +27 -7
- package/src/reference/gate-prose-notation.ts +224 -0
- package/src/reference/keyed-float-validate.ts +12 -9
- package/src/reference/keyed-jsx-floats.mjs +90 -41
- package/src/reference/knowledge-checks-validate.ts +130 -0
- package/src/reference/knowledge-checks.mjs +45 -0
- package/src/reference/lab-math-scope.ts +45 -3
- package/src/reference/math-glyphs.mjs +367 -0
- package/src/reference/mdx-attributes.mjs +38 -0
- package/src/reference/mixed-content.ts +69 -0
- package/src/reference/page-notation.ts +252 -0
- package/src/reference/raw-floats-validate.ts +103 -0
- package/src/reference/raw-floats.mjs +129 -0
- package/src/reference/rehype-heading-anchors.mjs +107 -1
- package/src/reference/rehype-table-header-labels.mjs +152 -0
- package/src/reference/remark-abbreviations.mjs +174 -0
- package/src/reference/remark-memo.mjs +339 -0
- package/src/reference/remark-notation.mjs +506 -50
- package/src/reference/remark-short-note.mjs +237 -0
- package/src/reference/types.ts +16 -0
- package/src/reference/units-vocab.ts +4 -0
- package/src/styles/global.css +1125 -50
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
/**
|
|
3
|
-
* Progressive enhancement for `[[eq-key]]` / `[[tab-key]]` / `[[fig-key]]`
|
|
3
|
+
* Progressive enhancement for `[[eq-key]]` / `[[tab-key]]` / `[[fig-key]]` /
|
|
4
|
+
* `[[dia-key]]`
|
|
4
5
|
* references in prose (F4, extended F-tables-figures) — one hover/pin/jump
|
|
5
|
-
* engine shared by all
|
|
6
|
+
* engine shared by all four keyed floats. This generalizes the original
|
|
6
7
|
* equation-only `EquationRefLayer`; the positioning, mutual-exclusion, and
|
|
7
8
|
* pin/jump/Escape mechanics are unchanged, parameterized over `KIND_CONFIG`
|
|
8
9
|
* below so a hover on any of the three trigger classes is handled the same
|
|
@@ -93,7 +94,10 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
93
94
|
clone.removeAttribute('data-eq-key');
|
|
94
95
|
clone.removeAttribute('data-eq-auto');
|
|
95
96
|
clone.classList.remove('keyed-equation', 'eq-ref-highlight');
|
|
96
|
-
|
|
97
|
+
// The number link and the "Copy LaTeX" button both belong on the real
|
|
98
|
+
// equation, not a hover preview of it — same principle as the table
|
|
99
|
+
// preview below never offering its live pagination/expand controls.
|
|
100
|
+
clone.querySelector('.keyed-equation__controls')?.remove();
|
|
97
101
|
return clone;
|
|
98
102
|
}
|
|
99
103
|
|
|
@@ -102,7 +106,104 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
102
106
|
return body ? document.importNode(body, true) : null;
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
// A table preview card is a static snapshot, not another place to keep
|
|
110
|
+
// paginating/expanding from — regardless of the live table's own current
|
|
111
|
+
// state (minimized, fully expanded, mid-scroll…) the clone always shows
|
|
112
|
+
// at most `KEEP_EACH_END * 2` rows with the "… N more rows …" separator
|
|
113
|
+
// centered, and never offers a way to reveal the rest or widen the table
|
|
114
|
+
// from inside the card (`Table.astro`'s own row-pagination and
|
|
115
|
+
// `TableOverflowExpander.astro`'s horizontal expand button, respectively —
|
|
116
|
+
// both belong on the real table, not a hover preview of it).
|
|
117
|
+
const TABLE_PREVIEW_KEEP_EACH_END = 3;
|
|
118
|
+
|
|
119
|
+
function capTablePreview(clone: HTMLElement): void {
|
|
120
|
+
const tbody = clone.querySelector('table')?.tBodies[0];
|
|
121
|
+
if (!tbody) return;
|
|
122
|
+
|
|
123
|
+
const moreRow = tbody.querySelector<HTMLElement>('.keyed-table__more-row');
|
|
124
|
+
const dataRows = Array.from(tbody.rows).filter((row) => row !== moreRow);
|
|
125
|
+
const totalRows = dataRows.length;
|
|
126
|
+
|
|
127
|
+
if (moreRow && totalRows > TABLE_PREVIEW_KEEP_EACH_END * 2) {
|
|
128
|
+
dataRows.forEach((row, index) => {
|
|
129
|
+
const inMiddle =
|
|
130
|
+
index >= TABLE_PREVIEW_KEEP_EACH_END &&
|
|
131
|
+
index < totalRows - TABLE_PREVIEW_KEEP_EACH_END;
|
|
132
|
+
row.hidden = inMiddle;
|
|
133
|
+
});
|
|
134
|
+
moreRow.hidden = false;
|
|
135
|
+
// `importNode` clones attributes (role/tabindex/class) but never JS
|
|
136
|
+
// listeners, so this row is already functionally inert here — strip
|
|
137
|
+
// the affordance too so it doesn't *look* clickable with nothing
|
|
138
|
+
// behind it.
|
|
139
|
+
moreRow.classList.remove('keyed-table__more-row--interactive');
|
|
140
|
+
moreRow.removeAttribute('role');
|
|
141
|
+
moreRow.removeAttribute('tabindex');
|
|
142
|
+
moreRow.removeAttribute('aria-label');
|
|
143
|
+
} else {
|
|
144
|
+
dataRows.forEach((row) => row.removeAttribute('hidden'));
|
|
145
|
+
moreRow?.remove();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// The pagination toggle/"Show less"/"Minimize" controls live outside
|
|
149
|
+
// `.keyed-table__body` (in the caption and after the body respectively),
|
|
150
|
+
// so cloning just the body already excludes them — only the horizontal
|
|
151
|
+
// overflow-expand button (`TableOverflowExpander.astro`) lives inside it.
|
|
152
|
+
clone
|
|
153
|
+
.querySelectorAll('.table-overflow-expand-btn')
|
|
154
|
+
.forEach((button) => button.remove());
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let diagramCloneSerial = 0;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* A diagram preview contains SVG fragment references (`url(#marker-id)`).
|
|
161
|
+
* Prefix every cloned id and rewrite those references so the preview cannot
|
|
162
|
+
* steal the moved/original diagram's arrow markers — or vice versa.
|
|
163
|
+
*/
|
|
164
|
+
function cloneDiagramBody(target: HTMLElement): HTMLElement | null {
|
|
165
|
+
const clone = cloneBody(target, 'diagram-scroll');
|
|
166
|
+
if (!clone) return null;
|
|
167
|
+
clone.removeAttribute('id');
|
|
168
|
+
clone.removeAttribute('tabindex');
|
|
169
|
+
clone.removeAttribute('aria-labelledby');
|
|
170
|
+
clone.setAttribute('aria-label', 'Diagram preview');
|
|
171
|
+
|
|
172
|
+
const prefix = `float-ref-diagram-${++diagramCloneSerial}-`;
|
|
173
|
+
const ids = new Map<string, string>();
|
|
174
|
+
for (const element of clone.querySelectorAll<HTMLElement>('[id]')) {
|
|
175
|
+
const oldId = element.id;
|
|
176
|
+
const nextId = `${prefix}${oldId}`;
|
|
177
|
+
ids.set(oldId, nextId);
|
|
178
|
+
element.id = nextId;
|
|
179
|
+
}
|
|
180
|
+
const referenceAttributes = [
|
|
181
|
+
'marker-start',
|
|
182
|
+
'marker-mid',
|
|
183
|
+
'marker-end',
|
|
184
|
+
'clip-path',
|
|
185
|
+
'mask',
|
|
186
|
+
'filter',
|
|
187
|
+
'fill',
|
|
188
|
+
'stroke',
|
|
189
|
+
'href',
|
|
190
|
+
'xlink:href',
|
|
191
|
+
];
|
|
192
|
+
for (const element of clone.querySelectorAll<HTMLElement>('*')) {
|
|
193
|
+
for (const attribute of referenceAttributes) {
|
|
194
|
+
const value = element.getAttribute(attribute);
|
|
195
|
+
if (!value) continue;
|
|
196
|
+
let rewritten = value;
|
|
197
|
+
for (const [oldId, nextId] of ids) {
|
|
198
|
+
rewritten = rewritten.split(`#${oldId}`).join(`#${nextId}`);
|
|
199
|
+
}
|
|
200
|
+
if (rewritten !== value) element.setAttribute(attribute, rewritten);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return clone;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const KINDS: Record<'equation' | 'table' | 'figure' | 'diagram', KindConfig> = {
|
|
106
207
|
equation: {
|
|
107
208
|
triggerClass: 'equation-ref',
|
|
108
209
|
hrefPrefix: '#eq-',
|
|
@@ -128,6 +229,7 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
128
229
|
revealOnPin: false,
|
|
129
230
|
fillContent(target, contentEl) {
|
|
130
231
|
const clone = cloneBody(target, 'keyed-table__body');
|
|
232
|
+
if (clone) capTablePreview(clone);
|
|
131
233
|
contentEl.replaceChildren(...(clone ? [clone] : []));
|
|
132
234
|
},
|
|
133
235
|
captionFor(target) {
|
|
@@ -155,6 +257,22 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
155
257
|
);
|
|
156
258
|
},
|
|
157
259
|
},
|
|
260
|
+
diagram: {
|
|
261
|
+
triggerClass: 'diagram-ref',
|
|
262
|
+
hrefPrefix: '#dia-',
|
|
263
|
+
numberClass: 'diagram__number',
|
|
264
|
+
numberDataKey: 'diaNumber',
|
|
265
|
+
highlightClass: 'dia-ref-highlight',
|
|
266
|
+
jumpLabel: 'diagram',
|
|
267
|
+
revealOnPin: false,
|
|
268
|
+
fillContent(target, contentEl) {
|
|
269
|
+
const clone = cloneDiagramBody(target);
|
|
270
|
+
contentEl.replaceChildren(...(clone ? [clone] : []));
|
|
271
|
+
},
|
|
272
|
+
captionFor(target) {
|
|
273
|
+
return target.querySelector('.diagram__caption-text')?.textContent ?? '';
|
|
274
|
+
},
|
|
275
|
+
},
|
|
158
276
|
};
|
|
159
277
|
|
|
160
278
|
const TRIGGER_SELECTOR = Object.values(KINDS)
|
|
@@ -197,6 +315,11 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
197
315
|
*/
|
|
198
316
|
const pageCache = new Map<string, Promise<Document>>();
|
|
199
317
|
|
|
318
|
+
/** A standalone lesson deliberately has no other course pages to fetch. */
|
|
319
|
+
const standalone = document.documentElement.hasAttribute(
|
|
320
|
+
'data-explico-standalone',
|
|
321
|
+
);
|
|
322
|
+
|
|
200
323
|
function fetchDoc(page: string): Promise<Document> {
|
|
201
324
|
let pending = pageCache.get(page);
|
|
202
325
|
if (!pending) {
|
|
@@ -232,6 +355,21 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
232
355
|
const panel = document.querySelector<HTMLElement>('[data-float-ref-panel]')!;
|
|
233
356
|
if (!panel || panel.dataset.floatRefReady === 'true') return;
|
|
234
357
|
|
|
358
|
+
// `.main-pane` (Starlight's `TwoColumnContent.astro`) sets
|
|
359
|
+
// `isolation: isolate`, which traps this panel's z-index inside it — the
|
|
360
|
+
// right "On this page" rail sits outside that isolation as a
|
|
361
|
+
// `position: fixed` sibling with no z-index of its own, and CSS still
|
|
362
|
+
// paints any positioned box ahead of a plain in-flow one regardless of
|
|
363
|
+
// z-index or DOM order. No z-index set here could ever win against that
|
|
364
|
+
// from inside `.main-pane`, so the panel is allowed to cover the rail
|
|
365
|
+
// (per its own design) by moving it out to `<body>` instead — the same
|
|
366
|
+
// fix the notation layer's popups already use for this exact trap (see
|
|
367
|
+
// `PopupStackConfig.container` in `popup-stack.ts`). `position: fixed`
|
|
368
|
+
// means the DOM parent doesn't affect its layout.
|
|
369
|
+
if (panel.parentElement !== document.body) {
|
|
370
|
+
document.body.appendChild(panel);
|
|
371
|
+
}
|
|
372
|
+
|
|
235
373
|
const refs = Array.from(
|
|
236
374
|
document.querySelectorAll<HTMLAnchorElement>(
|
|
237
375
|
Object.values(KINDS)
|
|
@@ -292,6 +430,32 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
292
430
|
target.querySelector(`.${kind.numberClass}`)?.classList.add('eq-number-revealed');
|
|
293
431
|
};
|
|
294
432
|
|
|
433
|
+
/**
|
|
434
|
+
* How much horizontal room the card may use: from the right edge of the
|
|
435
|
+
* left sidebar nav to the viewport edge. Unlike the old article-column
|
|
436
|
+
* clamp, this deliberately does not stop at the right "On this page"
|
|
437
|
+
* rail — a wide equation (e.g. an OLS estimator) needs the room more
|
|
438
|
+
* than the card needs to respect the ToC's column, and readers can
|
|
439
|
+
* still reach the ToC once the card closes.
|
|
440
|
+
*
|
|
441
|
+
* `.sidebar-pane` is `position: fixed` and reports its full-viewport
|
|
442
|
+
* geometry even while hidden below the sidebar breakpoint (Starlight
|
|
443
|
+
* hides it with `visibility`, not `display`), so that has to be checked
|
|
444
|
+
* explicitly rather than trusted from the rect alone.
|
|
445
|
+
*/
|
|
446
|
+
function horizontalRegion(edge: number): { start: number; end: number } {
|
|
447
|
+
const sidebarPane = document.querySelector<HTMLElement>('.sidebar-pane');
|
|
448
|
+
const sidebarVisible =
|
|
449
|
+
!!sidebarPane && getComputedStyle(sidebarPane).visibility !== 'hidden';
|
|
450
|
+
const sidebarRect = sidebarVisible
|
|
451
|
+
? sidebarPane!.getBoundingClientRect()
|
|
452
|
+
: null;
|
|
453
|
+
return {
|
|
454
|
+
start: Math.max(edge, sidebarRect?.right ?? edge),
|
|
455
|
+
end: window.innerWidth - edge,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
295
459
|
function position(trigger: HTMLElement) {
|
|
296
460
|
const edge = 12;
|
|
297
461
|
const gap = 10;
|
|
@@ -300,6 +464,16 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
300
464
|
const regionRect = safeRegion.getBoundingClientRect();
|
|
301
465
|
const anchorRect = trigger.getBoundingClientRect();
|
|
302
466
|
|
|
467
|
+
// Set before any width-dependent measurement below so the card has
|
|
468
|
+
// already grown (or not) to its final width by the time its rect is
|
|
469
|
+
// read for placement.
|
|
470
|
+
const { start: horizontalStart, end: horizontalEnd } =
|
|
471
|
+
horizontalRegion(edge);
|
|
472
|
+
panel.style.setProperty(
|
|
473
|
+
'--float-ref-max-width',
|
|
474
|
+
`${Math.max(horizontalEnd - horizontalStart, 0)}px`,
|
|
475
|
+
);
|
|
476
|
+
|
|
303
477
|
const headerBottom =
|
|
304
478
|
document
|
|
305
479
|
.querySelector<HTMLElement>('.header')
|
|
@@ -320,14 +494,6 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
320
494
|
: regionRect.top - gap - rect.height;
|
|
321
495
|
let left = anchorRect.left + anchorRect.width / 2 - rect.width / 2;
|
|
322
496
|
|
|
323
|
-
const article = document.querySelector<HTMLElement>('.sl-markdown-content');
|
|
324
|
-
const articleRect = article?.getBoundingClientRect();
|
|
325
|
-
const horizontalStart = Math.max(edge, articleRect?.left ?? edge);
|
|
326
|
-
const horizontalEnd = Math.min(
|
|
327
|
-
window.innerWidth - edge,
|
|
328
|
-
articleRect?.right ?? window.innerWidth - edge,
|
|
329
|
-
);
|
|
330
|
-
|
|
331
497
|
top = Math.max(verticalStart, Math.min(top, verticalEnd - rect.height));
|
|
332
498
|
left =
|
|
333
499
|
horizontalEnd - horizontalStart >= rect.width
|
|
@@ -391,6 +557,7 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
391
557
|
|
|
392
558
|
const crossPage = crossPageHref(trigger, kind);
|
|
393
559
|
if (crossPage) {
|
|
560
|
+
if (standalone) return;
|
|
394
561
|
void showCrossPage(trigger, kind, crossPage);
|
|
395
562
|
return;
|
|
396
563
|
}
|
|
@@ -533,6 +700,14 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
533
700
|
|
|
534
701
|
const isCrossPage = crossPageHref(trigger, kind) !== null;
|
|
535
702
|
|
|
703
|
+
// A diagram reference remains an ordinary navigation link. Hover may
|
|
704
|
+
// preview an off-screen diagram, but clicking must dismiss that card
|
|
705
|
+
// and take the reader to the real diagram in one gesture.
|
|
706
|
+
if (kind.jumpLabel === 'diagram' && !isCrossPage) {
|
|
707
|
+
clearAll();
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
|
|
536
711
|
// A card that is already open for this trigger — same-page *or*
|
|
537
712
|
// cross-page — pins in place instead of navigating. The only way to
|
|
538
713
|
// the float itself is now the card's own number/"Jump to …" link.
|
|
@@ -543,6 +718,12 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
543
718
|
}
|
|
544
719
|
|
|
545
720
|
if (isCrossPage) {
|
|
721
|
+
// The exporter rewrites this to the canonical course URL. Leave it
|
|
722
|
+
// as an ordinary link; an offline hover/click must never fetch it.
|
|
723
|
+
if (standalone) {
|
|
724
|
+
clearAll();
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
546
727
|
// No card open yet (keyboard, or a click that beat the hover): open
|
|
547
728
|
// it — pinned — rather than leave the page.
|
|
548
729
|
event.preventDefault();
|
|
@@ -599,7 +780,15 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
599
780
|
window.addEventListener(
|
|
600
781
|
'scroll',
|
|
601
782
|
() => {
|
|
602
|
-
if (mode
|
|
783
|
+
if (mode !== 'panel' || !activeTrigger) return;
|
|
784
|
+
if (
|
|
785
|
+
activeTarget?.ownerDocument === document &&
|
|
786
|
+
isFullyVisible(activeTarget)
|
|
787
|
+
) {
|
|
788
|
+
clearAll();
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
position(activeTrigger);
|
|
603
792
|
},
|
|
604
793
|
{ passive: true, capture: true },
|
|
605
794
|
);
|
|
@@ -613,19 +802,28 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
613
802
|
@layer starlight.components {
|
|
614
803
|
.float-ref-panel-body {
|
|
615
804
|
display: grid;
|
|
805
|
+
/* Grid items default to a content-based automatic minimum size, which
|
|
806
|
+
would let a wide equation inflate this track (and the card itself)
|
|
807
|
+
outward instead of scrolling inside `.float-ref-panel-content`. */
|
|
808
|
+
min-width: 0;
|
|
616
809
|
gap: 0.6rem;
|
|
617
810
|
}
|
|
618
811
|
|
|
619
812
|
.float-ref-panel-main {
|
|
620
813
|
display: flex;
|
|
621
|
-
|
|
814
|
+
min-width: 0;
|
|
815
|
+
/* Center, not baseline: a tall equation's own baseline sits wherever
|
|
816
|
+
its glyphs put it, which for a fraction or multi-row expression can
|
|
817
|
+
be well above center — baseline-aligning the number to that point
|
|
818
|
+
would leave it looking pinned near the top of the card, seemingly
|
|
819
|
+
above the equation, instead of beside it. */
|
|
820
|
+
align-items: center;
|
|
622
821
|
justify-content: space-between;
|
|
623
822
|
gap: 0.75rem;
|
|
624
823
|
}
|
|
625
824
|
|
|
626
825
|
.float-ref-panel-number {
|
|
627
826
|
flex: none;
|
|
628
|
-
align-self: flex-start;
|
|
629
827
|
margin: 0;
|
|
630
828
|
color: var(--sl-color-gray-3);
|
|
631
829
|
font-weight: 600;
|
|
@@ -642,6 +840,12 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
642
840
|
.float-ref-panel-content {
|
|
643
841
|
min-width: 0;
|
|
644
842
|
overflow-x: auto;
|
|
843
|
+
/* `overflow-x: auto` alone makes the block axis compute to `auto` too
|
|
844
|
+
(CSS Overflow §3), which would let a merely-tall equation grow its
|
|
845
|
+
own vertical scrollbar independent of the card's. Equations must
|
|
846
|
+
never scroll vertically on their own — only sideways, and only the
|
|
847
|
+
card as a whole. */
|
|
848
|
+
overflow-y: hidden;
|
|
645
849
|
color: var(--sl-color-text);
|
|
646
850
|
}
|
|
647
851
|
|
|
@@ -655,6 +859,20 @@ import HoverPanel from '../HoverPanel.astro';
|
|
|
655
859
|
|
|
656
860
|
.float-ref-panel-content :global(table) {
|
|
657
861
|
margin: 0;
|
|
862
|
+
/* 60% of the real table's own font-size (`global.css`'s
|
|
863
|
+
`.sl-markdown-content table` rule puts that at 90% of body text) —
|
|
864
|
+
this card sits outside `.sl-markdown-content` (moved to `<body>` at
|
|
865
|
+
runtime), so it's anchored to `--sl-text-base` directly rather than
|
|
866
|
+
inheriting that 90% rule. */
|
|
867
|
+
font-size: calc(var(--sl-text-base) * 0.9 * 0.6);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/* Same zebra striping formula as the real table
|
|
871
|
+
(`global.css`'s `.sl-markdown-content table … tbody tr:nth-child(even)`
|
|
872
|
+
rule), reproduced here because that rule is scoped to
|
|
873
|
+
`.sl-markdown-content`, which this cloned table sits outside of. */
|
|
874
|
+
.float-ref-panel-content :global(table tbody tr:nth-child(even)) {
|
|
875
|
+
background: color-mix(in srgb, var(--sl-color-bg) 85%, var(--sl-color-gray-5) 15%);
|
|
658
876
|
}
|
|
659
877
|
|
|
660
878
|
.float-ref-panel-caption {
|