From 2663d7eac6747302eab08921afbfcb5d01b216a4 Mon Sep 17 00:00:00 2001 From: Hisham Aburaqibah Date: Wed, 23 Sep 2026 21:57:24 +0200 Subject: [PATCH] feat: theme toggle --- CLAUDE.md | 7 +- .../components/ui/Navigation/Navigation.tsx | 13 +- .../components/ui/Navigation/ThemeToggle.tsx | 111 ++++++++++++++++++ apps/web/app/i18n/messages/ar.json | 2 + apps/web/app/i18n/messages/en.json | 2 + apps/web/app/lib/theme.ts | 33 ++++++ apps/web/app/root.tsx | 41 ++++++- apps/web/app/styles/README.md | 12 ++ apps/web/app/styles/semantic.css | 10 ++ 9 files changed, 222 insertions(+), 9 deletions(-) create mode 100644 apps/web/app/components/ui/Navigation/ThemeToggle.tsx create mode 100644 apps/web/app/lib/theme.ts diff --git a/CLAUDE.md b/CLAUDE.md index b28d21f..b370093 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -53,7 +53,12 @@ unreachable — the site must never 500 because Strapi is down. The site ships RTL Arabic; physical directions silently break it. Check: `grep -rnE "\b(pl|pr|ml|mr|left|right)-[0-9]" apps/web/app` → nothing meaningful. 3. **Surfaces, not a theme.** `:root` *is* the dark surface; `data-surface="light"` flips a - subtree and repaints itself. Do not add a global theme toggle or a `dark:` variant. + subtree and repaints itself. Never add a second theme system or a `dark:` variant. **The + one exception, accepted deliberately:** the nav's theme toggle flips *which* surface `` + stands on (dark default ↔ light), persisted via the `sharper-theme` cookie read in the root + loader and set by the root action — SSR-rendered so the first byte and first paint always + match. The mechanism stays surfaces-only: the toggle just re-roots them. `--surface-nav` + must keep a value in BOTH surface blocks. 4. **Figma is READ ONLY.** Only `get_design_context`, `get_screenshot`, `get_metadata`, `get_variable_defs`. Never call anything that writes (`use_figma`, `generate_figma_design`, `create_new_file`, `upload_assets`, shaders, plugins, …). Before the first diff --git a/apps/web/app/components/ui/Navigation/Navigation.tsx b/apps/web/app/components/ui/Navigation/Navigation.tsx index 70afbba..a8b37d4 100644 --- a/apps/web/app/components/ui/Navigation/Navigation.tsx +++ b/apps/web/app/components/ui/Navigation/Navigation.tsx @@ -10,6 +10,7 @@ import { import { Brand } from "./Brand"; import { DesktopNav } from "./DesktopNav"; import { MobileNav } from "./MobileNav"; +import { ThemeToggle } from "./ThemeToggle"; import { getDefaultNavItems, getNavigationStrings } from "./nav-items"; import { cx } from "./styles"; import type { NavItem, NavigationStrings, NavSurface } from "./types"; @@ -53,9 +54,10 @@ export interface NavigationProps { * and the whole tree moves into a full-screen drawer. * * EU VISIBILITY: the updated design has no funding badge in the bar - the - * Actions slot holds the language globe alone. The mandatory "Funded by the - * European Union" lockup is carried by