From 6206af8ce960b57441f8d4c9381d3f8ae5267c23 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 16 Jul 2026 23:58:57 -0700 Subject: [PATCH] FN-8146: restore persistent theme selection Restore the full Settings theme picker while preserving Shadcn Mono selections across reloads. - Merge the Settings selector into the current-theme row with shared dropdown controls. - Restore Shadcn Mono across theme metadata, token styles, and dashboard/desktop bootstrap validation. - Scope Mono light swatches correctly and cover restored options and persistence with tests. Files changed: .changeset/FN-8146-theme-dropdown-current-row.md | 7 +++ docs/dashboard-guide.md | 5 ++- packages/core/src/types/execution-and-ui.ts | 1 + .../dashboard/app/components/ThemeDropdown.css | 52 ++++++++++++++++++++++ .../dashboard/app/components/ThemeDropdown.tsx | 42 ++++++++++++++--- .../dashboard/app/components/ThemeSelector.css | 42 +---------------- .../dashboard/app/components/ThemeSelector.tsx | 45 +++++-------------- .../components/__tests__/ThemeDropdown.test.tsx | 46 ++++++++++++++++--- .../components/__tests__/ThemeSelector.test.tsx | 29 ++++++++---- .../__tests__/CommandCenterControls.test.tsx | 15 ++++++- packages/dashboard/app/components/themeOptions.ts | 2 + .../dashboard/app/hooks/__tests__/useTheme.test.ts | 8 ++-- packages/dashboard/app/hooks/useTheme.ts | 8 ++-- packages/dashboard/app/index.html | 5 +-- packages/dashboard/app/public/theme-data.css | 16 ++++++- packages/desktop/src/renderer/index.html | 1 + 16 files changed, 213 insertions(+), 111 deletions(-) Fusion-Task-Id: FN-8146 Fusion-Task-Lineage: 32ec7f21-ee6b-4459-8e7b-f5a5435c4994 Co-authored-by: Fusion (runfusion.ai) --- .../FN-8146-theme-dropdown-current-row.md | 7 +++ docs/dashboard-guide.md | 5 +- packages/core/src/types/execution-and-ui.ts | 1 + .../app/components/ThemeDropdown.css | 52 +++++++++++++++++++ .../app/components/ThemeDropdown.tsx | 42 ++++++++++++--- .../app/components/ThemeSelector.css | 42 +-------------- .../app/components/ThemeSelector.tsx | 45 ++++------------ .../__tests__/ThemeDropdown.test.tsx | 46 +++++++++++++--- .../__tests__/ThemeSelector.test.tsx | 29 ++++++++--- .../__tests__/CommandCenterControls.test.tsx | 15 +++++- .../dashboard/app/components/themeOptions.ts | 2 + .../app/hooks/__tests__/useTheme.test.ts | 8 +-- packages/dashboard/app/hooks/useTheme.ts | 8 ++- packages/dashboard/app/index.html | 5 +- packages/dashboard/app/public/theme-data.css | 16 +++++- packages/desktop/src/renderer/index.html | 1 + 16 files changed, 213 insertions(+), 111 deletions(-) create mode 100644 .changeset/FN-8146-theme-dropdown-current-row.md diff --git a/.changeset/FN-8146-theme-dropdown-current-row.md b/.changeset/FN-8146-theme-dropdown-current-row.md new file mode 100644 index 0000000000..b8e0770541 --- /dev/null +++ b/.changeset/FN-8146-theme-dropdown-current-row.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Settings theme selector is merged into the current-theme row and lists every color theme. +category: feature +dev: ThemeDropdown gains a current-row trigger variant used by ThemeSelector; the static preview markup/CSS was removed. Tests assert the explicit historical theme set on Settings and Command Center, including restored Shadcn Mono. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index c7c284bbeb..2fa4ec8961 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -1852,10 +1852,11 @@ Non-Command-Center dashboard CSS uses `--text` as the canonical primary text tok + -Dark/light modes via `data-theme`; fresh installs default to System mode so the resolved theme follows `prefers-color-scheme` until the user explicitly chooses Light, Dark, or System. 80 color themes via `data-color-theme` (lazy-loaded from `app/public/theme-data.css`), including Cobalt (saturated blue), Clay (warm terracotta), Moss (muted forest green), the Shadcn zinc-neutral theme with an orange default highlight/accent, Shadcn Custom (the same base with sanitized per-token color-picker overrides), and its color family: Shadcn Blue/Green/Red/Purple/Pink/Orange/Yellow, Shadcn Mono Red/Blue/Green/Purple/Pink/Orange/Yellow (grayscale surfaces with color-specific accents; legacy `shadcn-mono` selections migrate to Shadcn Mono Red), Shadcn Black (pure black and white), Shadcn Gray (fully neutral zinc-gray accent), and Shadcn Gray Blue (blue-gray slate neutral surfaces with a muted slate-blue accent). Air is the minimal, borderless, paper-like preset with near-monochrome tokens and CSS-only chrome flattening. Glass Silver preserves the Glass theme's frosted translucent surfaces and transparent modal overlay behavior while using silver and graphite accents instead of purple/pink. +Dark/light modes via `data-theme`; fresh installs default to System mode so the resolved theme follows `prefers-color-scheme` until the user explicitly chooses Light, Dark, or System. 81 color themes via `data-color-theme` (lazy-loaded from `app/public/theme-data.css`), including Cobalt (saturated blue), Clay (warm terracotta), Moss (muted forest green), the Shadcn zinc-neutral theme with an orange default highlight/accent, Shadcn Custom (the same base with sanitized per-token color-picker overrides), and its color family: Shadcn Blue/Green/Red/Purple/Pink/Orange/Yellow, Shadcn Mono and Shadcn Mono Red/Blue/Green/Purple/Pink/Orange/Yellow (grayscale surfaces with color-specific accents; Shadcn Mono retains its selected id), Shadcn Black (pure black and white), Shadcn Gray (fully neutral zinc-gray accent), and Shadcn Gray Blue (blue-gray slate neutral surfaces with a muted slate-blue accent). Air is the minimal, borderless, paper-like preset with near-monochrome tokens and CSS-only chrome flattening. Glass Silver preserves the Glass theme's frosted translucent surfaces and transparent modal overlay behavior while using silver and graphite accents instead of purple/pink. -Choose Shadcn variants from **Settings → Appearance** or from the Command Center **Overview** theme card; both use the same compact `ThemeDropdown`, labels, and color-chip swatches. The left sidebar active-item highlight and resize accent use the active theme's `--accent`, so they follow the selected Shadcn accent instead of staying fixed blue. +Choose color themes from **Settings → Appearance** or from the Command Center **Overview** theme card. Settings merges its selector into the current-theme row, which opens the full color-theme list; Command Center keeps the compact `ThemeDropdown` trigger. Both list every selectable color theme with the same labels and color-chip swatches. The left sidebar active-item highlight and resize accent use the active theme's `--accent`, so they follow the selected Shadcn accent instead of staying fixed blue. - **Base tokens** (`--bg`, `--surface`, etc.) — redefine in `:root`, `[data-theme="light"]`, and every theme block. - **Semantic tokens** (`--autopilot-pulse`, `--event-error-text`, `--badge-mission-*`, `--fab-*`) — `:root` + `[data-theme="light"]` only; no per-color-theme overrides. diff --git a/packages/core/src/types/execution-and-ui.ts b/packages/core/src/types/execution-and-ui.ts index 5bc639a18f..c7ec454ab1 100644 --- a/packages/core/src/types/execution-and-ui.ts +++ b/packages/core/src/types/execution-and-ui.ts @@ -128,6 +128,7 @@ export const COLOR_THEMES = [ "shadcn-pink", "shadcn-orange", "shadcn-yellow", + "shadcn-mono", "shadcn-mono-red", "shadcn-mono-blue", "shadcn-mono-green", diff --git a/packages/dashboard/app/components/ThemeDropdown.css b/packages/dashboard/app/components/ThemeDropdown.css index 0902f1b744..b00c67dee8 100644 --- a/packages/dashboard/app/components/ThemeDropdown.css +++ b/packages/dashboard/app/components/ThemeDropdown.css @@ -37,6 +37,54 @@ Glass theme surfaces create stronger translucent stacking contexts, so the Comma white-space: nowrap; } +.theme-dropdown-trigger--current-row { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto auto; + align-items: center; + gap: var(--space-md); + padding: var(--space-md) var(--space-lg); + border-color: var(--border); + background: var(--card); + color: var(--text); + text-align: start; +} + +.theme-dropdown-current-row-icon { + display: flex; + align-items: center; + justify-content: center; + inline-size: calc(var(--space-2xl) + var(--space-md)); + block-size: calc(var(--space-2xl) + var(--space-md)); + border-radius: var(--radius); + background: var(--surface); + color: var(--todo); +} + +.theme-dropdown-current-row-info { + display: grid; + gap: var(--space-xs); + min-inline-size: 0; +} + +.theme-dropdown-current-row-label { + color: var(--text-muted); + font-size: var(--font-size-sm); +} + +.theme-dropdown-current-row-value { + overflow: hidden; + color: var(--text); + font-weight: 600; + text-overflow: ellipsis; + white-space: nowrap; +} + +.theme-dropdown-trigger--current-row:hover, +.theme-dropdown-trigger--current-row:focus-visible { + border-color: var(--accent); + background: color-mix(in srgb, var(--card) 90%, var(--accent)); +} + .theme-dropdown-modes { display: flex; flex-wrap: wrap; @@ -109,4 +157,8 @@ Glass theme surfaces create stronger translucent stacking contexts, so the Comma .theme-dropdown-list { max-block-size: min(50vh, calc(var(--space-2xl) * 10)); } + + .theme-dropdown-trigger--current-row { + padding: var(--space-md); + } } diff --git a/packages/dashboard/app/components/ThemeDropdown.tsx b/packages/dashboard/app/components/ThemeDropdown.tsx index efb0117cb2..07f3f61c3b 100644 --- a/packages/dashboard/app/components/ThemeDropdown.tsx +++ b/packages/dashboard/app/components/ThemeDropdown.tsx @@ -15,6 +15,7 @@ interface ThemeDropdownProps { resolvedThemeMode?: "dark" | "light"; onThemeModeChange?: (mode: ThemeMode) => void; onShadcnCustomColorsChange?: (colors: Record) => void; + triggerVariant?: "compact" | "current-row"; } export function resolveColorTheme(colorTheme: ColorTheme) { @@ -35,6 +36,9 @@ function ThemeSwatch({ className }: { className: string }) { /* FNXC:Theme 2026-06-19-12:10: FN-6727 requires Command Center operators to change the global app theme from a compact dropdown that previews each color theme with the same rich swatch chips used by Settings; this component accepts App-threaded setters instead of creating another theme owner. + +FNXC:Theme 2026-07-16-14:30: +FN-8146 merges Settings' current-theme summary into this dropdown trigger. The Settings variant carries mode and combined-value context while Command Center retains the compact swatch-and-label trigger. */ export function ThemeDropdown({ colorTheme, @@ -44,6 +48,7 @@ export function ThemeDropdown({ resolvedThemeMode = themeMode === "light" ? "light" : "dark", onThemeModeChange, onShadcnCustomColorsChange = () => {}, + triggerVariant = "compact", }: ThemeDropdownProps) { const { t } = useTranslation("app"); const [open, setOpen] = useState(false); @@ -52,6 +57,13 @@ export function ThemeDropdown({ const optionRefs = useRef>([]); const currentTheme = useMemo(() => resolveColorTheme(colorTheme), [colorTheme]); + const currentMode = themeMode === "system" ? resolvedThemeMode : themeMode; + const CurrentModeIcon = THEME_MODES.find((mode) => mode.value === currentMode)?.icon; + const modeLabel = themeMode === "system" + ? t("theme.system", "System") + : t(`theme.${themeMode}`, themeMode ? `${themeMode.charAt(0).toUpperCase()}${themeMode.slice(1)}` : "Dark"); + const currentThemeLabel = t(`theme.colorTheme.${currentTheme.value}`, currentTheme.label); + const currentRowLabel = `${t("theme.currentTheme", "Current theme")} ${modeLabel} / ${currentThemeLabel}`; const listboxId = "theme-dropdown-listbox"; useEffect(() => { @@ -118,20 +130,38 @@ export function ThemeDropdown({ }; return ( -
+
diff --git a/packages/dashboard/app/components/ThemeSelector.css b/packages/dashboard/app/components/ThemeSelector.css index 24284e089a..a318cf6cf5 100644 --- a/packages/dashboard/app/components/ThemeSelector.css +++ b/packages/dashboard/app/components/ThemeSelector.css @@ -425,6 +425,7 @@ --swatch-sample-4: #27272a; } +.theme-swatch-shadcn-mono, .theme-swatch-shadcn-mono-red { --swatch-sample-1: #09090b; --swatch-sample-2: #18181b; @@ -786,6 +787,7 @@ --swatch-sample-4: #e4e4e7; } +[data-theme="light"] .theme-swatch-shadcn-mono, [data-theme="light"] .theme-swatch-shadcn-mono-red { --swatch-sample-1: #ffffff; --swatch-sample-2: #f4f4f5; @@ -1231,46 +1233,6 @@ box-shadow: var(--focus-ring-strong); } -/* Theme current preview in settings */ -.theme-current-preview { - display: flex; - align-items: center; - gap: var(--space-md); - padding: var(--space-md) var(--space-lg); - background: var(--card); - border: 1px solid var(--border); - border-radius: var(--radius); - margin-bottom: 20px; -} - -.theme-preview-icon { - display: flex; - align-items: center; - justify-content: center; - width: 40px; - height: 40px; - background: var(--surface); - border-radius: var(--radius); - color: var(--todo); -} - -.theme-preview-info { - flex: 1; -} - -.theme-preview-label { - font-size: 12px; - color: var(--text-muted); - margin-bottom: 2px; -} - -.theme-preview-value { - font-size: 14px; - font-weight: 600; - color: var(--text); - text-transform: capitalize; -} - @media (max-width: 768px) { /* Model combobox dropdown: mobile-friendly sizing */ .model-combobox-dropdown { diff --git a/packages/dashboard/app/components/ThemeSelector.tsx b/packages/dashboard/app/components/ThemeSelector.tsx index 9431b8d1d4..c747a876b8 100644 --- a/packages/dashboard/app/components/ThemeSelector.tsx +++ b/packages/dashboard/app/components/ThemeSelector.tsx @@ -1,10 +1,9 @@ import "./ThemeSelector.css"; import { useCallback } from "react"; import { useTranslation } from "react-i18next"; -import { Sun, Moon, Monitor } from "lucide-react"; import type { ThemeMode, ColorTheme } from "@fusion/core"; import { THEME_MODES } from "./themeOptions"; -import { ThemeDropdown, resolveColorTheme } from "./ThemeDropdown"; +import { ThemeDropdown } from "./ThemeDropdown"; interface ThemeSelectorProps { themeMode: ThemeMode; @@ -40,7 +39,6 @@ export function ThemeSelector({ onShadcnCustomColorsChange = () => {}, }: ThemeSelectorProps) { const { t } = useTranslation("app"); - const currentColorTheme = resolveColorTheme(colorTheme); const handleReset = useCallback(() => { onThemeModeChange("system"); /* @@ -71,26 +69,16 @@ export function ThemeSelector({ ))}
- {/* Current Theme Preview */} -
-
- {themeMode === "light" ? ( - - ) : themeMode === "dark" ? ( - - ) : ( - - )} -
-
-
{t("theme.currentTheme", "Current theme")}
-
- {themeMode === "system" ? "System" : `${themeMode.charAt(0).toUpperCase() + themeMode.slice(1)}`} - {" / "} - {currentColorTheme.label} -
-
-
+ {/* FNXC:Theme 2026-07-16-14:30: FN-8146 makes the current-theme row the sole Settings color-theme trigger, replacing the separate static preview and standalone dropdown without adding a second mode control. */} +
{t("theme.fontSize", "Font Size")}
@@ -106,17 +94,6 @@ export function ThemeSelector({ ))}
- {/* - FNXC:Theme 2026-07-16-12:00: - Settings Appearance reuses ThemeDropdown so it has the same compact, keyboard-accessible color-theme affordance as the Command Center. ThemeSelector retains its mode, font-size, and reset controls, while ThemeDropdown remains the sole custom-color picker owner to avoid duplicate controls. - */} - {/* Reset Button */}