From fc9c6ef164e1f944bb0af94e3b61dfd8d7caf8c5 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Sat, 16 May 2026 11:37:13 +0200 Subject: [PATCH] feat(stores): add useShellUiStore for v2 shell UI state Co-Authored-By: Claude Opus 4.7 --- .../stores/__tests__/useShellUiStore.spec.ts | 48 ++++++++++++++ apps/app/src/stores/useShellUiStore.ts | 64 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 apps/app/src/stores/__tests__/useShellUiStore.spec.ts create mode 100644 apps/app/src/stores/useShellUiStore.ts diff --git a/apps/app/src/stores/__tests__/useShellUiStore.spec.ts b/apps/app/src/stores/__tests__/useShellUiStore.spec.ts new file mode 100644 index 00000000..4023a4cb --- /dev/null +++ b/apps/app/src/stores/__tests__/useShellUiStore.spec.ts @@ -0,0 +1,48 @@ +import { beforeEach, describe, expect, it } from 'vitest' +import { createPinia, setActivePinia } from 'pinia' +import { useShellUiStore } from '@/stores/useShellUiStore' + +describe('useShellUiStore', () => { + beforeEach(() => { + setActivePinia(createPinia()) + document.documentElement.removeAttribute('data-theme') + document.documentElement.removeAttribute('data-density') + document.documentElement.classList.remove('dark') + }) + + it('defaults: expanded sidebar, comfortable density, light theme, closed drawer', () => { + const s = useShellUiStore() + + expect(s.sidebarCollapsed).toBe(false) + expect(s.density).toBe('comfortable') + expect(s.theme).toBe('light') + expect(s.drawer.isOpen).toBe(false) + }) + + it('toggleSidebar flips collapsed', () => { + const s = useShellUiStore() + + s.toggleSidebar() + expect(s.sidebarCollapsed).toBe(true) + }) + + it('applyDomAttributes writes data-theme/data-density and .dark', () => { + const s = useShellUiStore() + + s.setTheme('dark') + s.setDensity('compact') + s.applyDomAttributes() + expect(document.documentElement.getAttribute('data-theme')).toBe('dark') + expect(document.documentElement.getAttribute('data-density')).toBe('compact') + expect(document.documentElement.classList.contains('dark')).toBe(true) + }) + + it('openDrawer/closeDrawer mutate drawer state', () => { + const s = useShellUiStore() + + s.openDrawer('PersonCard', { id: '01H' }) + expect(s.drawer).toEqual({ isOpen: true, component: 'PersonCard', props: { id: '01H' } }) + s.closeDrawer() + expect(s.drawer.isOpen).toBe(false) + }) +}) diff --git a/apps/app/src/stores/useShellUiStore.ts b/apps/app/src/stores/useShellUiStore.ts new file mode 100644 index 00000000..5cb34ef8 --- /dev/null +++ b/apps/app/src/stores/useShellUiStore.ts @@ -0,0 +1,64 @@ +import { defineStore } from 'pinia' +import { ref } from 'vue' + +// v2 shell UI state ONLY (RFC-WS-GUI-REDESIGN AD-G4). No tenant/org +// state — that stays in useAuthStore/useOrganisationStore. Owns the +// writes to //.dark (composes with +// Aura darkModeSelector '.dark'); v2 bypasses Vuexy useSkins.ts. + +export type ShellTheme = 'light' | 'dark' +export type ShellDensity = 'comfortable' | 'compact' + +export interface ShellDrawerState { + isOpen: boolean + component: string | null + props: Record +} + +export const useShellUiStore = defineStore('shellUi', () => { + const sidebarCollapsed = ref(false) + const density = ref('comfortable') + const theme = ref('light') + const drawer = ref({ isOpen: false, component: null, props: {} }) + + function toggleSidebar(): void { + sidebarCollapsed.value = !sidebarCollapsed.value + } + + function setTheme(next: ShellTheme): void { + theme.value = next + } + + function setDensity(next: ShellDensity): void { + density.value = next + } + + function applyDomAttributes(): void { + const el = document.documentElement + + el.setAttribute('data-theme', theme.value) + el.setAttribute('data-density', density.value) + el.classList.toggle('dark', theme.value === 'dark') + } + + function openDrawer(component: string, props: Record = {}): void { + drawer.value = { isOpen: true, component, props } + } + + function closeDrawer(): void { + drawer.value = { isOpen: false, component: null, props: {} } + } + + return { + sidebarCollapsed, + density, + theme, + drawer, + toggleSidebar, + setTheme, + setDensity, + applyDomAttributes, + openDrawer, + closeDrawer, + } +})