feat: deliverables 3-6 — cold start, simple mode UI, bridge tests, docs
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Deliverable 3 — Cold Start Flow: - New: use-cold-start.ts — cold start detection + greeting management - Default Chinese greeting for hospital admin users - Phase tracking: idle → greeting_sent → waiting_response → completed Deliverable 4 — Simple Mode UI: - New: uiModeStore.ts — 'simple'|'professional' mode with localStorage - New: SimpleTopBar.tsx — minimal top bar with mode toggle - Modified: App.tsx — dual layout rendering based on UI mode - Modified: ChatArea.tsx — compact prop hides advanced controls - Default: 'simple' mode for zero-barrier first experience Deliverable 5 — Tauri Bridge Integration Tests: - New: tauri-bridge.integration.test.ts — 14 test cases - Covers: cold start, chat flow, persistence, memory, butler, UI mode, e2e - 14/14 passing Deliverable 6 — Release Documentation: - New: installation-guide.md — user-facing install guide (Chinese, no jargon) - New: hospital-deployment.md — IT admin deployment guide (Docker, GPO, SCCM)
This commit is contained in:
91
desktop/src/store/uiModeStore.ts
Normal file
91
desktop/src/store/uiModeStore.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* uiModeStore.ts - UI Mode Management Store
|
||||
*
|
||||
* Manages the toggle between simple mode and professional mode.
|
||||
* Persists preference to localStorage.
|
||||
*/
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { createLogger } from '../lib/logger';
|
||||
|
||||
const log = createLogger('uiModeStore');
|
||||
|
||||
// === Types ===
|
||||
|
||||
export type UIMode = 'simple' | 'professional';
|
||||
|
||||
export interface UIModeState {
|
||||
mode: UIMode;
|
||||
setMode: (mode: UIMode) => void;
|
||||
toggleMode: () => void;
|
||||
}
|
||||
|
||||
// === Constants ===
|
||||
|
||||
const UI_MODE_STORAGE_KEY = 'zclaw-ui-mode';
|
||||
const DEFAULT_MODE: UIMode = 'simple';
|
||||
|
||||
// === Persistence Helpers ===
|
||||
|
||||
function loadStoredMode(): UIMode {
|
||||
try {
|
||||
const stored = localStorage.getItem(UI_MODE_STORAGE_KEY);
|
||||
if (stored === 'simple' || stored === 'professional') {
|
||||
return stored;
|
||||
}
|
||||
} catch (err) {
|
||||
log.warn('Failed to read UI mode from localStorage:', err);
|
||||
}
|
||||
return DEFAULT_MODE;
|
||||
}
|
||||
|
||||
function persistMode(mode: UIMode): void {
|
||||
try {
|
||||
localStorage.setItem(UI_MODE_STORAGE_KEY, mode);
|
||||
} catch (err) {
|
||||
log.warn('Failed to persist UI mode:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// === Store ===
|
||||
|
||||
export const useUIModeStore = create<UIModeState>((set, get) => ({
|
||||
mode: loadStoredMode(),
|
||||
|
||||
setMode: (mode: UIMode) => {
|
||||
const current = get().mode;
|
||||
if (current === mode) return;
|
||||
|
||||
persistMode(mode);
|
||||
set({ mode });
|
||||
log.debug('UI mode changed:', mode);
|
||||
},
|
||||
|
||||
toggleMode: () => {
|
||||
const current = get().mode;
|
||||
const next: UIMode = current === 'simple' ? 'professional' : 'simple';
|
||||
|
||||
persistMode(next);
|
||||
set({ mode: next });
|
||||
log.debug('UI mode toggled:', current, '->', next);
|
||||
},
|
||||
}));
|
||||
|
||||
// === Non-hook Accessors ===
|
||||
|
||||
/**
|
||||
* Get current UI mode without React hook.
|
||||
*/
|
||||
export const getUIMode = (): UIMode => useUIModeStore.getState().mode;
|
||||
|
||||
/**
|
||||
* Check if current mode is simple.
|
||||
*/
|
||||
export const isSimpleMode = (): boolean => useUIModeStore.getState().mode === 'simple';
|
||||
|
||||
/**
|
||||
* Check if current mode is professional.
|
||||
*/
|
||||
export const isProfessionalMode = (): boolean => useUIModeStore.getState().mode === 'professional';
|
||||
|
||||
export default useUIModeStore;
|
||||
Reference in New Issue
Block a user