Add light mode + collapsible Settings cards + Appearance section#8
Merged
Conversation
Settings panel grows an 'Appearance' card at the top with a segmented Light / Dark / System theme picker. Dark stays the default (and survives hard reloads via an inline boot script that prevents FOUC); 'System' follows OS preference live via prefers-color-scheme. The API integrations (App Store Connect, Apple Search Ads) now live in collapsible cards that open automatically when not yet configured and collapse once Connected, with a green checkmark next to the status. Theme plumbing: - lib/theme.ts: localStorage-backed Theme store (light/dark/system), idempotent matchMedia listener, FOUC-free initTheme() called from main.ts - components/ThemePicker.svelte: controlled segmented control with sun/moon/laptop SVG icons - index.html: inline <script> in <head> applies the saved theme class before first paint so module scripts can't introduce a flash - app.css: light-mode scrollbar via html.dark scoping Components (20 .svelte files) get light-mode counterparts paired with the existing dark classes (bg-zinc-950 → bg-white dark:bg-zinc-950, etc.). zinc-500 left untouched where it reads on both backgrounds. Accent text (emerald/amber/red/blue -400) deepened in light mode for contrast. UI fixes surfaced by the migration: - Dashboard unread chart badge: kept text-zinc-950 on bg-amber-500 in both modes (yellow needs dark text) - CountryMultiCombobox/CountrySelect checkbox indicators: same fix - ChartsPage notification banner: text-blue-200 was unreadable on bg-blue-50, paired with text-blue-700 - Charts 'Back to Keywords' + AddAppModal submit: hover:bg-white in light mode made buttons disappear; mirrored to hover:bg-black - DotsIndicator empty dots: bg-zinc-700 was too dark on white; paired with bg-zinc-300 for figure/ground contrast in light mode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Settings panel grows an Appearance card at the top with a segmented Light / Dark / System theme picker, and the existing API integration sections (App Store Connect, Apple Search Ads) become collapsible cards with a green checkmark on the Connected status. The whole app picks up a light theme (dark stays the default).
Demo
Dark stays the default; switch to Light from Settings → Appearance.
Systemfollows the OS live viaprefers-color-scheme(test it by toggling macOS appearance — the page flips without you touching anything).What changed
New: theme infrastructure
web/src/lib/theme.ts— localStorage-backedThemestore (light/dark/system), idempotentmatchMedialistener for live OS-preference following.web/src/components/ThemePicker.svelte— controlled segmented picker with sun/moon/laptop SVG icons.web/index.html— inline<script>in<head>applies the saved theme class before first paint (module scripts can't avoid FOUC because they're deferred).web/src/main.ts— callsinitTheme()beforemountfor runtime listener setup.web/src/app.css— light scrollbar by default, dark scoped viahtml.dark.Settings panel UX
transition:slide(200ms) on expand/collapse;aria-expanded+aria-controlswired in for screen readers.Component sweep — 20 .svelte files
Existing dark-only color classes paired with light-mode counterparts using Tailwind's
dark:variant (darkMode: 'class'was already configured but never used). Mapping recipe:bg-zinc-950bg-white dark:bg-zinc-950bg-zinc-900/800/700bg-zinc-50/100/200 dark:bg-zinc-900/800/700text-zinc-100/200/300/400text-zinc-900/800/700/600 dark:text-zinc-100/200/300/400text-zinc-500text-emerald/amber/red/blue-400bg-zinc-100,text-zinc-950)UI fixes surfaced during the migration
bg-amber-500) had near-white text in light modetext-zinc-950in both modes — yellow needs dark text✓checkmarks had same yellow-contrast bugtext-blue-200) invisible onbg-blue-50text-blue-700hover:bg-whiteon light bg)hover:bg-black dark:hover:bg-whiteDotsIndicatorempty dots (bg-zinc-700) looked like filled dark dots on whitebg-zinc-300for the figure/ground recedeVerification
npm run check— 0 errors / 0 warnings across 146 filesRelationship to #7
#7 (the ASA docs-link copy edit) was branched off the same
mainand is still open. The two PRs both touchSettingsPanel.sveltebut at different lines:Whichever merges first, the other rebases cleanly. (I verified by stashing this work onto fresh
mainand getting only a one-line content overlap on the<code>element, which I kept aligned with main's text.)