diff --git a/apps/app/src/views/SettingsView.appearance-layout.test.tsx b/apps/app/src/views/SettingsView.appearance-layout.test.tsx new file mode 100644 index 00000000000..51e7ea82c2e --- /dev/null +++ b/apps/app/src/views/SettingsView.appearance-layout.test.tsx @@ -0,0 +1,90 @@ +// @vitest-environment jsdom + +import { cleanup, render, screen } from "@testing-library/react"; +import { afterEach, expect, it, vi } from "vitest"; +import { defaultAppTheme } from "@bb/domain"; +import { + resetPluginSlotStoreForTest, + setPluginSlotRegistrations, +} from "@/lib/plugin-slots"; +import { makePluginRegistrationSet } from "@/test/fixtures/plugins"; +import { AppearanceSettingsSection } from "./SettingsView"; + +afterEach(() => { + cleanup(); + window.localStorage.clear(); + resetPluginSlotStoreForTest(); +}); + +it("keeps appearance choices first and groups provider controls in Interface", () => { + setPluginSlotRegistrations( + "fixture", + makePluginRegistrationSet({ + experimentalSidebarHeaders: [ + { id: "header", title: "Fixture header", component: () => null }, + ], + sourceCodeRenderers: [ + { id: "source", title: "Fixture source", component: () => null }, + ], + diffRenderers: [ + { id: "diff", title: "Fixture diff", component: () => null }, + ], + threadLists: [ + { id: "threads", title: "Fixture threads", component: () => null }, + ], + experimentalSidebarNavigations: [ + { + id: "navigation", + title: "Fixture navigation", + component: () => null, + }, + ], + }), + ); + + render( + , + ); + + const labels = (section: HTMLElement) => + Array.from( + section.querySelectorAll("[data-control-placement]"), + (row) => row.querySelector("p")?.textContent, + ); + const appearance = screen + .getByRole("heading", { name: "Appearance" }) + .closest("section"); + const interfaceSection = screen + .getByRole("heading", { name: "Interface" }) + .closest("section"); + + expect(appearance).not.toBeNull(); + expect(interfaceSection).not.toBeNull(); + expect(labels(appearance!)).toEqual([ + "Theme", + "Palette", + "Favicon color", + "Fade inactive splits", + ]); + expect(labels(interfaceSection!)).toEqual([ + "Header", + "Source code", + "Diffs", + "Sidebar", + "Navigation", + "Sidebar footer", + ]); +}); diff --git a/apps/app/src/views/SettingsView.tsx b/apps/app/src/views/SettingsView.tsx index 26461d13733..2d274a4ff4e 100644 --- a/apps/app/src/views/SettingsView.tsx +++ b/apps/app/src/views/SettingsView.tsx @@ -696,145 +696,154 @@ export function AppearanceSettingsSection({ onAppearanceThemeChange(themeId); }; return ( - -
- - - - - - - - - - - {THEME_PREFERENCE_OPTIONS.map((option) => ( - onThemePreferenceChange(option.value)} +
+ +
+ + + + + + + {THEME_PREFERENCE_OPTIONS.map((option) => ( + onThemePreferenceChange(option.value)} + > + {option.label} + + + ))} + + + - - { - if (open) { - paletteSelectedRef.current = false; - onAppearanceThemePrefetch([ - ...builtInThemes.map((entry) => entry.id), - ...customThemes, - ...pluginThemes.map((theme) => theme.id), - ]); - return; - } - previewPalette(null); - }} + - - - - { + if (open) { + paletteSelectedRef.current = false; + onAppearanceThemePrefetch([ + ...builtInThemes.map((entry) => entry.id), + ...customThemes, + ...pluginThemes.map((theme) => theme.id), + ]); + return; + } + previewPalette(null); + }} > - {builtInThemes.map((entry) => ( - - {entry.name} - - ))} - {customThemes.map((name) => ( - - {name} - - ))} - {pluginThemes.map((theme) => ( - + + + + {builtInThemes.map((entry) => ( + + {entry.name} + + ))} + {customThemes.map((name) => ( + + {name} + + ))} + {pluginThemes.map((theme) => ( + + {theme.name} + + ({theme.pluginId}) + + + ))} + + + + Create + + + + - - - -
-
+ + +
+ + +
+ + + + + +
+
+
); }