fix(frontend): audit and fix all dark mode color violations across components (#708)#730
Conversation
… 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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Bundle Size Report
✅ Bundle size is within acceptable limits. |
There was a problem hiding this comment.
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
TrustBadgelow-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. |
| className={`h-4 w-4 shrink-0 rounded-full border-2 ${ | ||
| frequency === option.value | ||
| ? "border-brand bg-brand" | ||
| : "border-gray-300" | ||
| : "border-strong" | ||
| }`} |
There was a problem hiding this comment.
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).
| 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"); |
There was a problem hiding this comment.
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.
Summary
Closes #708 — Replaces all hardcoded Tailwind
gray-*andbg-whiteclasses with existing CSS-variable-backed semantic design tokens. These tokens automatically adapt to dark mode via[data-theme="dark"]overrides inglobals.css, eliminating the need for manualdark:prefix overrides.Changes (9 files, +16 / −16 lines)
Components Fixed (8 files)
ExportButton.tsxborder-gray-300 bg-white text-gray-700 hover:bg-gray-50+ 4dark:overridesborder-strong bg-surface text-foreground-secondary hover:bg-surface-subtleExportButton.tsxborder-gray-200 bg-white+ 2dark:overridesborder bg-surfaceExportButton.tsxtext-gray-700 hover:bg-gray-100+ 2dark:overrides (×2)text-foreground-secondary hover:bg-surface-mutedlists/shared/[token]/page.tsxbg-white/80(broken in dark mode — white tint on dark content)bg-surface(backdrop-blur provides glassy effect)notifications/page.tsxbg-gray-200+after:border-gray-300bg-surface-muted+after:border-strongnotifications/page.tsxborder-gray-300border-strongaccount/page.tsxborder-gray-200 hover:bg-gray-50border hover:bg-surface-subtlelearn/tryvit-score/page.tsxbg-gray-200 dark:bg-gray-700(×2)bg-[var(--color-border)](exact match: gray-200 light → gray-700 dark)TrustBadge.tsxtext-gray-500 dark:text-gray-400+bg-gray-100 dark:bg-gray-800/40text-foreground-muted+bg-surface-mutedAchievementBadge.tsxtext-gray-900 dark:text-gray-100/ lockedtext-gray-400 dark:text-gray-500text-foreground/text-foreground-mutedproduct/[id]/page.tsxbg-gray-100+bg-gray-400bg-surface-muted+bg-neutral-400Test Updated (1 file)
TrustBadge.test.tsx— Updated assertions frombg-gray-100/text-gray-500tobg-surface-muted/text-foreground-mutedFiles Audited & Exempt (no changes needed)
global-error.tsx#6b7280,#16a34ainline styles<html>/<body>— CSS variable system not availableopengraph-image.tsx,twitter-image.tsxImageResponselayout.tsx#ffffff/#111827metadatatheme-colormeta tag requires hex by specToggle.tsxbg-whiteknobCompareFloatingButton.tsxbg-white/20overlayImageLightbox.tsxbg-white/10,bg-white/20Chip.tsxdark:hover:bg-white/10dark:prefixAlso Fixed
hover:bg-surface-hovertoken withhover:bg-surface-subtle(pre-existing broken reference)Token Mapping Reference
bg-whitebg-surface#ffffff#111827bg-gray-50/hover:bg-gray-50bg-surface-subtle#f9fafb#1f2937bg-gray-100bg-surface-muted#f3f4f6#374151text-gray-700text-foreground-secondary#4b5563#d1d5dbtext-gray-500text-foreground-muted#6b7280#9ca3aftext-gray-900text-foreground#111827#f9fafbborder-gray-200border(default)#e5e7eb#374151border-gray-300border-strong#d1d5db#4b5563Verification
Tests covering changed components
TrustBadge.test.tsx— 18 tests ✓ (assertions updated)ExportButton.test.tsx— 24 tests ✓AchievementBadge.test.tsx— 19 tests ✓