mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-05-07 02:03:55 -05:00
dev
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e4069996d8 |
fix(theme): bridge dark mode to .quarto-dark body class
The site/about/about.css, site/community/community.css, and
site/newsletter/newsletter.css custom styles key dark-mode CSS
variables off `.quarto-dark { ... }` (and descendant chains like
`.quarto-dark .opening-lead`). That class is added by Quarto only when
the user clicks the toggle button — never on the OS-preferred dark
path. Result: a visitor whose browser is set to dark mode but who has
not toggled the site explicitly gets the dark <html data-bs-theme=dark>
background but the LIGHT mode `--ab-text: #1a1a2e` text, producing the
classic "Open by design." invisibility on /about/license.html and a
slate of low-contrast hero/body text across about/community/newsletter
pages.
Patch the central `apply()` so every theme transition — initial paint,
toggle click, OS-pref change, cross-tab storage event — also mirrors
the scheme onto `document.body.classList`. A MutationObserver covers
the FOUC window where <body> has not yet parsed at first apply().
This is intentionally a JS bridge rather than a CSS rewrite: the three
custom-CSS files have ~15 selectors keyed on `.quarto-dark` between
them, including descendant chains where a naive find/replace would
break selector grouping (`.quarto-dark .foo {...}` cannot become
`[data-bs-theme="dark"], .quarto-dark .foo {...}` — that comma turns
the first selector standalone). One JS line covers all of them and
keeps the CSS files unchanged.
|
||
|
|
d759f3c4c2 |
fix(theme): bridge Quarto's 'alternate'/'default' to data-bs-theme
Quarto's built-in toggle stores its color-scheme choice as
'alternate'/'default' under the same localStorage key (`quarto-color-scheme`)
that the shared theme-persist shim reads. The shim only recognized
'dark'/'light', so once a reader clicked the toggle it would, on the next
load, fall back to OS preference and apply data-bs-theme=light while
Quarto correctly enabled the dark stylesheet (or vice versa). The result
was a half-themed page — most visible to readers on macOS dark mode whose
stored choice was 'default' (light): Bootstrap's CSS-variable dark mode
kicked in via data-bs-theme=dark, but the dark-mode SCSS layer never
loaded, leaving a dark navbar against a light sidebar/content/announcement.
theme-persist now accepts both vocabularies on read (alternate→dark,
default→light) and wraps quartoToggleColorScheme so the html attribute
syncs immediately after a click instead of waiting for the next reload.
The wrapper is a no-op on non-Quarto subsites (StaffML/Next.js).
Quarto's startup still checks `=== 'alternate'`, so we do NOT rewrite
Quarto's stored values — only mirror them onto <html>.
Single shared file in include-in-header propagates to all 8 Quarto
subsites: book vol1+vol2, labs, kits, slides, instructors, site, mlsysim.
Verified with Playwright across the full vol1↔vol2 navigation + toggle
sequence and across {OS=dark|light} × {storage=null|default|alternate}
matrix: 5/10 mismatches before, 0 after.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
73967f7c42 |
PR-2: Visual polish (announcement bars, theme persistence, dev-mirror fix, audit script) (#1405)
* fix(dev-mirror): compute prefix from dev-side depth in rewrite-dev-urls.sh The previous implementation hard-coded PREFIX="../" for any non-root subsite, which silently mis-rewrote every absolute mlsysbook.ai link on the dev preview for nested subsites (vol1, vol2 — they live at /book/vol1/ and /book/vol2/ on dev). The most visible symptom was the navbar title-href landing one level too shallow: clicking the navbar title from inside Vol I went to /book/ instead of the unified landing page at the dev root. Fix: derive PREFIX from the number of path segments in the calling subsite's dev-side path (book/vol1 → 2 hops → '../../') and use the mlsysbook.ai key (not the dev-path) for self-link detection. Add an explicit error if the caller passes a subsite name that is not in the SUBSITES map, instead of silently producing wrong rewrites. Sample rewrites with the fix: vol1 page https://mlsysbook.ai/ → ../../ vol1 page https://mlsysbook.ai/vol2/ → ../../book/vol2/ vol1 page https://mlsysbook.ai/kits/ → ../../kits/ kits page https://mlsysbook.ai/ → ../ kits page https://mlsysbook.ai/vol1/ → ../book/vol1/ Live builds are unaffected — they use the original absolute URLs. * feat(book): per-volume announcement bars (Crimson / ETH-Blue) Split the shared book announcement bar into two volume-scoped files so each volume gets audience-appropriate copy AND inherits the right brand tint. Vol I keeps the Harvard-Crimson tint (its theme accent) and the Foundations-flavored content; Vol II picks up the ETH-Blue tint (its theme accent) and Scale-flavored content that leads with the new volume launch and the cross-ecosystem build path. Files: - announcement-vol1.yml — new, Vol I copy, no hard-coded color (uses `type: primary` so .announcement / .alert-primary get $accent = $brand-crimson via theme-harvard.scss) - announcement-vol2.yml — new, Vol II copy, same pattern but theme feeds $accent = $brand-eth-blue via theme-eth.scss - announcement.yml — emptied to a no-op with a deprecation note; keep for one release cycle to avoid breaking any external metadata reference, then delete The CSS that translates `type: primary` into the per-theme tint already lived in book/quarto/assets/styles/_base-styles.scss (`.announcement { background: linear-gradient(... lighten($accent, 52%) ...) }`). No SCSS changes needed — the previous behavior of a single shared bar just hid that the tint was already theme-driven. Resolves the "Vol II announcement should be ETH-themed" QA note. * feat(theme): cross-site dark-mode persistence + FOUC guard Make dark-mode preference flow seamlessly across every subsite under mlsysbook.ai (Quarto-built and Next.js alike) and eliminate the theme-flash that dark-mode readers see on first paint. Quarto subsites (book / labs / kits / slides / instructors / mlsysim / tinytorch / unified site): - shared/config/site-head.html now inlines a tiny pre-paint script that reads `quarto-color-scheme` from localStorage (or falls back to OS preference) and applies `data-bs-theme`, `data-quarto-color-scheme`, and `style.color-scheme` on <html> BEFORE any other script runs. Eliminates the visible flash that was happening because Quarto's own toggle script runs late. - Listens for `storage` events so a toggle in tab A propagates to tab B without a refresh. - Inlined deliberately: the script is tiny, must be synchronous in <head> to avoid the flash, and inlining sidesteps per-subsite asset path differences. Canonical externalized source kept at shared/scripts/theme-persist.js for documentation/testability — if you change one, mirror to the other. StaffML (Next.js): - public/theme-bootstrap.js now reads the Quarto-side key as a fallback when StaffML has no local preference, so a user toggling dark mode on the book lands here in dark mode on first visit. - components/ThemeProvider.tsx mirrors writes back to `quarto-color-scheme`, so navigating onward to any Quarto subsite inherits StaffML's choice. Both subsystems retain their own keys as primary so each app's behavior is unchanged in isolation. The `quarto-color-scheme` key is the bridge contract — keep it stable across all theme code paths. * test(audit): Playwright site-audit script (sidebar / darkmode / assets) Single Playwright-driven QA script that the release-prep plan needs in three flavors. Implemented as one CLI with three subcommands so the shared boilerplate (browser launch, URL list, output dirs, screenshot naming) lives in one place and the per-site source-of-truth list does too. Subcommands: sidebar Assert every Quarto subsite exposes a populated, visible #quarto-sidebar / .sidebar-navigation. Skips sites that intentionally have no sidebar (landing, slides, StaffML). Catches the regression where Vol I/II builds dropped the sidebar after a config refactor. darkmode Force dark-mode via localStorage + data attributes, scroll top→bottom in 800px chunks (so lazy content renders), and screenshot full-page into _audit/darkmode/<site>.png for eyeball review. Surfaces "half-themed" widgets that CSS linters can't find (announcement bar, footer tiles, code blocks, etc.). assets Listen for failed network requests + 4xx/5xx responses on every site URL. Catches the broken <img> embeds reported during dev-mirror review (TinyTorch big-picture PDF viewer, Vol II cover) before they hit production. Targets dev / live / local with --target. Use --only <substring> to narrow scope. JSON report written to _audit/<cmd>.json for CI ingest. Exits non-zero on issues so it can become a blocking CI check once the baseline is clean. Requires `npm i -D playwright && npx playwright install chromium`. |