Skip to content

feat: theme select with system option - #26

Merged
axisrow merged 1 commit into
mainfrom
codex/mobile-effects
Aug 12, 2026
Merged

feat: theme select with system option#26
axisrow merged 1 commit into
mainfrom
codex/mobile-effects

Conversation

@axisrow

@axisrow axisrow commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • Replaces the light/dark toggle button in the topbar with a <select> offering system / light / dark.
  • Persists the choice under a new theme-choice localStorage key, with a one-time migration of the legacy theme key.
  • Listens for OS-level theme changes and re-applies when the user's choice is "system".

Details

  • index.html: <head> bootstrap script resolves the theme before paint (avoids FOUC), performs the legacy-key migration, and stashes the resolved choice on document.documentElement.dataset.themeChoice for main.js to reuse without re-touching localStorage.
  • main.js: readStoredThemeChoice() / resolveTheme() / applyTheme() are the single set of helpers used by both the select's change handler and the prefers-color-scheme media-query listener.
  • styles.css: new .theme-select, .theme-select-label, .visually-hidden rules; adjusted mobile topbar grid columns to fit the wider control.
  • Cache-busting version strings bumped for main.js and styles.css per repo convention.

Testing

  • npm test — all 28 tests pass.

🤖 Generated with Claude Code

Replace the light/dark toggle button with a select control offering
system/light/dark, backed by a shared readStoredThemeChoice() helper
and a one-time migration of the legacy "theme" localStorage key into
"theme-choice".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RS53kTLmTNo4QVtiVrNLyj
@axisrow

axisrow commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 1) — round 4a33bea6-b683-4ce9-8012-affd25e97575

Reviewed locally (/review + Codex companion), no bots pinged.

Verdict Reviewer Finding Location
SKIP codex The new system-theme-change listener uses the modern MediaQueryList event API without a legacy fallback, matching an existing unguarded pattern already used twice elsewhere in the same file. main.js:251
IRRELEVANT claude A pre-existing redundant config assignment two lines apart lies outside this PR diff — unmodified code, not introduced here. main.js:189
IRRELEVANT claude A mobile topbar grid track appears unused, but the grid shape and spacer track predate this PR — only two column-index values changed here. styles.css:1533
IRRELEVANT claude A CPU-fallback check reads pre-override render options; the cited line number does not exist in the file, and the related code is unchanged pre-existing logic outside this diff. main.js (cited line invalid)
IRRELEVANT claude A flagged location in the bot-sync script was not touched by this PR at all, and the reviewer withdrew the claim after verification. profile/sync/build_pages.py:196

