Bug Description
Reframe currently renders two visually distinct dark modes depending on which code path applies the theme. The two screenshots below show the same page in dark mode but with noticeably different background colours:
- Dark mode A — deep black/navy (matches the CSS variable
--bg: #0f172a defined in globals.css)
- Dark mode B — lighter charcoal/slate gray (appears to come from Tailwind
dark:bg-* utility classes overriding or bypassing the CSS variable system)
This inconsistency makes the app look broken and unpolished. The upload card, the output size panel, and the preset grid all shift noticeably between the two states.
Root Cause (suspected)
The project defines dark mode via a CSS class strategy in src/app/globals.css:
.dark {
--bg: #0f172a;
--surface: #1e293b;
--border: #334155;
--text: #f1f5f9;
--muted: #94a3b8;
--accent: #3b82f6;
}
However, several components likely use Tailwind dark: utility classes (e.g. dark:bg-slate-900, dark:bg-gray-800) which use Tailwind's own dark mode detection and do not read from the CSS variables. When both systems are active, they produce different shades, causing the split appearance.
Additionally, the ThemeProvider in src/components/ThemeProvider.tsx may be toggling the dark class on <html> or <body> inconsistently, or there may be a race condition between the server-rendered class and the client-side hydration.
Steps to Reproduce
- Clone the repo and run
bun run dev
- Toggle dark mode using the theme toggle button
- Toggle back and forth several times
- Observe that the background shade changes between two distinct values
Also compare: hard-refresh in dark mode vs. toggling from light → dark — the initial render may use a different shade than the post-toggle render.
Expected Behaviour
One single, consistent dark background throughout the entire UI. All components should read from the CSS variable var(--bg) and var(--surface), not hard-coded Tailwind dark: values.
What to Fix
- Audit all components in
src/components/ for Tailwind dark:bg-*, dark:text-*, dark:border-* utilities — replace every one with the equivalent CSS variable token:
| Replace |
With |
dark:bg-slate-900 / dark:bg-gray-900 |
bg-[var(--bg)] |
dark:bg-slate-800 / dark:bg-gray-800 |
bg-[var(--surface)] |
dark:text-white / dark:text-slate-100 |
text-[var(--text)] |
dark:text-slate-400 |
text-[var(--muted)] |
dark:border-slate-700 |
border-[var(--border)] |
-
Verify ThemeProvider — ensure the dark class is only ever toggled on the <html> element, and that the initial class is set synchronously before first paint (to avoid a flash of wrong theme).
-
Remove any duplicate theme toggling logic — there should be exactly one source of truth for the theme state.
Files to Check
src/components/ThemeProvider.tsx
src/components/ThemeToggle.tsx
src/app/globals.css
src/app/layout.tsx
- All component files in
src/components/
Acceptance Criteria
Screen Recording Required
Your PR for this issue must include a screen recording showing dark mode toggling consistently on your local machine (bun run dev → http://localhost:3000) — record toggling light → dark → light → dark several times to prove the background shade is stable.
See CONTRIBUTING.md for how to record on your OS.
Bug Description
Reframe currently renders two visually distinct dark modes depending on which code path applies the theme. The two screenshots below show the same page in dark mode but with noticeably different background colours:
--bg: #0f172adefined inglobals.css)dark:bg-*utility classes overriding or bypassing the CSS variable system)This inconsistency makes the app look broken and unpolished. The upload card, the output size panel, and the preset grid all shift noticeably between the two states.
Root Cause (suspected)
The project defines dark mode via a CSS class strategy in
src/app/globals.css:However, several components likely use Tailwind
dark:utility classes (e.g.dark:bg-slate-900,dark:bg-gray-800) which use Tailwind's own dark mode detection and do not read from the CSS variables. When both systems are active, they produce different shades, causing the split appearance.Additionally, the
ThemeProviderinsrc/components/ThemeProvider.tsxmay be toggling thedarkclass on<html>or<body>inconsistently, or there may be a race condition between the server-rendered class and the client-side hydration.Steps to Reproduce
bun run devAlso compare: hard-refresh in dark mode vs. toggling from light → dark — the initial render may use a different shade than the post-toggle render.
Expected Behaviour
One single, consistent dark background throughout the entire UI. All components should read from the CSS variable
var(--bg)andvar(--surface), not hard-coded Tailwind dark: values.What to Fix
src/components/for Tailwinddark:bg-*,dark:text-*,dark:border-*utilities — replace every one with the equivalent CSS variable token:dark:bg-slate-900/dark:bg-gray-900bg-[var(--bg)]dark:bg-slate-800/dark:bg-gray-800bg-[var(--surface)]dark:text-white/dark:text-slate-100text-[var(--text)]dark:text-slate-400text-[var(--muted)]dark:border-slate-700border-[var(--border)]Verify
ThemeProvider— ensure thedarkclass is only ever toggled on the<html>element, and that the initial class is set synchronously before first paint (to avoid a flash of wrong theme).Remove any duplicate theme toggling logic — there should be exactly one source of truth for the theme state.
Files to Check
src/components/ThemeProvider.tsxsrc/components/ThemeToggle.tsxsrc/app/globals.csssrc/app/layout.tsxsrc/components/Acceptance Criteria
#0f172afor--bg)dark:utilities remain in component files — all colours come from CSS variablesbun run lintandbunx tsc --noEmitpassScreen Recording Required
Your PR for this issue must include a screen recording showing dark mode toggling consistently on your local machine (
bun run dev→ http://localhost:3000) — record toggling light → dark → light → dark several times to prove the background shade is stable.