[AI] Custom Themes - ability to define separate light/dark theme (#7145)

* [AI] Consolidate custom theme prefs and improve auto-mode UX

- Merge `installedCustomTheme` into `installedCustomLightTheme` so only
  two prefs exist (light + dark). The legacy asyncStorage key
  `installed-custom-theme` is preserved for backwards compatibility.
- In auto (System default) mode, the main Theme dropdown no longer
  surfaces the installed custom-light theme as an option; custom themes
  for light/dark are managed exclusively via the sub-selectors.
- Selecting "System default" resets both light and dark custom themes.
- Installing a custom theme from the main dropdown while in auto mode
  switches the base theme to "Light" so it applies directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add release notes for PR #7145

* Change category from Features to Enhancement

Custom Themes: separate light and dark theme options when selecting 'system default' theme.

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #7145

* Enhance ThemeSettings and UI components by adding maxWidth styling for better responsiveness. This change ensures that buttons and columns adapt to the full width of their containers.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Matiss Janis Aboltins
2026-03-11 18:07:06 +00:00
committed by GitHub
parent a65ab2b4ce
commit 8a8fb2da51
8 changed files with 231 additions and 63 deletions

View File

@@ -99,10 +99,16 @@ async function saveGlobalPrefs(prefs: GlobalPrefs) {
prefs.preferredDarkTheme,
);
}
if (prefs.installedCustomTheme !== undefined) {
if (prefs.installedCustomLightTheme !== undefined) {
await asyncStorage.setItem(
'installed-custom-theme',
prefs.installedCustomTheme,
prefs.installedCustomLightTheme,
);
}
if (prefs.installedCustomDarkTheme !== undefined) {
await asyncStorage.setItem(
'installed-custom-dark-theme',
prefs.installedCustomDarkTheme,
);
}
if (prefs.serverSelfSignedCert !== undefined) {
@@ -133,7 +139,8 @@ async function loadGlobalPrefs(): Promise<GlobalPrefs> {
language,
theme,
'preferred-dark-theme': preferredDarkTheme,
'installed-custom-theme': installedCustomTheme,
'installed-custom-theme': installedCustomLightTheme,
'installed-custom-dark-theme': installedCustomDarkTheme,
'server-self-signed-cert': serverSelfSignedCert,
syncServerConfig,
notifyWhenUpdateIsAvailable,
@@ -147,6 +154,7 @@ async function loadGlobalPrefs(): Promise<GlobalPrefs> {
'theme',
'preferred-dark-theme',
'installed-custom-theme',
'installed-custom-dark-theme',
'server-self-signed-cert',
'syncServerConfig',
'notifyWhenUpdateIsAvailable',
@@ -170,7 +178,8 @@ async function loadGlobalPrefs(): Promise<GlobalPrefs> {
preferredDarkTheme === 'dark' || preferredDarkTheme === 'midnight'
? preferredDarkTheme
: 'dark',
installedCustomTheme: installedCustomTheme || undefined,
installedCustomLightTheme: installedCustomLightTheme || undefined,
installedCustomDarkTheme: installedCustomDarkTheme || undefined,
serverSelfSignedCert: serverSelfSignedCert || undefined,
syncServerConfig: syncServerConfig || undefined,
notifyWhenUpdateIsAvailable:

View File

@@ -121,7 +121,8 @@ export type GlobalPrefs = Partial<{
colors: Record<string, string>;
}
>; // Complete plugin theme metadata
installedCustomTheme?: string; // JSON string of installed custom theme
installedCustomLightTheme?: string; // JSON of InstalledTheme for light custom theme (also used as single custom theme in non-auto mode)
installedCustomDarkTheme?: string; // JSON of InstalledTheme for auto-mode dark custom theme
documentDir: string; // Electron only
serverSelfSignedCert: string; // Electron only
syncServerConfig?: {
@@ -150,7 +151,8 @@ export type GlobalPrefsJson = Partial<{
language?: GlobalPrefs['language'];
theme?: GlobalPrefs['theme'];
'preferred-dark-theme'?: GlobalPrefs['preferredDarkTheme'];
'installed-custom-theme'?: GlobalPrefs['installedCustomTheme'];
'installed-custom-theme'?: GlobalPrefs['installedCustomLightTheme'];
'installed-custom-dark-theme'?: GlobalPrefs['installedCustomDarkTheme'];
plugins?: string; // "true" or "false"
'plugin-theme'?: string; // JSON string of complete plugin theme (current selected plugin theme)
'server-self-signed-cert'?: GlobalPrefs['serverSelfSignedCert'];