diff --git a/emrg/gui/renderer/app.js b/emrg/gui/renderer/app.js index 6343b313..32e6fc24 100644 --- a/emrg/gui/renderer/app.js +++ b/emrg/gui/renderer/app.js @@ -471,8 +471,7 @@ async function handleEvent(evt) { if (card.classList.contains("running")) { card.classList.remove("running"); card.classList.add("failed"); - const st = card.querySelector(".tool-status"); - if (st) st.textContent = "结果未知——连接中断"; + card.innerHTML = '连接中断,结果未知'; } } break; @@ -570,9 +569,11 @@ function handleToolStart(data) { appendMsg(node); state.groupNodes.set(rid, node); } + // P2:友好状态行(设计 §4.2)——琥珀色转动圆点 + 动词短语,无技术黑话 const card = document.createElement("div"); card.className = "tool-card running"; - card.innerHTML = ` ${escapeHtml(data.tool_name)} 运行中…`; + const phrase = toolPhrase(data.tool_name, "doing"); + card.innerHTML = `${escapeHtml(phrase)}`; appendMsg(card); state.toolCards.set(data.tool_call_id, card); } @@ -582,14 +583,21 @@ function handleToolEnd(data) { if (!card) return; const ok = !data.error; card.className = "tool-card " + (ok ? "done" : "failed"); + const phrase = toolPhrase(data.tool_name, ok ? "done" : "fail"); const elapsed = data.elapsed !== undefined ? `${data.elapsed.toFixed(1)}s` : ""; - card.querySelector(".tool-status").textContent = ok ? `完成 ${elapsed}` : `失败 ${elapsed}`; - // G91/G131:content 默认截断 2000 字符 + 展开(textContent 纯文本,不做 marked) const content = data.content || ""; + const toggle = content ? '展开 ⌄' : ""; + card.innerHTML = + `` + + `${escapeHtml(phrase)}` + + (elapsed ? `${elapsed}` : "") + + toggle; + // 原始输出默认折叠(渐进披露:点「展开」才看;G91/G131 保留 2000 字符截断) if (content) { const truncated = content.length > 2000 ? content.slice(0, 2000) + "…" : content; const body = document.createElement("div"); body.className = "tool-output"; + body.style.display = "none"; body.textContent = truncated; card.appendChild(body); if (content.length > 2000) { @@ -602,6 +610,14 @@ function handleToolEnd(data) { }); card.appendChild(btn); } + const tg = card.querySelector(".tool-toggle"); + if (tg) { + tg.addEventListener("click", () => { + const hidden = body.style.display === "none"; + body.style.display = hidden ? "block" : "none"; + tg.textContent = hidden ? "收起 ⌃" : "展开 ⌄"; + }); + } } scrollToBottom(); } diff --git a/emrg/gui/renderer/css/components.css b/emrg/gui/renderer/css/components.css index fd8dd24b..5b1a89fe 100644 --- a/emrg/gui/renderer/css/components.css +++ b/emrg/gui/renderer/css/components.css @@ -48,7 +48,7 @@ color: var(--text-1); border-radius: var(--radius-bubble) var(--radius-bubble) 6px var(--radius-bubble); } -/* EMRG:全宽无气泡,行首 ✦ 标识(P2 chat.js 渲染时加 ✦,P1 保留全宽样式) */ +/* EMRG:全宽无气泡,行首 ✦ 品牌标识(设计 §3.3;remote 有标签不加) */ .msg.assistant { align-self: flex-start; max-width: 100%; @@ -59,7 +59,9 @@ border-radius: 0; white-space: normal; } +.msg.assistant::before { content: "✦ "; color: var(--accent); font-weight: 600; } .msg.assistant.remote { border-left: 3px solid var(--amber); padding-left: var(--space-3); } +.msg.assistant.remote::before { content: none; } /* 系统提示:居中弱化小字 */ .msg.system { align-self: center; @@ -73,7 +75,7 @@ .remote-label { font-size: 11px; color: var(--amber); margin-bottom: var(--space-1); } .msg-body { color: var(--text-1); } -/* ── 工具过程(P2 改折叠友好行;P1 保留卡片样式保证功能)── */ +/* ── 工具过程:友好状态行(设计 §4.2 重点——折叠式,渐进披露)── */ .tool-card { align-self: flex-start; min-width: 320px; @@ -86,14 +88,43 @@ font-size: var(--text-secondary); margin: 2px 0; box-shadow: var(--shadow-sm); + display: flex; + align-items: center; + gap: var(--space-2); + flex-wrap: wrap; } .tool-card.running { border-left-color: var(--amber); } .tool-card.done { border-left-color: var(--accent); } .tool-card.failed { border-left-color: var(--red); } -.tool-icon { } -.tool-name { font-family: var(--font-mono); font-weight: 600; } -.tool-status { color: var(--text-2); margin-left: var(--space-2); font-size: var(--text-aux); } +/* 进行中:琥珀色温和转动圆点(不刺眼) */ +.tool-spin { + width: 12px; + height: 12px; + border-radius: 50%; + border: 2px solid var(--amber); + border-top-color: transparent; + animation: tool-spin 0.9s linear infinite; + flex-shrink: 0; +} +@keyframes tool-spin { to { transform: rotate(360deg); } } +/* 完成/失败图标 */ +.tool-icon { flex-shrink: 0; } +.tool-card.done .tool-icon { color: var(--accent); font-weight: 600; } +.tool-card.failed .tool-icon { color: var(--red); font-weight: 600; } +.tool-text { flex-shrink: 0; } +.tool-detail { color: var(--text-3); font-size: var(--text-aux); } +.tool-toggle { + color: var(--blue); + cursor: pointer; + font-size: var(--text-aux); + margin-left: auto; + flex-shrink: 0; + padding: 2px 4px; + border-radius: 6px; +} +.tool-toggle:hover { background: var(--bg-soft); } .tool-output { + flex-basis: 100%; margin-top: var(--space-2); background: var(--bg-soft); border-radius: var(--radius-input); @@ -106,6 +137,7 @@ word-break: break-all; } .tool-expand { + flex-basis: 100%; margin-top: var(--space-1); background: none; border: none; @@ -113,6 +145,7 @@ cursor: pointer; font-size: var(--text-aux); padding: 0; + text-align: left; } .tool-expand:hover { text-decoration: underline; } diff --git a/emrg/gui/renderer/index.html b/emrg/gui/renderer/index.html index b7189f82..9b908f00 100644 --- a/emrg/gui/renderer/index.html +++ b/emrg/gui/renderer/index.html @@ -115,6 +115,7 @@