Summary: No blocking issues found. 0 FIX, 1 SKIP (optional hardening, not a regression), 4 IRRELEVANT (out of this PR's diff scope or self-retracted by the reviewer).

@axisrow

axisrow commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

📋 Review summary — all cycles

Cycle Reviewer Finding Verdict Resolution
1 codex The new system-theme-change listener uses the modern MediaQueryList event API without a legacy addListener fallback, matching an existing unguarded pattern already used elsewhere in the same file. SKIP Left as-is — consistent with existing convention in the file, not a regression
1 claude 4 findings referencing pre-existing/unmodified code or non-existent line numbers IRRELEVANT No action — out of this PR's diff scope

Totals: 0 FIX, 1 SKIP, 4 IRRELEVANT, 0 UNVERIFIED. No blocking issues found by either reviewer.

@axisrow
axisrow merged commit f6b9da2 into main Aug 12, 2026
1 check passed
@axisrow
axisrow deleted the codex/mobile-effects branch August 12, 2026 03:47
axisrow added a commit that referenced this pull request Aug 13, 2026
Three follow-ups on the topbar icon work:

- Mobile topbar broke onto two rows. .topbar-inner declared four columns
  while only three children are visible there, and .topbar-actions was
  left to auto-placement after .menu-toggle had already claimed column 4
  — so the grid cursor had passed it and dropped the actions onto row 2.
  Pin brand/actions/burger to explicit row-1 columns over a 3-column
  track and right-align the actions.
- Restore the original ◐ glyph the pre-select toggle used, replacing the
  three-SVG sun/moon/monitor set.
- Translate the theme control back to English (Colour theme /
  System / Light / Dark); the page is lang="en" and everything else on it
  is English, but #26 introduced Russian strings here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0176vakGzooXWuenVBEeKosv
axisrow added a commit that referenced this pull request Aug 13, 2026
* fix: restore icon-style theme toggle and GitHub topbar buttons

The theme select and GitHub link had regressed to wide text pills after
the theme-select rework. Restore compact circular icon buttons for both:
the theme select now shows a sun/moon/monitor icon matching the current
mode (system/light/dark) with the native <select> as a transparent
click target on top, and the GitHub link is now an icon button with an
inline GitHub mark, matching the same icon-button style/size.

Fixes #37

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0176vakGzooXWuenVBEeKosv

* fix: repair mobile topbar row and restore the original theme glyph

Three follow-ups on the topbar icon work:

- Mobile topbar broke onto two rows. .topbar-inner declared four columns
  while only three children are visible there, and .topbar-actions was
  left to auto-placement after .menu-toggle had already claimed column 4
  — so the grid cursor had passed it and dropped the actions onto row 2.
  Pin brand/actions/burger to explicit row-1 columns over a 3-column
  track and right-align the actions.
- Restore the original ◐ glyph the pre-select toggle used, replacing the
  three-SVG sun/moon/monitor set.
- Translate the theme control back to English (Colour theme /
  System / Light / Dark); the page is lang="en" and everything else on it
  is English, but #26 introduced Russian strings here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0176vakGzooXWuenVBEeKosv

* style: let the effect canvases read through their copy panels

The panels overlaying a live canvas (stars, projects, proof, contact) each
painted a near-opaque plate -- 0.91 via .veil-panel, and 0.97 for proof --
so the field behind them was flattened into a flat rectangle.

Add a --veil-canvas token at 0.8 and point those four panels at it, leaving
--veil for .project-surface, which has no canvas behind it. 0.8 is the floor
rather than a taste call: composited over a black canvas pixel (mandelbrot
does reach 0,0,0) it holds the in-panel --ink-faint at 4.91:1 light / 5.74:1
dark, still clear of AA. At 0.72 that secondary copy drops to 3.96:1.

Mobile is deliberately untouched: those panels sit directly over the canvas
with no side-by-side layout, and the existing mobile rules already tune them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0176vakGzooXWuenVBEeKosv

* style: fade veil panels toward their canvas, tune effect motion

- Veil panels over a live canvas now use a directional gradient fade
  (matching .experience-field/.about-field) instead of a flat
  semi-transparent plate, so the effect visibly runs into the panel.
- projects-field-copy fades from the opposite side since its canvas
  sits to the left.
- Bump plasma motion speed, starfield particle count, and copper-bars
  alpha scale for more visible motion/contrast.
- Bump styles.css/effect-skins.js cache-busting query strings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0176vakGzooXWuenVBEeKosv

* fix: restore theme option contrast and cap starfield particle budget

- .theme-select inherits color: transparent into its <option> elements,
  making System/Light/Dark unreadable when the dropdown opens in browsers
  that render option text with the select's author color. Restore an
  explicit, opaque color/background on .theme-select option.
- The starfield preview skin raised particleCount to 900/1200, ~10x the
  vendored preview.mobile/preview.desktop budget (90/120). densityMode
  stays "explicit" here, so densityMax never clamps the value -- the
  prior comment's clamp claim was incorrect. Cap the override at 180/240
  (2x budget) and correct the comment.
- Add regression tests for both: option-list contrast and a particle-count
  ceiling relative to the vendored preview budget.
- Bump styles.css/effect-skins.js cache-busting query strings.

Fixes review findings from cycle 1 (codex + claude /review).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0176vakGzooXWuenVBEeKosv

---------

Co-authored-by: axisrow <axisrow@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant