feat(admin-ui): add responsive layout state

This commit is contained in:
duanshuwen committed 2026-08-26 20:35:29 +08:00
1 parent 63ce8797bc
commit 0b106a3dd2
2 files changed
+182

No files matched your search

@@ -0,0 +1,79 @@
import { createPinia, setActivePinia } from "pinia";
import { afterEach, describe, expect, it, vi } from "vitest";
import { useLayoutStore } from "./layout";
describe("layout store", () => {
afterEach(() => {
vi.unstubAllGlobals();
});
it.each([
[991, "mobile"],
[992, "desktop"],
[993, "desktop"],
] as const)("uses the strict mobile breakpoint at %spx", (width, expectedDevice) => {
setActivePinia(createPinia());
const store = useLayoutStore();
store.syncViewport(width);
expect(store.device).toBe(expectedDevice);
expect(store.sidebarOpened).toBe(expectedDevice === "desktop");
});
it("is safe to use without window", () => {
setActivePinia(createPinia());
const store = useLayoutStore();
expect(() => store.syncViewport()).not.toThrow();
expect(() => store.startViewportWatcher()).not.toThrow();
expect(store.device).toBe("desktop");
});
it("registers one resize watcher, updates on resize, and unsubscribes idempotently", () => {
const addEventListener = vi.fn();
const removeEventListener = vi.fn();
const browserWindow = { innerWidth: 993, addEventListener, removeEventListener };
vi.stubGlobal("window", browserWindow);
setActivePinia(createPinia());
const store = useLayoutStore();
const stop = store.startViewportWatcher();
const sameStop = store.startViewportWatcher();
const resizeHandler = addEventListener.mock.calls[0][1] as () => void;
expect(sameStop).toBe(stop);
expect(addEventListener).toHaveBeenCalledTimes(1);
expect(store.device).toBe("desktop");
browserWindow.innerWidth = 991;
resizeHandler();
expect(store.device).toBe("mobile");
expect(store.sidebarOpened).toBe(false);
stop();
stop();
expect(removeEventListener).toHaveBeenCalledTimes(1);
browserWindow.innerWidth = 993;
resizeHandler();
expect(store.device).toBe("mobile");
});
it("controls the sidebar and animation flag independently", () => {
setActivePinia(createPinia());
const store = useLayoutStore();
store.toggleSidebar({ withoutAnimation: true });
expect(store.sidebarOpened).toBe(false);
expect(store.withoutAnimation).toBe(true);
store.openSidebar({ withoutAnimation: false });
expect(store.sidebarOpened).toBe(true);
expect(store.withoutAnimation).toBe(false);
store.closeSidebar();
expect(store.sidebarOpened).toBe(false);
expect(store.withoutAnimation).toBe(false);
});
});