Learn: per-stage Open-in-Astrolabe hand-off links

This commit is contained in:
2026-07-04 19:43:15 +03:00
parent 194177c0c5
commit 42717fe4f7
2 changed files with 25 additions and 0 deletions
+13
View File
@@ -102,6 +102,19 @@
min-height: 180px;
}
/* The per-stage hand-off into the app: the stage's spec, self-contained, as a
snippet — opened in a new tab so the lesson keeps its place. */
.openLink {
display: inline-block;
margin-top: var(--space-3);
font-size: 13px;
color: var(--accent);
text-decoration: none;
}
.openLink:hover {
text-decoration: underline;
}
.note {
padding: var(--space-4) var(--space-5);
border-top: 1px solid var(--border);
+12
View File
@@ -2,6 +2,7 @@ import { useId, useMemo, useRef, useState, type KeyboardEvent, type ReactNode }
import type { Config } from 'vega-lite';
import { injectDatasets, type ProgressionStage } from '@core/lesson-parse';
import { formatSpec } from '@core/json-format';
import { specLinkHref } from '@core/spec-link';
import { changedLines } from '@core/spec-diff';
import { LandingChart } from '../landing/LandingChart';
import { Markdown } from './Markdown';
@@ -66,6 +67,14 @@ export function SpecProgression({
const activeStage = stages[active];
// Hand-off into the app (spec §01E → one-shot action links): the link carries
// the *injected* spec — the app has no lesson datasets, so the snippet must
// arrive self-contained even though the source pane shows data by name.
const openHref = useMemo(
() => specLinkHref(formatSpec(injectDatasets(activeStage.spec, datasets))),
[activeStage, datasets],
);
return (
<div className={styles.progression}>
<div
@@ -119,6 +128,9 @@ export function SpecProgression({
config={config}
className={styles.chart}
/>
<a className={styles.openLink} href={openHref} target="_blank" rel="noopener">
Open this stage in Astrolabe
</a>
</div>
</div>
<Markdown className={styles.note} source={activeStage.note} />