The milestone 2 parity page becomes the spec's dashboard: app bar with wordmark, disclaimer badge and About popover, theme toggle (persisted, defaults to prefers-color-scheme, applied pre-mount to avoid a flash), hero with the preset narrative and live toned percentages, scenario toolbar, panel cards with skeleton loading and dim-while-refreshing, legend, and footer. ComparisonTable evolves into the collapsed ResultsTable (test moved along, plus a formatPct rounding case). NetworkView renders the real topology with the spec's shape encodings. The layout is seeded d3-force (mulberry32 random source, seeded initial positions, 300 synchronous ticks, cached per graph hash); anisotropic forceX/forceY pulls settle the cloud into the wide card shape so the fit stays uniform-scale and the spacing organic. Justin asked for a taller network area (380x230) and a reading caption under the legend; the caption is study copy, so StudyPreset gains a readingCaption field. Slices still to come keep their controls visibly parked: Export and the panel kebab render disabled until slices 11 and 7.
28 lines
871 B
HTML
28 lines
871 B
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<link rel="icon" href="/favicon.ico">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>spreadlab</title>
|
|
<script>
|
|
// Apply the persisted (or preferred) theme before the app mounts so
|
|
// dark mode never flashes light. Kept in sync with useTheme.ts.
|
|
try {
|
|
var storedTheme = localStorage.getItem('spreadlab-theme')
|
|
if (
|
|
storedTheme === 'dark' ||
|
|
(storedTheme !== 'light' && matchMedia('(prefers-color-scheme: dark)').matches)
|
|
) {
|
|
document.documentElement.classList.add('dark')
|
|
}
|
|
} catch (storageError) {
|
|
/* default to light */
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div id="app"></div>
|
|
<script type="module" src="/src/main.ts"></script>
|
|
</body>
|
|
</html>
|