feat: add theme_mode, theme_light, theme_dark to UserAppearanceSettings (#25076)

Part 1: Backend portion of a change broken into 2 PRs.
Part 2: #25077 

Adds three new UserAppearanceSettings fields (theme_mode, theme_light,
theme_dark) on top of the existing theme_preference and terminal_font.
Replaces GetUserThemePreference and GetUserTerminalFont with a single
GetUserAppearanceSettings aggregate query. The PUT handler is wrapped in
db.InTx so sync-mode's mode + slot writes can never half-apply.
This commit is contained in:
Jaayden Halko
2026-05-14 05:44:05 +01:00
committed by GitHub
parent d147dd3bdd
commit 024132e8a4
23 changed files with 1209 additions and 223 deletions
+44 -4
View File
@@ -252,14 +252,54 @@ const (
TerminalFontJetBrainsMono TerminalFontName = "jetbrains-mono"
)
type ThemeMode string
const (
// ThemeModeUnset is the server-side default when the user has never
// set a theme_mode. It is also stored for legacy auto preferences so
// clients can migrate the old sync-with-system setting. Clients should
// inspect ThemePreference for legacy auto values before treating unset
// mode as ThemeModeSingle for backward compatibility with PR #24672.
ThemeModeUnset ThemeMode = ""
ThemeModeSync ThemeMode = "sync"
ThemeModeSingle ThemeMode = "single"
)
type UserAppearanceSettings struct {
ThemePreference string `json:"theme_preference"`
TerminalFont TerminalFontName `json:"terminal_font"`
// ThemePreference is the legacy single-field appearance setting. In
// "single" mode it mirrors the active theme. In "sync" mode modern
// clients normally mirror the active OS slot, but older clients can
// update only this field, so it may diverge from ThemeLight or
// ThemeDark until a modern client saves the full appearance state
// again.
ThemePreference string `json:"theme_preference"`
ThemeMode ThemeMode `json:"theme_mode"`
// Ignored when ThemeMode is "single"
ThemeLight string `json:"theme_light"`
// Ignored when ThemeMode is "single"
ThemeDark string `json:"theme_dark"`
TerminalFont TerminalFontName `json:"terminal_font"`
}
type UpdateUserAppearanceSettingsRequest struct {
ThemePreference string `json:"theme_preference" validate:"required"`
TerminalFont TerminalFontName `json:"terminal_font" validate:"required"`
ThemePreference string `json:"theme_preference" validate:"required"`
// ThemeMode is optional for backward compatibility. When empty,
// the server leaves theme_mode, theme_light, and theme_dark
// unchanged so older CLI clients do not erase sync-mode settings.
// Legacy auto preferences are the exception: they clear theme_mode
// so clients can migrate the old sync-with-system setting.
ThemeMode ThemeMode `json:"theme_mode" validate:"omitempty,oneof=sync single"`
// ThemeLight is required when ThemeMode is "sync". In "single"
// mode an empty value means "preserve the previously persisted
// slot" rather than "clear the slot", so partial updates that send
// only one slot keep the other intact.
ThemeLight string `json:"theme_light" validate:"required_if=ThemeMode sync,omitempty,oneof=light light-protan-deuter light-tritan dark dark-protan-deuter dark-tritan"`
// ThemeDark is required when ThemeMode is "sync". In "single" mode
// an empty value means "preserve the previously persisted slot"
// rather than "clear the slot", so partial updates that send only
// one slot keep the other intact.
ThemeDark string `json:"theme_dark" validate:"required_if=ThemeMode sync,omitempty,oneof=light light-protan-deuter light-tritan dark dark-protan-deuter dark-tritan"`
TerminalFont TerminalFontName `json:"terminal_font" validate:"required"`
}
type UserPreferenceSettings struct {