Zustand Stores
The shared library provides three Zustand stores at frontend/shared/src/stores/ that manage cross-workbench state coordination, user preferences, and the store index. These stores use Zustand's persist middleware for localStorage persistence and BroadcastChannel for cross-tab synchronization.
crossWorkbenchStore
File: frontend/shared/src/stores/crossWorkbenchStore.ts
The primary mechanism for sharing state between workbenches. Manages entity handoff, navigation requests, catalog context, and global filters.
State Interface
interface CrossWorkbenchState {
selectedEntity: SelectedEntity | null;
entityHistory: SelectedEntity[]; // Max 20 entries
activeCatalog: string | null;
activeSchema: string | null;
activeTable: string | null;
navigationRequest: NavigationRequest | null;
globalFilters: Record<string, unknown>;
globalTimeRange: GlobalTimeRange | null;
}Actions
| Action | Parameters | Description |
|---|---|---|
selectEntity | SelectedEntity | Set active entity and add to history |
clearEntity | - | Clear active entity |
setCatalogContext | catalog, schema?, table? | Set active catalog context |
requestNavigation | NavigationRequest | Request cross-workbench navigation |
clearNavigation | - | Clear navigation request |
setGlobalFilters | Record<string, unknown> | Replace all global filters |
mergeGlobalFilters | Record<string, unknown> | Merge into existing filters |
clearGlobalFilters | - | Clear all global filters |
setGlobalTimeRange | `GlobalTimeRange | null` |
Selectors
export const selectSelectedEntity = (state) => state.selectedEntity;
export const selectEntityHistory = (state) => state.entityHistory;
export const selectActiveCatalog = (state) => state.activeCatalog;
export const selectActiveSchema = (state) => state.activeSchema;
export const selectActiveTable = (state) => state.activeTable;
export const selectNavigationRequest = (state) => state.navigationRequest;
export const selectGlobalFilters = (state) => state.globalFilters;
export const selectGlobalTimeRange = (state) => state.globalTimeRange;BroadcastChannel Synchronization
Every mutation broadcasts to other browser tabs via the matih-cross-workbench BroadcastChannel. A guard flag (isReceiving) prevents infinite loops when receiving updates from other tabs.
preferencesStore
File: frontend/shared/src/stores/preferencesStore.ts
Manages user appearance, accessibility, and behavior preferences with immediate CSS variable application.
State Interface
interface UserPreferences {
theme: 'light' | 'dark' | 'system';
fontSize: 'small' | 'medium' | 'large';
density: 'compact' | 'comfortable' | 'spacious';
reducedMotion: boolean;
highContrast: boolean;
focusIndicators: 'default' | 'enhanced';
screenReaderOptimized: boolean;
fontScale: number;
commandPaletteRecentCommands: string[];
sidebarCollapsed: boolean;
notificationsEnabled: boolean;
soundEnabled: boolean;
}CSS Variable Application
Each preference change triggers immediate DOM updates:
| Preference | CSS Effect |
|---|---|
theme | Adds/removes light/dark class on <html> |
fontSize | Sets --font-size-multiplier (0.875, 1, 1.125) |
density | Sets --density-multiplier (0.75, 1, 1.25) |
reducedMotion | Adds/removes reduce-motion class |
highContrast | Adds/removes high-contrast class |
fontScale | Sets --font-scale property |
Derived Hooks
// Resolves 'system' to actual theme
export function useEffectiveTheme(): 'light' | 'dark';
// Combines user preference with system reduced motion
export function useShouldReduceMotion(): boolean;The store persists to matih-user-preferences in localStorage and rehydrates preferences on load, immediately applying CSS variables via onRehydrateStorage.