mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Learn: per-lesson URLs, a :::data shared-dataset construct, and a linked-views deep dive
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { useMemo, useState, type ReactNode } from 'react';
|
||||
import { chartConfigForSelection } from '@core/vega-themes';
|
||||
import type { UiTheme } from '@core/theme';
|
||||
import styles from './Learn.module.css';
|
||||
|
||||
type ChartConfig = ReturnType<typeof chartConfigForSelection>;
|
||||
|
||||
/**
|
||||
* Shared chrome for the learning section (header, footer, light/dark theme) wrapping
|
||||
* either the lesson index or one lesson. The theme state lives here because both the
|
||||
* header toggle and the chart config depend on it; it's handed to the page via a
|
||||
* render prop so a lesson's charts re-theme with the toggle.
|
||||
*
|
||||
* Theme handling mirrors the landing (light/dark via `data-theme` on the root),
|
||||
* duplicated rather than shared because the two entries are independent pages.
|
||||
*/
|
||||
export function LearnLayout({
|
||||
children,
|
||||
}: {
|
||||
children: (config: ChartConfig) => ReactNode;
|
||||
}): ReactNode {
|
||||
const [theme, setTheme] = useState<UiTheme>('light');
|
||||
const config = useMemo(() => chartConfigForSelection('astrolabe', theme), [theme]);
|
||||
|
||||
// TODO: this light/dark toggle is duplicated in landing/Landing.tsx — extract a
|
||||
// shared `useUiTheme()` hook into a home both marketing entries can import.
|
||||
function toggleTheme(): void {
|
||||
const next: UiTheme = theme === 'dark' ? 'light' : 'dark';
|
||||
setTheme(next);
|
||||
document.documentElement.dataset.theme = next;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<header className={styles.header}>
|
||||
<a className={styles.brand} href="/">
|
||||
Astrolabe
|
||||
</a>
|
||||
<nav className={styles.nav}>
|
||||
<a className={styles.kicker} href="/learn/">
|
||||
Vega-Lite, deeper
|
||||
</a>
|
||||
<button className={styles.ghost} type="button" onClick={toggleTheme}>
|
||||
{theme === 'dark' ? 'Light' : 'Dark'}
|
||||
</button>
|
||||
<a className={styles.appLink} href="/app/">
|
||||
Open the app
|
||||
</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main className={styles.main}>{children(config)}</main>
|
||||
|
||||
<footer className={styles.footer}>
|
||||
<span>An interactive deep dive into the parts of Vega-Lite the docs gloss over.</span>
|
||||
<a href="/">← Back to Astrolabe</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user