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

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:
iven
2026-04-09 09:51:56 +08:00
parent ffaee49d67
commit e6937e1e5f
8 changed files with 2031 additions and 4 deletions

View File

@@ -49,7 +49,7 @@ const DEFAULT_MESSAGE_HEIGHTS: Record<string, number> = {
// Threshold for enabling virtualization (messages count)
const VIRTUALIZATION_THRESHOLD = 100;
export function ChatArea() {
export function ChatArea({ compact }: { compact?: boolean }) {
const {
messages, isStreaming, isLoading,
sendMessage: sendToGateway, initStreamListener,
@@ -343,7 +343,7 @@ export function ChatArea() {
</div>
<div className="flex items-center gap-4">
{/* Token usage counter — DeerFlow-style plain text */}
{(totalInputTokens + totalOutputTokens) > 0 && (() => {
{!compact && (totalInputTokens + totalOutputTokens) > 0 && (() => {
const total = totalInputTokens + totalOutputTokens;
const display = total >= 1000 ? `${(total / 1000).toFixed(1)}K` : String(total);
return (
@@ -353,7 +353,7 @@ export function ChatArea() {
);
})()}
<OfflineIndicator compact />
{messages.length > 0 && (
{!compact && messages.length > 0 && (
<Button
variant="ghost"
size="sm"
@@ -561,11 +561,12 @@ export function ChatArea() {
>
<Paperclip className="w-5 h-5" />
</Button>
<ChatMode
{!compact && <ChatMode
value={chatMode}
onChange={setChatMode}
disabled={isStreaming}
/>
}
</div>
<div className="flex items-center gap-2">
<ModelSelector

View File

@@ -0,0 +1,54 @@
/**
* SimpleTopBar - Minimal top bar for simple UI mode
*
* Shows only the ZCLAW logo and a mode-toggle button.
* Designed for the streamlined "simple" experience.
*/
import { LayoutGrid } from 'lucide-react';
import { motion } from 'framer-motion';
// === Types ===
interface SimpleTopBarProps {
onToggleMode: () => void;
}
// === Component ===
export function SimpleTopBar({ onToggleMode }: SimpleTopBarProps) {
return (
<header className="h-10 bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-800 flex items-center px-4 flex-shrink-0 select-none">
{/* Logo */}
<div className="flex items-center gap-1.5">
<span className="font-bold text-lg bg-gradient-to-r from-orange-500 to-amber-500 bg-clip-text text-transparent">
ZCLAW
</span>
</div>
{/* Spacer */}
<div className="flex-1" />
{/* Mode toggle button */}
<motion.button
type="button"
onClick={onToggleMode}
className="
flex items-center gap-1.5 px-2.5 py-1 rounded-md
text-xs text-gray-500 dark:text-gray-400
hover:text-gray-900 dark:hover:text-gray-100
hover:bg-gray-100 dark:hover:bg-gray-800
transition-colors duration-150
"
whileHover={{ scale: 1.04 }}
whileTap={{ scale: 0.97 }}
title="切换到专业模式"
>
<LayoutGrid className="w-3.5 h-3.5" />
<span></span>
</motion.button>
</header>
);
}
export default SimpleTopBar;