From 08daa6b32e4dc256371b09fe85528479d73b0aa7 Mon Sep 17 00:00:00 2001 From: kenny lopez Date: Thu, 20 Aug 2026 09:00:46 +0100 Subject: [PATCH] fix(theme): constrain shared preference schema Signed-off-by: kenny lopez --- .../theme/communityThemePreference.test.mjs | 15 +++- .../community_theme_preference_test.dart | 10 +++ schema/community-theme-v1.json | 80 ++++++++++++++++++- 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/desktop/src/shared/theme/communityThemePreference.test.mjs b/desktop/src/shared/theme/communityThemePreference.test.mjs index 761fca602f..7675d0ec85 100644 --- a/desktop/src/shared/theme/communityThemePreference.test.mjs +++ b/desktop/src/shared/theme/communityThemePreference.test.mjs @@ -25,7 +25,12 @@ import { writeCommunityThemeOutbox, writeCommunityThemePreference, } from "./communityThemePreference.ts"; -import { GLASS_OPACITY_MAX, GLASS_OPACITY_MIN } from "./ThemeProvider.tsx"; +import { + ACCENT_COLORS, + GLASS_OPACITY_MAX, + GLASS_OPACITY_MIN, +} from "./ThemeProvider.tsx"; +import { SYNTAX_THEMES } from "./theme-loader.ts"; function localStorageStub() { const data = new Map(); @@ -361,6 +366,14 @@ test("desktop appearance limits match the shared wire contract", () => { DEFAULT_COMMUNITY_THEME.prominentActiveTab, contract.properties.prominentActiveTab.default, ); + assert.deepEqual( + [...contract.properties.theme.enum].sort(), + [...SYNTAX_THEMES].sort(), + ); + assert.deepEqual( + [...contract.properties.accent.enum].sort(), + ACCENT_COLORS.map(({ value }) => value).sort(), + ); }); test("appearance equality includes glass and prominent-tab choices", () => { diff --git a/mobile/test/shared/theme/community_theme_preference_test.dart b/mobile/test/shared/theme/community_theme_preference_test.dart index a180093a8a..f3f1898d83 100644 --- a/mobile/test/shared/theme/community_theme_preference_test.dart +++ b/mobile/test/shared/theme/community_theme_preference_test.dart @@ -77,6 +77,8 @@ void main() { final glassOpacity = properties['glassOpacity'] as Map; final prominentActiveTab = properties['prominentActiveTab'] as Map; + final theme = properties['theme'] as Map; + final accent = properties['accent'] as Map; expect(defaultCommunityGlassBackground, glassBackground['default'] as bool); expect(defaultCommunityGlassOpacity, glassOpacity['default'] as int); @@ -86,6 +88,14 @@ void main() { defaultCommunityProminentActiveTab, prominentActiveTab['default'] as bool, ); + expect( + theme['enum'], + unorderedEquals(themeCatalog.map((entry) => entry.name)), + ); + expect( + accent['enum'], + unorderedEquals(accentColors.map((entry) => entry.wireValue)), + ); }); test('rejects invalid theme and appearance values', () { diff --git a/schema/community-theme-v1.json b/schema/community-theme-v1.json index 3ccc5e29e4..cf45ef8abf 100644 --- a/schema/community-theme-v1.json +++ b/schema/community-theme-v1.json @@ -18,10 +18,86 @@ "const": 1 }, "theme": { - "type": "string" + "type": "string", + "enum": [ + "buzz", + "buzz-dark", + "andromeeda", + "aurora-x", + "ayu-dark", + "catppuccin-frappe", + "catppuccin-latte", + "catppuccin-macchiato", + "catppuccin-mocha", + "dark-plus", + "dracula", + "dracula-soft", + "everforest-dark", + "everforest-light", + "github-dark", + "github-dark-default", + "github-dark-dimmed", + "github-dark-high-contrast", + "github-light", + "github-light-default", + "github-light-high-contrast", + "gruvbox-dark-hard", + "gruvbox-dark-medium", + "gruvbox-dark-soft", + "gruvbox-light-hard", + "gruvbox-light-medium", + "gruvbox-light-soft", + "houston", + "kanagawa-dragon", + "kanagawa-lotus", + "kanagawa-wave", + "laserwave", + "light-plus", + "material-theme", + "material-theme-darker", + "material-theme-lighter", + "material-theme-ocean", + "material-theme-palenight", + "min-dark", + "min-light", + "monokai", + "night-owl", + "nord", + "one-dark-pro", + "one-light", + "plastic", + "poimandres", + "red", + "rose-pine", + "rose-pine-dawn", + "rose-pine-moon", + "slack-dark", + "slack-ochin", + "snazzy-light", + "solarized-dark", + "solarized-light", + "synthwave-84", + "tokyo-night", + "vesper", + "vitesse-black", + "vitesse-dark", + "vitesse-light" + ] }, "accent": { - "type": "string" + "type": "string", + "enum": [ + "neutral", + "#3b82f6", + "#06b6d4", + "#22c55e", + "#f97316", + "#ef4444", + "#ec4899", + "#c0a2f1", + "#a855f7", + "#6366f1" + ] }, "followSystem": { "type": "boolean"