mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 09:28:14 +00:00
gui+webui: 聊天界面升级(PiDeck风格思考/工具卡片+滴入动画) & 流式卡顿修复(防抖局部增量渲染) & 主题系统修复(启动恢复色板/弹窗溢出wrap)
This commit is contained in:
@ -289,6 +289,8 @@ function toggleAppearance() {
|
||||
(() => {
|
||||
var saved = localStorage.getItem("ha-theme");
|
||||
setTheme(saved || "light");
|
||||
var savedColor = localStorage.getItem("ha-color");
|
||||
if (savedColor) setColor(savedColor);
|
||||
var finalSrc = localStorage.getItem("ha-bg-final");
|
||||
var img = localStorage.getItem("ha-bg-img");
|
||||
var blur = localStorage.getItem("ha-bg-blur");
|
||||
@ -963,6 +965,27 @@ function chanLetter(src) {
|
||||
return /[A-Za-z0-9]/.test(ch) ? ch : "C";
|
||||
}
|
||||
|
||||
// PiDeck 风格思考卡片:Brain 图标 + 折叠时单行预览(流式中扫光)+ 展开/收起
|
||||
// PiDeck 风格思考卡片:Brain 图标 + 折叠单行预览(流式中扫光)+ 展开懒加载全文
|
||||
function renderReasoningCard(text, isStreaming, idx) {
|
||||
var preview =
|
||||
typeof marked === "undefined"
|
||||
? escHtml(text).replace(/<[^>]+>/g, " ").slice(0, 60)
|
||||
: text.replace(/[\s\n]+/g, " ").slice(0, 60);
|
||||
return (
|
||||
'<div class="reasoning-card' + (isStreaming ? " rc-streaming" : "") + '" data-idx="' + (idx | 0) + '">' +
|
||||
'<div class="reasoning-head" onclick="toggleReasoning(this)">' +
|
||||
'<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="rc-ico"><path d="M9 3a2 2 0 0 0-2 2v2a2 2 0 0 1-2 2H3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2a2 2 0 0 1 2 2v2a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-2a2 2 0 0 1 2-2h2a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2a2 2 0 0 1-2-2V3a2 2 0 0 0-2-2H9zM12 8v4m0 4h.01"/></svg>' +
|
||||
'<span class="rc-title">' + (isStreaming ? __("思考中...","Thinking...") : __("思考","Thinking")) + '</span>' +
|
||||
'<span class="rc-chev">▾</span></div>' +
|
||||
'<div class="reasoning-body" style="display:' + (isStreaming ? "block" : "none") + '">' +
|
||||
(isStreaming
|
||||
? '<div class="reasoning-preview">' + escHtml(preview) + '</div><div class="reasoning-sweep"></div>'
|
||||
: '<div class="reasoning-content">' + (typeof marked !== "undefined" ? marked.parse(text) : escHtml(text)) + '</div>') +
|
||||
'</div></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function renderChat() {
|
||||
if (!_chatLayoutBuilt) {
|
||||
buildChatLayout();
|
||||
@ -1068,24 +1091,7 @@ function renderChat() {
|
||||
var isChan = !!(m.source && m.source !== "webui");
|
||||
var rc = "";
|
||||
if (m.reasoning_content) {
|
||||
var rcBody =
|
||||
typeof marked === "undefined"
|
||||
? escHtml(m.reasoning_content)
|
||||
: marked.parse(m.reasoning_content);
|
||||
rc =
|
||||
'<div class="msg-bubble"><div class="reasoning">' +
|
||||
"<div class=\"reasoning-title\" onclick=\"var n=this.nextElementSibling;n.style.display=n.style.display==='none'?'block':'none';this.textContent=this.textContent==='" +
|
||||
__("展开思考", "Expand") +
|
||||
"'?'" +
|
||||
__("收起思考", "Collapse") +
|
||||
"':'" +
|
||||
__("展开思考", "Expand") +
|
||||
"'\">" +
|
||||
__("展开思考", "Expand") +
|
||||
"</div>" +
|
||||
'<div class="reasoning-body" style="display:none">' +
|
||||
rcBody +
|
||||
"</div></div></div>";
|
||||
rc = renderReasoningCard(m.reasoning_content, isStreamingLast, i);
|
||||
}
|
||||
var tcs = "";
|
||||
if (m.tool_calls && m.tool_calls.length > 0) {
|
||||
@ -1099,41 +1105,47 @@ function renderChat() {
|
||||
? JSON.stringify(tc.result, null, 1)
|
||||
: String(tc.result)
|
||||
: "";
|
||||
var statusIcon =
|
||||
var running = !resultStr && tc.status !== "denied";
|
||||
var error = tc.status === "error" || tc.status === "denied" || !!tc.error;
|
||||
var drip = newlyDone.indexOf(tc.tool || tc.name || "") !== -1 ? " tool-drip-in" : "";
|
||||
var iconSvg =
|
||||
error
|
||||
? '<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M5.6 5.6l12.8 12.8"/></svg>'
|
||||
: running
|
||||
? '<span class="tc-spinner"></span>'
|
||||
: '<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4L3 18l3 3 6.3-6.3a4 4 0 0 0 5.4-5.4l-2.9 2.9-2.5-.6-.6-2.5z"/></svg>';
|
||||
var statusHtml =
|
||||
tc.status === "denied"
|
||||
? '<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" style="color:var(--error);vertical-align:-1px"><circle cx="12" cy="12" r="9"/><path d="M5.6 5.6l12.8 12.8"/></svg>'
|
||||
: '<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" style="color:var(--accent);vertical-align:-1px"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4L3 18l3 3 6.3-6.3a4 4 0 0 0 5.4-5.4l-2.9 2.9-2.5-.6-.6-2.5z"/></svg>';
|
||||
? '<span class="tc-state tc-deny">' + __("已拒绝","Denied") + "</span>"
|
||||
: running
|
||||
? '<span class="tc-state tc-run">' + __("调用中","Running") + "</span>"
|
||||
: '<span class="tc-state tc-done">' + __("完成","Done") + "</span>";
|
||||
var pluginHtml = tc.plugin
|
||||
? '<span class="tc-plugin">' + escHtml(tc.plugin) + "</span>"
|
||||
: "";
|
||||
tcs +=
|
||||
'<div class="msg-bubble"><div class="tool-call' +
|
||||
(newlyDone.indexOf(tc.tool || tc.name || "") === -1
|
||||
? ""
|
||||
: " tool-drip-in") +
|
||||
'<div class="tool-card' +
|
||||
(error ? " tc-error" : running ? " tc-running" : " tc-done") +
|
||||
drip +
|
||||
'" data-tool="' +
|
||||
escHtml(tc.tool || tc.name || "") +
|
||||
'" onclick="toggleToolCall(this)">' +
|
||||
'<div class="tc-line"><span class="tc-ico">' +
|
||||
statusIcon +
|
||||
iconSvg +
|
||||
'</span><span class="tc-name">' +
|
||||
escHtml(tc.tool || tc.name || "") +
|
||||
"</span>" +
|
||||
(tc.status === "denied"
|
||||
? '<span class="tc-state tc-deny">' +
|
||||
__("已拒绝", "Denied") +
|
||||
"</span>"
|
||||
: resultStr
|
||||
? '<span class="tc-state tc-done">' +
|
||||
__("完成", "Done") +
|
||||
"</span>"
|
||||
: '<span class="tc-state tc-run">' +
|
||||
__("调用中", "Running") +
|
||||
"</span>") +
|
||||
pluginHtml +
|
||||
statusHtml +
|
||||
'<span class="tc-caret">▾</span></div>' +
|
||||
'<div class="tc-detail" style="display:none">' +
|
||||
(argsStr && argsStr !== "{}"
|
||||
? '<div class="tc-args">' + escHtml(argsStr) + "</div>"
|
||||
? '<div class="tc-args"><div class="tc-detail-label">' + __("参数","Args") + "</div>" + escHtml(argsStr) + "</div>"
|
||||
: "") +
|
||||
(resultStr
|
||||
? '<div class="tc-result">' + escHtml(resultStr) + "</div>"
|
||||
? '<div class="tc-result"><div class="tc-detail-label">' + __("结果","Result") + "</div>" + escHtml(resultStr) + "</div>"
|
||||
: "") +
|
||||
"</div></div></div>";
|
||||
"</div></div>";
|
||||
});
|
||||
}
|
||||
var body = rc + tcs;
|
||||
@ -1302,6 +1314,29 @@ function toggleToolCall(el) {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleReasoning(el) {
|
||||
var card = el.closest(".reasoning-card");
|
||||
if (!card) return;
|
||||
var body = card.querySelector(".reasoning-body");
|
||||
if (!body) return;
|
||||
var open = body.style.display !== "none";
|
||||
if (open) {
|
||||
body.style.display = "none";
|
||||
card.classList.remove("open");
|
||||
return;
|
||||
}
|
||||
// 展开时懒加载全文(流式中只有 preview,未 parse 全文)
|
||||
var content = card.querySelector(".reasoning-content");
|
||||
if (content && !content.childElementCount) {
|
||||
var idx = parseInt(card.getAttribute("data-idx"), 10) || 0;
|
||||
var text = (state.messages[idx] && state.messages[idx].reasoning_content) || "";
|
||||
content.innerHTML =
|
||||
typeof marked !== "undefined" ? marked.parse(text) : escHtml(text);
|
||||
}
|
||||
body.style.display = "block";
|
||||
card.classList.add("open");
|
||||
}
|
||||
|
||||
function renderChatStarmap() {
|
||||
var cont = document.getElementById("sm-container-chat");
|
||||
if (!cont) return;
|
||||
@ -4487,10 +4522,78 @@ async function connectFetchSSE(url) {
|
||||
|
||||
function rerenderChatIfActive() {
|
||||
var tab = document.getElementById("view-chat");
|
||||
if (tab && tab.classList.contains("active")) {
|
||||
renderChat();
|
||||
renderChatStarmap();
|
||||
renderTerminals();
|
||||
renderCmdHistory();
|
||||
if (!tab || !tab.classList.contains("active")) return;
|
||||
// 流式增量路径:防抖合并 + 只更新最后一条消息的正文/思考节点,避免全量重建
|
||||
var msgs = state.messages;
|
||||
var last = msgs.length ? msgs[msgs.length - 1] : null;
|
||||
var streamingLast =
|
||||
!!last && last.role === "assistant" && !last._final && state.chatLoading;
|
||||
if (streamingLast) {
|
||||
if (state._streamTimer) clearTimeout(state._streamTimer);
|
||||
state._streamTimer = setTimeout(function () {
|
||||
state._streamTimer = null;
|
||||
renderChatStreamChunk();
|
||||
}, 90);
|
||||
return;
|
||||
}
|
||||
// 非流式(完成/工具/历史变化):全量渲染
|
||||
if (state._streamTimer) {
|
||||
clearTimeout(state._streamTimer);
|
||||
state._streamTimer = null;
|
||||
}
|
||||
renderChat();
|
||||
renderChatStarmap();
|
||||
renderTerminals();
|
||||
renderCmdHistory();
|
||||
}
|
||||
|
||||
// 流式增量渲染:仅更新最后一条 assistant 消息的正文(渐进,节流 parse)与思考预览
|
||||
function renderChatStreamChunk() {
|
||||
var msgsEl = document.getElementById("chat-msgs");
|
||||
var msgs = state.messages;
|
||||
var last = msgs.length ? msgs[msgs.length - 1] : null;
|
||||
if (!msgsEl || !last) return;
|
||||
var el = msgsEl.lastElementChild;
|
||||
if (!el) {
|
||||
renderChat();
|
||||
return;
|
||||
}
|
||||
// 更新正文文本(节流 parse:内容变化 >200 字符或时间 >300ms 才 parse)
|
||||
var textEl = el.querySelector(".msg-bubble .text");
|
||||
var c = last.content || "";
|
||||
if (textEl) {
|
||||
var now = Date.now();
|
||||
var lastParse = el.__lastParse || 0;
|
||||
var lastLen = el.__lastLen || 0;
|
||||
if (c.length - lastLen > 200 || now - lastParse > 300) {
|
||||
textEl.innerHTML =
|
||||
typeof marked !== "undefined" ? marked.parse(c) : escHtml(c);
|
||||
el.__lastParse = now;
|
||||
el.__lastLen = c.length;
|
||||
} else {
|
||||
// 小增量:纯文本渐进,避免反复 parse
|
||||
var tail = c.slice(lastLen);
|
||||
if (tail) {
|
||||
var tn = document.createTextNode(tail);
|
||||
textEl.appendChild(tn);
|
||||
}
|
||||
el.__lastLen = c.length;
|
||||
}
|
||||
if (state.chatStick !== false) {
|
||||
try {
|
||||
msgsEl.scrollTop = msgsEl.scrollHeight;
|
||||
} catch (e) {}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 思考预览更新(流式中折叠,只刷 preview + sweep)
|
||||
var rc = el.querySelector(".reasoning-card.rc-streaming .reasoning-preview");
|
||||
if (rc && last.reasoning_content) {
|
||||
var prev = last.reasoning_content.replace(/[\s\n]+/g, " ").slice(0, 60);
|
||||
rc.textContent = prev;
|
||||
return;
|
||||
}
|
||||
// 兜底:结构变化则全量
|
||||
renderChat();
|
||||
}
|
||||
|
||||
|
||||
@ -553,11 +553,15 @@ body.maximized .tb-max svg {
|
||||
filter: blur(calc(var(--bg-blur, 0) * 1px));
|
||||
transition: filter 0.25s var(--ease-out);
|
||||
}
|
||||
|
||||
.palette-pop {
|
||||
position: fixed;
|
||||
bottom: 56px;
|
||||
left: 6px;
|
||||
width: 210px;
|
||||
width: 216px;
|
||||
max-width: calc(100vw - 24px);
|
||||
max-height: calc(100vh - 120px);
|
||||
overflow-y: auto;
|
||||
padding: 12px;
|
||||
background: var(--glass-bg-strong);
|
||||
backdrop-filter: blur(12px);
|
||||
@ -586,7 +590,7 @@ body.maximized .tb-max svg {
|
||||
margin: 3px;
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
transition: transform 0.15s;
|
||||
transition: transform 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.palette-pop button.cdot:hover {
|
||||
transform: scale(1.25);
|
||||
@ -607,27 +611,33 @@ body.maximized .tb-max svg {
|
||||
margin-bottom: 6px;
|
||||
outline: none;
|
||||
}
|
||||
.palette-pop input[type="range"] {
|
||||
width: 80px;
|
||||
margin: 0;
|
||||
accent-color: var(--accent);
|
||||
vertical-align: middle;
|
||||
}
|
||||
.palette-pop .pp-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
gap: 5px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.palette-pop .pp-row .btn {
|
||||
padding: 3px 10px;
|
||||
padding: 3px 9px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.palette-pop .pp-val {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 10px;
|
||||
color: var(--text-muted);
|
||||
min-width: 96px;
|
||||
min-width: 0;
|
||||
text-align: right;
|
||||
margin-left: auto;
|
||||
}
|
||||
.palette-pop input[type="range"] {
|
||||
width: 72px;
|
||||
margin: 0;
|
||||
accent-color: var(--accent);
|
||||
vertical-align: middle;
|
||||
}
|
||||
.lang-btn {
|
||||
font-size: 13px;
|
||||
@ -1179,26 +1189,73 @@ code {
|
||||
max-width: 100%;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
.msg-bubble .reasoning {
|
||||
border-left: 2px solid #dddddd;
|
||||
padding-left: 8px;
|
||||
|
||||
/* ===== 思考卡片(PiDeck 风格)===== */
|
||||
.reasoning-card {
|
||||
margin: 6px 0;
|
||||
font-size: 11px;
|
||||
opacity: 0.8;
|
||||
border: 1px dashed var(--kv-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--bg-panel, var(--bg-hover));
|
||||
overflow: hidden;
|
||||
}
|
||||
.msg-bubble .reasoning-title {
|
||||
.reasoning-card .reasoning-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
padding: 6px 10px;
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
user-select: none;
|
||||
margin-bottom: 2px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.reasoning-card .reasoning-head:hover {
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
.reasoning-card .rc-ico {
|
||||
color: var(--accent);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.reasoning-card .rc-title {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.reasoning-card .rc-chev {
|
||||
margin-left: auto;
|
||||
font-size: 10px;
|
||||
color: var(--text-muted);
|
||||
transition: transform 0.2s var(--ease-out);
|
||||
}
|
||||
.reasoning-card.open .rc-chev {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.reasoning-card .reasoning-body {
|
||||
padding: 4px 10px 8px;
|
||||
}
|
||||
.reasoning-card .reasoning-content {
|
||||
line-height: 1.5;
|
||||
color: var(--text-tertiary);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
.reasoning-card .reasoning-content p {
|
||||
margin: 4px 0;
|
||||
}
|
||||
.reasoning-card .reasoning-sweep {
|
||||
height: 2px;
|
||||
border-radius: 2px;
|
||||
margin-top: 6px;
|
||||
background: linear-gradient(90deg, transparent, var(--accent), transparent);
|
||||
background-size: 200% 100%;
|
||||
animation: reasoningSweep 1.2s var(--ease-out) infinite;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.msg-bubble .reasoning-body {
|
||||
line-height: 1.4;
|
||||
@keyframes reasoningSweep {
|
||||
from { background-position: 200% 0; }
|
||||
to { background-position: -200% 0; }
|
||||
}
|
||||
.msg-bubble .tool-call {
|
||||
background: var(--bg-hover);
|
||||
|
||||
/* ===== 工具卡片(PiDeck 风格,扁平不套气泡)===== */
|
||||
.tool-card {
|
||||
background: var(--bg-panel, var(--bg-hover));
|
||||
color: var(--text-secondary);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 7px 10px;
|
||||
@ -1207,55 +1264,101 @@ code {
|
||||
border: 1px solid var(--kv-border);
|
||||
border-left: 3px solid var(--accent);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s var(--ease-out), background 0.2s var(--ease-out);
|
||||
}
|
||||
.msg-bubble .tool-call .tc-line {
|
||||
.tool-card.tc-running {
|
||||
border-left-color: var(--accent);
|
||||
}
|
||||
.tool-card.tc-done {
|
||||
border-left-color: rgba(23, 169, 100, 0.8);
|
||||
}
|
||||
.tool-card.tc-error {
|
||||
border-left-color: var(--error, #db3694);
|
||||
}
|
||||
.tool-card .tc-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 11px;
|
||||
user-select: none;
|
||||
}
|
||||
.msg-bubble .tool-call .tc-ico {
|
||||
.tool-card .tc-ico {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
color: var(--accent);
|
||||
}
|
||||
.msg-bubble .tool-call .tc-name {
|
||||
.tool-card.tc-error .tc-ico {
|
||||
color: var(--error, #db3694);
|
||||
}
|
||||
.tool-card.tc-done .tc-ico {
|
||||
color: rgba(23, 169, 100, 0.9);
|
||||
}
|
||||
.tool-card .tc-name {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.msg-bubble .tool-call .tc-state {
|
||||
margin-left: 6px;
|
||||
.tool-card .tc-plugin {
|
||||
font-size: 9.5px;
|
||||
color: var(--text-muted);
|
||||
background: var(--pre-bg);
|
||||
border-radius: 4px;
|
||||
padding: 0 4px;
|
||||
line-height: 1.6;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.tool-card .tc-state {
|
||||
margin-left: auto;
|
||||
font-size: 9.5px;
|
||||
font-weight: 500;
|
||||
padding: 1px 6px;
|
||||
border-radius: 999px;
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.msg-bubble .tool-call .tc-run {
|
||||
.tool-card .tc-run {
|
||||
background: rgba(63, 110, 245, 0.18);
|
||||
color: #a3b8ff;
|
||||
}
|
||||
.msg-bubble .tool-call .tc-done {
|
||||
.tool-card .tc-done {
|
||||
background: rgba(23, 169, 100, 0.18);
|
||||
color: #6ee7a8;
|
||||
}
|
||||
.msg-bubble .tool-call .tc-deny {
|
||||
.tool-card .tc-deny {
|
||||
background: rgba(219, 54, 148, 0.18);
|
||||
color: #ff9ec6;
|
||||
}
|
||||
.msg-bubble .tool-call .tc-caret {
|
||||
.tool-card .tc-spinner {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(63, 110, 245, 0.25);
|
||||
border-top-color: #3f6ef5;
|
||||
animation: spin 0.7s linear infinite;
|
||||
display: inline-block;
|
||||
}
|
||||
.tool-card .tc-caret {
|
||||
font-size: 10px;
|
||||
color: var(--text-muted);
|
||||
transition: transform 0.15s var(--ease-out);
|
||||
}
|
||||
.msg-bubble .tool-call.open .tc-caret {
|
||||
.tool-card.open .tc-caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.msg-bubble .tool-call .tc-detail {
|
||||
.tool-card .tc-detail {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.msg-bubble .tool-call .tc-args {
|
||||
.tool-card .tc-detail-label {
|
||||
font-size: 9.5px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.tool-card .tc-args,
|
||||
.tool-card .tc-result {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
opacity: 0.85;
|
||||
@ -1267,29 +1370,37 @@ code {
|
||||
border-radius: 4px;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
.msg-bubble .tool-call .tc-result {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
.tool-card .tc-result {
|
||||
opacity: 0.72;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
margin-top: 5px;
|
||||
background: var(--pre-bg);
|
||||
color: var(--pre-color);
|
||||
border-radius: 4px;
|
||||
padding: 5px 7px;
|
||||
max-height: 80px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
[data-theme="light"] .msg-bubble .tool-call .tc-run {
|
||||
[data-theme="light"] .tool-card .tc-run {
|
||||
color: #3f6ef5;
|
||||
}
|
||||
[data-theme="light"] .msg-bubble .tool-call .tc-done {
|
||||
[data-theme="light"] .tool-card .tc-done {
|
||||
color: #128a52;
|
||||
}
|
||||
[data-theme="light"] .msg-bubble .tool-call .tc-deny {
|
||||
[data-theme="light"] .tool-card .tc-deny {
|
||||
color: #c2185b;
|
||||
}
|
||||
.tool-card.tool-drip-in {
|
||||
animation: toolDripIn 0.32s var(--ease-out) both;
|
||||
}
|
||||
@keyframes toolDripIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-18px) scale(0.96);
|
||||
}
|
||||
70% {
|
||||
opacity: 1;
|
||||
transform: translateY(2px) scale(1.005);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
.msg-bubble .thinking-tools {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
|
||||
Reference in New Issue
Block a user