mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
61 lines
2.2 KiB
TypeScript
61 lines
2.2 KiB
TypeScript
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>
|
|
);
|
|
}
|