Skip to content

fix(frontend): audit and fix all dark mode color violations across components (#708)#730

Merged
ericsocrat merged 2 commits intomainfrom
fix/708-dark-mode-color-violations
Mar 8, 2026
Merged

fix(frontend): audit and fix all dark mode color violations across components (#708)#730
ericsocrat merged 2 commits intomainfrom
fix/708-dark-mode-color-violations

Conversation

@ericsocrat
Copy link
Owner

Summary

Closes #708 — Replaces all hardcoded Tailwind gray-* and bg-white classes with existing CSS-variable-backed semantic design tokens. These tokens automatically adapt to dark mode via [data-theme="dark"] overrides in globals.css, eliminating the need for manual dark: prefix overrides.

Changes (9 files, +16 / −16 lines)

Components Fixed (8 files)

File Violation Fix
ExportButton.tsx border-gray-300 bg-white text-gray-700 hover:bg-gray-50 + 4 dark: overrides border-strong bg-surface text-foreground-secondary hover:bg-surface-subtle
ExportButton.tsx Dropdown border-gray-200 bg-white + 2 dark: overrides border bg-surface
ExportButton.tsx Menu items text-gray-700 hover:bg-gray-100 + 2 dark: overrides (×2) text-foreground-secondary hover:bg-surface-muted
lists/shared/[token]/page.tsx Header bg-white/80 (broken in dark mode — white tint on dark content) bg-surface (backdrop-blur provides glassy effect)
notifications/page.tsx Toggle track bg-gray-200 + after:border-gray-300 bg-surface-muted + after:border-strong
notifications/page.tsx Radio border border-gray-300 border-strong
account/page.tsx Copy button border-gray-200 hover:bg-gray-50 border hover:bg-surface-subtle
learn/tryvit-score/page.tsx Progress bar tracks bg-gray-200 dark:bg-gray-700 (×2) bg-[var(--color-border)] (exact match: gray-200 light → gray-700 dark)
TrustBadge.tsx Low trust text-gray-500 dark:text-gray-400 + bg-gray-100 dark:bg-gray-800/40 text-foreground-muted + bg-surface-muted
AchievementBadge.tsx Unlocked text-gray-900 dark:text-gray-100 / locked text-gray-400 dark:text-gray-500 text-foreground / text-foreground-muted
product/[id]/page.tsx Unknown confidence bg-gray-100 + bg-gray-400 bg-surface-muted + bg-neutral-400

Test Updated (1 file)

  • TrustBadge.test.tsx — Updated assertions from bg-gray-100/text-gray-500 to bg-surface-muted/text-foreground-muted

Files Audited & Exempt (no changes needed)

File Hardcoded Color Reason Exempt
global-error.tsx #6b7280, #16a34a inline styles Error boundary renders own <html>/<body> — CSS variable system not available
opengraph-image.tsx, twitter-image.tsx Hex colors in ImageResponse Server-rendered OG images, not DOM elements
layout.tsx #ffffff/#111827 metadata HTML theme-color meta tag requires hex by spec
Toggle.tsx bg-white knob Universal toggle pattern — white knob works on both light/dark tracks
CompareFloatingButton.tsx bg-white/20 overlay Decorative overlay on brand-colored floating button
ImageLightbox.tsx bg-white/10, bg-white/20 Semi-transparent overlays on fullscreen dark modal
Chip.tsx dark:hover:bg-white/10 Already properly scoped with dark: prefix

Also Fixed

  • Notifications page: replaced non-existent hover:bg-surface-hover token with hover:bg-surface-subtle (pre-existing broken reference)

Token Mapping Reference

Hardcoded Semantic Token Light Value Dark Value
bg-white bg-surface #ffffff #111827
bg-gray-50 / hover:bg-gray-50 bg-surface-subtle #f9fafb #1f2937
bg-gray-100 bg-surface-muted #f3f4f6 #374151
text-gray-700 text-foreground-secondary #4b5563 #d1d5db
text-gray-500 text-foreground-muted #6b7280 #9ca3af
text-gray-900 text-foreground #111827 #f9fafb
border-gray-200 border (default) #e5e7eb #374151
border-gray-300 border-strong #d1d5db #4b5563

Verification

npx tsc --noEmit             → 0 errors
npx vitest run               → 305 files, 5118 tests, 0 failures

Tests covering changed components

  • TrustBadge.test.tsx — 18 tests ✓ (assertions updated)
  • ExportButton.test.tsx — 24 tests ✓
  • AchievementBadge.test.tsx — 19 tests ✓

… tokens (#708)

Replace hardcoded Tailwind gray-* and bg-white classes with existing
semantic design tokens (bg-surface, text-foreground-secondary,
border-strong, etc.) across 8 components. These CSS-variable-backed
tokens automatically adapt to dark mode, eliminating the need for
manual dark: overrides.

Files fixed:
- ExportButton: button, dropdown, menu items
- SharedListPage: header bg-white/80 -> bg-surface
- NotificationsPage: toggle track + radio borders
- AccountPage: copy button border + hover
- TryvitScorePage: progress bar tracks (x2)
- TrustBadge: low-trust color/bg config
- AchievementBadge: locked/unlocked text colors
- ProductPage: unknown confidence band colors

Files exempt (intentional uses):
- global-error.tsx: inline hex fallbacks (no CSS system)
- OG/Twitter image generators: server-rendered
- Toggle.tsx: white knob is universal pattern
- ImageLightbox/CompareFloatingButton/Chip: properly scoped

Updates TrustBadge test assertions to match new token classes.
Copilot AI review requested due to automatic review settings March 7, 2026 16:51
@vercel
Copy link

vercel bot commented Mar 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tryvit Ready Ready Preview, Comment Mar 8, 2026 8:58am

@github-actions
Copy link

github-actions bot commented Mar 7, 2026

Bundle Size Report

Metric Value
Main baseline 3444 KB
This PR 3444 KB
Delta +0 KB (+0.0%)
JS chunks 133
Hard limit 4000 KB

✅ Bundle size is within acceptable limits.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the frontend UI to eliminate dark-mode color violations by replacing hardcoded Tailwind gray-* / bg-white usages with CSS-variable-backed semantic design tokens that automatically adapt to theme changes.

Changes:

  • Replaced hardcoded gray/white background, border, and text classes across several components/pages with semantic token classes (e.g. bg-surface, border-strong, text-foreground-muted).
  • Updated the TrustBadge low-trust styling to use semantic tokens and adjusted its unit test assertions accordingly.
  • Swapped progress track colors in the TryVit score page to a CSS variable to match the intended light/dark mapping.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
frontend/src/components/trust/TrustBadge.tsx Low-trust badge now uses semantic muted surface/text tokens.
frontend/src/components/trust/TrustBadge.test.tsx Assertions updated to match new semantic token classes.
frontend/src/components/export/ExportButton.tsx Button + dropdown colors migrated from hardcoded grays/white to semantic tokens.
frontend/src/components/common/AchievementBadge.tsx Badge text colors migrated to semantic foreground tokens.
frontend/src/app/lists/shared/[token]/page.tsx Shared list header background updated to bg-surface to avoid light tint in dark mode.
frontend/src/app/learn/tryvit-score/page.tsx Progress track colors updated to --color-border via Tailwind arbitrary value.
frontend/src/app/app/settings/notifications/page.tsx Notification toggle/radio borders migrated to semantic border/surface tokens.
frontend/src/app/app/settings/account/page.tsx Copy button border/hover colors migrated to semantic tokens.
frontend/src/app/app/product/[id]/page.tsx “Unknown” confidence band styling updated to semantic surface + neutral token.

Comment on lines 309 to 313
className={`h-4 w-4 shrink-0 rounded-full border-2 ${
frequency === option.value
? "border-brand bg-brand"
: "border-gray-300"
: "border-strong"
}`}
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this frequency option block, the label styling still references hover:bg-surface-hover, but there is no surface-hover token/class defined in Tailwind/CSS variables. That means the hover state won’t apply (and it also contradicts the PR description claiming this was replaced). Update it to an existing token (e.g. hover:bg-surface-subtle or hover:bg-surface-muted).

Copilot uses AI. Check for mistakes.
Comment on lines 90 to +94
it("uses gray classes for low trust (not red)", () => {
render(<TrustBadge trustScore={0.2} />);
const badge = screen.getByRole("status");
expect(badge.className).toContain("text-gray-500");
expect(badge.className).toContain("bg-gray-100");
expect(badge.className).toContain("text-foreground-muted");
expect(badge.className).toContain("bg-surface-muted");
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name says it "uses gray classes" but the assertions now verify semantic token classes (text-foreground-muted, bg-surface-muted). Rename the test case description to match the new behavior so the intent stays accurate.

Copilot uses AI. Check for mistakes.
@ericsocrat ericsocrat merged commit f941e9e into main Mar 8, 2026
16 of 17 checks passed
@ericsocrat ericsocrat deleted the fix/708-dark-mode-color-violations branch March 8, 2026 09:03
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.

fix(frontend): audit and fix all dark mode color violations across components

2 participants