From ef587e5356fba426c11f0e3d80446b92df0a80ab Mon Sep 17 00:00:00 2001 From: shravanithouta108 Date: Fri, 19 Jun 2026 17:02:03 +0530 Subject: [PATCH 1/2] feat: wire up light/dark mode toggle end-to-end (darkMode class, theme-light vars, color token mapping) --- frontend/src/index.css | 16 ++++++++++++++++ frontend/tailwind.config.js | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/frontend/src/index.css b/frontend/src/index.css index 31549e3b4..a74e62f3c 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -3855,3 +3855,19 @@ button, white-space: nowrap; } } + +/* ============================================ + Light Theme Overrides + ============================================ */ +.theme-light { + --bg-primary: #f8f9fa; + --bg-secondary: #ffffff; + --bg-tertiary: #f1f3f5; + --bg-elevated: #e9ecef; + --accent-silver: #6c757d; + --accent-silver-dim: #adb5bd; + --accent-silver-bright: #212529; + --text-primary: #212529; + --text-secondary: #495057; + --text-muted: #6c757d; +} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 3b803a0d2..b5fe353cd 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,5 +1,6 @@ /** @type {import('tailwindcss').Config} */ export default { + darkMode: 'class', content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx}", @@ -7,6 +8,15 @@ export default { theme: { extend: { colors: { + 'primary': 'var(--bg-primary)', + 'secondary': 'var(--bg-secondary)', + 'bg-primary': 'var(--bg-primary)', + 'bg-secondary': 'var(--bg-secondary)', + 'bg-tertiary': 'var(--bg-tertiary)', + 'bg-elevated': 'var(--bg-elevated)', + 'primary-text': 'var(--text-primary)', + 'secondary-text': 'var(--text-secondary)', + 'muted': 'var(--text-muted)', 'charcoal-dark': '#0a0a0c', charcoal: { light: '#1d1d21', From 3c6b0260df004dbf499634a5c45af088ea128bdf Mon Sep 17 00:00:00 2001 From: shravanithouta108 Date: Sun, 21 Jun 2026 13:13:18 +0530 Subject: [PATCH 2/2] test(frontend): assert dark/theme-light class is applied to document root on toggle --- .../unit/components/ThemeToggle.test.tsx | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/frontend/testing/unit/components/ThemeToggle.test.tsx b/frontend/testing/unit/components/ThemeToggle.test.tsx index e678b92d7..c8c2bb8b2 100644 --- a/frontend/testing/unit/components/ThemeToggle.test.tsx +++ b/frontend/testing/unit/components/ThemeToggle.test.tsx @@ -55,6 +55,34 @@ describe('ThemeToggle', () => { expect(button).toHaveAttribute('aria-pressed', 'true') }) + it('applies the dark class to document root and removes theme-light', async () => { + localStorage.setItem(STORAGE_KEY, 'light') + document.documentElement.classList.remove('dark') + document.documentElement.classList.add('theme-light') + const user = userEvent.setup() + renderWithTheme() + + const button = screen.getByRole('button') + await user.click(button) + + expect(document.documentElement.classList.contains('dark')).toBe(true) + expect(document.documentElement.classList.contains('theme-light')).toBe(false) + }) + + it('applies the theme-light class to document root and removes dark', async () => { + localStorage.setItem(STORAGE_KEY, 'dark') + document.documentElement.classList.add('dark') + document.documentElement.classList.remove('theme-light') + const user = userEvent.setup() + renderWithTheme() + + const button = screen.getByRole('button') + await user.click(button) + + expect(document.documentElement.classList.contains('theme-light')).toBe(true) + expect(document.documentElement.classList.contains('dark')).toBe(false) + }) + it('aria-label reflects the target theme, not the current one', () => { localStorage.setItem(STORAGE_KEY, 'dark') renderWithTheme()