diff --git a/README.md b/README.md index 19f4ed0f..498137db 100644 --- a/README.md +++ b/README.md @@ -4,87 +4,103 @@ ![BitFun](./png/BitFun_title.png) +**AI assistant with personality and memory** + +Hand over the work, keep the life + +AI Agent workspace for coding and knowledge work +
[![GitHub release](https://img.shields.io/github/v/release/GCWing/BitFun?style=flat-square&color=blue)](https://github.com/GCWing/BitFun/releases) +[![Website](https://img.shields.io/badge/Website-openbitfun.com-6f42c1?style=flat-square)](https://openbitfun.com/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)](https://github.com/GCWing/BitFun/blob/main/LICENSE) [![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS-blue?style=flat-square)](https://github.com/GCWing/BitFun)
--- +## Introduction -## A Word Up Front +In the age of AI, true human-machine collaboration is not just a ChatBox, but a partner that understands you, works with you, keeps evolving, and gets things done anytime, anywhere. That is where BitFun begins. -In the age of AI, true human–machine collaboration isn't just a ChatBox — it's a partner that knows you, accompanies you, and gets things done for you anywhere, anytime. That's where BitFun's exploration begins. +BitFun is a next-generation AI assistant with built-in **Code Agent** and **Cowork Agent**. It has memory, personality, and the ability to evolve over time. You can remotely control the desktop through mobile QR pairing or Telegram / Feishu bots, send instructions, and watch each execution step in real time while the Agent keeps working in the background. -## What Is BitFun +Built with **Rust + TypeScript** for an ultra-lightweight, fluid, cross-platform experience. -BitFun is a next-generation Agent system built around the idea of **"AI assistants with personality and memory"**. +![BitFun](./png/first_screen_screenshot.png) -Every user has their own Agent assistant — one that remembers your habits and preferences, carries a unique personality, and keeps growing over time. On top of this assistant, BitFun ships with two built-in capabilities: **Code Agent** (coding assistant) and **Cowork Agent** (knowledge work assistant), along with a unified extension mechanism to define additional Agent roles as needed. +--- -Your assistant isn't confined to the desktop — it can be reached through multiple channels, such as Telegram, WhatsApp, and other social platforms, letting you issue instructions anytime, anywhere. Tasks keep running in the background, and you check in or give feedback whenever convenient. +## Dual Modes -Built with **Rust + TypeScript** for an ultra-lightweight, fluid, cross-platform experience. +BitFun provides two modes for different kinds of work: -![BitFun](./png/first_screen_screenshot.png) +- **Assistant Mode**: warmer, preference-aware, and backed by long-term memory. Best for ongoing collaboration, such as maintaining a project or preserving your writing and design style. +- **Professional Mode**: token-efficient, execution-first, and context-clean. Best for short, focused tasks like fixing a bug or updating a small feature. -### Agent System +--- -| Agent | Role | Core Capabilities | -|---|---|---| -| **Personal Assistant (WIP🚧)** (default) | Your dedicated AI companion | Long-term memory, personality settings, cross-scenario orchestration, continuous growth | -| **Code Agent** | Coding assistant | Conversation-driven coding, multi-mode task execution, autonomous read / edit / run / verify | -| **Cowork Agent** | Knowledge work assistant | File management, document generation, report organization, autonomous multi-step task execution | -| **Custom Agent** | Domain specialist | Quickly define a domain-specific Agent with Markdown | +## Remote Control -### Code Agent Working Modes +With QR pairing, your phone instantly becomes a remote command center for the desktop Agent. Send one message and the desktop AI starts working right away. -Code Agent is built for software development, offering multiple modes that cover the full cycle from day-to-day coding to deep debugging, with deep integration into MCP, Skills, and Rules: +The desktop generates a QR code, and the mobile browser opens the remote interface after scanning it, with no app installation required. -| Mode | Scenario | Characteristics | -|------|----------|-----------------| -| **Agentic** | Day-to-day coding | Conversation-driven; AI autonomously reads, edits, runs, and verifies. | -| **Plan** | Complex tasks | Plan first, then execute; align on critical changes upfront. | -| **Debug** | Hard problems | Instrument & trace → compare paths → root-cause analysis → verify fix. | -| **Review** | Code review | Review code based on key repository conventions. | +Besides mobile QR pairing, BitFun also supports Telegram / Feishu bots for remote instructions and real-time progress tracking. -### Cowork Agent Workflow +| Feature | Description | +|---|---| +| **QR Pairing** | Scan a QR code generated by the desktop, complete key exchange, and bind a long-lived connection | +| **Full Control** | View sessions, switch modes, send instructions, and control the desktop workflow remotely | +| **Real-time Streaming** | Every Agent step and tool call can be viewed live on your phone | -Cowork Agent is designed for everyday work, following a "clarify first, execute next, stay trackable" collaboration principle, with built-in office Skills and access to the Skill marketplace: +## Agent System -| Skill | Trigger | Core Capabilities | +| Agent | Role | Core Capabilities | |---|---|---| -| **PDF** | Working with .pdf files | Read/extract text & tables, merge/split/rotate, watermark, fill forms, encrypt/decrypt, OCR scanned PDFs | -| **DOCX** | Create or edit Word documents | Create/edit .docx, styles/TOC/headers & footers, image insertion, comments & tracked changes | -| **XLSX** | Working with spreadsheets | Create/analyze .xlsx/.csv, formulas & formatting, financial model standards (color coding, formula validation) | -| **PPTX** | Build presentations | Create/edit .pptx from scratch, visual design guidelines, automated visual QA | -| **agent-browser** | Browser interaction needed | Browser automation: open pages, click/fill forms, screenshot, scrape data, web app testing | -| **skill-creator** | Creating a custom Skill | Guides authoring new Skills to extend the Agent's domain-specific capabilities | -| **find-skills** | Looking for ready-made capabilities | Discover and install community-contributed reusable Skills from the Skill marketplace | +| **Personal Assistant** (Beta) | Your dedicated AI companion | Long-term memory and personality settings; can orchestrate Code / Cowork / custom Agents on demand, and continuously evolve | +| **Code Agent** | Coding assistant | Four modes: Agentic (autonomous read / edit / run / verify) / Plan (plan first, then execute) / Debug (instrumentation to root cause) / Review (repository-aware code review) | +| **Cowork Agent** | Knowledge work assistant | Built-in PDF / DOCX / XLSX / PPTX handling, and can fetch and extend suitable capability packages from the Skill marketplace | +| **Custom Agent** | Domain specialist | Quickly define a domain-specific Agent with Markdown | --- -### Extensibility +## Ecosystem -- **MCP Protocol**: Extend with external tools and resources via MCP servers; supports MCP Apps. -- **Skills**: Markdown/script-based capability packages that teach the Agent specific tasks (auto-reads Cursor, Claude Code, Codex configs). -- **Agent Customization**: Quickly define a specialized Agent's personality, memory scope, and capabilities with Markdown. -- **Rules**: Project/global-level convention injection; auto-reads Cursor and other mainstream tool configs. -- **Hooks (WIP🚧)**: Inject deterministic automation logic at key task milestones. +> It keeps growing. + +Mini Apps emerge from conversations, Skills evolve in the community, and Agents improve through collaboration. + +| Layer | Description | +|---|---| +| **Mini Apps** | Generate runnable interfaces from a prompt and package them into desktop apps with one click | +| **Skill Marketplace** | Install community capability packs so Agents can learn new skills quickly | +| **MCP Protocol** | Connect external tools and resources to extend Agent capabilities beyond the local system | +| **Custom Agents** | Define roles, memory, and capability boundaries with Markdown | +| **ACP Protocol (WIP)** | A structured multi-Agent communication standard for interoperating with mainstream AI tools | --- +## Platform Support + +The project is built with Rust + TypeScript for cross-platform reuse, keeping your Agent available wherever you work. + +| Form Factor | Supported Platforms | Status | +|---|---|---| +| **Desktop** | Windows, macOS | ✅ Supported (Tauri) | +| **Remote Control** | Mobile browser, Telegram, Feishu | ✅ Supported | + +--- ## Quick Start -### Use Directly +### Download and Use -Download the latest installer for the desktop app from [Release](https://github.com/GCWing/BitFun/releases). After installation, configure your model and you're ready to go. +Download the latest desktop installer from [Releases](https://github.com/GCWing/BitFun/releases). After installation, configure your model and start using BitFun. -Other form factors are currently only specification drafts and not yet developed. If needed, please build from source. +> CLI, Server, and native mobile apps are still in planning or development. Desktop and remote control are already supported. ### Build from Source @@ -106,38 +122,31 @@ pnpm run desktop:dev pnpm run desktop:build ``` -For more details, see the [Contributing Guide](./CONTRIBUTING.md). - -## Platform Support - -The project uses a Rust + TypeScript tech stack, supporting cross-platform and multi-form-factor reuse — keeping your Agent assistant always online and reachable everywhere. - -| Form Factor | Supported Platforms | Status | -|-------------|---------------------|--------| -| **Desktop** (Tauri) | Windows, macOS | ✅ Supported | -| **CLI** | Windows, macOS, Linux | 🚧 In Development | -| **Server** | - | 🚧 In Development | -| **Mobile** (Native App) | iOS, Android | 🚧 In Development | -| **Social Platform Integration** | Telegram, WhatsApp, Discord, etc. | 🚧 In Development | - +For more details, see the [Chinese Contributing Guide](./CONTRIBUTING_CN.md). +--- ## Contributing -We welcome great ideas and code contributions. We are maximally accepting of AI-generated code. Please submit PRs to the dev branch first; we will periodically review and sync to the main branch. + +We welcome great ideas and code contributions. We are maximally accepting of AI-generated code. Please submit PRs to the `dev` branch first; we will periodically review and sync to the main branch. Key contribution areas we focus on: -1. Contributing good ideas/creativity (features, interactions, visuals, etc.), submit issues -2. Optimizing the Agent system and its effectiveness +1. Contributing good ideas and creativity in features, interaction, and visual design via Issues +2. Optimizing the Agent system and overall quality 3. Improving system stability and foundational capabilities -4. Expanding the ecosystem (Skills, MCP, LSP plugins, or better support for specific vertical development scenarios) +4. Expanding the ecosystem, including Skills, MCP, LSP plugins, and support for vertical development scenarios +--- ## Disclaimer -1. This project is built in spare time for exploring and researching next-generation human–machine collaborative interaction, not for commercial profit. -2. 97%+ of this project was built with Vibe Coding. Feedback on code issues is also welcome—refactoring and optimization can be done via AI. + +1. This project is built in spare time for exploring and researching next-generation human-machine collaboration, not for commercial profit. +2. 97%+ of this project was built with Vibe Coding. Feedback on code issues is also welcome, and refactoring or optimization through AI is encouraged. 3. This project depends on and references many open-source projects. Thanks to all open-source authors. **If your rights are affected, please contact us for rectification.** ---
-The world is being rewritten—this time, we are all holding the pen. + +The world is being rewritten, and this time, we are all holding the pen. +
diff --git a/README.zh-CN.md b/README.zh-CN.md index b0fe30c8..62f89f28 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,10 +4,18 @@ ![BitFun](./png/BitFun_title.png) +**有个性,有记忆的 AI 助理** + +工作交给它,生活留给你 + +面向编程与知识工作的 AI Agent 工作台 + +
[![GitHub release](https://img.shields.io/github/v/release/GCWing/BitFun?style=flat-square&color=blue)](https://github.com/GCWing/BitFun/releases) +[![Website](https://img.shields.io/badge/Website-openbitfun.com-6f42c1?style=flat-square)](https://openbitfun.com/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)](https://github.com/GCWing/BitFun/blob/main/LICENSE) [![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS-blue?style=flat-square)](https://github.com/GCWing/BitFun) @@ -15,85 +23,95 @@ --- -## 写在前面的话 +## 简介 -AI 时代,真正的人机协同不是简单的ChatBox,而是一个懂你、陪你并且随时随地替你做事的伙伴。BitFun 的探索,从这里开始。 +AI 时代,真正的人机协同不是简单的 ChatBox,而是一个懂你、陪你、自我成长并且随时随地替你做事的伙伴。BitFun 的探索,从这里开始。 -## 什么是 BitFun +BitFun 是一款内置 **Code Agent** 与 **Cowork Agent** 的新一代 AI 助理,有记忆、有个性,能自我迭代。可通过手机扫码或 Telegram / 飞书 Bot 随时遥控桌面端——下达指令、实时查看每一步执行过程,让 Agent 在后台替你做事。 -BitFun 是一个以 **"有个性、有记忆的 AI 助理"** 为核心的新一代 Agent 系统。 -每一位用户都拥有属于自己的 Agent 助理——它记得你的习惯与偏好,拥有独特的性格设定,并随时间持续成长。在这个助理之上,BitFun 默认内置了 **Code Agent**(代码代理)与 **Cowork Agent**(桌面端工作助理)两种专业能力,并提供统一的扩展机制供用户按需定制更多 Agent 角色。 +![BitFun 产品界面](./png/first_screen_screenshot-zh-CN.png) -你的助理不只存在于桌面——可以通过多种媒体方式联系,比如通过 Telegram、WhatsApp 等社交平台,都可以随时随地向它下达指令,任务在后台持续推进,你只需在方便时查看进度或给出反馈。 +--- -以 **Rust + TypeScript** 构建,追求极致轻量与流畅的跨平台体验。 +## 双模式协同 -![BitFun](./png/first_screen_screenshot-zh-CN.png) +BitFun 提供两种模式,适配不同场景需求: -### Agent 体系 +- **助理模式(Assistant Mode)**:有温度,记住偏好,具备长期记忆。适合持续协作类任务,如维护项目、延续你的审美与工作习惯。 +- **专业模式(Professional Mode)**:省 token,直达执行,干净上下文。适合即时执行类任务,如修一个 bug、改一处样式。 -| Agent | 定位 | 核心能力 | -|---|---|---| -| **个人助理(WIP🚧)**(默认) | 你专属的 AI 伙伴 | 长期记忆、个性设定、跨场景调度、持续成长 | -| **Code Agent** | 代码代理 | 对话驱动编码,多模式任务执行,自主读/改/跑/验证 | -| **Cowork Agent** | 知识工作代理 | 文件管理、文档生成、报告整理、多步任务自主执行 | -| **自定义 Agent** | 垂域专家 | 通过 Markdown 快速定义专属领域 Agent | +--- -### Code Agent 工作模式 +## 远程遥控 -Code Agent 专为软件开发设计,支持多种工作模式覆盖从日常编码到疑难排查的全流程,并深度集成 MCP、Skills、Rules 等扩展体系: -| 模式 | 场景 | 特点 | -|---|---|---| -| **Agentic** | 日常编码 | 对话驱动,AI 自主完成读/改/跑/验证 | -| **Plan** | 复杂任务 | 先规划后执行,关键改动点提前对齐 | -| **Debug** | 疑难问题 | 插桩取证 → 路径对比 → 根因定位 → 验证修复 | -| **Review** | 代码审查 | 基于仓库关键规范进行代码审查 | +扫码配对,手机即刻变成桌面 Agent 的远程指挥中心。一条消息,桌面上的 AI 立刻开始工作。 +桌面端生成二维码,手机浏览器扫码打开即可使用,无需安装 App。 -### Cowork Agent 工作方式 +除手机扫码外,也支持接入 Telegram / 飞书 Bot 远程下达指令,并实时查看 Agent 的执行进度。 -Cowork Agent 专为日常工作设计,遵循"先澄清、再执行、可追踪"的协作原则,内置多个常用办公Skill,并对接skill市场: +| 特性 | 说明 | +|---|---| +| **扫码配对** | 扫描桌面端二维码,密钥交换完成,一次绑定长期连接 | +| **完整遥控** | 查看会话列表、切换模式、下达指令,桌面端一切尽在掌控 | +| **实时推流** | Agent 执行的每一步、每个工具调用,手机端实时可见 | -| Skill | 触发场景 | 核心能力 | + + +## Agent 体系 + +| Agent | 定位 | 核心能力 | |---|---|---| -| **PDF** | 处理 .pdf 文件 | 读取/提取文本与表格、合并/拆分/旋转、添加水印、填写表单、加密解密、OCR 扫描版 | -| **DOCX** | 创建或编辑 Word 文档 | 创建/编辑 .docx、样式/目录/页眉页脚、插入图片、批注与追踪修订 | -| **XLSX** | 处理电子表格 | 创建/分析 .xlsx/.csv,公式与格式化,财务模型规范(颜色编码、公式校验) | -| **PPTX** | 制作演示文稿 | 从零创建/编辑 .pptx,视觉设计规范,自动 QA 视觉检查 | -| **agent-browser** | 需要操控网页 | 浏览器自动化:打开网页、点击/填表、截图、抓取数据、Web 测试 | -| **skill-creator** | 创建自定义 Skill | 引导创作新 Skill,扩展 Agent 的专业能力范围 | -| **find-skills** | 寻找现成能力包 | 从 Skill 市场发现并安装社区贡献的可复用 Skill | +| **个人助理**(Beta) | 你专属的 AI 伙伴 | 长期记忆、个性设定;按需调度 Code / Cowork / 自定义 Agent,并可自我迭代成长 | +| **Code Agent** | 代码代理 | 四种模式:Agentic(自主读改跑验证)/ Plan(先规划后执行)/ Debug(插桩取证→根因定位)/ Review(基于仓库规范审查) | +| **Cowork Agent** | 知识工作代理 | 内置 PDF / DOCX / XLSX / PPTX 处理,可从 Skill 市场按需获取和扩展能力包 | +| **自定义 Agent** | 垂域专家 | 通过 Markdown 快速定义专属领域 Agent | ---- -### 扩展能力 +## 生态扩展 + +> 它会自己成长。 + +Mini Apps 从对话中涌现,Skills 在社区里更新,Agent 在协作中进化。 -- **MCP 协议**:通过 MCP 服务器扩展外部工具与资源,支持MCP APP -- **Skills**:Markdown/脚本等能力包,教 Agent 完成特定任务(自动读取 Cursor、Claude Code、Codex 等配置) -- **Agent 自定义**:通过 Markdown 快速定义专属 Agent 的性格、记忆与能力范围 -- **Rules**:项目/全局级规范注入,自动读取 Cursor 等主流工具配置 -- **Hooks(WIP🚧)**:在任务关键节点注入确定性自动化逻辑 +| 扩展层 | 说明 | +|---|---| +| **Mini Apps** | 从一句需求生成可运行界面,并可一键打包成桌面应用 | +| **Skills 市场** | 安装社区能力包,让 Agent 快速获得新技能 | +| **MCP 协议** | 接入外部工具和资源,把 Agent 的能力延伸到系统之外 | +| **自定义 Agent** | 用 Markdown 定义角色、记忆和能力范围 | +| **ACP 协议(WIP)** | 结构化多 Agent 通信标准,让 BitFun 与主流 AI 工具互联协作 | --- +## 平台支持 + +项目采用 Rust + TypeScript 技术栈,支持跨平台和多形态复用,确保你的 Agent 助理随时在线、随处可达。 + +| 形态 | 支持平台 | 状态 | +|---|---|---| +| **Desktop**| Windows、macOS | ✅ 已支持 (Tauri) | +| **远程控制** | 手机浏览器、Telegram、飞书 | ✅ 已支持 | + +--- ## 快速开始 -### 直接使用 +### 直接下载使用 -桌面端程序在 [Release](https://github.com/GCWing/BitFun/releases) 处下载最新安装包,安装后配置模型即可开始使用。 +在 [Releases](https://github.com/GCWing/BitFun/releases) 页面下载最新桌面端安装包,安装后配置模型即可开始使用。 -其他形态暂时仅是规范雏形未完成开发,如有需要请从源码构建。 +> CLI、Server 和原生移动 App 仍在规划或开发中;当前已支持桌面端与远程控制能力。 ### 从源码构建 -请确保已安装以下前置依赖: +**前置依赖:** -- Node.js(推荐 LTS 版本) -- pnpm -- Rust 工具链(通过 [rustup](https://rustup.rs/) 安装) +- [Node.js](https://nodejs.org/)(推荐 LTS 版本) +- [pnpm](https://pnpm.io/) +- [Rust 工具链](https://rustup.rs/) - [Tauri 前置依赖](https://v2.tauri.app/start/prerequisites/)(桌面端开发需要) ```bash @@ -109,36 +127,31 @@ pnpm run desktop:build 更多详情请参阅[贡献指南](./CONTRIBUTING_CN.md)。 -## 平台支持 - -项目采用 Rust + TypeScript 技术栈,支持跨平台和多形态复用,确保你的 Agent 助理随时在线、随处可达。 - -| 形态 | 支持平台 | 状态 | -|------|----------|------| -| **Desktop**(Tauri) | Windows、macOS | ✅ 已支持 | -| **CLI** | Windows、macOS、Linux | 🚧 开发中 | -| **Server** | - | 🚧 开发中 | -| **手机端**(独立 App) | iOS、Android | 🚧 开发中 | -| **社交平台接入** | Telegram、WhatsApp、Discord 等 | 🚧 开发中 | +--- +## 贡献 +欢迎大家贡献好的创意和代码,我们对 AI 生成代码抱有最大的接纳程度。请 PR 优先提交至 `dev` 分支,我们会定期审视后同步到主干。 -## 贡献 -欢迎大家贡献好的创意和代码,我们对AI生成代码抱有最大的接纳程度, 请PR优先提交至dev分支,我们会定期审视后同步到主干。 +**我们重点关注的贡献方向:** -我们重点关注的贡献方向: -1. 贡献好的想法/创意(功能、交互、视觉等),提交问题 -2. 优化Agent系统和效果 -3. 对提升系统稳定性和完善基础能力 -4. 扩展生态(SKill、MCP、LSP插件,或者对某些垂域开发场景的更好支持) +1. 贡献好的想法 / 创意(功能、交互、视觉等),提交 Issue +2. 优化 Agent 系统和效果 +3. 提升系统稳定性和完善基础能力 +4. 扩展生态(Skill、MCP、LSP 插件,或对某些垂域开发场景的更好支持) +--- ## 声明 -1. 本项目为业余时间探索、研究构建下一代人机协同交互,非商用盈利项目 -2. 本项目 97%+ 由 Vibe Coding 完成,代码问题也欢迎指正,可通过AI进行重构优化。 -3. 项目依赖和参考了众多开源软件,感谢所有开源作者,**如侵犯您的相关权益请联系我们整改**。 + +1. 本项目为业余时间探索、研究构建下一代人机协同交互,非商用盈利项目。 +2. 本项目 97%+ 由 Vibe Coding 完成,代码问题也欢迎指正,可通过 AI 进行重构优化。 +3. 本项目依赖和参考了众多开源软件,感谢所有开源作者。**如侵犯您的相关权益请联系我们整改。** --- +
+ 世界正在被改写,这一次,你我皆是执笔人 +
diff --git a/src/web-ui/src/app/components/NavPanel/NavPanel.scss b/src/web-ui/src/app/components/NavPanel/NavPanel.scss index 4607d69f..77bf149d 100644 --- a/src/web-ui/src/app/components/NavPanel/NavPanel.scss +++ b/src/web-ui/src/app/components/NavPanel/NavPanel.scss @@ -118,8 +118,8 @@ $_section-header-height: 24px; flex-direction: column; align-items: stretch; gap: $size-gap-2; - margin: $size-gap-2 $size-gap-2 $size-gap-2; - padding: 0 $size-gap-1; + margin: $size-gap-2; + padding: 0; overflow: visible; } @@ -233,11 +233,12 @@ $_section-header-height: 24px; &__mode-switch-label { display: inline-flex; align-items: center; - gap: 8px; - font-size: 13px; + gap: 6px; + font-size: 11px; font-weight: 600; line-height: 1.15; color: var(--color-text-primary); + white-space: nowrap; } &__mode-switch-sub { @@ -472,7 +473,7 @@ $_section-header-height: 24px; flex: 1 1 auto; overflow-y: auto; overflow-x: hidden; - padding: $size-gap-3 0 $size-gap-2; + padding: $size-gap-3 0 $size-gap-2 0; &::-webkit-scrollbar { width: 3px; } &::-webkit-scrollbar-track { background: transparent; } @@ -496,7 +497,7 @@ $_section-header-height: 24px; align-items: center; gap: $size-gap-1; height: $_section-header-height; - padding: 0 $size-gap-3; + padding: 0 $size-gap-2; margin: 0 $size-gap-2; border-radius: 4px; opacity: 0.72; @@ -1036,7 +1037,7 @@ $_section-header-height: 24px; align-items: center; gap: $size-gap-2; height: $_item-height; - padding: 0 $size-gap-2 0 $size-gap-3; + padding: 0 $size-gap-2; border: none; border-radius: 4px; background: transparent; diff --git a/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceItem.tsx b/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceItem.tsx index a566f536..002d3e08 100644 --- a/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceItem.tsx +++ b/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceItem.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; -import { Folder, FolderOpen, MoreHorizontal, GitBranch, FolderSearch, Plus, ChevronDown, Bot, Trash2, RotateCcw } from 'lucide-react'; +import { Folder, FolderOpen, MoreHorizontal, GitBranch, FolderSearch, Plus, ChevronDown, Trash2, RotateCcw } from 'lucide-react'; import { ConfirmDialog, Tooltip } from '@/component-library'; import { useI18n } from '@/infrastructure/i18n'; import { useWorkspaceContext } from '@/infrastructure/contexts/WorkspaceContext'; @@ -251,6 +251,151 @@ const WorkspaceItem: React.FC = ({ } }, [handleActivate, openNavScene, switchLeftPanelTab, t]); + if (workspace.workspaceKind === WorkspaceKind.Assistant) { + return ( +
+
+ + + +
+ + + +
+ +
+ + {menuOpen && menuPosition && createPortal( +
+ + {isDefaultAssistantWorkspace && ( + + )} + {isNamedAssistantWorkspace && ( + + )} + +
, + document.body + )} +
+
+ +
+ +
+ + setDeleteDialogOpen(false)} + onConfirm={() => { void handleConfirmDeleteAssistant(); }} + title={t('nav.workspaces.deleteAssistantDialog.title', { name: workspaceDisplayName })} + message={t('nav.workspaces.deleteAssistantDialog.message')} + confirmText={t('nav.workspaces.actions.deleteAssistant')} + cancelText={t('actions.cancel')} + confirmDanger + /> + setResetDialogOpen(false)} + onConfirm={() => { void handleConfirmResetWorkspace(); }} + title={t('nav.workspaces.resetWorkspaceDialog.title', { name: workspaceDisplayName })} + message={t('nav.workspaces.resetWorkspaceDialog.message')} + confirmText={t('nav.workspaces.actions.resetWorkspace')} + cancelText={t('actions.cancel')} + confirmDanger + preview={`${t('nav.workspaces.resetWorkspaceDialog.pathLabel')}\n${workspace.rootPath}`} + /> +
+ ); + } + return (
= ({ >
-
- - - -
- -
- - {menuOpen && menuPosition && createPortal( -
- {workspace.workspaceKind === WorkspaceKind.Assistant ? ( - + +
+ +
+ + {menuOpen && menuPosition && createPortal( +
+ + - ) : ( - <> - - - - )} - {workspace.workspaceKind !== WorkspaceKind.Assistant && ( - )} - - {isDefaultAssistantWorkspace && ( - - )} - {isNamedAssistantWorkspace && ( - - )} - {workspace.workspaceKind !== WorkspaceKind.Assistant && ( - )} -
, - document.body - )} +
, + document.body + )} +
@@ -418,28 +520,6 @@ const WorkspaceItem: React.FC = ({ repositoryPath={workspace.rootPath} title={t('nav.workspaces.actions.newWorktree')} /> - - setDeleteDialogOpen(false)} - onConfirm={() => { void handleConfirmDeleteAssistant(); }} - title={t('nav.workspaces.deleteAssistantDialog.title', { name: workspaceDisplayName })} - message={t('nav.workspaces.deleteAssistantDialog.message')} - confirmText={t('nav.workspaces.actions.deleteAssistant')} - cancelText={t('actions.cancel')} - confirmDanger - /> - setResetDialogOpen(false)} - onConfirm={() => { void handleConfirmResetWorkspace(); }} - title={t('nav.workspaces.resetWorkspaceDialog.title', { name: workspaceDisplayName })} - message={t('nav.workspaces.resetWorkspaceDialog.message')} - confirmText={t('nav.workspaces.actions.resetWorkspace')} - cancelText={t('actions.cancel')} - confirmDanger - preview={`${t('nav.workspaces.resetWorkspaceDialog.pathLabel')}\n${workspace.rootPath}`} - />
); }; diff --git a/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceListSection.scss b/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceListSection.scss index 485bf7f0..ecf65807 100644 --- a/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceListSection.scss +++ b/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceListSection.scss @@ -77,7 +77,7 @@ gap: 2px; padding: $size-gap-1; border-radius: $size-radius-base; - background: color-mix(in srgb, var(--element-bg-soft) 38%, transparent); + background: transparent; border: 1px solid transparent; transition: background $motion-fast $easing-standard, border-color $motion-fast $easing-standard; @@ -91,7 +91,7 @@ } &.is-active { - background: color-mix(in srgb, var(--element-bg-soft) 75%, transparent); + background: transparent; border-color: transparent; } @@ -147,6 +147,7 @@ } &__workspace-item-card { + position: relative; display: flex; align-items: center; width: 100%; @@ -181,9 +182,9 @@ align-items: center; justify-content: center; flex-shrink: 0; - width: 28px; + width: 26px; min-height: 30px; - padding: 0 0 0 $size-gap-1; + padding: 0 0 0 4px; border: none; border-radius: 6px 0 0 6px; background: transparent; @@ -212,7 +213,7 @@ align-items: center; gap: 6px; min-height: 30px; - padding: 0 58px 0 2px; + padding: 0 58px 0 4px; border: none; border-radius: 0 6px 6px 0; background: transparent; @@ -221,6 +222,50 @@ text-align: left; } + &__workspace-item-avatar { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + flex-shrink: 0; + border-radius: 50%; + background: color-mix(in srgb, var(--color-accent-500) 22%, transparent); + color: var(--color-accent-400); + overflow: hidden; + + .bitfun-nav-panel__workspace-item-avatar-letter { + font-size: 16px; + font-weight: 700; + line-height: 1; + text-transform: uppercase; + transition: opacity $motion-fast $easing-standard, + transform $motion-fast $easing-standard; + opacity: 1; + transform: scale(1); + } + + .bitfun-nav-panel__workspace-item-icon-toggle { + position: absolute; + display: inline-flex; + align-items: center; + justify-content: center; + inset: 0; + opacity: 0; + transform: scale(0.7); + color: var(--color-accent-400); + + svg { + transition: transform $motion-fast $easing-standard; + } + + &.is-collapsed svg { + transform: rotate(-90deg); + } + } + } + &__workspace-item-icon { position: relative; display: inline-flex; @@ -321,8 +366,9 @@ &__workspace-item-menu { position: absolute; - top: 6px; + top: 50%; right: 6px; + transform: translateY(-50%); display: inline-flex; align-items: center; gap: 4px; @@ -474,3 +520,242 @@ pointer-events: none; } } + +// ── 助理模式 item(独立样式,不与专业模式共享)────────────────────────────── +.bitfun-nav-panel { + &__assistant-item { + position: relative; + display: flex; + flex-direction: column; + gap: 2px; + padding: $size-gap-1; + border-radius: $size-radius-base; + background: transparent; + border: 1px solid transparent; + transition: background $motion-fast $easing-standard, + border-color $motion-fast $easing-standard; + + &.is-dragging { + opacity: 0.42; + + .bitfun-nav-panel__assistant-item-card { + cursor: grabbing; + } + } + + &.is-active { + background: transparent; + border-color: transparent; + } + + &:not(.is-active):not(:hover):not(:focus-within):not(.is-menu-open) { + .bitfun-nav-panel__assistant-item-menu { + opacity: 0; + visibility: hidden; + pointer-events: none; + } + } + } + + &__assistant-item-card { + position: relative; + display: flex; + align-items: center; + width: 100%; + border-radius: 6px; + color: var(--color-text-secondary); + transition: color $motion-fast $easing-standard, + background $motion-fast $easing-standard; + + &[draggable='true'] { + cursor: grab; + } + + &:hover { + color: var(--color-text-primary); + background: color-mix(in srgb, var(--element-bg-soft) 72%, transparent); + + .bitfun-nav-panel__assistant-item-avatar-letter { + opacity: 0; + transform: scale(0.6); + } + + .bitfun-nav-panel__assistant-item-icon-toggle { + opacity: 1; + transform: scale(1); + } + } + } + + &__assistant-item-collapse-btn { + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 44px; + min-height: 44px; + padding: 0; + border: none; + border-radius: 6px 0 0 6px; + background: transparent; + color: inherit; + cursor: pointer; + + &:hover { + background: color-mix(in srgb, var(--element-bg-medium) 60%, transparent); + + .bitfun-nav-panel__assistant-item-avatar-letter { + opacity: 0; + transform: scale(0.6); + } + + .bitfun-nav-panel__assistant-item-icon-toggle { + opacity: 1; + transform: scale(1); + } + } + } + + &__assistant-item-avatar { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + flex-shrink: 0; + border-radius: 50%; + background: color-mix(in srgb, var(--color-accent-500) 22%, transparent); + color: var(--color-accent-400); + overflow: hidden; + } + + &__assistant-item-avatar-letter { + font-size: 15px; + font-weight: 700; + line-height: 1; + text-transform: uppercase; + transition: opacity $motion-fast $easing-standard, + transform $motion-fast $easing-standard; + opacity: 1; + transform: scale(1); + } + + &__assistant-item-icon-toggle { + position: absolute; + display: inline-flex; + align-items: center; + justify-content: center; + inset: 0; + opacity: 0; + transform: scale(0.7); + color: var(--color-accent-400); + transition: opacity $motion-fast $easing-standard, + transform $motion-fast $easing-standard; + + svg { + transition: transform $motion-fast $easing-standard; + } + + &.is-collapsed svg { + transform: rotate(-90deg); + } + } + + &__assistant-item-name-btn { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + gap: 6px; + min-height: 44px; + padding: 0 58px 0 6px; + border: none; + border-radius: 0 6px 6px 0; + background: transparent; + color: inherit; + cursor: pointer; + text-align: left; + } + + &__assistant-item-label { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 12px; + font-weight: 600; + } + + &__assistant-item-badge { + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + padding: 1px 6px; + border-radius: 999px; + background: color-mix(in srgb, var(--color-accent-200) 88%, transparent); + color: var(--color-accent-500); + font-size: 10px; + font-weight: 700; + line-height: 1.4; + white-space: nowrap; + } + + &__assistant-item-menu { + position: absolute; + top: 50%; + right: 6px; + transform: translateY(-50%); + display: inline-flex; + align-items: center; + gap: 4px; + transition: opacity $motion-fast $easing-standard, + visibility $motion-fast $easing-standard; + } + + &__assistant-item-menu-trigger { + display: inline-flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + border: none; + border-radius: 6px; + background: transparent; + color: var(--color-text-muted); + cursor: pointer; + transition: color $motion-fast $easing-standard, + background $motion-fast $easing-standard; + + &:hover, + &.is-open { + color: var(--color-text-primary); + background: var(--element-bg-medium); + } + } + + &__assistant-item-sessions { + overflow: hidden; + max-height: 600px; + transition: max-height $motion-base $easing-standard, + opacity $motion-fast $easing-standard; + opacity: 1; + + &.is-collapsed { + max-height: 0; + opacity: 0; + pointer-events: none; + } + + .bitfun-nav-panel__inline-list { + margin-left: 18px; + margin-right: 0; + padding-top: 0; + } + + .bitfun-nav-panel__inline-empty { + padding-left: $size-gap-1; + } + } +} diff --git a/src/web-ui/src/app/layout/WorkspaceBody.scss b/src/web-ui/src/app/layout/WorkspaceBody.scss index 757e3af6..24eaac06 100644 --- a/src/web-ui/src/app/layout/WorkspaceBody.scss +++ b/src/web-ui/src/app/layout/WorkspaceBody.scss @@ -25,6 +25,7 @@ $_nav-collapsed-width: 80px; background: var(--color-bg-primary); color: var(--color-text-primary); padding: 0 $size-gap-2 $size-gap-2 $size-gap-2; + gap: $size-gap-2; } // ── Left column: NavBar on top, NavPanel below ─────────── diff --git a/src/web-ui/src/flow_chat/tool-cards/GitToolDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/GitToolDisplay.scss index 4e4f50b1..c8f3ff8e 100644 --- a/src/web-ui/src/flow_chat/tool-cards/GitToolDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/GitToolDisplay.scss @@ -153,7 +153,6 @@ } &.stderr { - border-left: 3px solid rgba(239, 68, 68, 0.5); background: rgba(239, 68, 68, 0.05); } diff --git a/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.scss index a3c46e89..a97e1f68 100644 --- a/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.scss @@ -24,105 +24,116 @@ /* Standard card layout */ .flow-tool-card.todo-write-card { - width: 85%; - max-width: 500px; - margin-left: auto; - margin-right: auto; + width: 100%; display: block; - background: var(--color-bg-flowchat); - border: 1px solid var(--border-base); - border-radius: 6px; - margin-top: 6px; - margin-bottom: 6px; + background: transparent; + border: none; + border-radius: 0; + margin-top: 12px; + margin-bottom: 12px; padding: 0; - overflow: hidden; - transition: all 0.2s ease; + overflow: visible; box-sizing: border-box; position: relative; - &:hover { - border-color: var(--border-medium); - } - + /* Header: dashed lines left & right, content centered */ .tool-card-header { display: flex; align-items: center; - justify-content: space-between; - padding: 8px 12px; - background: var(--color-bg-flowchat); - gap: 8px; - - .tool-info { - display: flex; - align-items: center; - gap: 6px; - flex-shrink: 0; + gap: 10px; + padding: 0; + background: transparent; + user-select: none; - .tool-icon { - display: flex; - align-items: center; - color: var(--tool-card-text-muted); - - svg { - width: 12px; - height: 12px; - } - } + &.clickable { + cursor: pointer; + } - .tool-label { - font-size: 11px; - font-weight: 500; - color: var(--tool-card-text-secondary); - - &--completed { - color: var(--color-success); - } - } + /* Left dashed line */ + &::before, + &::after { + content: ''; + flex: 1; + height: 0; + border-top: 1px dashed var(--border-base); + transition: border-top 0.2s ease; + min-width: 16px; + } - .tool-icon--completed { - color: var(--color-success); - } + &.clickable:hover::before, + &.clickable:hover::after { + border-top: 1px solid var(--border-medium); + } + + &.clickable:hover .todo-header-center { + border-color: var(--border-medium); + background: rgba(255, 255, 255, 0.12); + box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.04); + } + + &.clickable:hover .expand-icon { + color: var(--tool-card-text-secondary); + } + + &.clickable:hover .track-dots { + gap: 4px; } } + /* Centered content pill */ + .todo-header-center { + display: flex; + align-items: center; + gap: 6px; + flex-shrink: 0; + padding: 3px 8px; + border-radius: 20px; + background: var(--element-bg-subtle, rgba(255, 255, 255, 0.04)); + border: 1px solid var(--border-base); + transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease; + max-width: 70%; + } + + .track-dots, + .todo-track, + .current-task-inline { + } + + /* All-completed label inside pill */ + .all-completed-icon { + color: var(--color-success); + flex-shrink: 0; + } + + .all-completed-label { + font-size: 11px; + font-weight: 500; + color: var(--color-success); + white-space: nowrap; + } + /* Inline current task */ .current-task-inline { display: flex; align-items: center; - gap: 5px; - flex: 1; + gap: 4px; min-width: 0; - padding: 2px 0; + max-width: 200px; overflow: hidden; .inline-task-icon { flex-shrink: 0; - width: 11px; - height: 11px; - - &--in-progress { - color: var(--color-info); - } - - &--completed { - color: var(--color-success); - } - - &--pending { - color: var(--tool-card-text-muted); - opacity: 0.6; - } - - &--cancelled { - color: var(--color-error); - opacity: 0.6; - } + width: 10px; + height: 10px; + + &--in-progress { color: var(--color-info); } + &--completed { color: var(--color-success); } + &--pending { color: var(--tool-card-text-muted); opacity: 0.6; } + &--cancelled { color: var(--color-error); opacity: 0.6; } } .inline-task-text { - flex: 1; - min-width: 0; - font-size: 11px; + font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -131,167 +142,128 @@ .inline-task-more { flex-shrink: 0; - font-size: 10px; + font-size: 9px; color: var(--tool-card-text-muted); - padding: 1px 4px; - background: rgba(255, 255, 255, 0.05); + padding: 0 3px; + background: rgba(255, 255, 255, 0.06); border-radius: 3px; } - &--in_progress { - .inline-task-text { - color: var(--tool-card-text-primary); - font-weight: 500; - } - } - - &--completed { - .inline-task-text { - color: var(--tool-card-text-muted); - text-decoration: line-through; - opacity: 0.7; - } + &--in_progress .inline-task-text { + color: var(--tool-card-text-primary); + font-weight: 500; } - &--pending { - .inline-task-text { - color: var(--tool-card-text-secondary); - } + &--completed .inline-task-text { + color: var(--tool-card-text-muted); + text-decoration: line-through; + opacity: 0.7; } - &--cancelled { - .inline-task-text { - color: var(--tool-card-text-muted); - text-decoration: line-through; - opacity: 0.5; - } + &--cancelled .inline-task-text { + color: var(--tool-card-text-muted); + text-decoration: line-through; + opacity: 0.5; } } - .todo-track { + .track-dots { display: flex; align-items: center; - gap: 10px; - flex: 1; - justify-content: flex-end; + gap: 3px; + flex-shrink: 0; + transition: gap 0.2s ease; } - .track-dots { + /* Progress track (stats + chevron) */ + .todo-track { display: flex; align-items: center; - gap: 4px; + gap: 5px; + flex-shrink: 0; } .track-dot { - width: 8px; - height: 8px; + width: 6px; + height: 6px; border-radius: 50%; - position: relative; cursor: pointer; - transition: all 0.15s ease; - - &--completed { - background: var(--color-success); - } + transition: transform 0.15s ease, opacity 0.15s ease; - &--in_progress { - background: var(--color-info); - } - - &--pending { - background: var(--tool-card-text-muted); - opacity: 0.4; - } - - &--cancelled { - background: var(--color-error); - opacity: 0.6; - } + &--completed { background: var(--color-success); } + &--in_progress { background: var(--color-info); } + &--pending { background: var(--tool-card-text-muted); opacity: 0.35; } + &--cancelled { background: var(--color-error); opacity: 0.5; } &:hover, &--hovered { - transform: scale(1.5); + transform: scale(1.6); + opacity: 1; } } + .track-stats { + font-size: 10px; + font-family: var(--tool-card-font-mono); + color: var(--tool-card-text-muted); + letter-spacing: 0.02em; + } - .track-expand-btn { - display: flex; - align-items: center; - gap: 4px; - padding: 2px 6px; - background: transparent; - border: 1px solid transparent; - border-radius: 4px; - cursor: pointer; - transition: all 0.15s ease; + .expand-icon { + color: var(--tool-card-text-muted); + transition: transform 0.2s ease, color 0.2s ease; flex-shrink: 0; - - &:hover { - background: rgba(255, 255, 255, 0.08); - border-color: var(--border-base); - } - - &.expanded { - background: rgba(255, 255, 255, 0.05); - } - - .track-stats { - font-size: 10px; - font-family: var(--tool-card-font-mono); - color: var(--tool-card-text-muted); - } - - svg { - color: var(--tool-card-text-muted); - transition: transform 0.2s ease; - } - - &:hover svg { - color: var(--tool-card-text-secondary); - } } - /* Expanded list */ .todo-full-list { - border-top: 1px solid var(--border-base); - max-height: 200px; + margin-top: 6px; + border: 1px solid var(--border-base); + border-radius: 6px; + background: var(--element-bg-subtle, rgba(255, 255, 255, 0.03)); + max-height: 240px; overflow-y: auto; - animation: slideDown 0.2s ease; + overflow-x: hidden; + animation: slideDown 0.18s ease; + &::-webkit-scrollbar { + width: 3px; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &::-webkit-scrollbar-thumb { + background: var(--border-base); + border-radius: 2px; + } } @keyframes slideDown { - from { - opacity: 0; - max-height: 0; - } - to { - opacity: 1; - max-height: 200px; - } + from { opacity: 0; transform: translateY(-4px); } + to { opacity: 1; transform: translateY(0); } } .todo-item { display: flex; align-items: center; - padding: 5px 12px; + padding: 5px 10px; font-size: 11px; - transition: background 0.15s ease; - border-bottom: 1px solid var(--border-base); + transition: background 0.12s ease; + border-bottom: 1px solid var(--border-subtle); + position: relative; &:last-child { border-bottom: none; } &:hover { - background: rgba(255, 255, 255, 0.03); + background: var(--element-bg-subtle, rgba(255, 255, 255, 0.04)); } + /* in_progress: subtle highlight */ &.status-in_progress { - background: rgba(59, 130, 246, 0.08); - + background: var(--color-info-bg); + .todo-content { color: var(--tool-card-text-primary); font-weight: 500; @@ -302,59 +274,108 @@ .todo-content { text-decoration: line-through; color: var(--tool-card-text-muted); - opacity: 0.6; + opacity: 0.55; } } &.status-cancelled { - opacity: 0.5; + opacity: 0.45; } - &.status-pending { - .todo-content { - color: var(--tool-card-text-secondary); - } + &.status-pending .todo-content { + color: var(--tool-card-text-secondary); } } .todo-item-left { display: flex; align-items: center; - gap: 8px; + gap: 7px; flex: 1; min-width: 0; } .todo-status-icon { flex-shrink: 0; - width: 12px; - height: 12px; + width: 11px; + height: 11px; + + &--completed { color: var(--color-success); } + &--in-progress { color: var(--color-info); } + &--pending { color: var(--tool-card-text-muted); opacity: 0.5; } + &--cancelled { color: var(--color-error); opacity: 0.6; } + } + + .todo-content { + flex: 1; + color: var(--tool-card-text-secondary); + line-height: 1.4; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } - &--completed { - color: var(--color-success); + /* All-completed state: dashed lines turn green */ + &:not(.all-completed) { + .tool-card-header.clickable:hover::before, + .tool-card-header.clickable:hover::after { + border-top: 1px solid var(--border-medium); } - &--in-progress { - color: var(--color-info); + .tool-card-header.clickable:hover .track-dot--in_progress { + box-shadow: 0 0 4px var(--color-info); } - &--pending { - color: var(--tool-card-text-muted); - opacity: 0.5; + .tool-card-header.clickable:hover .track-dot--pending { + opacity: 0.6; + } + } + + &.all-completed { + .tool-card-header::before, + .tool-card-header::after { + border-color: var(--color-success); + opacity: 0.3; } - &--cancelled { - color: var(--color-error); + .todo-header-center { + border-color: var(--color-success); opacity: 0.6; } + + .tool-card-header.clickable:hover::before, + .tool-card-header.clickable:hover::after { + border-top: 1px solid var(--color-success); + opacity: 0.5; + } + + .tool-card-header.clickable:hover .todo-header-center { + opacity: 1; + background: rgba(34, 197, 94, 0.12); + box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.06); + } } +} - .todo-content { - flex: 1; - color: var(--tool-card-text-secondary); - line-height: 1.4; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; +/* Light theme overrides */ +:root[data-theme-type="light"], +[data-theme*="light"] { + .flow-tool-card.todo-write-card { + .todo-header-center { + background: rgba(0, 0, 0, 0.03); + } + + .tool-card-header.clickable:hover .todo-header-center { + background: rgba(0, 0, 0, 0.07); + box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.03); + } + + &.all-completed .tool-card-header.clickable:hover .todo-header-center { + background: var(--color-success-bg); + } + + &:not(.all-completed) .tool-card-header.clickable:hover .track-dot--in_progress { + box-shadow: 0 0 4px var(--color-info); + } } } diff --git a/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.tsx b/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.tsx index 8ccc1fb7..0cc8b9db 100644 --- a/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.tsx +++ b/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.tsx @@ -124,59 +124,43 @@ export const TodoWriteDisplay: React.FC = ({ }, [hoveredTask, inProgressTasks]); return ( -
-
-
- - {isLoading ? ( - - ) : isAllCompleted ? ( - - ) : ( - - )} - - - {isAllCompleted ? t('toolCards.todoWrite.allCompleted') : t('toolCards.todoWrite.tasks')} - +
+
0 ? 'clickable' : ''}`} + onClick={todosToDisplay.length > 0 ? () => setExpandedState(!isExpanded) : undefined} + > +
+ {isAllCompleted ? ( + <> + + {t('toolCards.todoWrite.allCompleted')} + + ) : ( + <> + {todosToDisplay.length > 0 && ( +
+ {todosToDisplay.map((todo: any, idx: number) => renderTrackDot(todo, idx))} +
+ )} + + {!isExpanded && todosToDisplay.length > 0 && currentDisplayTask && ( +
+ {currentDisplayTask.content} + {inProgressTasks.length > 1 && !hoveredTask && ( + +{inProgressTasks.length - 1} + )} +
+ )} + + {todosToDisplay.length > 0 && ( +
+ {taskStats.completed}/{taskStats.total} + {isExpanded ? : } +
+ )} + + )}
- - {!isExpanded && todosToDisplay.length > 0 && currentDisplayTask && ( -
- {currentDisplayTask.status === 'completed' && ( - - )} - {currentDisplayTask.status === 'in_progress' && ( - - )} - {currentDisplayTask.status === 'pending' && ( - - )} - {currentDisplayTask.status === 'cancelled' && ( - - )} - {currentDisplayTask.content} - {inProgressTasks.length > 1 && !hoveredTask && ( - +{inProgressTasks.length - 1} - )} -
- )} - - {todosToDisplay.length > 0 && ( -
-
- {todosToDisplay.map((todo: any, idx: number) => renderTrackDot(todo, idx))} -
- -
- )}
{isExpanded && todosToDisplay.length > 0 && ( diff --git a/src/web-ui/src/locales/en-US/common.json b/src/web-ui/src/locales/en-US/common.json index e7468604..ffb3e37d 100644 --- a/src/web-ui/src/locales/en-US/common.json +++ b/src/web-ui/src/locales/en-US/common.json @@ -97,9 +97,9 @@ "shell": "Shell" }, "displayModes": { - "pro": "Pro Mode", + "pro": "Expert Mode", "assistant": "Assistant Mode", - "switchToPro": "Click to switch to Pro mode", + "switchToPro": "Click to switch to Expert mode", "switchToAssistant": "Click to switch to Assistant mode", "proDesc": "Best for focused, one-shot tasks with a clear goal.", "assistantDesc": "Best for ongoing work with context and personal preferences." diff --git a/src/web-ui/src/locales/en-US/flow-chat.json b/src/web-ui/src/locales/en-US/flow-chat.json index dd0f7d34..1ef8c10f 100644 --- a/src/web-ui/src/locales/en-US/flow-chat.json +++ b/src/web-ui/src/locales/en-US/flow-chat.json @@ -191,7 +191,7 @@ "noMatchingCommand": "No matching command", "selectHint": "↑↓ Select · Enter Confirm · Esc Cancel", "current": "Current", - "professionalMode": "Professional Mode", + "professionalMode": "Expert Mode", "designMode": "Design Mode", "templateHint": "Press Tab for next placeholder, Shift+Tab for previous, Esc to exit", "templateProgress": "{{current}} / {{total}}",