diff --git a/desktop/package.json b/desktop/package.json
index c2d21ac..b8cb662 100644
--- a/desktop/package.json
+++ b/desktop/package.json
@@ -22,9 +22,13 @@
"dependencies": {
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-opener": "^2",
+ "clsx": "^2.1.1",
+ "framer-motion": "^12.36.0",
"lucide-react": "^0.577.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
+ "smol-toml": "^1.6.0",
+ "tailwind-merge": "^3.5.0",
"tweetnacl": "^1.0.3",
"zustand": "^5.0.11"
},
diff --git a/desktop/pnpm-lock.yaml b/desktop/pnpm-lock.yaml
index 5f5d258..b7c1bbb 100644
--- a/desktop/pnpm-lock.yaml
+++ b/desktop/pnpm-lock.yaml
@@ -14,6 +14,12 @@ importers:
'@tauri-apps/plugin-opener':
specifier: ^2
version: 2.5.3
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
+ framer-motion:
+ specifier: ^12.36.0
+ version: 12.36.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
lucide-react:
specifier: ^0.577.0
version: 0.577.0(react@19.2.4)
@@ -23,6 +29,12 @@ importers:
react-dom:
specifier: ^19.1.0
version: 19.2.4(react@19.2.4)
+ smol-toml:
+ specifier: ^1.6.0
+ version: 1.6.0
+ tailwind-merge:
+ specifier: ^3.5.0
+ version: 3.5.0
tweetnacl:
specifier: ^1.0.3
version: 1.0.3
@@ -684,6 +696,10 @@ packages:
caniuse-lite@1.0.30001777:
resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==}
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
@@ -731,6 +747,20 @@ packages:
fraction.js@5.3.4:
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
+ framer-motion@12.36.0:
+ resolution: {integrity: sha512-4PqYHAT7gev0ke0wos+PyrcFxI0HScjm3asgU8nSYa8YzJFuwgIvdj3/s3ZaxLq0bUSboIn19A2WS/MHwLCvfw==}
+ peerDependencies:
+ '@emotion/is-prop-valid': '*'
+ react: ^18.0.0 || ^19.0.0
+ react-dom: ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/is-prop-valid':
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -845,6 +875,12 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+ motion-dom@12.36.0:
+ resolution: {integrity: sha512-Ep1pq8P88rGJ75om8lTCA13zqd7ywPGwCqwuWwin6BKc0hMLkVfcS6qKlRqEo2+t0DwoUcgGJfXwaiFn4AOcQA==}
+
+ motion-utils@12.36.0:
+ resolution: {integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -895,10 +931,17 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
+ smol-toml@1.6.0:
+ resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==}
+ engines: {node: '>= 18'}
+
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ tailwind-merge@3.5.0:
+ resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==}
+
tailwindcss@4.2.1:
resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==}
@@ -910,6 +953,9 @@ packages:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
tweetnacl@1.0.3:
resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==}
@@ -1458,6 +1504,8 @@ snapshots:
caniuse-lite@1.0.30001777: {}
+ clsx@2.1.1: {}
+
convert-source-map@2.0.0: {}
csstype@3.2.3: {}
@@ -1512,6 +1560,15 @@ snapshots:
fraction.js@5.3.4: {}
+ framer-motion@12.36.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ dependencies:
+ motion-dom: 12.36.0
+ motion-utils: 12.36.0
+ tslib: 2.8.1
+ optionalDependencies:
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+
fsevents@2.3.3:
optional: true
@@ -1588,6 +1645,12 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
+ motion-dom@12.36.0:
+ dependencies:
+ motion-utils: 12.36.0
+
+ motion-utils@12.36.0: {}
+
ms@2.1.3: {}
nanoid@3.3.11: {}
@@ -1650,8 +1713,12 @@ snapshots:
semver@6.3.1: {}
+ smol-toml@1.6.0: {}
+
source-map-js@1.2.1: {}
+ tailwind-merge@3.5.0: {}
+
tailwindcss@4.2.1: {}
tapable@2.3.0: {}
@@ -1661,6 +1728,8 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
+ tslib@2.8.1: {}
+
tweetnacl@1.0.3: {}
typescript@5.8.3: {}
diff --git a/desktop/src/App.tsx b/desktop/src/App.tsx
index a898493..193faf1 100644
--- a/desktop/src/App.tsx
+++ b/desktop/src/App.tsx
@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
+import { motion, AnimatePresence } from 'framer-motion';
import './index.css';
import { Sidebar, MainViewType } from './components/Sidebar';
import { ChatArea } from './components/ChatArea';
@@ -10,6 +11,9 @@ import { TeamCollaborationView } from './components/TeamCollaborationView';
import { useGatewayStore } from './store/gatewayStore';
import { useTeamStore } from './store/teamStore';
import { getStoredGatewayToken } from './lib/gateway-client';
+import { pageVariants, defaultTransition, fadeInVariants } from './lib/animations';
+import { Bot, Users } from 'lucide-react';
+import { EmptyState } from './components/ui';
type View = 'main' | 'settings';
@@ -66,48 +70,51 @@ function App() {
/>
{/* 中间区域 */}
-
- {mainContentView === 'hands' && selectedHandId ? (
- setSelectedHandId(undefined)}
- />
- ) : mainContentView === 'hands' ? (
-
-
-
- 🤖
-
-
选择一个 Hand
-
- 从左侧列表中选择一个自主能力包,查看其任务清单和执行结果。
-
-
-
- ) : mainContentView === 'workflow' ? (
-
-
-
- ) : mainContentView === 'team' ? (
- activeTeam ? (
-
+
+
+ {mainContentView === 'hands' && selectedHandId ? (
+ setSelectedHandId(undefined)}
+ />
+ ) : mainContentView === 'hands' ? (
+ }
+ title="Select a Hand"
+ description="Choose an autonomous capability package from the list on the left to view its task list and execution results."
+ />
+ ) : mainContentView === 'workflow' ? (
+
+
+
+ ) : mainContentView === 'team' ? (
+ activeTeam ? (
+
+ ) : (
+ }
+ title="Select or Create a Team"
+ description="Choose a team from the list on the left, or click + to create a new multi-Agent collaboration team."
+ />
+ )
) : (
-
-
-
- 👥
-
-
选择或创建团队
-
- 从左侧列表选择一个团队,或点击 + 创建新的多 Agent 协作团队。
-
-
-
- )
- ) : (
-
- )}
-
+
+ )}
+
+
{/* 右侧边栏 */}
diff --git a/desktop/src/components/ChatArea.tsx b/desktop/src/components/ChatArea.tsx
index 20e7e0a..11a0aff 100644
--- a/desktop/src/components/ChatArea.tsx
+++ b/desktop/src/components/ChatArea.tsx
@@ -1,7 +1,10 @@
import { useState, useEffect, useRef, useCallback } from 'react';
+import { motion, AnimatePresence } from 'framer-motion';
import { useChatStore, Message } from '../store/chatStore';
import { useGatewayStore } from '../store/gatewayStore';
-import { Paperclip, ChevronDown, Terminal, SquarePen, ArrowUp } from 'lucide-react';
+import { Paperclip, ChevronDown, Terminal, SquarePen, ArrowUp, MessageSquare } from 'lucide-react';
+import { Button, EmptyState } from './ui';
+import { listItemVariants, defaultTransition, fadeInVariants } from '../lib/animations';
const MODELS = ['glm-5', 'qwen3.5-plus', 'kimi-k2.5', 'minimax-m2.5'];
@@ -58,56 +61,84 @@ export function ChatArea() {
return (
<>
{/* Header */}
-
+
-
{currentAgent?.name || 'ZCLAW'}
+ {currentAgent?.name || 'ZCLAW'}
{isStreaming ? (
-
-
+
+
正在输入中
) : (
-
-
+
+
{connected ? 'Gateway 已连接' : 'Gateway 未连接'}
)}
{messages.length > 0 && (
-
+
)}
{/* Messages */}
-
- {messages.length === 0 && (
-
-
欢迎使用 ZCLAW 🦞
-
{connected ? '发送消息开始对话' : '请先在设置中连接 Gateway'}
-
- )}
+
+
+ {messages.length === 0 && (
+
+ }
+ title="欢迎使用 ZCLAW"
+ description={connected ? '发送消息开始对话' : '请先在设置中连接 Gateway'}
+ />
+
+ )}
- {messages.map((message) => (
-
- ))}
+ {messages.map((message) => (
+
+
+
+ ))}
+
{/* Input */}
-
+
-
-