feat(hands): restructure Hands UI with Chinese localization

Major changes:
- Add HandList.tsx component for left sidebar
- Add HandTaskPanel.tsx for middle content area
- Restructure Sidebar tabs: 分身/HANDS/Workflow
- Remove Hands tab from RightPanel
- Localize all UI text to Chinese
- Archive legacy OpenClaw documentation
- Add Hands integration lessons document
- Update feature checklist with new components

UI improvements:
- Left sidebar now shows Hands list with status icons
- Middle area shows selected Hand's tasks and results
- Consistent styling with Tailwind CSS
- Chinese status labels and buttons

Documentation:
- Create docs/archive/openclaw-legacy/ for old docs
- Add docs/knowledge-base/hands-integration-lessons.md
- Update docs/knowledge-base/feature-checklist.md
- Update docs/knowledge-base/README.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-14 23:16:32 +08:00
parent 67e1da635d
commit 07079293f4
126 changed files with 36229 additions and 1035 deletions

View File

@@ -1,28 +1,42 @@
import { useState, useEffect } from 'react';
import './index.css';
import { Sidebar } from './components/Sidebar';
import { Sidebar, MainViewType } from './components/Sidebar';
import { ChatArea } from './components/ChatArea';
import { RightPanel } from './components/RightPanel';
import { SettingsLayout } from './components/Settings/SettingsLayout';
import { HandTaskPanel } from './components/HandTaskPanel';
import { WorkflowList } from './components/WorkflowList';
import { TriggersPanel } from './components/TriggersPanel';
import { useGatewayStore } from './store/gatewayStore';
import { getStoredGatewayToken } from './lib/gateway-client';
type View = 'main' | 'settings';
function App() {
const [view, setView] = useState<View>('main');
const [mainContentView, setMainContentView] = useState<MainViewType>('chat');
const [selectedHandId, setSelectedHandId] = useState<string | undefined>(undefined);
const { connect, connectionState } = useGatewayStore();
// Auto-connect to Gateway on startup
useEffect(() => {
document.title = 'ZCLAW';
}, []);
useEffect(() => {
if (connectionState === 'disconnected') {
// Try default port 18789 first, then fallback to 18790
connect('ws://127.0.0.1:18789').catch(() => {
connect('ws://127.0.0.1:18790').catch(() => {
// Silent fail — user can manually connect via Settings
});
});
const gatewayToken = getStoredGatewayToken();
connect(undefined, gatewayToken).catch(() => {});
}
}, []);
}, [connect, connectionState]);
// 当切换到非 hands 视图时清除选中的 Hand
const handleMainViewChange = (view: MainViewType) => {
setMainContentView(view);
if (view !== 'hands') {
// 可选:清除选中的 Hand
// setSelectedHandId(undefined);
}
};
if (view === 'settings') {
return <SettingsLayout onBack={() => setView('main')} />;
@@ -31,13 +45,42 @@ function App() {
return (
<div className="h-screen flex overflow-hidden text-gray-800 text-sm">
{/* 左侧边栏 */}
<Sidebar onOpenSettings={() => setView('settings')} />
{/* 中间对话区域 */}
<main className="flex-1 flex flex-col bg-white relative">
<ChatArea />
<Sidebar
onOpenSettings={() => setView('settings')}
onMainViewChange={handleMainViewChange}
selectedHandId={selectedHandId}
onSelectHand={setSelectedHandId}
/>
{/* 中间区域 */}
<main className="flex-1 flex flex-col bg-white relative overflow-hidden">
{mainContentView === 'hands' && selectedHandId ? (
<HandTaskPanel
handId={selectedHandId}
onBack={() => setSelectedHandId(undefined)}
/>
) : mainContentView === 'hands' ? (
<div className="flex-1 flex items-center justify-center p-6">
<div className="text-center">
<div className="w-20 h-20 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-4xl">🤖</span>
</div>
<h3 className="text-lg font-semibold text-gray-700 mb-2"> Hand</h3>
<p className="text-sm text-gray-400 max-w-sm">
</p>
</div>
</div>
) : mainContentView === 'workflow' ? (
<div className="flex-1 overflow-y-auto p-6 space-y-6">
<WorkflowList />
<TriggersPanel />
</div>
) : (
<ChatArea />
)}
</main>
{/* 右侧边栏 */}
<RightPanel />
</div>
@@ -45,3 +88,5 @@ function App() {
}
export default App;