feat(stores): add useShellUiStore for v2 shell UI state

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 11:37:13 +02:00
parent 9754d26e07
commit fc9c6ef164
2 changed files with 112 additions and 0 deletions

View File

@@ -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)
})
})

View File

@@ -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 <html data-theme>/<html data-density>/.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<string, unknown>
}
export const useShellUiStore = defineStore('shellUi', () => {
const sidebarCollapsed = ref(false)
const density = ref<ShellDensity>('comfortable')
const theme = ref<ShellTheme>('light')
const drawer = ref<ShellDrawerState>({ 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<string, unknown> = {}): 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,
}
})