Replace accent presets with the sunset-to-sea family

Swap Toffee/Slate/Evergreen/Lavender for rose/coral/amber/teal — four ramps
sharing one lightness/saturation curve (src/renderer/src/theme.ts). Default
accent is now teal. Updates ACCENT_COLORS (src/shared/ipc.ts), the settings
default + stale-value coercion (src/main/settings.ts), the dev/store fallbacks
(main.tsx, store/settings.ts), and the native window background to match the
new pageBackground.light (src/main/index.ts).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 13:10:53 -04:00
parent 18e1d9a24d
commit af9300d5e3
6 changed files with 104 additions and 123 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ let mainWindow: BrowserWindow | null = null
// src/renderer/src/theme.ts. Set as the window's NATIVE background so the // src/renderer/src/theme.ts. Set as the window's NATIVE background so the
// one-frame compositor repaint (when a tooltip/dropdown overlay first paints on // one-frame compositor repaint (when a tooltip/dropdown overlay first paints on
// Windows) shows the app's current color instead of a mismatched white flash. // Windows) shows the app's current color instead of a mismatched white flash.
const THEME_BACKGROUND = { light: '#f6f1ef', dark: '#161618' } as const const THEME_BACKGROUND = { light: '#f7f7f8', dark: '#161618' } as const
// 'system' isn't a real background — resolve it against the OS's current // 'system' isn't a real background — resolve it against the OS's current
// preference (nativeTheme.themeSource defaults to 'system', so this tracks it // preference (nativeTheme.themeSource defaults to 'system', so this tracks it
+6 -1
View File
@@ -23,7 +23,7 @@ const DEFAULTS: Settings = {
maxConcurrent: 2, maxConcurrent: 2,
filenameTemplate: '%(title)s.%(ext)s', filenameTemplate: '%(title)s.%(ext)s',
theme: 'light', theme: 'light',
accentColor: 'toffee', accentColor: 'teal',
clipboardWatch: true, clipboardWatch: true,
downloadOptions: DEFAULT_DOWNLOAD_OPTIONS, downloadOptions: DEFAULT_DOWNLOAD_OPTIONS,
proxy: '', proxy: '',
@@ -106,6 +106,11 @@ export function getSettings(): Settings {
if (!downloadOptionsEqual(sanitized, cur.downloadOptions)) { if (!downloadOptionsEqual(sanitized, cur.downloadOptions)) {
s.set('downloadOptions', sanitized) s.set('downloadOptions', sanitized)
} }
// Coerce an accentColor left over from a renamed/removed preset (e.g. an old
// 'toffee' or 'indigo' default) onto the current default, so it resolves cleanly.
if (!(ACCENT_COLORS as readonly string[]).includes(cur.accentColor)) {
s.set('accentColor', DEFAULTS.accentColor)
}
return s.store return s.store
} }
+1 -1
View File
@@ -18,7 +18,7 @@ if (import.meta.env.DEV && !window.api) {
maxConcurrent: 2, maxConcurrent: 2,
filenameTemplate: '%(title)s.%(ext)s', filenameTemplate: '%(title)s.%(ext)s',
theme: 'light', theme: 'light',
accentColor: 'toffee', accentColor: 'teal',
clipboardWatch: true, clipboardWatch: true,
downloadOptions: DEFAULT_DOWNLOAD_OPTIONS, downloadOptions: DEFAULT_DOWNLOAD_OPTIONS,
proxy: '', proxy: '',
+1 -1
View File
@@ -12,7 +12,7 @@ const FALLBACK: Settings = {
maxConcurrent: 2, maxConcurrent: 2,
filenameTemplate: '%(title)s.%(ext)s', filenameTemplate: '%(title)s.%(ext)s',
theme: 'light', theme: 'light',
accentColor: 'toffee', accentColor: 'teal',
clipboardWatch: true, clipboardWatch: true,
downloadOptions: DEFAULT_DOWNLOAD_OPTIONS, downloadOptions: DEFAULT_DOWNLOAD_OPTIONS,
proxy: '', proxy: '',
+94 -118
View File
@@ -6,88 +6,87 @@ import {
} from '@fluentui/react-components' } from '@fluentui/react-components'
import type { AccentColor } from '@shared/ipc' import type { AccentColor } from '@shared/ipc'
// Toffee-brown brand ramp. The product palette (50950) is remapped onto // "Sunset-to-sea" accent family. All four ramps are built the same way — one
// Fluent's 16-stop BrandVariants (10 = darkest … 160 = lightest) so the LIGHT // shared lightness/saturation curve mapped onto Fluent's 16 BrandVariants stops:
// primary lands on toffee-600 (#825e4a) at index 80, and the DARK primary on a // a deep near-black floor (idx 10), a white-text-safe LIGHT primary at idx 80, a
// lightened toffee-400 (#b5917d) — applied via toffeeDarkOverrides below. // bright DARK-mode lift at idx 110 (applied via buildDarkOverrides), and a near-
const toffee: BrandVariants = { // white top (idx 160). The idx-80 primaries are tuned to equal luminance so none
10: '#17100d', // reads louder than the rest. Hues are three analogous warms — rose → coral →
20: '#201713', // amber — plus teal as the cool complement that anchors the set.
30: '#2e211a', const rose: BrandVariants = {
40: '#412f25', 10: '#20090f',
50: '#4f3a2d', 20: '#3b0e1a',
60: '#614638', 30: '#581124',
70: '#735140', 40: '#75132d',
80: '#825e4a', 50: '#921637',
90: '#946b54', 60: '#ae1941',
100: '#a2755d', 70: '#c91e4c',
110: '#b5917d', 80: '#dc2a5a',
120: '#c7ac9e', 90: '#e34670',
130: '#d3bcae', 100: '#eb6186',
140: '#dac8be', 110: '#f17e9d',
150: '#ece3df', 120: '#f197af',
160: '#f6f1ef' 130: '#f0b0c1',
140: '#f0c9d3',
150: '#f2dfe4',
160: '#f8f2f3'
} }
// Additional accent presets (Phase E). Each ramp reuses toffee's exact const coral: BrandVariants = {
// lightness curve at a different hue, so they read as siblings rather than 10: '#210e08',
// arbitrary colors — only `buildDarkOverrides` below differs from toffee's 20: '#39150b',
// hand-tuned dark lift. 30: '#541c0d',
const slate: BrandVariants = { 40: '#6f230e',
10: '#0f1215', 50: '#8a2a0f',
20: '#15191e', 60: '#a43111',
30: '#1e242a', 70: '#bc3915',
40: '#2b323b', 80: '#d3421a',
50: '#343d48', 90: '#e85831',
60: '#404c59', 100: '#f07554',
70: '#4b5968', 110: '#f5957a',
80: '#566576', 120: '#f4a893',
90: '#617387', 130: '#f3bdae',
100: '#6b7e94', 140: '#f1d0c7',
110: '#8998a9', 150: '#f3e3de',
120: '#a6b2bf', 160: '#f8f3f1'
130: '#b7c0cb',
140: '#c4cbd4',
150: '#e1e5ea',
160: '#f1f2f5'
} }
const evergreen: BrandVariants = { const amber: BrandVariants = {
10: '#0d1712', 10: '#221907',
20: '#12211a', 20: '#342507',
30: '#1a2e25', 30: '#463107',
40: '#254134', 40: '#593d06',
50: '#2d4f3f', 50: '#6b4905',
60: '#37624e', 60: '#7d5506',
70: '#40735b', 70: '#8d6007',
80: '#498368', 80: '#9c6b0a',
90: '#549576', 90: '#c8890a',
100: '#5ca382', 100: '#f4a60a',
110: '#7cb69b', 110: '#f7b634',
120: '#9dc8b4', 120: '#f8c359',
130: '#afd2c2', 130: '#f3ce83',
140: '#bedacd', 140: '#f0daad',
150: '#deede6', 150: '#f1e7d3',
160: '#eff6f3' 160: '#f9f6f1'
} }
const lavender: BrandVariants = { const teal: BrandVariants = {
10: '#120e16', 10: '#091f20',
20: '#191320', 20: '#0a2d2e',
30: '#231b2d', 30: '#0b3c3e',
40: '#32273f', 40: '#0c4b4d',
50: '#3d2f4d', 50: '#0d595c',
60: '#4b3a5f', 60: '#0e686b',
70: '#58446f', 70: '#117578',
80: '#644e7e', 80: '#148185',
90: '#725890', 90: '#18a8ad',
100: '#7d619e', 100: '#19d2d9',
110: '#9781b1', 110: '#33e4ea',
120: '#b1a0c5', 120: '#5ce6ea',
130: '#c0b2d0', 130: '#86e6e9',
140: '#cbc0d8', 140: '#afe7e9',
150: '#e5dfec', 150: '#d3edee',
160: '#f2f0f6' 160: '#f2f8f8'
} }
// Rounder corners — buttons/inputs ~10px, cards ~16px. NOT pills. // Rounder corners — buttons/inputs ~10px, cards ~16px. NOT pills.
@@ -101,32 +100,8 @@ const friendlyRadii = {
// Dark mode keeps Fluent's NEUTRAL (charcoal) surfaces and uses the accent // Dark mode keeps Fluent's NEUTRAL (charcoal) surfaces and uses the accent
// ramp only for buttons/links. The default dark brand is too low-contrast on // ramp only for buttons/links. The default dark brand is too low-contrast on
// near-black, so lift the brand to ramp-110 and flip on-brand text to dark for // near-black, so lift the brand to ramp-110 and flip on-brand text to dark for
// legible buttons. Toffee's lift was hand-tuned (hover/pressed/stroke shades // legible buttons. buildDarkOverrides derives that whole shape — hover/pressed/
// don't land exactly on ramp stops); newer presets use buildDarkOverrides, // stroke shades and all — directly from each ramp's own stops.
// which derives the same shape directly from each ramp's own stops.
const toffeeDarkOverrides = {
colorBrandBackground: '#b5917d',
colorBrandBackgroundHover: '#c19f8c',
colorBrandBackgroundPressed: '#a2755d',
colorBrandBackgroundSelected: '#b5917d',
colorNeutralForegroundOnBrand: '#1c1611',
colorCompoundBrandBackground: '#b5917d',
colorCompoundBrandBackgroundHover: '#c19f8c',
colorCompoundBrandBackgroundPressed: '#a2755d',
colorCompoundBrandForeground1: '#c7ac9e',
colorCompoundBrandForeground1Hover: '#d3bcae',
colorCompoundBrandForeground1Pressed: '#b5917d',
colorCompoundBrandStroke: '#b5917d',
colorCompoundBrandStrokeHover: '#c19f8c',
colorBrandForeground1: '#c7ac9e',
colorBrandForeground2: '#d3bcae',
colorBrandForegroundLink: '#c7ac9e',
colorBrandForegroundLinkHover: '#d3bcae',
colorBrandForegroundLinkPressed: '#b5917d',
colorBrandStroke1: '#b5917d',
colorBrandStroke2: '#5f4636'
} as const
function buildDarkOverrides(ramp: BrandVariants): Record<string, string> { function buildDarkOverrides(ramp: BrandVariants): Record<string, string> {
return { return {
colorBrandBackground: ramp[110], colorBrandBackground: ramp[110],
@@ -174,10 +149,10 @@ function buildPreset(
} }
export const ACCENT_PRESETS: Record<AccentColor, AccentPreset> = { export const ACCENT_PRESETS: Record<AccentColor, AccentPreset> = {
toffee: buildPreset('Toffee', toffee, toffeeDarkOverrides), rose: buildPreset('Rose', rose, buildDarkOverrides(rose)),
slate: buildPreset('Slate', slate, buildDarkOverrides(slate)), coral: buildPreset('Coral', coral, buildDarkOverrides(coral)),
evergreen: buildPreset('Evergreen', evergreen, buildDarkOverrides(evergreen)), amber: buildPreset('Amber', amber, buildDarkOverrides(amber)),
lavender: buildPreset('Lavender', lavender, buildDarkOverrides(lavender)) teal: buildPreset('Teal', teal, buildDarkOverrides(teal))
} }
export const ACCENT_OPTIONS: { value: AccentColor; label: string; swatch: string }[] = ( export const ACCENT_OPTIONS: { value: AccentColor; label: string; swatch: string }[] = (
@@ -189,29 +164,30 @@ export const ACCENT_OPTIONS: { value: AccentColor; label: string; swatch: string
})) }))
export function getTheme(accent: AccentColor, mode: 'light' | 'dark'): Theme { export function getTheme(accent: AccentColor, mode: 'light' | 'dark'): Theme {
const preset = ACCENT_PRESETS[accent] ?? ACCENT_PRESETS.toffee const preset = ACCENT_PRESETS[accent] ?? ACCENT_PRESETS.teal
return mode === 'dark' ? preset.dark : preset.light return mode === 'dark' ? preset.dark : preset.light
} }
// Page background behind the app shell. Light: warm toffee paper. Dark: neutral // Page background behind the app shell. Light: a clean, barely-cool off-white.
// charcoal (NOT brown) — the accent shows up only on buttons/links, independent // Dark: neutral charcoal. Intentionally accent-INDEPENDENT — the accent shows up
// of which preset is chosen. // only on buttons/links, so this stays neutral whichever preset is chosen.
// Keep light/dark in sync with THEME_BACKGROUND in src/main/index.ts.
export const pageBackground = { export const pageBackground = {
light: '#f6f1ef', light: '#f7f7f8',
dark: '#161618' dark: '#161618'
} }
// Per-kind thumbnail tints. Video vs audio differ by ramp DEPTH rather than a // Per-kind thumbnail tints. Video vs audio differ by ramp DEPTH rather than a
// competing hue, keeping the monochrome-warm Studio look. Theme-aware (light/ // competing hue, keeping a monochrome look. Theme-aware (light/dark) but
// dark) but intentionally NOT accent-aware — these sit on the neutral card // intentionally NOT accent-aware — a fixed neutral grey that sits quietly on the
// surface and shouldn't shift hue when the user picks a different accent. // card surface under any of the accent presets, warm or cool.
export const thumbColors = { export const thumbColors = {
light: { light: {
video: { bg: '#ece3df', fg: '#825e4a' }, video: { bg: '#eeeef0', fg: '#5e616a' },
audio: { bg: '#dac8be', fg: '#5f4636' } audio: { bg: '#e2e2e6', fg: '#4a4d55' }
}, },
dark: { dark: {
video: { bg: '#252025', fg: '#c7ac9e' }, video: { bg: '#26262a', fg: '#b5b6bd' },
audio: { bg: '#2b2620', fg: '#b5917d' } audio: { bg: '#2c2c31', fg: '#a0a1aa' }
} }
} as const } as const
+1 -1
View File
@@ -77,7 +77,7 @@ export const COOKIE_BROWSERS = ['chrome', 'edge', 'firefox', 'brave', 'opera', '
export type CookieBrowser = (typeof COOKIE_BROWSERS)[number] export type CookieBrowser = (typeof COOKIE_BROWSERS)[number]
/** Accent color presets for the brand ramp (see src/renderer/src/theme.ts). */ /** Accent color presets for the brand ramp (see src/renderer/src/theme.ts). */
export const ACCENT_COLORS = ['toffee', 'slate', 'evergreen', 'lavender'] as const export const ACCENT_COLORS = ['rose', 'coral', 'amber', 'teal'] as const
export type AccentColor = (typeof ACCENT_COLORS)[number] export type AccentColor = (typeof ACCENT_COLORS)[number]
/** UI color theme: an explicit mode, or 'system' to follow the OS preference. */ /** UI color theme: an explicit mode, or 'system' to follow the OS preference. */