3.2 KiB
11 — The Learning Section (/learn/)
An interactive deep-dive into Vega-Lite, served at /learn/: a marketing surface separate
from the app, where each lesson walks a spec from an 80%-naive version to a polished one to
teach the grammar's dormant power and funnel readers into the app.
A marketing surface, like the landing
/learn/ is a third Vite entry (learn/index.html → src/learn/) alongside the landing
(/) and the app (/app/), under the same marketing-surface rules:
- Reuses
src/coreand the landing'sLandingChartonly — never stores, modals, orchestration, or app components. Vega is lazy-loaded throughLandingChart, so the entry stays light. - Out of PWA scope. The service worker is scoped to
/app/, so the learning pages stay uncontrolled, always-fresh, and indexable — the point for organic-reach content.
Lessons are markdown; the renderer is general
A lesson is a .md file in src/learn/lessons/, discovered with import.meta.glob — so
adding a lesson is dropping a file, with no registry to edit. A lesson is a free-form
document of ordered blocks, not a fixed template:
| Authored as | Block | Rendered by |
|---|---|---|
| plain markdown | prose |
Markdown |
:::progression wrapping ## stages + fenced specs |
progression |
SpecProgression |
a bare fenced vega-lite block |
chart |
LandingChart |
:::name … ::: |
callout |
Markdown (styled by name) |
Inside a :::progression, each ## heading is a stage: heading → tab label, prose → note,
the following fenced vega-lite block → spec. Inline data repeats per fenced block — there
is no shared-data construct.
The pipeline
lessons/*.md → import.meta.glob (in LearnPage) → parseLesson (core/lesson-parse) →
LessonBlock[] → LearnPage block dispatch → Markdown | SpecProgression | LandingChart.
SpecProgression renders each stage's spec with formatSpec (core/json-format) and
highlights what the stage changed with changedLines (core/spec-diff, an LCS line-diff).
Rules
- The engine consumes plain data, so the authoring surface is swappable.
SpecProgression,spec-diff, andformatSpectake parsed blocks and specs and know nothing about markdown — the parser is the only thing coupled to the.mdformat. The authoring format can change without touching the widget. - Parsing, diff, and formatting are pure and live in
core(tested hardest); rendering and the markdown library live insrc/learn. Core stays dependency-free —markedis imported only bysrc/learn/Markdown. dangerouslySetInnerHTMLrenders first-party lesson files (repo content authored by us), never user input — not an XSS surface.- Lesson specs are fenced JSON parsed with
JSON.parse; the source pane re-formats them withformatSpecso the shown JSON matches the editor's house style.