feat(ui): refine sidebar workspace and code blocks
This commit is contained in:
parent
348cad2b1a
commit
3bc6f718eb
150
agentskills/ui-aesthetic-design/SKILL.md
Normal file
150
agentskills/ui-aesthetic-design/SKILL.md
Normal file
@ -0,0 +1,150 @@
|
||||
---
|
||||
name: ui-aesthetic-design
|
||||
description: 用于进行高质量 UI 美学设计、界面精致化、组件视觉评审与前端 demo 设计的通用设计规范。当任务涉及现代系统界面、侧边栏、资源面板、消息流、代码展示、按钮、hover/active 状态、二级菜单、展示项/可选项区分、内容对齐、图标视觉体积对齐、浅色/深色主题等 UI 美学问题时使用。
|
||||
---
|
||||
|
||||
# UI Aesthetic Design
|
||||
|
||||
当设计、评审或实现 UI 改动时使用此 skill。目标不是做通用 SaaS 模板,而是形成克制、现代、精致、像成熟 AI 系统产品的界面。
|
||||
|
||||
## 核心审美方向
|
||||
|
||||
整体风格参考 ChatGPT / Claude / Linear 一类现代 AI 系统的克制感:
|
||||
|
||||
- 使用干净的浅色/深色表面、细边框、轻量阴影和安静的 hover 状态。
|
||||
- 避免过度发光、重阴影、毛玻璃、强模糊、圆角矩形套圆角矩形、霓虹渐变和无意义装饰。
|
||||
- 优先使用细线图标、浅灰 hover 底色、短而稳定的动效。
|
||||
- 布局要紧凑但不拥挤,信息密度可以高,但不能乱。
|
||||
- 精致感来自准确的间距、对齐、命中区域、状态反馈和微交互,而不是视觉噪音。
|
||||
|
||||
## 颜色与字体层级
|
||||
|
||||
使用少量语义化颜色:
|
||||
|
||||
- 背景/表面:浅色模式使用白色或近白;深色模式使用近黑或炭黑。
|
||||
- 主文字:高对比,用于主要内容。
|
||||
- 次文字:浅灰,用于路径、状态、元信息、辅助说明。
|
||||
- 边框:中性 1px 细边框。
|
||||
- Hover:低透明度灰色填充。
|
||||
- Active/当前项:略强的低透明度灰色,或明确但克制的选择标记。
|
||||
- Danger:只用于删除等破坏性操作。
|
||||
|
||||
字体层级:
|
||||
|
||||
- 主内容文字应更深、更大或更有字重。
|
||||
- 次内容文字应更浅、更小。
|
||||
- 不要为了“丰富界面”凭空添加解释性次级文本;只有真实数据结构里存在时才显示。
|
||||
- 紧凑面板里的行默认单行显示,长文本截断;不要因为某条内容更长就撑高行高,除非产品信息结构明确需要多行。
|
||||
|
||||
## 对齐原则
|
||||
|
||||
追求**内容对齐**,不是容器对齐,也不是机械文字左对齐。
|
||||
|
||||
- 对齐有意义的视觉内容,而不是外层矩形框。
|
||||
- 如果某一行由 SVG + 文字组成,标题或相关内容应根据 SVG 的视觉位置做对齐,而不是盲目对齐文字边缘。
|
||||
- 如果下方具体内容本身没有图标,不要为了凑齐文字起点而乱加假图标。
|
||||
- 按实际视觉体积对齐:不同 SVG 的 viewBox 和形状不同,真实尺寸可以不同,只要视觉大小一致。
|
||||
- 不要强行把所有 SVG 设成同样宽高。
|
||||
- 可以统一按钮命中区域,但图标本身大小要按视觉体积校准。
|
||||
|
||||
## 组件状态原则
|
||||
|
||||
状态设计必须反映真实语义:
|
||||
|
||||
- Hover:只用于可交互项。
|
||||
- Active/当前:只用于当前选择、当前模式或当前项。
|
||||
- Disabled:降低对比度,并移除点击暗示。
|
||||
- 展示内容:不要看起来像按钮;避免 hover 底色、阴影、指针光标。
|
||||
- 可点击内容:可以使用轻量 hover 底色、指针光标和当前项标记。
|
||||
|
||||
不要把“有没有阴影”当成唯一状态区别。状态语义应该通过结构、标记、间距和交互暗示共同表达。
|
||||
|
||||
## 可选项 vs 展示项
|
||||
|
||||
设计前必须先判断内容类型。
|
||||
|
||||
### 可选项
|
||||
|
||||
用于用户从多个选项中选择一个,例如环境切换、资源位置切换、账号/空间切换、筛选条件切换。
|
||||
|
||||
- 必须有明确的“可选择”视觉语义,例如 radio 圆点、check 标记或清晰的选中行。
|
||||
- 当前项必须一眼能看出来。
|
||||
- 可以有浅灰 hover 底色。
|
||||
- 行本身可以是可点击的。
|
||||
- `默认`、`当前` 这类 badge 只是元信息,不能单独承担“这是可选项”的职责。
|
||||
|
||||
### 展示项
|
||||
|
||||
用于展示状态或列表数据,例如任务条目、命令摘要、进程摘要、通知摘要,除非真实组件会打开详情。
|
||||
|
||||
- 保持安静,不要做成按钮或卡片。
|
||||
- 不要乱加假图标。
|
||||
- 不要加卡片阴影或嵌套圆角容器。
|
||||
- 如果真实产品里不是可点击项,就不要加 hover 效果。
|
||||
- 紧凑面板中使用统一行高和单行截断。
|
||||
- 只显示真实数据模型里存在的字段。
|
||||
|
||||
## 二级菜单与更多操作
|
||||
|
||||
二级菜单要一致、克制、可读:
|
||||
|
||||
- 使用紧凑浮层,带轻量边框、适中圆角和轻阴影。
|
||||
- 菜单选项无论文字长短,hover 背景宽度必须一样长。
|
||||
- 菜单宽度由最长内容决定,所有选项填满同一宽度。
|
||||
- 不要让每个选项的阴影/hover 背景长度随文字变短变长。
|
||||
- 文案要短。
|
||||
- 删除等破坏性项只用 danger 色区分,不要用更大尺寸或更重阴影。
|
||||
- 列表行右侧 `...` 使用简单圆点视觉;hover 可以只变色,不一定加背景。
|
||||
|
||||
## 侧边栏展开原则
|
||||
|
||||
消息类/导航类侧边栏可使用“遮罩露出”模型,而不是新建一个展开浮层:
|
||||
|
||||
- 把侧边栏理解为一张完整面板,被一个移动边界遮住。
|
||||
- 收起态只露出固定图标列。
|
||||
- 展开时右侧竖线向右移动,内容被裁切后逐渐露出。
|
||||
- 每个动作从始至终只有一个图标,不要展开后再出现第二个图标。
|
||||
- 图标右侧文字和新出现的列表内容同时执行两种效果:淡入 + 随移动边界逐渐露出。
|
||||
- 展开时不应挤压主内容布局;如设计目标是覆盖/露出,就保持主布局稳定。
|
||||
- 收起态 hover 只作用在图标的圆角正方形上,不要露出被裁切的大圆角整行背景。
|
||||
- 展开态 hover 才可以作用于整行。
|
||||
|
||||
## 资源面板原则
|
||||
|
||||
资源面板、管理面板、辅助面板应避免旧式“圆角矩形套圆角矩形套圆角矩形”的低级感。
|
||||
|
||||
- 优先做窄而扁平的面板;如果它位于主导航旁边,可以让展开后的侧边栏完整覆盖它。
|
||||
- 顶部标题显示当前内容类型,例如资源、环境、任务、命令、通知、日志等。不要把所有模式标题硬塞到同一种视觉层级里。
|
||||
- 标题下方可放一个“模式切换按钮”,点击展开二级菜单;旁边按需放紧凑管理图标按钮。
|
||||
- 不要把浅色小号“管理”文字按钮放在大标题同一行,容易层级违和;优先使用图标按钮。
|
||||
- 不要无意义增加搜索框;只有真实工作流需要搜索或过滤时才加。
|
||||
- 层级资源树可以使用文件/文件夹/类别图标,因为这类图标本身承载结构语义。
|
||||
- 环境/空间/资源位置切换属于可选项 UI,不是普通展示文本。
|
||||
- 任务、命令、进程、通知等区域按真实数据字段显示:
|
||||
- 任务/进程:标识、摘要、状态、可选当前步骤。
|
||||
- 命令/作业:命令或作业预览、状态、返回码/结果码。
|
||||
- 清单/待办:序号、标题、状态;如果存在总说明,可单独显示。
|
||||
- 内容行默认统一高度,除非真实信息结构明确需要展开。
|
||||
|
||||
## 代码展示原则
|
||||
|
||||
代码块、日志块或等宽文本展示精致化时:
|
||||
|
||||
- 做成现代 artifact/card 感:1px 细边框、较大圆角、清晰 header/body 分区。
|
||||
- 避免粗边框和重嵌套面板。
|
||||
- 复制/运行按钮要遵循同一套按钮系统。
|
||||
- Header 里的语言名称是次级信息;代码内容才是主内容。
|
||||
- padding、等宽字体、行高要统一;流式输出时避免视觉抖动。
|
||||
|
||||
## 实现前检查清单
|
||||
|
||||
修改 UI 前必须:
|
||||
|
||||
1. 先读取真实组件、状态或数据结构,不准凭印象设计假数据。
|
||||
2. 判断每个内容是可选项、可点击动作,还是展示内容。
|
||||
3. 按视觉内容对齐,而不是按容器边缘或文字边缘机械对齐。
|
||||
4. 复用产品已有图标资源或统一图标库,不要自己编造 SVG。
|
||||
5. 统一图标命中区域,但按视觉体积调整真实图标大小。
|
||||
6. 避免嵌套卡片、大阴影和假的 hover 暗示。
|
||||
7. 同时检查浅色和深色模式。
|
||||
8. 写 demo 时也要贴近真实产品结构和真实字段;如必须使用示例数据,要保持字段语义真实,不要写臆想说明。
|
||||
200
docs/code_block_demo.html
Normal file
200
docs/code_block_demo.html
Normal file
@ -0,0 +1,200 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Code Block Demo</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #ffffff;
|
||||
--text: #111111;
|
||||
--muted: #6f6f6f;
|
||||
--surface: #ffffff;
|
||||
--border: rgba(0, 0, 0, 0.105);
|
||||
--hover: rgba(0, 0, 0, 0.055);
|
||||
--radius: 20px;
|
||||
--mono: "SF Mono", "JetBrains Mono", "Menlo", "Monaco", "Consolas", monospace;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
color-scheme: dark;
|
||||
--bg: #1a1a1a;
|
||||
--text: #f3f3f3;
|
||||
--muted: #9b9b9b;
|
||||
--surface: #1a1a1a;
|
||||
--border: rgba(255, 255, 255, 0.13);
|
||||
--hover: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 48px 24px;
|
||||
}
|
||||
button { font: inherit; }
|
||||
.page { width: min(960px, 100%); }
|
||||
.topbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 24px; }
|
||||
.title { margin: 0; font-size: 30px; line-height: 1.12; letter-spacing: -0.045em; font-weight: 680; }
|
||||
.subtitle { margin: 6px 0 0; color: var(--muted); font-size: 14px; line-height: 1.35; }
|
||||
.theme-toggle { height: 36px; border: 1px solid var(--border); border-radius: 999px; background: transparent; color: var(--text); padding: 0 13px; cursor: pointer; }
|
||||
.theme-toggle:hover { background: var(--hover); }
|
||||
.message { max-width: 860px; font-size: 16px; line-height: 1.65; }
|
||||
.message p { margin: 0 0 14px; }
|
||||
|
||||
.code-block {
|
||||
margin: 16px 0 28px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
background: var(--surface);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.code-top {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 0 12px 0 18px;
|
||||
background: var(--surface);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.code-lang {
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.01em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 0;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
cursor: pointer;
|
||||
transition: background 140ms ease, color 140ms ease;
|
||||
}
|
||||
.copy-btn:hover {
|
||||
background: var(--hover);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: inline-block;
|
||||
background: currentColor;
|
||||
mask: var(--icon-url) center / contain no-repeat;
|
||||
-webkit-mask: var(--icon-url) center / contain no-repeat;
|
||||
}
|
||||
.icon-copy { --icon-url: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2024%2024%22%20width=%2248%22%20height=%2248%22%20fill=%22none%22%20stroke=%22%23000000%22%20stroke-width=%222%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%20style=%22opacity:1;%22%3E%3Crect%20width=%2214%22%20height=%2214%22%20x=%228%22%20y=%228%22%20rx=%222%22%20ry=%222%22/%3E%3Cpath%20d=%22M4%2016c-1.1%200-2-.9-2-2V4c0-1.1.9-2%202-2h10c1.1%200%202%20.9%202%202%22/%3E%3C/svg%3E"); }
|
||||
.icon-check { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M20%206%209%2017l-5-5%22%20/%3E%0A%3C/svg%3E"); }
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
padding: 24px 28px 28px;
|
||||
background: var(--surface);
|
||||
overflow: auto;
|
||||
font-family: var(--mono);
|
||||
font-size: 15px;
|
||||
line-height: 1.64;
|
||||
tab-size: 4;
|
||||
}
|
||||
code { font-family: inherit; color: var(--text); white-space: pre; }
|
||||
|
||||
.kw { color: #c13f7a; }
|
||||
.fn { color: #6a45c2; }
|
||||
.str { color: #08863f; }
|
||||
.num { color: #8b5e00; }
|
||||
.op { color: #c13f7a; }
|
||||
:root[data-theme="dark"] .kw { color: #ff7ab2; }
|
||||
:root[data-theme="dark"] .fn { color: #b69cff; }
|
||||
:root[data-theme="dark"] .str { color: #5fd38d; }
|
||||
:root[data-theme="dark"] .num { color: #e4b86a; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="page">
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<h1 class="title">代码块 Demo</h1>
|
||||
<p class="subtitle">顶部更矮;顶部和代码区同色;只用一条细线分割;不添加不存在的功能。</p>
|
||||
</div>
|
||||
<button class="theme-toggle" id="themeToggle" type="button">深色模式</button>
|
||||
</header>
|
||||
|
||||
<section class="message">
|
||||
<p>示例代码块:</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-top">
|
||||
<span class="code-lang">Python</span>
|
||||
<button class="copy-btn" type="button" title="复制代码" aria-label="复制代码" data-copy="pythonCode">
|
||||
<span class="icon icon-copy" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
<pre><code id="pythonCode"><span class="kw">import</span> random
|
||||
<span class="kw">from</span> datetime <span class="kw">import</span> datetime
|
||||
|
||||
quotes <span class="op">=</span> [
|
||||
<span class="str">"Stay curious."</span>,
|
||||
<span class="str">"Code is poetry."</span>,
|
||||
<span class="str">"Small steps every day."</span>,
|
||||
<span class="str">"Debugging is detective work."</span>,
|
||||
]
|
||||
|
||||
<span class="kw">def</span> <span class="fn">random_quote</span>():
|
||||
now <span class="op">=</span> datetime.now().strftime(<span class="str">"%Y-%m-%d %H:%M:%S"</span>)
|
||||
quote <span class="op">=</span> random.choice(quotes)
|
||||
<span class="kw">return</span> <span class="str">f"[{now}] {quote}"</span>
|
||||
|
||||
<span class="kw">if</span> __name__ <span class="op">==</span> <span class="str">"__main__"</span>:
|
||||
<span class="kw">for</span> i <span class="kw">in</span> range(<span class="num">3</span>):
|
||||
print(random_quote())</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-top">
|
||||
<span class="code-lang">powershell</span>
|
||||
<button class="copy-btn" type="button" title="复制代码" aria-label="复制代码" data-copy="psCode">
|
||||
<span class="icon icon-copy" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
<pre><code id="psCode">Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const root = document.documentElement;
|
||||
const themeToggle = document.getElementById('themeToggle');
|
||||
themeToggle.addEventListener('click', () => {
|
||||
const next = root.dataset.theme === 'dark' ? 'light' : 'dark';
|
||||
root.dataset.theme = next;
|
||||
themeToggle.textContent = next === 'dark' ? '浅色模式' : '深色模式';
|
||||
});
|
||||
|
||||
document.querySelectorAll('.copy-btn').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
// file:// 预览下不调用剪贴板 API,避免浏览器安全报错;这里只演示点击后的视觉反馈。
|
||||
const icon = button.querySelector('.icon');
|
||||
icon.className = 'icon icon-check';
|
||||
setTimeout(() => { icon.className = 'icon icon-copy'; }, 1000);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
581
docs/sidebar_overlay_demo.html
Normal file
581
docs/sidebar_overlay_demo.html
Normal file
@ -0,0 +1,581 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Sidebar Reveal Demo</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #ffffff;
|
||||
--sidebar-bg: #fbfbfb;
|
||||
--text: #111111;
|
||||
--muted: #8f8f8f;
|
||||
--border: rgba(0, 0, 0, 0.09);
|
||||
--hover: rgba(0, 0, 0, 0.055);
|
||||
--hover-strong: rgba(0, 0, 0, 0.095);
|
||||
--active: rgba(0, 0, 0, 0.078);
|
||||
--menu-bg: #ffffff;
|
||||
--menu-shadow: 0 12px 28px rgba(0, 0, 0, 0.14);
|
||||
--collapsed-width: 52px;
|
||||
--expanded-width: 306px;
|
||||
--icon-cell: 40px;
|
||||
--row-height: 40px;
|
||||
--row-radius: 12px;
|
||||
--anim: 320ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
color-scheme: dark;
|
||||
--bg: #1a1a1a;
|
||||
--sidebar-bg: #0f0f0f;
|
||||
--text: #f4f4f4;
|
||||
--muted: #8f8f8f;
|
||||
--border: rgba(255, 255, 255, 0.105);
|
||||
--hover: rgba(255, 255, 255, 0.078);
|
||||
--hover-strong: rgba(255, 255, 255, 0.13);
|
||||
--active: rgba(255, 255, 255, 0.105);
|
||||
--menu-bg: #202020;
|
||||
--menu-shadow: 0 18px 36px rgba(0, 0, 0, 0.42);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.app {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.main {
|
||||
min-width: 0;
|
||||
height: 100vh;
|
||||
margin-left: var(--collapsed-width);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding: 28px 32px;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
margin: 0;
|
||||
font-size: 34px;
|
||||
line-height: 1.1;
|
||||
font-weight: 620;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.main-title span {
|
||||
color: var(--muted);
|
||||
font-weight: 430;
|
||||
}
|
||||
|
||||
.sidebar-frame {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
width: var(--collapsed-width);
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: var(--sidebar-bg);
|
||||
border-right: 1px solid var(--border);
|
||||
transition: width var(--anim), background 160ms ease, border-color 160ms ease;
|
||||
will-change: width;
|
||||
}
|
||||
|
||||
.sidebar-frame.open {
|
||||
width: var(--expanded-width);
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
width: var(--expanded-width);
|
||||
height: 100%;
|
||||
background: var(--sidebar-bg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 18px 8px 14px 6px;
|
||||
transition: background 160ms ease;
|
||||
}
|
||||
|
||||
.sidebar-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.sidebar-bottom {
|
||||
margin-top: 8px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.side-row,
|
||||
.search-shell,
|
||||
.conversation-row {
|
||||
width: 100%;
|
||||
min-height: var(--row-height);
|
||||
border: 0;
|
||||
border-radius: var(--row-radius);
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
display: grid;
|
||||
grid-template-columns: var(--icon-cell) minmax(0, 1fr);
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.side-row,
|
||||
.conversation-row {
|
||||
cursor: pointer;
|
||||
transition: background 140ms ease, color 140ms ease;
|
||||
}
|
||||
|
||||
.side-row:hover,
|
||||
.conversation-row:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.side-icon {
|
||||
width: var(--icon-cell);
|
||||
height: var(--row-height);
|
||||
border-radius: var(--row-radius);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: currentColor;
|
||||
flex: 0 0 auto;
|
||||
transition: background 140ms ease;
|
||||
}
|
||||
|
||||
.sidebar-frame:not(.open) .side-row:hover .side-icon,
|
||||
.sidebar-frame:not(.open) .theme-toggle:hover .side-icon,
|
||||
.sidebar-frame:not(.open) .conversation-row:hover .side-icon {
|
||||
background: var(--hover);
|
||||
}
|
||||
|
||||
.sidebar-frame.open .side-row:hover,
|
||||
.sidebar-frame.open .side-row.active,
|
||||
.sidebar-frame.open .conversation-row:hover,
|
||||
.sidebar-frame.open .conversation-row.menu-open {
|
||||
background: var(--hover);
|
||||
}
|
||||
|
||||
.side-icon svg {
|
||||
display: block;
|
||||
stroke: currentColor;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/* 保留视觉校准:按钮容器统一,图标真实尺寸不机械统一 */
|
||||
.side-icon--chat svg { width: 29px; height: 29px; }
|
||||
.side-icon--pencil svg { width: 22px; height: 22px; }
|
||||
.side-icon--workspace svg { width: 23px; height: 23px; }
|
||||
.side-icon--monitor svg { width: 23px; height: 23px; }
|
||||
.side-icon--theme svg { width: 22px; height: 22px; }
|
||||
.side-icon--user svg { width: 22px; height: 22px; }
|
||||
|
||||
.side-label,
|
||||
.search-area,
|
||||
.conversation-list,
|
||||
.conversation-title,
|
||||
.conversation-more {
|
||||
opacity: 0;
|
||||
transition: opacity 220ms ease;
|
||||
transition-delay: 0ms;
|
||||
}
|
||||
|
||||
.sidebar-frame.open .side-label,
|
||||
.sidebar-frame.open .search-area,
|
||||
.sidebar-frame.open .conversation-list,
|
||||
.sidebar-frame.open .conversation-title,
|
||||
.sidebar-frame.open .conversation-more {
|
||||
opacity: 1;
|
||||
transition-delay: 80ms;
|
||||
}
|
||||
|
||||
.side-label {
|
||||
min-width: 0;
|
||||
padding-left: 8px;
|
||||
padding-right: 12px;
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.015em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.search-area {
|
||||
flex: 0 0 auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.search-shell {
|
||||
height: var(--row-height);
|
||||
overflow: hidden;
|
||||
transition: background 140ms ease;
|
||||
}
|
||||
|
||||
.search-shell:focus-within,
|
||||
.search-shell:hover {
|
||||
background: var(--hover);
|
||||
}
|
||||
|
||||
.search-input {
|
||||
min-width: 0;
|
||||
width: calc(var(--expanded-width) - var(--icon-cell) - 22px);
|
||||
height: var(--row-height);
|
||||
border: 0;
|
||||
outline: 0;
|
||||
padding: 0 12px 0 8px;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
font-size: 14px;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.search-input::placeholder {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.conversation-list {
|
||||
min-height: 0;
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
padding-top: 12px;
|
||||
padding-right: 0;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.conversation-row {
|
||||
position: relative;
|
||||
grid-template-columns: minmax(0, 1fr) 40px;
|
||||
min-height: var(--row-height);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.conversation-title {
|
||||
min-width: 0;
|
||||
padding-left: 12px;
|
||||
padding-right: 4px;
|
||||
color: var(--text);
|
||||
font-size: 14px;
|
||||
line-height: 1.25;
|
||||
letter-spacing: -0.01em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.conversation-more {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 0;
|
||||
border-radius: 9px;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
cursor: pointer;
|
||||
justify-self: start;
|
||||
visibility: hidden;
|
||||
transition: background 140ms ease, color 140ms ease, opacity 160ms ease;
|
||||
}
|
||||
|
||||
.conversation-row:hover .conversation-more,
|
||||
.conversation-row.menu-open .conversation-more {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.conversation-more:hover,
|
||||
.conversation-row.menu-open .conversation-more {
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.conversation-more svg {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
stroke: currentColor;
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
z-index: 80;
|
||||
width: max-content;
|
||||
min-width: 92px;
|
||||
padding: 6px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 14px;
|
||||
background: var(--menu-bg);
|
||||
box-shadow: var(--menu-shadow);
|
||||
opacity: 0;
|
||||
transform: translateY(-4px) scale(0.98);
|
||||
pointer-events: none;
|
||||
transition:
|
||||
opacity 120ms ease,
|
||||
transform 150ms cubic-bezier(0.22, 1, 0.36, 1),
|
||||
background 160ms ease,
|
||||
border-color 160ms ease;
|
||||
}
|
||||
|
||||
.context-menu.open {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.menu-button {
|
||||
width: max-content;
|
||||
min-width: 80px;
|
||||
height: 36px;
|
||||
border: 0;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
display: grid;
|
||||
grid-template-columns: 24px auto;
|
||||
align-items: center;
|
||||
padding: 0 10px 0 8px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
letter-spacing: -0.01em;
|
||||
transition: background 140ms ease;
|
||||
}
|
||||
|
||||
.menu-button:hover {
|
||||
background: var(--hover);
|
||||
}
|
||||
|
||||
.menu-button.danger {
|
||||
color: #d6483b;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .menu-button.danger {
|
||||
color: #ff7b72;
|
||||
}
|
||||
|
||||
.menu-button svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
stroke: currentColor;
|
||||
}
|
||||
|
||||
.demo-hint {
|
||||
position: fixed;
|
||||
left: calc(var(--collapsed-width) + 20px);
|
||||
bottom: 18px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar-frame" id="sidebar" aria-label="对话侧边栏">
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-top">
|
||||
<button class="side-row" id="toggleSidebar" type="button" aria-label="展开对话记录" aria-expanded="false">
|
||||
<span class="side-icon side-icon--chat" aria-hidden="true">
|
||||
<svg viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 6.5c0-1.38 1.12-2.5 2.5-2.5h13c1.38 0 2.5 1.12 2.5 2.5v8.5c0 1.38-1.12 2.5-2.5 2.5h-5.6l-3.4 3.2.6-3.2H7.5c-1.38 0-2.5-1.12-2.5-2.5V6.5z" stroke-width="1.45" stroke-linejoin="round" />
|
||||
<path d="M9 9.5h10" stroke-width="1.45" stroke-linecap="round" />
|
||||
<path d="M9 13h6" stroke-width="1.45" stroke-linecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="side-label">对话记录</span>
|
||||
</button>
|
||||
|
||||
<button class="side-row" type="button" aria-label="新建对话">
|
||||
<span class="side-icon side-icon--pencil" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="m15 5 4 4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="side-label">新建对话</span>
|
||||
</button>
|
||||
|
||||
<button class="side-row" type="button" aria-label="工作区">
|
||||
<span class="side-icon side-icon--workspace" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 3 4.5 7.15v9.7L12 21l7.5-4.15v-9.7L12 3Z" stroke-width="1.55" stroke-linejoin="round" />
|
||||
<path d="M4.8 7.35 12 11.5l7.2-4.15M12 11.5V21" stroke-width="1.55" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="side-label">工作区</span>
|
||||
</button>
|
||||
|
||||
<button class="side-row" type="button" aria-label="虚拟显示器">
|
||||
<span class="side-icon side-icon--monitor" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="3.5" y="5" width="17" height="12" rx="2" stroke-width="1.55" />
|
||||
<path d="M9 21h6M12 17v4" stroke-width="1.55" stroke-linecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="side-label">虚拟显示器</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="search-area" aria-label="搜索对话">
|
||||
<label class="search-shell">
|
||||
<span class="side-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:22px;height:22px;stroke:currentColor">
|
||||
<circle cx="11" cy="11" r="7" stroke-width="1.55" />
|
||||
<path d="m20 20-3.4-3.4" stroke-width="1.55" stroke-linecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<input class="search-input" type="search" placeholder="搜索对话" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="conversation-list" aria-label="对话记录">
|
||||
<div class="conversation-row" data-title="随意的 py 代码块">
|
||||
<span class="conversation-title">随意的 py 代码块</span>
|
||||
<button class="conversation-more" type="button" aria-label="更多操作">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M6 12h.01M12 12h.01M18 12h.01" stroke-width="3" stroke-linecap="round" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="conversation-row" data-title="前端现代化设计讨论">
|
||||
<span class="conversation-title">前端现代化设计讨论</span>
|
||||
<button class="conversation-more" type="button" aria-label="更多操作">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M6 12h.01M12 12h.01M18 12h.01" stroke-width="3" stroke-linecap="round" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="conversation-row" data-title="审批面板覆盖窗口方案">
|
||||
<span class="conversation-title">审批面板覆盖窗口方案</span>
|
||||
<button class="conversation-more" type="button" aria-label="更多操作">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M6 12h.01M12 12h.01M18 12h.01" stroke-width="3" stroke-linecap="round" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="conversation-row" data-title="CLI 显示层细节修复">
|
||||
<span class="conversation-title">CLI 显示层细节修复</span>
|
||||
<button class="conversation-more" type="button" aria-label="更多操作">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M6 12h.01M12 12h.01M18 12h.01" stroke-width="3" stroke-linecap="round" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="conversation-row" data-title="个人空间设置页重设计">
|
||||
<span class="conversation-title">个人空间设置页重设计</span>
|
||||
<button class="conversation-more" type="button" aria-label="更多操作">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M6 12h.01M12 12h.01M18 12h.01" stroke-width="3" stroke-linecap="round" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-bottom">
|
||||
<button class="side-row theme-toggle" id="themeToggle" type="button" aria-label="切换深色模式">
|
||||
<span class="side-icon side-icon--theme" aria-hidden="true">
|
||||
<svg class="theme-icon theme-icon-light" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="4" stroke-width="1.55" />
|
||||
<path d="M12 2.8v2.3M12 18.9v2.3M4.2 4.2l1.6 1.6M18.2 18.2l1.6 1.6M2.8 12h2.3M18.9 12h2.3M4.2 19.8l1.6-1.6M18.2 5.8l1.6-1.6" stroke-width="1.55" stroke-linecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="side-label">浅色模式</span>
|
||||
</button>
|
||||
|
||||
<button class="side-row" type="button" aria-label="个人空间">
|
||||
<span class="side-icon side-icon--user" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="8" r="4" stroke-width="1.6" />
|
||||
<path d="M4.5 21a7.5 7.5 0 0 1 15 0" stroke-width="1.6" stroke-linecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="side-label">个人空间</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<h1 class="main-title">AI Agent <span>Auto</span></h1>
|
||||
</main>
|
||||
|
||||
<div class="context-menu" id="contextMenu" role="menu" aria-hidden="true">
|
||||
<button class="menu-button" type="button" role="menuitem">
|
||||
<svg viewBox="0 0 24 24" fill="none"><rect x="8" y="8" width="11" height="11" rx="2" stroke-width="1.55"/><path d="M5 15V7a2 2 0 0 1 2-2h8" stroke-width="1.55" stroke-linecap="round"/></svg>
|
||||
<span>复制</span>
|
||||
</button>
|
||||
<button class="menu-button danger" type="button" role="menuitem">
|
||||
<svg viewBox="0 0 24 24" fill="none"><path d="M4 7h16M10 11v6M14 11v6M6 7l1 14h10l1-14M9 7V4h6v3" stroke-width="1.55" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
<span>删除</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-hint">点击第一个按钮折叠/露出;对话行 hover 后显示 ...;点击 ... 打开二级菜单。</div>
|
||||
|
||||
<script>
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const toggle = document.getElementById('toggleSidebar');
|
||||
const themeToggle = document.getElementById('themeToggle');
|
||||
const contextMenu = document.getElementById('contextMenu');
|
||||
let menuOwner = null;
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
const isOpen = sidebar.classList.toggle('open');
|
||||
toggle.setAttribute('aria-expanded', String(isOpen));
|
||||
toggle.setAttribute('aria-label', isOpen ? '收起对话记录' : '展开对话记录');
|
||||
if (!isOpen) closeMenu();
|
||||
});
|
||||
|
||||
themeToggle.addEventListener('click', () => {
|
||||
const root = document.documentElement;
|
||||
const next = root.dataset.theme === 'dark' ? 'light' : 'dark';
|
||||
root.dataset.theme = next;
|
||||
themeToggle.querySelector('.side-label').textContent = next === 'dark' ? '深色模式' : '浅色模式';
|
||||
themeToggle.setAttribute('aria-label', next === 'dark' ? '切换浅色模式' : '切换深色模式');
|
||||
});
|
||||
|
||||
function closeMenu() {
|
||||
contextMenu.classList.remove('open');
|
||||
contextMenu.setAttribute('aria-hidden', 'true');
|
||||
if (menuOwner) menuOwner.classList.remove('menu-open');
|
||||
menuOwner = null;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.conversation-more').forEach((button) => {
|
||||
button.addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
const row = button.closest('.conversation-row');
|
||||
if (menuOwner === row && contextMenu.classList.contains('open')) {
|
||||
closeMenu();
|
||||
return;
|
||||
}
|
||||
closeMenu();
|
||||
menuOwner = row;
|
||||
row.classList.add('menu-open');
|
||||
const rect = button.getBoundingClientRect();
|
||||
contextMenu.style.left = '0px';
|
||||
contextMenu.style.top = `${rect.bottom + 6}px`;
|
||||
contextMenu.classList.add('open');
|
||||
contextMenu.setAttribute('aria-hidden', 'false');
|
||||
const menuWidth = contextMenu.offsetWidth;
|
||||
contextMenu.style.left = `${Math.min(rect.right - menuWidth, window.innerWidth - menuWidth - 12)}px`;
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
if (!contextMenu.contains(event.target)) closeMenu();
|
||||
});
|
||||
|
||||
window.addEventListener('resize', closeMenu);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
556
docs/sidebar_workspace_demo.html
Normal file
556
docs/sidebar_workspace_demo.html
Normal file
@ -0,0 +1,556 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Sidebar + Workspace Demo</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #ffffff;
|
||||
--panel-bg: #fbfbfb;
|
||||
--text: #111111;
|
||||
--muted: #8f8f8f;
|
||||
--border: rgba(0, 0, 0, 0.09);
|
||||
--hover: rgba(0, 0, 0, 0.055);
|
||||
--hover-strong: rgba(0, 0, 0, 0.095);
|
||||
--menu-bg: #ffffff;
|
||||
--menu-shadow: 0 12px 28px rgba(0, 0, 0, 0.14);
|
||||
--collapsed-width: 52px;
|
||||
--expanded-width: 306px;
|
||||
--workspace-width: calc(var(--expanded-width) - var(--collapsed-width));
|
||||
--icon-cell: 40px;
|
||||
--row-height: 40px;
|
||||
--row-radius: 12px;
|
||||
--anim: 320ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
color-scheme: dark;
|
||||
--bg: #1a1a1a;
|
||||
--panel-bg: #0f0f0f;
|
||||
--text: #f4f4f4;
|
||||
--muted: #8f8f8f;
|
||||
--border: rgba(255, 255, 255, 0.105);
|
||||
--hover: rgba(255, 255, 255, 0.078);
|
||||
--hover-strong: rgba(255, 255, 255, 0.13);
|
||||
--menu-bg: #202020;
|
||||
--menu-shadow: 0 18px 36px rgba(0, 0, 0, 0.42);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; height: 100vh; background: var(--bg); color: var(--text); overflow: hidden; }
|
||||
button, input { font: inherit; }
|
||||
button { -webkit-tap-highlight-color: transparent; }
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
width: var(--icon-size, 20px);
|
||||
height: var(--icon-size, 20px);
|
||||
background: currentColor;
|
||||
mask: var(--icon-url) center / contain no-repeat;
|
||||
-webkit-mask: var(--icon-url) center / contain no-repeat;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.icon-chat { --icon-url: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2032%2032%22%20fill=%22none%22%20stroke=%22currentColor%22%20stroke-width=%222.2%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%3E%0A%20%20%3Cpath%20d=%22M6%207c0-2%201.6-3.6%203.6-3.6h13c2%200%203.6%201.6%203.6%203.6v10c0%202-1.6%203.6-3.6%203.6h-6.2L12.4%2025l0.7-4.4H9.6c-2%200-3.6-1.6-3.6-3.6V7Z%22%20/%3E%0A%20%20%3Cpath%20d=%22M10.4%2011h11.2%22%20/%3E%0A%20%20%3Cpath%20d=%22M10.4%2015h7.2%22%20/%3E%0A%3C/svg%3E"); --icon-size: 29px; }
|
||||
.icon-pencil { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M21.174%206.812a1%201%200%200%200-3.986-3.987L3.842%2016.174a2%202%200%200%200-.5.83l-1.321%204.352a.5.5%200%200%200%20.623.622l4.353-1.32a2%202%200%200%200%20.83-.497z%22%20/%3E%0A%20%20%3Cpath%20d=%22m15%205%204%204%22%20/%3E%0A%3C/svg%3E"); --icon-size: 22px; }
|
||||
.icon-layers { --icon-url: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2024%2024%22%20width=%2248%22%20height=%2248%22%20fill=%22none%22%20stroke=%22#000000%22%20stroke-width=%222%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%20style=%22opacity:1;%22%3E%3Cpath%20d=%22M12.83%202.18a2%202%200%200%200-1.66%200L2.6%206.08a1%201%200%200%200%200%201.83l8.58%203.91a2%202%200%200%200%201.66%200l8.58-3.9a1%201%200%200%200%200-1.83z%22/%3E%3Cpath%20d=%22M2%2012a1%201%200%200%200%20.58.91l8.6%203.91a2%202%200%200%200%201.65%200l8.58-3.9A1%201%200%200%200%2022%2012%22/%3E%3Cpath%20d=%22M2%2017a1%201%200%200%200%20.58.91l8.6%203.91a2%202%200%200%200%201.65%200l8.58-3.9A1%201%200%200%200%2022%2017%22/%3E%3C/svg%3E"); --icon-size: 23px; }
|
||||
.icon-monitor { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Crect%20width=%2220%22%20height=%2214%22%20x=%222%22%20y=%223%22%20rx=%222%22%20/%3E%0A%20%20%3Cline%20x1=%228%22%20x2=%2216%22%20y1=%2221%22%20y2=%2221%22%20/%3E%0A%20%20%3Cline%20x1=%2212%22%20x2=%2212%22%20y1=%2217%22%20y2=%2221%22%20/%3E%0A%3C/svg%3E"); --icon-size: 23px; }
|
||||
.icon-search { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22m21%2021-4.34-4.34%22%20/%3E%0A%20%20%3Ccircle%20cx=%2211%22%20cy=%2211%22%20r=%228%22%20/%3E%0A%3C/svg%3E"); --icon-size: 22px; }
|
||||
.icon-user { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M19%2021v-2a4%204%200%200%200-4-4H9a4%204%200%200%200-4%204v2%22%20/%3E%0A%20%20%3Ccircle%20cx=%2212%22%20cy=%227%22%20r=%224%22%20/%3E%0A%3C/svg%3E"); --icon-size: 22px; }
|
||||
.icon-folder { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M20%2020a2%202%200%200%200%202-2V8a2%202%200%200%200-2-2h-7.9a2%202%200%200%201-1.69-.9L9.6%203.9A2%202%200%200%200%207.93%203H4a2%202%200%200%200-2%202v13a2%202%200%200%200%202%202Z%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-folder-open { --icon-url: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2024%2024%22%20width=%2248%22%20height=%2248%22%20fill=%22none%22%20stroke=%22#000000%22%20stroke-width=%222%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22%20style=%22opacity:1;%22%3E%3Cpath%20%20%20%20%20%20d=%22m6%2014l1.5-2.9A2%202%200%200%201%209.24%2010H20a2%202%200%200%201%201.94%202.5l-1.54%206a2%202%200%200%201-1.95%201.5H4a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h3.9a2%202%200%200%201%201.69.9l.81%201.2a2%202%200%200%200%201.67.9H18a2%202%200%200%201%202%202v2%22/%3E%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-file { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M6%2022a2%202%200%200%201-2-2V4a2%202%200%200%201%202-2h8a2.4%202.4%200%200%201%201.704.706l3.588%203.588A2.4%202.4%200%200%201%2020%208v12a2%202%200%200%201-2%202z%22%20/%3E%0A%20%20%3Cpath%20d=%22M14%202v5a1%201%200%200%200%201%201h5%22%20/%3E%0A%3C/svg%3E"); --icon-size: 17px; }
|
||||
.icon-bot { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M12%208V4H8%22%20/%3E%0A%20%20%3Crect%20width=%2216%22%20height=%2212%22%20x=%224%22%20y=%228%22%20rx=%222%22%20/%3E%0A%20%20%3Cpath%20d=%22M2%2014h2%22%20/%3E%0A%20%20%3Cpath%20d=%22M20%2014h2%22%20/%3E%0A%20%20%3Cpath%20d=%22M15%2013v2%22%20/%3E%0A%20%20%3Cpath%20d=%22M9%2013v2%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-terminal { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M12%2019h8%22%20/%3E%0A%20%20%3Cpath%20d=%22m4%2017%206-6-6-6%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-sticky { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M21%209a2.4%202.4%200%200%200-.706-1.706l-3.588-3.588A2.4%202.4%200%200%200%2015%203H5a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h14a2%202%200%200%200%202-2z%22%20/%3E%0A%20%20%3Cpath%20d=%22M15%203v5a1%201%200%200%200%201%201h5%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-check { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M20%206%209%2017l-5-5%22%20/%3E%0A%3C/svg%3E"); --icon-size: 17px; }
|
||||
.icon-clock { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Ccircle%20cx=%2212%22%20cy=%2212%22%20r=%229%22%20/%3E%0A%20%20%3Cpath%20d=%22M12%207v5l3%203%22%20/%3E%0A%3C/svg%3E"); --icon-size: 17px; }
|
||||
.icon-laptop { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M18%205a2%202%200%200%201%202%202v8.526a2%202%200%200%200%20.212.897l1.068%202.127a1%201%200%200%201-.9%201.45H3.62a1%201%200%200%201-.9-1.45l1.068-2.127A2%202%200%200%200%204%2015.526V7a2%202%200%200%201%202-2z%22%20/%3E%0A%20%20%3Cpath%20d=%22M20.054%2015.987H3.946%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-settings { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M9.671%204.136a2.34%202.34%200%200%201%204.659%200%202.34%202.34%200%200%200%203.319%201.915%202.34%202.34%200%200%201%202.33%204.033%202.34%202.34%200%200%200%200%203.831%202.34%202.34%200%200%201-2.33%204.033%202.34%202.34%200%200%200-3.319%201.915%202.34%202.34%200%200%201-4.659%200%202.34%202.34%200%200%200-3.32-1.915%202.34%202.34%200%200%201-2.33-4.033%202.34%202.34%200%200%200%200-3.831A2.34%202.34%200%200%201%206.35%206.051a2.34%202.34%200%200%200%203.319-1.915%22%20/%3E%0A%20%20%3Ccircle%20cx=%2212%22%20cy=%2212%22%20r=%223%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-trash { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M19%206v14a2%202%200%200%201-2%202H7a2%202%200%200%201-2-2V6%22%20/%3E%0A%20%20%3Cpath%20d=%22M3%206h18%22%20/%3E%0A%20%20%3Cpath%20d=%22M8%206V4a2%202%200%200%201%202-2h4a2%202%200%200%201%202%202v2%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-copy { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Crect%20width=%228%22%20height=%224%22%20x=%228%22%20y=%222%22%20rx=%221%22%20ry=%221%22%20/%3E%0A%20%20%3Cpath%20d=%22M16%204h2a2%202%200%200%201%202%202v14a2%202%200%200%201-2%202H6a2%202%200%200%201-2-2V6a2%202%200%200%201%202-2h2%22%20/%3E%0A%3C/svg%3E"); --icon-size: 18px; }
|
||||
.icon-sun { --icon-url: url("data:image/svg+xml,%3Csvg%0A%20%20xmlns=%22http://www.w3.org/2000/svg%22%0A%20%20width=%2224%22%0A%20%20height=%2224%22%0A%20%20viewBox=%220%200%2024%2024%22%0A%20%20fill=%22none%22%0A%20%20stroke=%22currentColor%22%0A%20%20stroke-width=%222%22%0A%20%20stroke-linecap=%22round%22%0A%20%20stroke-linejoin=%22round%22%0A%3E%0A%20%20%3Cpath%20d=%22M11.017%202.814a1%201%200%200%201%201.966%200l1.051%205.558a2%202%200%200%200%201.594%201.594l5.558%201.051a1%201%200%200%201%200%201.966l-5.558%201.051a2%202%200%200%200-1.594%201.594l-1.051%205.558a1%201%200%200%201-1.966%200l-1.051-5.558a2%202%200%200%200-1.594-1.594l-5.558-1.051a1%201%200%200%201%200-1.966l5.558-1.051a2%202%200%200%200%201.594-1.594z%22%20/%3E%0A%20%20%3Cpath%20d=%22M20%202v4%22%20/%3E%0A%20%20%3Cpath%20d=%22M22%204h-4%22%20/%3E%0A%20%20%3Ccircle%20cx=%224%22%20cy=%2220%22%20r=%222%22%20/%3E%0A%3C/svg%3E"); --icon-size: 22px; }
|
||||
|
||||
.app { position: relative; height: 100vh; background: var(--bg); }
|
||||
.main { min-width: 0; height: 100vh; margin-left: var(--expanded-width); display: flex; align-items: flex-start; justify-content: center; padding: 28px 32px; }
|
||||
.main-title { margin: 0; font-size: 34px; line-height: 1.1; font-weight: 620; letter-spacing: -0.04em; }
|
||||
.main-title span { color: var(--muted); font-weight: 430; }
|
||||
|
||||
/* 工作区:窄、扁平、无大卡片嵌套。展开的对话栏会完整盖住它。 */
|
||||
.workspace-panel {
|
||||
position: fixed;
|
||||
left: var(--collapsed-width);
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
width: var(--workspace-width);
|
||||
height: 100vh;
|
||||
background: var(--panel-bg);
|
||||
border-right: 1px solid var(--border);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 18px 10px 14px;
|
||||
overflow: hidden;
|
||||
transition: background 160ms ease, border-color 160ms ease;
|
||||
}
|
||||
|
||||
.workspace-title {
|
||||
height: 40px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0 0 16px;
|
||||
font-size: 18px;
|
||||
font-weight: 660;
|
||||
letter-spacing: -0.035em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.workspace-controls {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 40px;
|
||||
gap: 4px;
|
||||
margin: 4px 0 10px;
|
||||
}
|
||||
|
||||
.workspace-switch,
|
||||
.workspace-manage {
|
||||
height: 40px;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
transition: background 140ms ease, color 140ms ease;
|
||||
}
|
||||
|
||||
.workspace-switch:hover,
|
||||
.workspace-manage:hover { background: var(--hover); }
|
||||
|
||||
.workspace-switch {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 32px minmax(0, 1fr) 18px;
|
||||
align-items: center;
|
||||
padding: 0 10px 0 8px;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
letter-spacing: -0.012em;
|
||||
}
|
||||
|
||||
.workspace-switch .icon { justify-self: center; color: var(--text); }
|
||||
.workspace-switch-label { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.chevron { width: 8px; height: 8px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg) translateY(-2px); opacity: .55; justify-self: center; }
|
||||
|
||||
.workspace-manage { display: grid; place-items: center; color: var(--text); }
|
||||
|
||||
.workspace-body { min-height: 0; flex: 1 1 auto; overflow: hidden; display: flex; flex-direction: column; }
|
||||
.workspace-view { display: none; min-height: 0; flex: 1 1 auto; overflow-y: auto; scrollbar-width: thin; padding-top: 2px; }
|
||||
.workspace-view.active { display: block; }
|
||||
|
||||
.content-row {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
border-radius: 10px;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
color: var(--text);
|
||||
font-size: 13px;
|
||||
letter-spacing: -0.01em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content-row + .content-row { margin-top: 1px; }
|
||||
.content-main { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.content-meta { color: var(--muted); font-size: 12px; white-space: nowrap; }
|
||||
|
||||
/* 文件树是真实可操作树:保留文件/文件夹图标和 hover,其他内容区不做按钮感。 */
|
||||
.file-row {
|
||||
grid-template-columns: 20px 20px minmax(0, 1fr) auto;
|
||||
gap: 4px;
|
||||
padding: 0 8px 0 2px;
|
||||
cursor: pointer;
|
||||
transition: background 140ms ease;
|
||||
}
|
||||
.file-row:hover { background: var(--hover); }
|
||||
.file-row .icon { color: var(--muted); justify-self: center; }
|
||||
.file-arrow { width: 16px; text-align: center; color: var(--muted); font-size: 11px; }
|
||||
.file-row.depth-1 { padding-left: 16px; }
|
||||
.file-row.depth-2 { padding-left: 30px; }
|
||||
|
||||
.plain-row {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 8px;
|
||||
padding: 0 10px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.option-row {
|
||||
height: 44px;
|
||||
grid-template-columns: 20px minmax(0, 1fr) auto;
|
||||
gap: 8px;
|
||||
padding: 0 10px 0 8px;
|
||||
cursor: pointer;
|
||||
transition: background 140ms ease, color 140ms ease;
|
||||
}
|
||||
.option-row:hover { background: var(--hover); }
|
||||
.option-row.selected { background: var(--hover); }
|
||||
.option-marker {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
border-radius: 999px;
|
||||
border: 1.5px solid var(--muted);
|
||||
justify-self: center;
|
||||
position: relative;
|
||||
opacity: .85;
|
||||
}
|
||||
.option-row.selected .option-marker {
|
||||
border-color: var(--text);
|
||||
opacity: 1;
|
||||
}
|
||||
.option-row.selected .option-marker::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 3px;
|
||||
border-radius: inherit;
|
||||
background: var(--text);
|
||||
}
|
||||
.host-copy { min-width: 0; display: grid; grid-template-rows: 18px 16px; }
|
||||
.host-label { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 13px; font-weight: 560; }
|
||||
.host-path { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--muted); font-size: 12px; }
|
||||
.host-badges { display: inline-flex; gap: 4px; align-items: center; }
|
||||
.host-badge { color: var(--muted); font-size: 11px; }
|
||||
|
||||
.todo-instruction {
|
||||
margin-top: 8px;
|
||||
padding: 0 10px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
line-height: 1.35;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.empty-row {
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* 侧边栏:同一张完整侧边栏被裁切暴露。 */
|
||||
.sidebar-frame {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
width: var(--collapsed-width);
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: var(--panel-bg);
|
||||
border-right: 1px solid var(--border);
|
||||
transition: width var(--anim), background 160ms ease, border-color 160ms ease;
|
||||
will-change: width;
|
||||
}
|
||||
.sidebar-frame.open { width: var(--expanded-width); }
|
||||
.sidebar-content { width: var(--expanded-width); height: 100%; background: var(--panel-bg); display: flex; flex-direction: column; padding: 18px 8px 14px 6px; transition: background 160ms ease; }
|
||||
.sidebar-top { display: flex; flex-direction: column; gap: 2px; flex: 0 0 auto; }
|
||||
.sidebar-bottom { margin-top: 8px; flex: 0 0 auto; }
|
||||
|
||||
.side-row,
|
||||
.search-shell,
|
||||
.conversation-row { width: 100%; min-height: var(--row-height); border: 0; border-radius: var(--row-radius); background: transparent; color: var(--text); display: grid; grid-template-columns: var(--icon-cell) minmax(0, 1fr); align-items: center; padding: 0; text-align: left; }
|
||||
.side-row,
|
||||
.conversation-row { cursor: pointer; transition: background 140ms ease, color 140ms ease; }
|
||||
.side-row:hover,
|
||||
.conversation-row:hover { background: transparent; }
|
||||
.side-icon { width: var(--icon-cell); height: var(--row-height); border-radius: var(--row-radius); display: grid; place-items: center; color: currentColor; flex: 0 0 auto; transition: background 140ms ease; }
|
||||
.sidebar-frame:not(.open) .side-row:hover .side-icon,
|
||||
.sidebar-frame:not(.open) .theme-toggle:hover .side-icon { background: var(--hover); }
|
||||
.sidebar-frame.open .side-row:hover,
|
||||
.sidebar-frame.open .side-row.active,
|
||||
.sidebar-frame.open .conversation-row:hover,
|
||||
.sidebar-frame.open .conversation-row.menu-open { background: var(--hover); }
|
||||
|
||||
.side-label,
|
||||
.search-area,
|
||||
.conversation-list,
|
||||
.conversation-title,
|
||||
.conversation-more { opacity: 0; transition: opacity 220ms ease; transition-delay: 0ms; }
|
||||
.sidebar-frame.open .side-label,
|
||||
.sidebar-frame.open .search-area,
|
||||
.sidebar-frame.open .conversation-list,
|
||||
.sidebar-frame.open .conversation-title,
|
||||
.sidebar-frame.open .conversation-more { opacity: 1; transition-delay: 80ms; }
|
||||
.side-label { min-width: 0; padding-left: 8px; padding-right: 12px; font-size: 15px; line-height: 1; letter-spacing: -0.015em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
|
||||
.search-area { flex: 0 0 auto; margin-top: 10px; }
|
||||
.search-shell { height: var(--row-height); overflow: hidden; transition: background 140ms ease; }
|
||||
.search-shell:focus-within,
|
||||
.search-shell:hover { background: var(--hover); }
|
||||
.search-input { min-width: 0; width: calc(var(--expanded-width) - var(--icon-cell) - 22px); height: var(--row-height); border: 0; outline: 0; padding: 0 12px 0 8px; background: transparent; color: var(--text); font-size: 14px; letter-spacing: -0.01em; }
|
||||
.search-input::placeholder { color: var(--muted); }
|
||||
|
||||
.conversation-list { min-height: 0; flex: 1 1 auto; overflow-y: auto; padding-top: 12px; padding-right: 0; scrollbar-width: thin; }
|
||||
.conversation-row { position: relative; grid-template-columns: minmax(0, 1fr) 40px; min-height: var(--row-height); margin: 0; }
|
||||
.conversation-title { min-width: 0; padding-left: 12px; padding-right: 4px; color: var(--text); font-size: 14px; line-height: 1.25; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.conversation-more { width: 30px; height: 30px; border: 0; border-radius: 9px; background: transparent; color: var(--muted); display: grid; place-items: center; cursor: pointer; justify-self: start; visibility: hidden; transition: color 140ms ease, opacity 160ms ease; }
|
||||
.conversation-row:hover .conversation-more,
|
||||
.conversation-row.menu-open .conversation-more { visibility: visible; }
|
||||
.conversation-more:hover,
|
||||
.conversation-row.menu-open .conversation-more { background: transparent; color: var(--text); }
|
||||
.more-dots {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
.more-dots::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 10px;
|
||||
width: 3.5px;
|
||||
height: 3.5px;
|
||||
border-radius: 999px;
|
||||
background: currentColor;
|
||||
box-shadow: 5.5px 0 0 currentColor, 11px 0 0 currentColor;
|
||||
}
|
||||
|
||||
.floating-menu {
|
||||
position: fixed;
|
||||
z-index: 80;
|
||||
width: max-content;
|
||||
min-width: 92px;
|
||||
padding: 6px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 14px;
|
||||
background: var(--menu-bg);
|
||||
box-shadow: var(--menu-shadow);
|
||||
opacity: 0;
|
||||
transform: translateY(-4px) scale(0.98);
|
||||
pointer-events: none;
|
||||
transition: opacity 120ms ease, transform 150ms cubic-bezier(0.22, 1, 0.36, 1), background 160ms ease, border-color 160ms ease;
|
||||
}
|
||||
.floating-menu.open { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
|
||||
.menu-button { width: max-content; min-width: 80px; height: 36px; border: 0; border-radius: 10px; background: transparent; color: var(--text); display: grid; grid-template-columns: 24px auto; gap: 4px; align-items: center; padding: 0 10px 0 8px; text-align: left; cursor: pointer; font-size: 14px; letter-spacing: -0.01em; transition: background 140ms ease; }
|
||||
.menu-button:hover { background: var(--hover); }
|
||||
.menu-button.danger { color: #d6483b; }
|
||||
:root[data-theme="dark"] .menu-button.danger { color: #ff7b72; }
|
||||
|
||||
.demo-hint { position: fixed; left: calc(var(--expanded-width) + 20px); bottom: 18px; color: var(--muted); font-size: 13px; pointer-events: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="workspace-panel" aria-label="工作区">
|
||||
<h2 class="workspace-title" id="workspaceTitle">工作区</h2>
|
||||
<div class="workspace-controls">
|
||||
<button class="workspace-switch" id="workspaceSwitch" type="button" aria-haspopup="menu" aria-expanded="false">
|
||||
<span class="icon icon-folder-open" id="workspaceSwitchIcon" aria-hidden="true"></span>
|
||||
<span class="workspace-switch-label" id="workspaceSwitchLabel">工作区文件</span>
|
||||
<span class="chevron" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button class="workspace-manage" type="button" aria-label="管理工作区">
|
||||
<span class="icon icon-folder" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="workspace-body">
|
||||
<div class="workspace-view active" data-view="files">
|
||||
<div class="content-row file-row"><span class="file-arrow">▾</span><span class="icon icon-folder-open"></span><span class="content-main">static</span><span class="content-meta"></span></div>
|
||||
<div class="content-row file-row depth-1"><span class="file-arrow"></span><span class="icon icon-file"></span><span class="content-main">App.vue</span><span class="content-meta"></span></div>
|
||||
<div class="content-row file-row depth-1"><span class="file-arrow">▾</span><span class="icon icon-folder-open"></span><span class="content-main">components</span><span class="content-meta"></span></div>
|
||||
<div class="content-row file-row depth-2"><span class="file-arrow"></span><span class="icon icon-file"></span><span class="content-main">ConversationSidebar.vue</span><span class="content-meta"></span></div>
|
||||
<div class="content-row file-row depth-2"><span class="file-arrow"></span><span class="icon icon-file"></span><span class="content-main">LeftPanel.vue</span><span class="content-meta"></span></div>
|
||||
<div class="content-row file-row"><span class="file-arrow">▸</span><span class="icon icon-folder"></span><span class="content-main">server</span><span class="content-meta"></span></div>
|
||||
<div class="content-row file-row"><span class="file-arrow"></span><span class="icon icon-file"></span><span class="content-main">main.py</span><span class="content-meta"></span></div>
|
||||
</div>
|
||||
|
||||
<div class="workspace-view" data-view="host">
|
||||
<div class="content-row option-row selected"><span class="option-marker" aria-hidden="true"></span><span class="host-copy"><span class="host-label">agents</span><span class="host-path">/Users/jojo/Desktop/agents/正在修复中/agents</span></span><span class="host-badges"><span class="host-badge">默认</span><span class="host-badge">当前</span></span></div>
|
||||
<div class="content-row option-row"><span class="option-marker" aria-hidden="true"></span><span class="host-copy"><span class="host-label">前端工作区</span><span class="host-path">/Users/jojo/Desktop/frontend</span></span><span class="host-badges"></span></div>
|
||||
<div class="content-row option-row"><span class="option-marker" aria-hidden="true"></span><span class="host-copy"><span class="host-label">未配置路径</span><span class="host-path">(未配置路径)</span></span><span class="host-badges"></span></div>
|
||||
</div>
|
||||
|
||||
<div class="workspace-view" data-view="agents">
|
||||
<div class="content-row plain-row"><span class="content-main">#1 正在整理侧边栏与工作区样式</span><span class="content-meta">running</span></div>
|
||||
<div class="content-row plain-row"><span class="content-main">#2 等待下一轮验证</span><span class="content-meta">idle</span></div>
|
||||
<div class="content-row plain-row"><span class="content-main">当前:read_file</span><span class="content-meta"></span></div>
|
||||
</div>
|
||||
|
||||
<div class="workspace-view" data-view="commands">
|
||||
<div class="content-row plain-row"><span class="content-main">npm --prefix cli run typecheck</span><span class="content-meta">completed</span></div>
|
||||
<div class="content-row plain-row"><span class="content-main">python -m unittest test.test_server_refactor_smoke</span><span class="content-meta">running</span></div>
|
||||
<div class="content-row plain-row"><span class="content-main">状态码:--</span><span class="content-meta"></span></div>
|
||||
</div>
|
||||
|
||||
<div class="workspace-view" data-view="todos">
|
||||
<div class="content-row plain-row"><span class="content-main">task1:确定侧边栏动画模型</span><span class="content-meta">完成</span></div>
|
||||
<div class="content-row plain-row"><span class="content-main">task2:工作区视觉改造</span><span class="content-meta">未完成</span></div>
|
||||
<div class="content-row plain-row"><span class="content-main">task3:代码块精致化</span><span class="content-meta">未完成</span></div>
|
||||
<div class="todo-instruction">指令:按真实数据结构设计显示区域,不添加额外说明卡片。</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<aside class="sidebar-frame" id="sidebar" aria-label="对话侧边栏">
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-top">
|
||||
<button class="side-row" id="toggleSidebar" type="button" aria-label="展开对话记录" aria-expanded="false">
|
||||
<span class="side-icon"><span class="icon icon-chat" aria-hidden="true"></span></span>
|
||||
<span class="side-label">对话记录</span>
|
||||
</button>
|
||||
<button class="side-row" type="button" aria-label="新建对话"><span class="side-icon"><span class="icon icon-pencil"></span></span><span class="side-label">新建对话</span></button>
|
||||
<button class="side-row" type="button" aria-label="工作区"><span class="side-icon"><span class="icon icon-layers"></span></span><span class="side-label">工作区</span></button>
|
||||
<button class="side-row" type="button" aria-label="虚拟显示器"><span class="side-icon"><span class="icon icon-monitor"></span></span><span class="side-label">虚拟显示器</span></button>
|
||||
</div>
|
||||
|
||||
<div class="search-area" aria-label="搜索对话"><label class="search-shell"><span class="side-icon"><span class="icon icon-search"></span></span><input class="search-input" type="search" placeholder="搜索对话" /></label></div>
|
||||
|
||||
<div class="conversation-list" aria-label="对话记录">
|
||||
<div class="conversation-row"><span class="conversation-title">随意的 py 代码块</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
|
||||
<div class="conversation-row"><span class="conversation-title">前端现代化设计讨论</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
|
||||
<div class="conversation-row"><span class="conversation-title">审批面板覆盖窗口方案</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
|
||||
<div class="conversation-row"><span class="conversation-title">CLI 显示层细节修复</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
|
||||
<div class="conversation-row"><span class="conversation-title">个人空间设置页重设计</span><button class="conversation-more" type="button" aria-label="更多操作"><span class="more-dots" aria-hidden="true"></span></button></div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-bottom">
|
||||
<button class="side-row theme-toggle" id="themeToggle" type="button" aria-label="切换深色模式"><span class="side-icon"><span class="icon icon-sun"></span></span><span class="side-label">浅色模式</span></button>
|
||||
<button class="side-row" type="button" aria-label="个人空间"><span class="side-icon"><span class="icon icon-user"></span></span><span class="side-label">个人空间</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="main"><h1 class="main-title">AI Agent <span>Auto</span></h1></main>
|
||||
|
||||
<div class="floating-menu" id="conversationMenu" role="menu" aria-hidden="true">
|
||||
<button class="menu-button" type="button" role="menuitem"><span class="icon icon-copy"></span><span>复制</span></button>
|
||||
<button class="menu-button danger" type="button" role="menuitem"><span class="icon icon-trash"></span><span>删除</span></button>
|
||||
</div>
|
||||
|
||||
<div class="floating-menu" id="workspaceMenu" role="menu" aria-hidden="true">
|
||||
<button class="menu-button" type="button" data-view-target="files"><span class="icon icon-folder-open"></span><span>工作区文件</span></button>
|
||||
<button class="menu-button" type="button" data-view-target="host"><span class="icon icon-laptop"></span><span>宿主机工作区</span></button>
|
||||
<button class="menu-button" type="button" data-view-target="agents"><span class="icon icon-bot"></span><span>子智能体</span></button>
|
||||
<button class="menu-button" type="button" data-view-target="commands"><span class="icon icon-terminal"></span><span>后台指令</span></button>
|
||||
<button class="menu-button" type="button" data-view-target="todos"><span class="icon icon-sticky"></span><span>待办事项</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-hint">工作区为扁平窄面板;展开侧边栏会完整盖住工作区。</div>
|
||||
|
||||
<script>
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const toggle = document.getElementById('toggleSidebar');
|
||||
const themeToggle = document.getElementById('themeToggle');
|
||||
const conversationMenu = document.getElementById('conversationMenu');
|
||||
const workspaceMenu = document.getElementById('workspaceMenu');
|
||||
const workspaceSwitch = document.getElementById('workspaceSwitch');
|
||||
const workspaceTitle = document.getElementById('workspaceTitle');
|
||||
const workspaceSwitchLabel = document.getElementById('workspaceSwitchLabel');
|
||||
const workspaceSwitchIcon = document.getElementById('workspaceSwitchIcon');
|
||||
let conversationOwner = null;
|
||||
|
||||
const viewMeta = {
|
||||
files: { title: '工作区', label: '工作区文件', icon: 'icon-folder-open' },
|
||||
host: { title: '宿主机工作区', label: '宿主机工作区', icon: 'icon-laptop' },
|
||||
agents: { title: '子智能体', label: '子智能体', icon: 'icon-bot' },
|
||||
commands: { title: '后台指令', label: '后台指令', icon: 'icon-terminal' },
|
||||
todos: { title: '待办事项', label: '待办事项', icon: 'icon-sticky' }
|
||||
};
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
const isOpen = sidebar.classList.toggle('open');
|
||||
toggle.setAttribute('aria-expanded', String(isOpen));
|
||||
toggle.setAttribute('aria-label', isOpen ? '收起对话记录' : '展开对话记录');
|
||||
if (!isOpen) closeConversationMenu();
|
||||
});
|
||||
|
||||
themeToggle.addEventListener('click', () => {
|
||||
const root = document.documentElement;
|
||||
const next = root.dataset.theme === 'dark' ? 'light' : 'dark';
|
||||
root.dataset.theme = next;
|
||||
themeToggle.querySelector('.side-label').textContent = next === 'dark' ? '深色模式' : '浅色模式';
|
||||
});
|
||||
|
||||
function positionMenu(menu, anchor) {
|
||||
const rect = anchor.getBoundingClientRect();
|
||||
menu.style.left = '0px';
|
||||
menu.style.top = `${rect.bottom + 6}px`;
|
||||
menu.classList.add('open');
|
||||
menu.setAttribute('aria-hidden', 'false');
|
||||
const width = menu.offsetWidth;
|
||||
menu.style.left = `${Math.min(rect.right - width, window.innerWidth - width - 12)}px`;
|
||||
}
|
||||
|
||||
function closeConversationMenu() {
|
||||
conversationMenu.classList.remove('open');
|
||||
conversationMenu.setAttribute('aria-hidden', 'true');
|
||||
if (conversationOwner) conversationOwner.classList.remove('menu-open');
|
||||
conversationOwner = null;
|
||||
}
|
||||
|
||||
function closeWorkspaceMenu() {
|
||||
workspaceMenu.classList.remove('open');
|
||||
workspaceMenu.setAttribute('aria-hidden', 'true');
|
||||
workspaceSwitch.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
|
||||
document.querySelectorAll('.conversation-more').forEach((button) => {
|
||||
button.addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
closeWorkspaceMenu();
|
||||
const row = button.closest('.conversation-row');
|
||||
if (conversationOwner === row && conversationMenu.classList.contains('open')) {
|
||||
closeConversationMenu();
|
||||
return;
|
||||
}
|
||||
closeConversationMenu();
|
||||
conversationOwner = row;
|
||||
row.classList.add('menu-open');
|
||||
positionMenu(conversationMenu, button);
|
||||
});
|
||||
});
|
||||
|
||||
workspaceSwitch.addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
closeConversationMenu();
|
||||
if (workspaceMenu.classList.contains('open')) {
|
||||
closeWorkspaceMenu();
|
||||
} else {
|
||||
workspaceSwitch.setAttribute('aria-expanded', 'true');
|
||||
positionMenu(workspaceMenu, workspaceSwitch);
|
||||
}
|
||||
});
|
||||
|
||||
workspaceMenu.querySelectorAll('[data-view-target]').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
const view = button.dataset.viewTarget;
|
||||
document.querySelectorAll('.workspace-view').forEach((node) => node.classList.toggle('active', node.dataset.view === view));
|
||||
const meta = viewMeta[view];
|
||||
workspaceTitle.textContent = meta.title;
|
||||
workspaceSwitchLabel.textContent = meta.label;
|
||||
workspaceSwitchIcon.className = `icon ${meta.icon}`;
|
||||
closeWorkspaceMenu();
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
if (!conversationMenu.contains(event.target)) closeConversationMenu();
|
||||
if (!workspaceMenu.contains(event.target) && !workspaceSwitch.contains(event.target)) closeWorkspaceMenu();
|
||||
});
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
closeConversationMenu();
|
||||
closeWorkspaceMenu();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -226,7 +226,10 @@
|
||||
>
|
||||
默认工作区
|
||||
</span>
|
||||
<span v-if="item.workspace_id === hostWorkspaceId" class="host-workspace-badge current">
|
||||
<span
|
||||
v-if="item.workspace_id === hostWorkspaceId"
|
||||
class="host-workspace-badge current"
|
||||
>
|
||||
当前
|
||||
</span>
|
||||
</span>
|
||||
@ -237,7 +240,9 @@
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="file-tree-empty">暂无工作区,点击右侧 + 新建</div>
|
||||
<div class="host-workspace-hint" v-if="hostWorkspaceSwitching">正在切换,请稍候…</div>
|
||||
<div class="host-workspace-hint" v-if="hostWorkspaceSwitching">
|
||||
正在切换,请稍候…
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="file-tree-empty">{{ fileTreeMessage }}</div>
|
||||
</template>
|
||||
|
||||
@ -1,49 +1,43 @@
|
||||
<template>
|
||||
<aside class="conversation-sidebar" :class="{ collapsed, 'monitor-mode': monitorModeActive }">
|
||||
<div class="conversation-header" :class="{ 'collapsed-layout': collapsed }">
|
||||
<template v-if="collapsed">
|
||||
<div class="collapsed-header-buttons">
|
||||
<div class="conversation-sidebar-inner">
|
||||
<div class="conversation-primary-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="collapsed-control-btn conversation-menu-btn"
|
||||
title="展开对话记录"
|
||||
class="sidebar-nav-row conversation-menu-btn"
|
||||
:title="collapsed ? '展开对话记录' : '收起对话记录'"
|
||||
@click="$emit('toggle')"
|
||||
>
|
||||
<span class="sr-only">展开对话记录</span>
|
||||
<span class="chat-icon" data-tutorial="conversation-menu" aria-hidden="true">
|
||||
<slot name="collapsed-chat-icon">
|
||||
<span
|
||||
class="sidebar-nav-icon chat-icon"
|
||||
data-tutorial="conversation-menu"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<svg viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5 6.5c0-1.38 1.12-2.5 2.5-2.5h13c1.38 0 2.5 1.12 2.5 2.5v8.5c0 1.38-1.12 2.5-2.5 2.5h-5.6l-3.4 3.2.6-3.2H7.5c-1.38 0-2.5-1.12-2.5-2.5V6.5z"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-width="1.45"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9 9.5h10"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M9 13h6"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.7"
|
||||
stroke-width="1.45"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path d="M9 13h6" stroke="currentColor" stroke-width="1.45" stroke-linecap="round" />
|
||||
</svg>
|
||||
</slot>
|
||||
</span>
|
||||
<span class="sidebar-nav-label">对话记录</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="collapsed-control-btn quick-plus-btn"
|
||||
title="快捷新建对话"
|
||||
@click="$emit('create')"
|
||||
|
||||
<button type="button" class="sidebar-nav-row" title="新建对话" @click="$emit('create')">
|
||||
<span
|
||||
class="sidebar-nav-icon pencil-icon"
|
||||
data-tutorial="quick-new-conversation"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span class="sr-only">新建对话</span>
|
||||
<span class="pencil-icon" data-tutorial="quick-new-conversation" aria-hidden="true">
|
||||
<slot name="collapsed-create-icon">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
@ -51,131 +45,62 @@
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.8"
|
||||
stroke-width="1.6"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
|
||||
fill="none"
|
||||
/>
|
||||
<path d="m15 5 4 4" fill="none" />
|
||||
<path d="m15 5 4 4" />
|
||||
</svg>
|
||||
</slot>
|
||||
</span>
|
||||
<span class="sidebar-nav-label">新建对话</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="collapsed-control-btn workspace-control-btn"
|
||||
class="sidebar-nav-row workspace-control-btn"
|
||||
:class="{ active: workspaceCollapsed }"
|
||||
:title="workspaceCollapsed ? '显示工作区' : '隐藏工作区'"
|
||||
@click="$emit('toggle-workspace')"
|
||||
>
|
||||
<span class="sr-only">{{ workspaceCollapsed ? '显示工作区' : '隐藏工作区' }}</span>
|
||||
<span
|
||||
class="icon icon-md"
|
||||
data-tutorial="workspace-toggle"
|
||||
aria-hidden="true"
|
||||
:style="iconStyle('layers')"
|
||||
></span>
|
||||
<span class="sidebar-nav-icon" data-tutorial="workspace-toggle" aria-hidden="true">
|
||||
<span class="icon icon-md" :style="iconStyle('layers')"></span>
|
||||
</span>
|
||||
<span class="sidebar-nav-label">工作区</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="collapsed-control-btn monitor-mode-btn"
|
||||
class="sidebar-nav-row monitor-mode-btn"
|
||||
:class="{ active: displayMode === 'monitor', blocked: displayModeDisabled }"
|
||||
@click="$emit('toggle-display-mode')"
|
||||
:aria-disabled="displayModeDisabled"
|
||||
:title="displayMode === 'monitor' ? '退出显示器' : '虚拟显示器'"
|
||||
@click="$emit('toggle-display-mode')"
|
||||
>
|
||||
<span class="sr-only">{{
|
||||
displayMode === 'monitor' ? '退出显示器' : '虚拟显示器'
|
||||
}}</span>
|
||||
<span
|
||||
class="icon icon-md"
|
||||
data-tutorial="monitor-toggle"
|
||||
aria-hidden="true"
|
||||
:style="iconStyle('monitor')"
|
||||
></span>
|
||||
<span class="sidebar-nav-icon" data-tutorial="monitor-toggle" aria-hidden="true">
|
||||
<span class="icon icon-md" :style="iconStyle('monitor')"></span>
|
||||
</span>
|
||||
<span class="sidebar-nav-label">虚拟显示器</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button
|
||||
class="new-conversation-btn"
|
||||
:class="{ 'icon-only': monitorModeActive }"
|
||||
:title="monitorModeActive ? '新建对话' : undefined"
|
||||
@click="$emit('create')"
|
||||
>
|
||||
<template v-if="monitorModeActive">
|
||||
<span
|
||||
class="monitor-icon-slot icon icon-md"
|
||||
:style="iconStyle('pencil')"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span class="sr-only">新建对话</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="btn-icon">+</span>
|
||||
<span class="btn-text">新建对话</span>
|
||||
</template>
|
||||
</button>
|
||||
<button
|
||||
v-if="resolvedShowCollapseButton"
|
||||
class="toggle-sidebar-btn"
|
||||
data-tutorial="conversation-collapse"
|
||||
:class="{ 'icon-only': monitorModeActive }"
|
||||
:title="monitorModeActive ? (collapsed ? '展开对话记录' : '折叠对话记录') : undefined"
|
||||
@click="$emit('toggle')"
|
||||
>
|
||||
<template v-if="resolvedCollapseButtonVariant === 'toggle'">
|
||||
<template v-if="monitorModeActive">
|
||||
<span
|
||||
class="monitor-icon-slot icon icon-md"
|
||||
:style="iconStyle(collapsed ? 'menu' : 'x')"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span class="sr-only">{{ collapsed ? '展开对话记录' : '折叠对话记录' }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span
|
||||
v-if="collapsed"
|
||||
class="icon icon-md"
|
||||
:style="iconStyle('menu')"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span v-else class="toggle-arrow" aria-hidden="true">←</span>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="monitorModeActive">
|
||||
<span
|
||||
class="monitor-icon-slot icon icon-md"
|
||||
:style="iconStyle('x')"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span class="sr-only">关闭侧边栏</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="toggle-close" aria-hidden="true">×</span>
|
||||
</template>
|
||||
</template>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template v-if="!collapsed">
|
||||
<div class="conversation-search">
|
||||
<div class="search-input-wrap">
|
||||
<label class="search-input-wrap">
|
||||
<span class="sidebar-nav-icon search-inline-icon" aria-hidden="true">
|
||||
<span class="icon icon-sm" :style="iconStyle('search')"></span>
|
||||
</span>
|
||||
<input
|
||||
class="search-input"
|
||||
:value="searchQuery"
|
||||
placeholder="搜索对话..."
|
||||
placeholder="搜索对话"
|
||||
@input="$emit('search', ($event.target as HTMLInputElement).value)"
|
||||
@keydown.enter.prevent="
|
||||
$emit('search-submit', ($event.target as HTMLInputElement).value)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="conversation-list">
|
||||
@ -194,33 +119,53 @@
|
||||
:key="conv.id"
|
||||
class="conversation-item"
|
||||
:class="{ active: conv.id === currentConversationId }"
|
||||
@click="$emit('select', conv.id)"
|
||||
@click="
|
||||
openActionMenuId = null;
|
||||
$emit('select', conv.id);
|
||||
"
|
||||
>
|
||||
<div class="conversation-title">{{ conv.title }}</div>
|
||||
<div class="conversation-meta">
|
||||
<span class="conversation-time">{{ formatTime(conv.updated_at) }}</span>
|
||||
<span class="conversation-counts">
|
||||
{{ conv.total_messages || 0 }}条消息
|
||||
<span v-if="(conv.total_tools || 0) > 0"> · {{ conv.total_tools }}工具</span>
|
||||
</span>
|
||||
<div
|
||||
class="conversation-action-wrap"
|
||||
:class="{ 'menu-open': openActionMenuId === conv.id }"
|
||||
@click.stop
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="conversation-more-btn"
|
||||
title="更多操作"
|
||||
aria-label="更多操作"
|
||||
:aria-expanded="openActionMenuId === conv.id"
|
||||
@click="toggleActionMenu(conv.id)"
|
||||
>
|
||||
<span aria-hidden="true"></span>
|
||||
</button>
|
||||
<div
|
||||
class="conversation-actions-menu"
|
||||
:class="{ open: openActionMenuId === conv.id }"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
@click="
|
||||
openActionMenuId = null;
|
||||
$emit('duplicate', conv.id);
|
||||
"
|
||||
>
|
||||
<span class="icon icon-sm" :style="iconStyle('copy')" aria-hidden="true"></span>
|
||||
<span>复制</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="danger"
|
||||
@click="
|
||||
openActionMenuId = null;
|
||||
$emit('delete', conv.id);
|
||||
"
|
||||
>
|
||||
<span class="icon icon-sm" :style="iconStyle('trash')" aria-hidden="true"></span>
|
||||
<span>删除</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="conversation-actions" @click.stop>
|
||||
<button
|
||||
type="button"
|
||||
class="conversation-action-btn delete-btn"
|
||||
title="删除对话"
|
||||
@click="$emit('delete', conv.id)"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="conversation-action-btn copy-btn"
|
||||
title="复制对话"
|
||||
@click="$emit('duplicate', conv.id)"
|
||||
>
|
||||
⧉
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -254,43 +199,35 @@
|
||||
<div v-else-if="displayConversations.length" class="search-done">已全部搜索</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="conversation-collapsed-spacer"></div>
|
||||
</template>
|
||||
|
||||
<div class="conversation-personal-entry" :class="{ collapsed, active: personalPageVisible }">
|
||||
<div class="conversation-personal-entry" :class="{ active: personalPageVisible }">
|
||||
<button
|
||||
type="button"
|
||||
class="personal-page-btn"
|
||||
class="sidebar-nav-row personal-page-btn"
|
||||
data-tutorial="open-personal-space"
|
||||
:class="{ 'icon-only': collapsed }"
|
||||
title="个人页面"
|
||||
title="个人空间"
|
||||
@click="$emit('personal')"
|
||||
>
|
||||
<span class="sr-only">个人页面</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span class="sidebar-nav-icon" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="personal-label" v-if="!collapsed">个人空间</span>
|
||||
</span>
|
||||
<span class="sidebar-nav-label personal-label">个人空间</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({ name: 'ConversationSidebar' });
|
||||
|
||||
import { computed } from 'vue';
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useUiStore } from '@/stores/ui';
|
||||
import { useConversationStore } from '@/stores/conversation';
|
||||
@ -325,6 +262,7 @@ defineEmits<{
|
||||
(event: 'delete', id: string): void;
|
||||
(event: 'duplicate', id: string): void;
|
||||
(event: 'toggle-workspace'): void;
|
||||
(event: 'toggle-display-mode'): void;
|
||||
}>();
|
||||
|
||||
const uiStore = useUiStore();
|
||||
@ -350,15 +288,30 @@ const {
|
||||
} = storeToRefs(conversationStore);
|
||||
const { visible: personalPageVisible } = storeToRefs(personalizationStore);
|
||||
|
||||
const formatTime = (value: unknown) => (props.formatTime ? props.formatTime(value) : String(value));
|
||||
const iconStyle = (key: string) => (props.iconStyle ? props.iconStyle(key) : {});
|
||||
const resolvedShowCollapseButton = computed(() => props.showCollapseButton);
|
||||
const resolvedCollapseButtonVariant = computed(() => props.collapseButtonVariant);
|
||||
const displayMode = computed(() => props.displayMode);
|
||||
const monitorModeActive = computed(
|
||||
() => displayMode.value === 'monitor' || uiChatDisplayMode.value === 'monitor'
|
||||
);
|
||||
const displayModeDisabled = computed(() => props.displayModeDisabled);
|
||||
const openActionMenuId = ref<string | null>(null);
|
||||
|
||||
const toggleActionMenu = (conversationId: string) => {
|
||||
openActionMenuId.value = openActionMenuId.value === conversationId ? null : conversationId;
|
||||
};
|
||||
|
||||
const closeActionMenu = () => {
|
||||
openActionMenuId.value = null;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', closeActionMenu);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', closeActionMenu);
|
||||
});
|
||||
|
||||
const displayConversations = computed(() =>
|
||||
searchActive.value ? searchResults.value : conversations.value
|
||||
);
|
||||
|
||||
@ -41,8 +41,18 @@
|
||||
bottom: -8px;
|
||||
height: 16px;
|
||||
background: var(--chat-surface-color);
|
||||
mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.6) 55%, rgba(0, 0, 0, 0) 100%);
|
||||
-webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.6) 55%, rgba(0, 0, 0, 0) 100%);
|
||||
mask-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 1) 0%,
|
||||
rgba(0, 0, 0, 0.6) 55%,
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
-webkit-mask-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 1) 0%,
|
||||
rgba(0, 0, 0, 0.6) 55%,
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
backdrop-filter: blur(14px);
|
||||
-webkit-backdrop-filter: blur(14px);
|
||||
pointer-events: none;
|
||||
@ -53,7 +63,7 @@
|
||||
font-size: 15px;
|
||||
line-height: 1.4;
|
||||
letter-spacing: 0.02em;
|
||||
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
|
||||
max-width: 60%;
|
||||
color: #0f172a;
|
||||
text-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
|
||||
@ -132,7 +142,9 @@
|
||||
|
||||
.scroll-to-bottom-fade-enter-active,
|
||||
.scroll-to-bottom-fade-leave-active {
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
transition:
|
||||
opacity 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
}
|
||||
|
||||
.scroll-to-bottom-fade-enter-from,
|
||||
@ -180,7 +192,6 @@
|
||||
.assistant-message .message-text {
|
||||
padding: 16px 8px !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 额外的手机端样式,不依赖 mobile 类 */
|
||||
@ -205,7 +216,7 @@
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
line-height: 1.35;
|
||||
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
|
||||
cursor: pointer;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
@ -364,7 +375,9 @@
|
||||
|
||||
.header-menu-enter-active,
|
||||
.header-menu-leave-active {
|
||||
transition: all 0.16s ease, opacity 0.16s ease;
|
||||
transition:
|
||||
all 0.16s ease,
|
||||
opacity 0.16s ease;
|
||||
transform-origin: top left;
|
||||
}
|
||||
|
||||
@ -1010,7 +1023,10 @@ body[data-theme='dark'] .more-icon {
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
transition: color 0.18s ease, border-color 0.18s ease, background 0.18s ease;
|
||||
transition:
|
||||
color 0.18s ease,
|
||||
border-color 0.18s ease,
|
||||
background 0.18s ease;
|
||||
}
|
||||
|
||||
.chat-inline-card__refresh-btn:hover {
|
||||
@ -1054,12 +1070,16 @@ body[data-theme='dark'] .more-icon {
|
||||
}
|
||||
|
||||
/* 兼容旧类名(可逐步移除) */
|
||||
.chat-inline-image__error { @extend .chat-inline-card__error; }
|
||||
.chat-inline-image figcaption { @extend .chat-inline-card__caption; }
|
||||
.chat-inline-image__error {
|
||||
@extend .chat-inline-card__error;
|
||||
}
|
||||
.chat-inline-image figcaption {
|
||||
@extend .chat-inline-card__caption;
|
||||
}
|
||||
|
||||
/* show_html 在 streaming 重建期间会短暂回到原始标签,需提供稳定占位避免 scrollHeight 抖动 */
|
||||
show_html:not([data-rendered="1"]),
|
||||
show-html:not([data-rendered="1"]) {
|
||||
show_html:not([data-rendered='1']),
|
||||
show-html:not([data-rendered='1']) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
@ -1073,16 +1093,26 @@ show-html:not([data-rendered="1"]) {
|
||||
box-shadow: var(--claude-shadow);
|
||||
}
|
||||
|
||||
show_html:not([data-rendered="1"])[ratio="1:1"],
|
||||
show-html:not([data-rendered="1"])[ratio="1:1"] { aspect-ratio: 1 / 1; }
|
||||
show_html:not([data-rendered="1"])[ratio="16:9"],
|
||||
show-html:not([data-rendered="1"])[ratio="16:9"] { aspect-ratio: 16 / 9; }
|
||||
show_html:not([data-rendered="1"])[ratio="9:16"],
|
||||
show-html:not([data-rendered="1"])[ratio="9:16"] { aspect-ratio: 9 / 16; }
|
||||
show_html:not([data-rendered="1"])[ratio="4:3"],
|
||||
show-html:not([data-rendered="1"])[ratio="4:3"] { aspect-ratio: 4 / 3; }
|
||||
show_html:not([data-rendered="1"])[ratio="3:4"],
|
||||
show-html:not([data-rendered="1"])[ratio="3:4"] { aspect-ratio: 3 / 4; }
|
||||
show_html:not([data-rendered='1'])[ratio='1:1'],
|
||||
show-html:not([data-rendered='1'])[ratio='1:1'] {
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
show_html:not([data-rendered='1'])[ratio='16:9'],
|
||||
show-html:not([data-rendered='1'])[ratio='16:9'] {
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
show_html:not([data-rendered='1'])[ratio='9:16'],
|
||||
show-html:not([data-rendered='1'])[ratio='9:16'] {
|
||||
aspect-ratio: 9 / 16;
|
||||
}
|
||||
show_html:not([data-rendered='1'])[ratio='4:3'],
|
||||
show-html:not([data-rendered='1'])[ratio='4:3'] {
|
||||
aspect-ratio: 4 / 3;
|
||||
}
|
||||
show_html:not([data-rendered='1'])[ratio='3:4'],
|
||||
show-html:not([data-rendered='1'])[ratio='3:4'] {
|
||||
aspect-ratio: 3 / 4;
|
||||
}
|
||||
|
||||
.text-output .text-content {
|
||||
padding: 0 20px 0 15px;
|
||||
@ -1092,9 +1122,13 @@ show-html:not([data-rendered="1"])[ratio="3:4"] { aspect-ratio: 3 / 4; }
|
||||
}
|
||||
|
||||
.text-output pre {
|
||||
font-family: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', 'Menlo', 'Monaco', 'Courier New', monospace !important;
|
||||
font-family:
|
||||
'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', 'Menlo', 'Monaco', 'Courier New',
|
||||
monospace !important;
|
||||
font-variant-ligatures: none;
|
||||
font-feature-settings: 'liga' 0, 'calt' 0;
|
||||
font-feature-settings:
|
||||
'liga' 0,
|
||||
'calt' 0;
|
||||
line-height: 1.55;
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
@ -1103,9 +1137,13 @@ show-html:not([data-rendered="1"])[ratio="3:4"] { aspect-ratio: 3 / 4; }
|
||||
}
|
||||
|
||||
.text-output pre code {
|
||||
font-family: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', 'Menlo', 'Monaco', 'Courier New', monospace !important;
|
||||
font-family:
|
||||
'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', 'Menlo', 'Monaco', 'Courier New',
|
||||
monospace !important;
|
||||
font-variant-ligatures: none;
|
||||
font-feature-settings: 'liga' 0, 'calt' 0;
|
||||
font-feature-settings:
|
||||
'liga' 0,
|
||||
'calt' 0;
|
||||
line-height: 1.55;
|
||||
text-shadow: none;
|
||||
animation: none !important; /* 防止外部动画样式影响代码块,导致视觉抖动 */
|
||||
@ -1241,17 +1279,19 @@ show-html:not([data-rendered="1"])[ratio="3:4"] { aspect-ratio: 3 / 4; }
|
||||
}
|
||||
|
||||
.code-block-wrapper {
|
||||
border: 2px solid var(--claude-border);
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--claude-border);
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
margin: 16px 0;
|
||||
background: var(--theme-surface-soft);
|
||||
background: var(--theme-surface-strong, #ffffff);
|
||||
min-height: 80px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.code-block-header {
|
||||
background: var(--theme-chip-bg);
|
||||
padding: 10px 16px;
|
||||
min-height: 44px;
|
||||
background: var(--theme-surface-strong, #ffffff);
|
||||
padding: 0 12px 0 18px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
@ -1260,8 +1300,10 @@ show-html:not([data-rendered="1"])[ratio="3:4"] { aspect-ratio: 3 / 4; }
|
||||
|
||||
.code-language {
|
||||
color: var(--claude-text-secondary);
|
||||
font-size: 13px;
|
||||
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.01em;
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@ -1270,34 +1312,53 @@ show-html:not([data-rendered="1"])[ratio="3:4"] { aspect-ratio: 3 / 4; }
|
||||
height: 32px;
|
||||
border: none;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
border-radius: 10px;
|
||||
background-color: transparent;
|
||||
background-image: url('/static/icons/copy.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 20px;
|
||||
color: var(--claude-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
opacity: 0.9;
|
||||
transition:
|
||||
background-color 140ms ease,
|
||||
color 140ms ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copy-code-btn::before {
|
||||
content: '';
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
background: currentColor;
|
||||
mask: url('/static/icons/copy.svg') center / contain no-repeat;
|
||||
-webkit-mask: url('/static/icons/copy.svg') center / contain no-repeat;
|
||||
}
|
||||
|
||||
.copy-code-btn:hover {
|
||||
opacity: 0.7;
|
||||
background-color: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
|
||||
color: var(--claude-text);
|
||||
}
|
||||
|
||||
.copy-code-btn.copied {
|
||||
background-image: url('/static/icons/check.svg');
|
||||
.copy-code-btn.copied::before {
|
||||
mask-image: url('/static/icons/check.svg');
|
||||
-webkit-mask-image: url('/static/icons/check.svg');
|
||||
}
|
||||
|
||||
.code-block-wrapper pre {
|
||||
background: #ffffff !important;
|
||||
padding: 16px !important;
|
||||
background: var(--theme-surface-strong, #ffffff) !important;
|
||||
padding: 24px 28px 28px !important;
|
||||
margin: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
border: none !important;
|
||||
font-family: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', 'Menlo', 'Monaco', 'Courier New', monospace !important;
|
||||
font-family:
|
||||
'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', 'Menlo', 'Monaco', 'Courier New',
|
||||
monospace !important;
|
||||
font-variant-ligatures: none;
|
||||
font-feature-settings: 'liga' 0, 'calt' 0;
|
||||
line-height: 1.55;
|
||||
font-feature-settings:
|
||||
'liga' 0,
|
||||
'calt' 0;
|
||||
font-size: 15px;
|
||||
line-height: 1.64;
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
scrollbar-gutter: stable;
|
||||
@ -1307,11 +1368,15 @@ show-html:not([data-rendered="1"])[ratio="3:4"] { aspect-ratio: 3 / 4; }
|
||||
.code-block-wrapper pre code {
|
||||
background: transparent !important;
|
||||
padding: 0 !important;
|
||||
color: #000000;
|
||||
font-family: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', 'Menlo', 'Monaco', 'Courier New', monospace !important;
|
||||
color: var(--claude-text);
|
||||
font-family:
|
||||
'JetBrains Mono', 'SF Mono', 'Fira Code', 'Consolas', 'Menlo', 'Monaco', 'Courier New',
|
||||
monospace !important;
|
||||
font-variant-ligatures: none;
|
||||
font-feature-settings: 'liga' 0, 'calt' 0;
|
||||
line-height: 1.55;
|
||||
font-feature-settings:
|
||||
'liga' 0,
|
||||
'calt' 0;
|
||||
line-height: 1.64;
|
||||
text-shadow: none;
|
||||
animation: none !important; /* 避免被其他动画样式污染导致行距抖动 */
|
||||
}
|
||||
@ -1326,6 +1391,11 @@ show-html:not([data-rendered="1"])[ratio="3:4"] { aspect-ratio: 3 / 4; }
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0; }
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
justify-content: center;
|
||||
z-index: 400;
|
||||
padding: 20px;
|
||||
transition: opacity 0.25s ease, backdrop-filter 0.25s ease;
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
backdrop-filter 0.25s ease;
|
||||
will-change: opacity, backdrop-filter;
|
||||
}
|
||||
|
||||
@ -64,7 +66,9 @@
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 14px 28px rgba(189, 93, 58, 0.2);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
transition:
|
||||
transform 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.personal-page-close:hover {
|
||||
@ -82,7 +86,9 @@
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease, box-shadow 0.2s ease;
|
||||
transition:
|
||||
background 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.personal-page-logout:hover {
|
||||
@ -147,7 +153,7 @@
|
||||
}
|
||||
|
||||
.switch-slider::before {
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 4px;
|
||||
@ -179,7 +185,10 @@
|
||||
border: 1px solid var(--theme-control-border);
|
||||
background: var(--theme-surface-muted);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
box-shadow 0.2s ease,
|
||||
background 0.2s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@ -224,7 +233,10 @@
|
||||
stroke-width: 5;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
transition: stroke-dasharray 0.5s ease, stroke-dashoffset 0.5s ease, stroke 0.2s ease;
|
||||
transition:
|
||||
stroke-dasharray 0.5s ease,
|
||||
stroke-dashoffset 0.5s ease,
|
||||
stroke 0.2s ease;
|
||||
stroke-dasharray: 241 9999999;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
@ -286,7 +298,10 @@
|
||||
background: transparent;
|
||||
color: var(--claude-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
|
||||
transition:
|
||||
background 0.2s ease,
|
||||
color 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.personal-tab-desc {
|
||||
@ -851,9 +866,15 @@
|
||||
border-radius: 32px;
|
||||
min-height: 220px;
|
||||
overflow: hidden;
|
||||
background: radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.65), rgba(104, 147, 255, 0.2))
|
||||
background: radial-gradient(
|
||||
circle at 20% 20%,
|
||||
rgba(255, 255, 255, 0.65),
|
||||
rgba(104, 147, 255, 0.2)
|
||||
)
|
||||
rgba(28, 27, 41, 0.95);
|
||||
box-shadow: 0 25px 60px rgba(24, 20, 37, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.4);
|
||||
box-shadow:
|
||||
0 25px 60px rgba(24, 20, 37, 0.45),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.experiment-visual::after {
|
||||
@ -878,7 +899,8 @@
|
||||
.experiment-grid {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
|
||||
background-image:
|
||||
linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px);
|
||||
background-size: 32px 32px;
|
||||
opacity: 0.4;
|
||||
@ -997,7 +1019,7 @@
|
||||
}
|
||||
|
||||
.liquid-glass-panel::before {
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -15%;
|
||||
background:
|
||||
@ -1009,7 +1031,7 @@
|
||||
}
|
||||
|
||||
.liquid-glass-panel::after {
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background:
|
||||
@ -1080,7 +1102,9 @@
|
||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.12));
|
||||
backdrop-filter: blur(18px);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s ease, background 0.2s ease;
|
||||
transition:
|
||||
transform 0.15s ease,
|
||||
background 0.2s ease;
|
||||
}
|
||||
|
||||
.liquid-glass-btn:hover:not(:disabled) {
|
||||
@ -1137,7 +1161,10 @@
|
||||
padding: 16px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
box-shadow 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -1359,7 +1386,10 @@
|
||||
gap: 10px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
box-shadow 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
}
|
||||
|
||||
.theme-card:hover {
|
||||
@ -1461,8 +1491,18 @@
|
||||
bottom: -8px;
|
||||
height: 16px;
|
||||
background: var(--chat-surface-color, #ffffff);
|
||||
mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.6) 55%, rgba(0, 0, 0, 0) 100%);
|
||||
-webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.6) 55%, rgba(0, 0, 0, 0) 100%);
|
||||
mask-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 1) 0%,
|
||||
rgba(0, 0, 0, 0.6) 55%,
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
-webkit-mask-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 1) 0%,
|
||||
rgba(0, 0, 0, 0.6) 55%,
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
backdrop-filter: blur(14px);
|
||||
-webkit-backdrop-filter: blur(14px);
|
||||
pointer-events: none;
|
||||
@ -1597,7 +1637,7 @@
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@ -1627,7 +1667,7 @@
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 1.35;
|
||||
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
|
||||
cursor: pointer;
|
||||
transition: color 0.15s ease;
|
||||
flex-shrink: 0;
|
||||
@ -1699,7 +1739,9 @@
|
||||
|
||||
.mobile-panel-menu-enter-active,
|
||||
.mobile-panel-menu-leave-active {
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
transition:
|
||||
opacity 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
}
|
||||
|
||||
.mobile-panel-menu-enter-from,
|
||||
@ -1897,7 +1939,9 @@
|
||||
|
||||
.desktop-approval-fade-enter-active .desktop-approval-sheet,
|
||||
.desktop-approval-fade-leave-active .desktop-approval-sheet {
|
||||
transition: transform 0.22s ease, opacity 0.22s ease;
|
||||
transition:
|
||||
transform 0.22s ease,
|
||||
opacity 0.22s ease;
|
||||
}
|
||||
|
||||
.desktop-approval-fade-enter-from .desktop-approval-sheet,
|
||||
@ -1925,7 +1969,9 @@
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
z-index: 2200;
|
||||
transition: opacity 0.25s ease, backdrop-filter 0.25s ease;
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
backdrop-filter 0.25s ease;
|
||||
will-change: opacity, backdrop-filter;
|
||||
}
|
||||
|
||||
@ -1936,7 +1982,9 @@
|
||||
border-radius: 18px;
|
||||
padding: 24px;
|
||||
box-shadow: var(--theme-shadow-soft);
|
||||
transition: transform 0.25s ease, opacity 0.25s ease;
|
||||
transition:
|
||||
transform 0.25s ease,
|
||||
opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.confirm-title {
|
||||
@ -2005,7 +2053,9 @@
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
z-index: 2200;
|
||||
transition: opacity 0.25s ease, backdrop-filter 0.25s ease;
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
backdrop-filter 0.25s ease;
|
||||
}
|
||||
|
||||
.subagent-activity-modal {
|
||||
@ -2071,7 +2121,9 @@
|
||||
font-size: 12px;
|
||||
padding: 4px 10px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease, border-color 0.2s ease;
|
||||
transition:
|
||||
background 0.2s ease,
|
||||
border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.subagent-stop-btn:hover:not(:disabled) {
|
||||
@ -2181,10 +2233,11 @@
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
.confirm-dialog-fade-enter-active,
|
||||
.confirm-dialog-fade-leave-active {
|
||||
transition: opacity 0.25s ease, backdrop-filter 0.25s ease;
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
backdrop-filter 0.25s ease;
|
||||
}
|
||||
|
||||
.confirm-dialog-fade-enter-from,
|
||||
@ -2195,7 +2248,9 @@
|
||||
|
||||
.confirm-dialog-fade-enter-active .confirm-modal,
|
||||
.confirm-dialog-fade-leave-active .confirm-modal {
|
||||
transition: transform 0.25s ease, opacity 0.25s ease;
|
||||
transition:
|
||||
transform 0.25s ease,
|
||||
opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.confirm-dialog-fade-enter-from .confirm-modal,
|
||||
@ -2509,7 +2564,9 @@
|
||||
|
||||
.personal-page-vertical-enter-active,
|
||||
.personal-page-vertical-leave-active {
|
||||
transition: opacity 0.35s ease, transform 0.35s ease;
|
||||
transition:
|
||||
opacity 0.35s ease,
|
||||
transform 0.35s ease;
|
||||
}
|
||||
|
||||
.personal-page-vertical-enter-from {
|
||||
@ -2524,7 +2581,9 @@
|
||||
|
||||
.personal-page-fade-enter-active,
|
||||
.personal-page-fade-leave-active {
|
||||
transition: opacity 0.25s ease, backdrop-filter 0.25s ease;
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
backdrop-filter 0.25s ease;
|
||||
}
|
||||
|
||||
.personal-page-fade-enter-from,
|
||||
@ -2535,7 +2594,9 @@
|
||||
|
||||
.personal-page-overlay.personal-page-fade-enter-active .personal-page-card,
|
||||
.personal-page-overlay.personal-page-fade-leave-active .personal-page-card {
|
||||
transition: transform 0.25s ease, opacity 0.25s ease;
|
||||
transition:
|
||||
transform 0.25s ease,
|
||||
opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.personal-page-overlay.personal-page-fade-enter-from .personal-page-card,
|
||||
@ -2547,7 +2608,9 @@
|
||||
/* 通用覆盖层淡入动画(复用个人空间动效) */
|
||||
.overlay-fade-enter-active,
|
||||
.overlay-fade-leave-active {
|
||||
transition: opacity 0.25s ease, backdrop-filter 0.25s ease;
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
backdrop-filter 0.25s ease;
|
||||
}
|
||||
.overlay-fade-enter-from,
|
||||
.overlay-fade-leave-to {
|
||||
@ -2556,7 +2619,9 @@
|
||||
}
|
||||
.overlay-fade-enter-active > *:first-child,
|
||||
.overlay-fade-leave-active > *:first-child {
|
||||
transition: transform 0.25s ease, opacity 0.25s ease;
|
||||
transition:
|
||||
transform 0.25s ease,
|
||||
opacity 0.25s ease;
|
||||
}
|
||||
.overlay-fade-enter-from > *:first-child,
|
||||
.overlay-fade-leave-to > *:first-child {
|
||||
@ -2625,7 +2690,9 @@
|
||||
padding: 8px 14px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
||||
transition:
|
||||
transform 0.18s ease,
|
||||
box-shadow 0.18s ease;
|
||||
}
|
||||
|
||||
.loading-refresh-btn:hover {
|
||||
@ -2722,7 +2789,8 @@
|
||||
}
|
||||
|
||||
@keyframes box1 {
|
||||
0%, 50% {
|
||||
0%,
|
||||
50% {
|
||||
transform: translate(100%, 0);
|
||||
}
|
||||
|
||||
@ -2746,7 +2814,8 @@
|
||||
}
|
||||
|
||||
@keyframes box3 {
|
||||
0%, 50% {
|
||||
0%,
|
||||
50% {
|
||||
transform: translate(100%, 100%);
|
||||
}
|
||||
|
||||
@ -2815,23 +2884,6 @@ body[data-theme='light'] {
|
||||
background: #ececec;
|
||||
}
|
||||
|
||||
.personal-page-btn {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn:hover,
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn:focus-visible {
|
||||
background: #ececec;
|
||||
}
|
||||
|
||||
.code-block-header {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 机器人图标保持黑色 */
|
||||
.status-logo {
|
||||
color: #0d0d0d;
|
||||
@ -2850,7 +2902,9 @@ body[data-theme='light'] {
|
||||
}
|
||||
|
||||
.mode-indicator:focus-visible {
|
||||
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.12);
|
||||
box-shadow:
|
||||
0 0 0 2px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.mode-indicator .icon {
|
||||
@ -2901,60 +2955,6 @@ body[data-theme='light'] {
|
||||
color: #676767 !important;
|
||||
}
|
||||
|
||||
/* 对话记录栏 - 统一使用浅灰色背景 */
|
||||
.new-conversation-btn {
|
||||
background: #ececec !important;
|
||||
color: #0d0d0d !important;
|
||||
border-color: rgba(0, 0, 0, 0.1) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.new-conversation-btn:hover {
|
||||
background: #e0e0e0 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.conversation-item {
|
||||
background: #ffffff !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.conversation-item:hover {
|
||||
background: #f5f5f5 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.conversation-item.active {
|
||||
background: #f5f5f5 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.toggle-sidebar-btn {
|
||||
background: #ececec !important;
|
||||
border-color: rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
.toggle-sidebar-btn:hover {
|
||||
background: #e0e0e0 !important;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
background: #ececec !important;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
background: #e0e0e0 !important;
|
||||
}
|
||||
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn {
|
||||
background: #ececec !important;
|
||||
}
|
||||
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn:hover,
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn:focus-visible {
|
||||
background: #e0e0e0 !important;
|
||||
}
|
||||
|
||||
/* 删除按钮 - 使用深灰色 */
|
||||
.conversation-action-btn.delete-btn {
|
||||
background: #6b6b6b !important;
|
||||
@ -3073,27 +3073,6 @@ body[data-theme='dark'] {
|
||||
background: #353535;
|
||||
}
|
||||
|
||||
.personal-page-btn {
|
||||
background: #2a2a2a;
|
||||
}
|
||||
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn {
|
||||
background: #2a2a2a;
|
||||
}
|
||||
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn:hover,
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn:focus-visible {
|
||||
background: #353535;
|
||||
}
|
||||
|
||||
.code-block-header {
|
||||
background: #2a2a2a;
|
||||
}
|
||||
|
||||
.copy-code-btn {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
/* 机器人图标保持白色 */
|
||||
.status-logo {
|
||||
color: #ffffff;
|
||||
@ -3112,7 +3091,9 @@ body[data-theme='dark'] {
|
||||
}
|
||||
|
||||
.mode-indicator:focus-visible {
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1), 0 3px 6px rgba(0, 0, 0, 0.4);
|
||||
box-shadow:
|
||||
0 0 0 2px rgba(255, 255, 255, 0.1),
|
||||
0 3px 6px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.mode-indicator .icon {
|
||||
@ -3128,29 +3109,6 @@ body[data-theme='dark'] {
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
/* 对话侧边栏图标颜色 */
|
||||
.conversation-header button,
|
||||
.workspace-immersive-btn {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.conversation-header button svg,
|
||||
.workspace-immersive-btn svg {
|
||||
stroke: #ffffff;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
/* 个人空间按钮 - 移除圆形外框 */
|
||||
.personal-page-btn.icon-only {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.personal-page-btn.icon-only:hover {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* 个人空间选择栏 - 文字颜色 */
|
||||
.run-mode-title {
|
||||
color: #ffffff !important;
|
||||
@ -3196,60 +3154,6 @@ body[data-theme='dark'] {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
/* 对话记录栏 - 统一使用深灰色背景 */
|
||||
.new-conversation-btn {
|
||||
background: #2a2a2a !important;
|
||||
color: #ffffff !important;
|
||||
border-color: rgba(255, 255, 255, 0.1) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.new-conversation-btn:hover {
|
||||
background: #3a3a3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.conversation-item {
|
||||
background: #2a2a2a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.conversation-item:hover {
|
||||
background: #3a3a3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.conversation-item.active {
|
||||
background: #3a3a3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.toggle-sidebar-btn {
|
||||
background: #2a2a2a !important;
|
||||
border-color: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.toggle-sidebar-btn:hover {
|
||||
background: #3a3a3a !important;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
background: #2a2a2a !important;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
background: #3a3a3a !important;
|
||||
}
|
||||
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn {
|
||||
background: #2a2a2a !important;
|
||||
}
|
||||
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn:hover,
|
||||
.conversation-personal-entry:not(.collapsed) .personal-page-btn:focus-visible {
|
||||
background: #3a3a3a !important;
|
||||
}
|
||||
|
||||
/* 删除按钮 - 使用浅灰色 */
|
||||
.conversation-action-btn.delete-btn {
|
||||
background: #6b6b6b !important;
|
||||
@ -3795,8 +3699,14 @@ body[data-theme='dark'] {
|
||||
}
|
||||
|
||||
@keyframes tutorialClickPulse {
|
||||
0% { opacity: 1; transform: scale(0.6); }
|
||||
100% { opacity: 0; transform: scale(1.8); }
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scale(0.6);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(1.8);
|
||||
}
|
||||
}
|
||||
|
||||
.tutorial-popover {
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-shrink: 0;
|
||||
margin-left: 52px;
|
||||
}
|
||||
|
||||
/* 侧边栏 */
|
||||
@ -79,7 +80,7 @@
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.status-brand {
|
||||
.status-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
@ -143,7 +144,10 @@
|
||||
background: linear-gradient(135deg, var(--mode-indicator-color-1), var(--mode-indicator-color-2));
|
||||
color: #fffef8;
|
||||
box-shadow: 0 8px 20px var(--mode-indicator-shadow);
|
||||
transition: background 0.35s ease, box-shadow 0.35s ease, transform 0.25s ease;
|
||||
transition:
|
||||
background 0.35s ease,
|
||||
box-shadow 0.35s ease,
|
||||
transform 0.25s ease;
|
||||
}
|
||||
|
||||
.mode-indicator:hover {
|
||||
@ -151,7 +155,9 @@
|
||||
}
|
||||
|
||||
.mode-indicator:focus-visible {
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8), 0 8px 20px var(--mode-indicator-shadow);
|
||||
box-shadow:
|
||||
0 0 0 2px rgba(255, 255, 255, 0.8),
|
||||
0 8px 20px var(--mode-indicator-shadow);
|
||||
}
|
||||
|
||||
.mode-indicator.fast {
|
||||
@ -182,13 +188,15 @@
|
||||
height: 12px;
|
||||
border-radius: 6px;
|
||||
background: #e34d4d;
|
||||
transition: background 0.2s ease, box-shadow 0.2s ease;
|
||||
transition:
|
||||
background 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.connection-dot::after {
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
@ -206,7 +214,9 @@
|
||||
|
||||
.mode-icon-enter-active,
|
||||
.mode-icon-leave-active {
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
transition:
|
||||
opacity 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
}
|
||||
|
||||
.mode-icon-enter-from,
|
||||
@ -258,7 +268,9 @@
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
transition:
|
||||
background 0.2s,
|
||||
border-color 0.2s;
|
||||
}
|
||||
|
||||
.sidebar-manage-btn:hover {
|
||||
@ -443,9 +455,11 @@
|
||||
padding: 12px 14px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
|
||||
[data-theme="dark"] & {
|
||||
[data-theme='dark'] & {
|
||||
background: rgba(30, 30, 30, 0.6);
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
@ -455,7 +469,7 @@
|
||||
border-color: #6c5ce7;
|
||||
box-shadow: 0 6px 16px rgba(108, 92, 231, 0.15);
|
||||
|
||||
[data-theme="dark"] & {
|
||||
[data-theme='dark'] & {
|
||||
border-color: #8b7ce7;
|
||||
box-shadow: 0 6px 16px rgba(139, 124, 231, 0.25);
|
||||
}
|
||||
@ -517,7 +531,7 @@
|
||||
border: 1px dashed var(--claude-border);
|
||||
text-align: center;
|
||||
|
||||
[data-theme="dark"] & {
|
||||
[data-theme='dark'] & {
|
||||
background: rgba(20, 20, 20, 0.9);
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
@ -604,7 +618,9 @@
|
||||
text-align: left;
|
||||
color: var(--claude-text);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease, transform 0.2s ease;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
border-color: var(--claude-accent);
|
||||
@ -664,18 +680,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="dark"] .host-workspace-header-box {
|
||||
[data-theme='dark'] .host-workspace-header-box {
|
||||
background: rgba(30, 30, 30, 0.78);
|
||||
border-color: rgba(160, 160, 160, 0.45);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .host-workspace-card {
|
||||
[data-theme='dark'] .host-workspace-card {
|
||||
&.active {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="dark"] .host-workspace-badge {
|
||||
[data-theme='dark'] .host-workspace-badge {
|
||||
&.default {
|
||||
color: #f7c56f;
|
||||
border-color: rgba(247, 197, 111, 0.35);
|
||||
@ -750,7 +766,9 @@
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
transition: background 0.2s ease, transform 0.2s ease;
|
||||
transition:
|
||||
background 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
text-align: left;
|
||||
font-family: inherit;
|
||||
}
|
||||
@ -843,3 +861,78 @@
|
||||
cursor: not-allowed;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Targeted refinement: keep workspace content/layout, only polish switcher/menu/manage controls. */
|
||||
.sidebar-manage-btn {
|
||||
height: 32px;
|
||||
border: 0;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
color: var(--claude-text);
|
||||
padding: 0 11px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background 140ms ease,
|
||||
color 140ms ease;
|
||||
}
|
||||
|
||||
.sidebar-manage-btn:hover {
|
||||
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.sidebar-view-toggle {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 10px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--claude-text);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition:
|
||||
background 140ms ease,
|
||||
color 140ms ease;
|
||||
}
|
||||
|
||||
.sidebar-view-toggle:hover {
|
||||
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
|
||||
}
|
||||
|
||||
.panel-menu {
|
||||
left: calc(100% + 8px);
|
||||
top: 0;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
background: var(--theme-surface-strong, #ffffff);
|
||||
border: 1px solid var(--claude-border);
|
||||
border-radius: 14px;
|
||||
padding: 6px;
|
||||
box-shadow: var(--theme-shadow-soft);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.panel-menu button {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
border-radius: 10px;
|
||||
color: var(--claude-text);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition:
|
||||
background 140ms ease,
|
||||
color 140ms ease;
|
||||
}
|
||||
|
||||
.panel-menu button:hover,
|
||||
.panel-menu button.active {
|
||||
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,10 +3,6 @@
|
||||
/* ========================================= */
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.conversation-sidebar {
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
.left-sidebar,
|
||||
.right-sidebar {
|
||||
width: 300px !important;
|
||||
|
||||
@ -10,6 +10,7 @@ export const ICONS = Object.freeze({
|
||||
checkbox: '/static/icons/checkbox.svg',
|
||||
circleAlert: '/static/icons/circle-alert.svg',
|
||||
clipboard: '/static/icons/clipboard.svg',
|
||||
copy: '/static/icons/copy.svg',
|
||||
clock: '/static/icons/clock.svg',
|
||||
eye: '/static/icons/eye.svg',
|
||||
file: '/static/icons/file.svg',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user