From 185658bf5b877f308069839d945ff6f8e3e78bfb Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Sun, 19 Apr 2026 14:15:10 +0700 Subject: [PATCH] feat(web): add light/dark theme toggle to public nav MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Public layout only had the language switcher next to the auth block — users reading the public site had no way to toggle theme, while the dashboard layout has always had one. Mirror the dashboard's toggle: Moon icon when the app is in light mode, Sun icon when in dark mode, aria-label pulled from the `dashboard.darkMode`/`lightMode` strings that are already translated. Sits between LanguageSwitcher and the user/auth block so it's visible on both desktop and mobile headers without adding to the hamburger menu. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/web/app/[locale]/(public)/layout.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/web/app/[locale]/(public)/layout.tsx b/apps/web/app/[locale]/(public)/layout.tsx index a457714..39e6b1c 100644 --- a/apps/web/app/[locale]/(public)/layout.tsx +++ b/apps/web/app/[locale]/(public)/layout.tsx @@ -1,11 +1,12 @@ 'use client'; -import { LogOut, Menu, User as UserIcon, X } from 'lucide-react'; +import { LogOut, Menu, Moon, Sun, User as UserIcon, X } from 'lucide-react'; import { usePathname } from 'next/navigation'; import { useTranslations } from 'next-intl'; import { useState } from 'react'; import { CompareFloatingBar } from '@/components/comparison/compare-floating-bar'; import { NotificationBell } from '@/components/notifications/notification-bell'; +import { useTheme } from '@/components/providers/theme-provider'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { LanguageSwitcher } from '@/components/ui/language-switcher'; @@ -33,6 +34,7 @@ export default function PublicLayout({ children }: { children: React.ReactNode } const pathname = usePathname(); const router = useRouter(); const { user, logout } = useAuthStore(); + const { theme, toggleTheme } = useTheme(); const t = useTranslations(); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); @@ -109,6 +111,19 @@ export default function PublicLayout({ children }: { children: React.ReactNode }
+ {user ? ( <> {/* Bell only on sm+ to avoid overcrowding mobile header */}