From 962cdb968dcb2a08f42a7219483e5afb44bfa6d3 Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Tue, 28 Jul 2026 03:17:55 +0800 Subject: [PATCH] style(webui): animate settings section transitions --- .../src/components/settings/SettingsView.tsx | 6 +++- webui/src/tests/app-layout.test.tsx | 30 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/webui/src/components/settings/SettingsView.tsx b/webui/src/components/settings/SettingsView.tsx index 1dcf16d2c..f5801187c 100644 --- a/webui/src/components/settings/SettingsView.tsx +++ b/webui/src/components/settings/SettingsView.tsx @@ -2347,8 +2347,12 @@ export function SettingsView({ )} >
{ expect(window.location.hash).toBe("#/settings?section=voice"); }); - it("opens Apps from the main sidebar without replacing the sidebar", async () => { + it("transitions between Apps and Skills without replacing the sidebar", async () => { mockFetchRoutes({ "/api/settings": baseSettingsPayload(), "/api/settings/cli-apps": { apps: [], installed_count: 0, catalog_updated_at: "2026-04-18" }, "/api/settings/mcp-presets": { presets: [], installed_count: 0 }, + "/api/webui/skills": { skills: [] }, }); render(); @@ -2080,7 +2081,34 @@ describe("App layout", () => { "aria-current", "page", ); + expect(screen.getByTestId("settings-section-transition")).toHaveAttribute( + "data-settings-section", + "apps", + ); + expect(screen.getByTestId("settings-section-transition")).toHaveClass( + "animate-in", + "fade-in-0", + "slide-in-from-bottom-1", + "duration-200", + "motion-reduce:animate-none", + ); expect(document.title).toBe("Apps · nanobot"); + + fireEvent.click(within(sidebar).getByRole("button", { name: "Skills" })); + + expect(await screen.findByRole("heading", { name: "Skills" })).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByTestId("settings-section-transition")).toHaveAttribute( + "data-settings-section", + "skills", + ); + }); + expect(screen.getByRole("navigation", { name: "Sidebar navigation" })).toBeInTheDocument(); + expect(within(sidebar).getByRole("button", { name: "Skills" })).toHaveAttribute( + "aria-current", + "page", + ); + expect(document.title).toBe("Skills · nanobot"); }); it("returns from settings to the blank start page when no session was active", async () => {