@co0ontty/wand 1.32.1 → 1.32.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/web-ui/content/scripts.js +39 -67
- package/dist/web-ui/content/styles.css +61 -74
- package/package.json +1 -1
|
@@ -1786,6 +1786,9 @@
|
|
|
1786
1786
|
'<span class="chat-unread-bubble-icon"><svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3.5v9M3.5 8l4.5 4.5L12.5 8"/></svg></span>' +
|
|
1787
1787
|
'<span class="chat-unread-bubble-count" aria-hidden="true"></span>' +
|
|
1788
1788
|
'</button>' +
|
|
1789
|
+
// 排队气泡宿主:贴在对话显示区域的右下角(在"回复中"状态线上方),
|
|
1790
|
+
// 不进输入框 panel。updateQueueBar() 仅在 queuedMessages 非空时显形。
|
|
1791
|
+
'<div id="queue-bar-host" class="queue-bar-host" hidden></div>' +
|
|
1789
1792
|
'</div>' +
|
|
1790
1793
|
'<div id="blank-chat" class="blank-chat' + (state.selectedId ? " hidden" : "") + '">' +
|
|
1791
1794
|
'<div class="blank-chat-inner">' +
|
|
@@ -1814,10 +1817,7 @@
|
|
|
1814
1817
|
'</div>' +
|
|
1815
1818
|
'</div>' +
|
|
1816
1819
|
'<div class="input-panel' + (state.selectedId ? "" : " hidden") + '">' +
|
|
1817
|
-
//
|
|
1818
|
-
// 显形。位置在 composer-top-row(含 "回复中" 状态条)之上,对话框右下角,
|
|
1819
|
-
// 不进入输入框内部。所有内容由 updater 注入;这里只保留稳定的外层骨架。
|
|
1820
|
-
'<div id="queue-bar-host" class="queue-bar-host" hidden></div>' +
|
|
1820
|
+
// #queue-bar-host 已搬到 #chat-output 内部(对话区右下角),不在这里了。
|
|
1821
1821
|
'<div class="composer-top-row">' +
|
|
1822
1822
|
'<div id="todo-progress" class="todo-progress hidden">' +
|
|
1823
1823
|
'<div class="todo-progress-header" id="todo-progress-toggle">' +
|
|
@@ -8214,9 +8214,9 @@
|
|
|
8214
8214
|
return "会话已结束";
|
|
8215
8215
|
}
|
|
8216
8216
|
// 结构化会话在出 token 时,输入框仍然可用——告诉用户默认行为是排队,
|
|
8217
|
-
//
|
|
8217
|
+
// 想插队请按气泡上的 ⚡ 按钮。短语尽量短,避免在窄屏手机上换行。
|
|
8218
8218
|
if (isStructuredSession(session) && session.structuredState && session.structuredState.inFlight) {
|
|
8219
|
-
return "回复中…Enter 排队 ·
|
|
8219
|
+
return "回复中…Enter 排队 · ⚡ 立即发送";
|
|
8220
8220
|
}
|
|
8221
8221
|
return "";
|
|
8222
8222
|
}
|
|
@@ -12544,12 +12544,15 @@
|
|
|
12544
12544
|
return 0;
|
|
12545
12545
|
}
|
|
12546
12546
|
|
|
12547
|
-
function renderQueueBarHtml(items, inFlight, atCapacity
|
|
12547
|
+
function renderQueueBarHtml(items, inFlight, atCapacity) {
|
|
12548
|
+
// 底部独立 ⚡ 按钮已下线,每条 chip 内部自带 ⚡ "立即"按钮 ——
|
|
12549
|
+
// 这样用户一眼就能看出"是把哪一条插队"。
|
|
12548
12550
|
var single = items.length <= 1;
|
|
12549
12551
|
var barClass = "queue-bar";
|
|
12550
12552
|
if (atCapacity) barClass += " queue-bar-capacity";
|
|
12551
12553
|
if (inFlight) barClass += " queue-bar-inflight";
|
|
12552
12554
|
var expandedIdx = queueBarExpandedIndex(items.length);
|
|
12555
|
+
var promoteTip = inFlight ? "中断当前回复,立即发送这条" : "立即发送这条";
|
|
12553
12556
|
var chips = "";
|
|
12554
12557
|
for (var i = 0; i < items.length; i++) {
|
|
12555
12558
|
var raw = items[i] == null ? "" : String(items[i]);
|
|
@@ -12557,13 +12560,21 @@
|
|
|
12557
12560
|
var itemClass = "queue-bar-item";
|
|
12558
12561
|
if (isExpanded) itemClass += " expanded";
|
|
12559
12562
|
if (single) itemClass += " queue-bar-item-single";
|
|
12560
|
-
//
|
|
12561
|
-
var titleAttr = isExpanded ? raw + "
|
|
12563
|
+
// chip 本体是"拖拽起手区";内部 ⚡ 按钮独占 click 用于立即发送、× 用于删除。
|
|
12564
|
+
var titleAttr = isExpanded ? raw + "(按住可拖动调序)" : raw;
|
|
12562
12565
|
chips +=
|
|
12563
12566
|
'<li class="' + itemClass + '" data-index="' + i + '" data-action="drag"' +
|
|
12564
12567
|
' title="' + escapeHtml(titleAttr) + '">' +
|
|
12565
12568
|
'<span class="queue-bar-item-index" aria-hidden="true">' + (i + 1) + '</span>' +
|
|
12566
12569
|
'<span class="queue-bar-item-text">' + escapeHtml(queueChipTruncate(raw)) + '</span>' +
|
|
12570
|
+
'<button type="button" class="queue-bar-item-promote" data-action="promote-item"' +
|
|
12571
|
+
' title="' + escapeHtml(promoteTip) + '" aria-label="立即发送这条"' +
|
|
12572
|
+
' tabindex="' + (isExpanded ? "0" : "-1") + '">' +
|
|
12573
|
+
'<svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">' +
|
|
12574
|
+
'<path d="M13 2 L4 14 L11 14 L10 22 L20 9 L13 9 Z"/>' +
|
|
12575
|
+
'</svg>' +
|
|
12576
|
+
'<span class="queue-bar-item-promote-label">立即</span>' +
|
|
12577
|
+
'</button>' +
|
|
12567
12578
|
'<button type="button" class="queue-bar-item-delete" data-action="delete"' +
|
|
12568
12579
|
' aria-label="删除这条排队消息" title="删除" tabindex="' + (isExpanded ? "0" : "-1") + '">' +
|
|
12569
12580
|
'<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor"' +
|
|
@@ -12575,13 +12586,6 @@
|
|
|
12575
12586
|
return (
|
|
12576
12587
|
'<div class="' + barClass + '" data-queue-bar="1">' +
|
|
12577
12588
|
'<ol class="queue-bar-list" data-queue-list="1">' + chips + '</ol>' +
|
|
12578
|
-
'<button type="button" class="queue-bar-promote" data-action="promote"' +
|
|
12579
|
-
' title="中断当前回复,立刻发送队首这条"' +
|
|
12580
|
-
' aria-label="' + escapeHtml(immediateLabel) + '队首">' +
|
|
12581
|
-
'<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">' +
|
|
12582
|
-
'<path d="M13 2 L4 14 L11 14 L10 22 L20 9 L13 9 Z"/>' +
|
|
12583
|
-
'</svg>' +
|
|
12584
|
-
'</button>' +
|
|
12585
12589
|
'</div>'
|
|
12586
12590
|
);
|
|
12587
12591
|
}
|
|
@@ -12607,9 +12611,8 @@
|
|
|
12607
12611
|
host.hidden = false;
|
|
12608
12612
|
var inFlight = !!(session.structuredState && session.structuredState.inFlight && session.status === "running");
|
|
12609
12613
|
var atCapacity = queue.length >= QUEUE_BAR_MAX;
|
|
12610
|
-
var immediateLabel = inFlight ? "立即" : "发送";
|
|
12611
12614
|
|
|
12612
|
-
host.innerHTML = renderQueueBarHtml(queue, inFlight, atCapacity
|
|
12615
|
+
host.innerHTML = renderQueueBarHtml(queue, inFlight, atCapacity);
|
|
12613
12616
|
}
|
|
12614
12617
|
|
|
12615
12618
|
// 只切换 .expanded class,不重建 DOM —— 避免鼠标移过去触发的重建
|
|
@@ -12711,10 +12714,6 @@
|
|
|
12711
12714
|
});
|
|
12712
12715
|
}
|
|
12713
12716
|
|
|
12714
|
-
function queueBarPromoteHead() {
|
|
12715
|
-
queueBarPromoteIndex(0);
|
|
12716
|
-
}
|
|
12717
|
-
|
|
12718
12717
|
// 把队列里第 index 条剥下来,作为新的输入立刻发送出去。
|
|
12719
12718
|
// - inFlight:interrupt + preserveQueue(中断当前回复,保留其它排队)
|
|
12720
12719
|
// - 非 inFlight:当作普通新消息发出去
|
|
@@ -12815,7 +12814,6 @@
|
|
|
12815
12814
|
startY: ev.clientY,
|
|
12816
12815
|
gap: gap,
|
|
12817
12816
|
queueSnapshot: queue,
|
|
12818
|
-
moved: false, // 没真正拖动过 → 抬手时按 tap 处理:promote 这条
|
|
12819
12817
|
};
|
|
12820
12818
|
|
|
12821
12819
|
chipEl.classList.add("dragging");
|
|
@@ -12863,8 +12861,6 @@
|
|
|
12863
12861
|
if (!d || ev.pointerId !== d.pointerId) return;
|
|
12864
12862
|
ev.preventDefault();
|
|
12865
12863
|
var deltaY = ev.clientY - d.startY;
|
|
12866
|
-
// 4px 阈值过滤抖动 / 触屏轻微滑动;超过才算"真的在拖",否则抬手当 tap。
|
|
12867
|
-
if (Math.abs(deltaY) > 4) d.moved = true;
|
|
12868
12864
|
d.itemEl.style.transform = "translateY(" + deltaY + "px)";
|
|
12869
12865
|
|
|
12870
12866
|
// 拖动中心 Y 决定目标插入位置
|
|
@@ -12899,7 +12895,6 @@
|
|
|
12899
12895
|
var origIndex = d.origIndex;
|
|
12900
12896
|
var targetIndex = d.targetIndex;
|
|
12901
12897
|
var queueSnapshot = d.queueSnapshot;
|
|
12902
|
-
var wasTap = !d.moved;
|
|
12903
12898
|
|
|
12904
12899
|
// 清掉 inline transform 让 CSS 自然回位
|
|
12905
12900
|
d.siblings.forEach(function(el) {
|
|
@@ -12911,9 +12906,9 @@
|
|
|
12911
12906
|
state.queueBarDrag = null;
|
|
12912
12907
|
|
|
12913
12908
|
if (origIndex === targetIndex) {
|
|
12914
|
-
//
|
|
12909
|
+
// 没动 → 单纯刷新一下。立即发送由 chip 内部的 ⚡ 按钮触发,
|
|
12910
|
+
// 不在 chip 本体上做隐式 tap-to-promote(容易误触)。
|
|
12915
12911
|
updateQueueBar();
|
|
12916
|
-
if (wasTap) queueBarPromoteIndex(origIndex);
|
|
12917
12912
|
return;
|
|
12918
12913
|
}
|
|
12919
12914
|
|
|
@@ -12960,19 +12955,18 @@
|
|
|
12960
12955
|
var actionEl = ev.target && ev.target.closest ? ev.target.closest("[data-action]") : null;
|
|
12961
12956
|
if (!actionEl || !host.contains(actionEl)) return;
|
|
12962
12957
|
var action = actionEl.getAttribute("data-action");
|
|
12963
|
-
|
|
12964
|
-
|
|
12965
|
-
|
|
12966
|
-
// 把这条直接 promote 出去。
|
|
12967
|
-
ev.preventDefault();
|
|
12968
|
-
ev.stopPropagation();
|
|
12969
|
-
var idx = Number(actionEl.getAttribute("data-index"));
|
|
12970
|
-
queueBarPromoteIndex(idx);
|
|
12971
|
-
return;
|
|
12972
|
-
}
|
|
12958
|
+
// chip 本体(data-action="drag")由 pointerdown 走 drag-or-tap 流程;
|
|
12959
|
+
// click 阶段不处理,否则会和拖拽收尾冲突。
|
|
12960
|
+
if (action === "drag") return;
|
|
12973
12961
|
ev.preventDefault();
|
|
12974
12962
|
ev.stopPropagation();
|
|
12975
|
-
if (action === "promote") {
|
|
12963
|
+
if (action === "promote-item") {
|
|
12964
|
+
// chip 内部的 ⚡ "立即"按钮:把这一条剥下来插队发送,让用户一眼看到
|
|
12965
|
+
// 自己点的就是哪一条。
|
|
12966
|
+
var pItem = actionEl.closest(".queue-bar-item");
|
|
12967
|
+
if (pItem) queueBarPromoteIndex(Number(pItem.getAttribute("data-index")));
|
|
12968
|
+
return;
|
|
12969
|
+
}
|
|
12976
12970
|
if (action === "delete") {
|
|
12977
12971
|
var itemEl = actionEl.closest(".queue-bar-item");
|
|
12978
12972
|
if (itemEl) queueBarDeleteItem(Number(itemEl.getAttribute("data-index")));
|
|
@@ -12990,10 +12984,11 @@
|
|
|
12990
12984
|
if (state.queueBarDrag) return;
|
|
12991
12985
|
setQueueBarHoverIndex(null);
|
|
12992
12986
|
});
|
|
12993
|
-
// 整个气泡都是拖拽起手区。
|
|
12987
|
+
// 整个气泡都是拖拽起手区。chip 内部的 ⚡ / × 按钮通过 closest 跳过,
|
|
12988
|
+
// 让 click 阶段去处理它们。
|
|
12994
12989
|
host.addEventListener("pointerdown", function(ev) {
|
|
12995
12990
|
if (ev.button !== undefined && ev.button !== 0) return;
|
|
12996
|
-
if (ev.target && ev.target.closest && ev.target.closest('[data-action="delete"], [data-action="promote"]')) return;
|
|
12991
|
+
if (ev.target && ev.target.closest && ev.target.closest('[data-action="delete"], [data-action="promote-item"]')) return;
|
|
12997
12992
|
var chip = ev.target && ev.target.closest ? ev.target.closest('.queue-bar-item') : null;
|
|
12998
12993
|
if (!chip) return;
|
|
12999
12994
|
// 拖拽前先把这条切到 expanded(鼠标按下时通常已经 hovered,但触屏没 hover)
|
|
@@ -13044,38 +13039,15 @@
|
|
|
13044
13039
|
});
|
|
13045
13040
|
}
|
|
13046
13041
|
|
|
13047
|
-
//
|
|
13048
|
-
//
|
|
13042
|
+
// 结构化会话的"对话视图"现在只渲染真实的 user/assistant turn。排队消息(还没
|
|
13043
|
+
// flush 出去那批)由 .queue-bar 在对话区右下角统一展示,不再在 chat 流里贴一份
|
|
13044
|
+
// 半透明 "排队中" 用户气泡——避免同一条消息在 UI 上出现两次。
|
|
13049
13045
|
function buildMessagesForRender(session, messages) {
|
|
13050
13046
|
var sanitized = Array.isArray(messages) ? stripRenderOnlyStructuredMessages(messages) : [];
|
|
13051
13047
|
var base = Array.isArray(sanitized) ? sanitized.slice() : [];
|
|
13052
13048
|
if (!session || session.sessionKind !== "structured") {
|
|
13053
13049
|
return base;
|
|
13054
13050
|
}
|
|
13055
|
-
var queued = getStructuredQueuedInputs(session);
|
|
13056
|
-
if (queued && queued.length > 0) {
|
|
13057
|
-
// Collect recent user message texts to deduplicate against queued items.
|
|
13058
|
-
// A queued message that already appears as a real user turn should not
|
|
13059
|
-
// be rendered a second time with the "排队中" badge.
|
|
13060
|
-
var existingUserTexts = {};
|
|
13061
|
-
for (var ei = base.length - 1; ei >= 0 && Object.keys(existingUserTexts).length < queued.length + 5; ei--) {
|
|
13062
|
-
var em = base[ei];
|
|
13063
|
-
if (em && em.role === "user" && Array.isArray(em.content)) {
|
|
13064
|
-
for (var ej = 0; ej < em.content.length; ej++) {
|
|
13065
|
-
if (em.content[ej] && em.content[ej].type === "text" && em.content[ej].text) {
|
|
13066
|
-
existingUserTexts[em.content[ej].text] = (existingUserTexts[em.content[ej].text] || 0) + 1;
|
|
13067
|
-
}
|
|
13068
|
-
}
|
|
13069
|
-
}
|
|
13070
|
-
}
|
|
13071
|
-
for (var qi = 0; qi < queued.length; qi++) {
|
|
13072
|
-
if (existingUserTexts[queued[qi]]) {
|
|
13073
|
-
existingUserTexts[queued[qi]]--;
|
|
13074
|
-
continue; // Skip — this queued text is already shown as a real message
|
|
13075
|
-
}
|
|
13076
|
-
base.push({ role: "user", content: [{ type: "text", text: queued[qi], __queued: true }] });
|
|
13077
|
-
}
|
|
13078
|
-
}
|
|
13079
13051
|
if (session.structuredState && session.structuredState.inFlight) {
|
|
13080
13052
|
var last = base[base.length - 1];
|
|
13081
13053
|
if (!last || last.role !== "assistant") {
|
|
@@ -6457,23 +6457,33 @@
|
|
|
6457
6457
|
}
|
|
6458
6458
|
|
|
6459
6459
|
/* ─────────────────────────────────────────────────────────────────────
|
|
6460
|
-
排队消息条(.queue-bar)——
|
|
6461
|
-
|
|
6462
|
-
|
|
6460
|
+
排队消息条(.queue-bar)—— 绝对定位在对话显示区域(.chat-container)的右下角,
|
|
6461
|
+
压在 "回复中" 状态线之上。
|
|
6462
|
+
交互:
|
|
6463
|
+
· 默认只展开队首 chip(橙色完整气泡,显示编号 + 文本 + ⚡ 立即 + × 删除)
|
|
6463
6464
|
· 其他 chip 收成一根小横杠(橙色细线,宽 32px 高 4px)
|
|
6464
6465
|
· 鼠标悬到任一横杠 → 该条展开、原本展开的收回横杠
|
|
6465
|
-
·
|
|
6466
|
-
|
|
6466
|
+
· 悬停期间可按住 chip 本体上下拖拽换序
|
|
6467
|
+
· chip 内部 ⚡ "立即"按钮:把这一条剥下来插队发送(看得见点的是哪一条)
|
|
6468
|
+
· chip 内部 × 按钮:单独删除这一条
|
|
6467
6469
|
───────────────────────────────────────────────────────────────────── */
|
|
6468
6470
|
.queue-bar-host {
|
|
6471
|
+
position: absolute;
|
|
6472
|
+
right: 14px;
|
|
6473
|
+
bottom: 10px;
|
|
6474
|
+
max-width: calc(100% - 28px);
|
|
6475
|
+
z-index: 14; /* 必须高于 .chat-unread-bubble(z-index 13) 和 ::after fade(z-index 12) */
|
|
6476
|
+
pointer-events: none; /* host 自身不挡点击,bar 内子节点 auto */
|
|
6469
6477
|
display: flex;
|
|
6470
6478
|
justify-content: flex-end;
|
|
6471
|
-
|
|
6472
|
-
position: relative;
|
|
6473
|
-
z-index: 2;
|
|
6474
|
-
pointer-events: none; /* host 自身不挡点击,bar 内子节点 auto */
|
|
6479
|
+
transition: bottom 220ms var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1));
|
|
6475
6480
|
}
|
|
6476
6481
|
.queue-bar-host[hidden] { display: none; }
|
|
6482
|
+
/* 当"回到最新"胶囊也在显示时,把排队气泡条向上抬一截,避免叠在它头上。
|
|
6483
|
+
sibling 选择器走得通是因为 #queue-bar-host 在 DOM 里紧跟在 .chat-unread-bubble 后面。 */
|
|
6484
|
+
.chat-unread-bubble.visible ~ .queue-bar-host {
|
|
6485
|
+
bottom: 52px;
|
|
6486
|
+
}
|
|
6477
6487
|
|
|
6478
6488
|
.queue-bar {
|
|
6479
6489
|
pointer-events: auto;
|
|
@@ -6629,88 +6639,65 @@
|
|
|
6629
6639
|
}
|
|
6630
6640
|
.queue-bar-item-delete svg { flex-shrink: 0; }
|
|
6631
6641
|
|
|
6632
|
-
/* ⚡ 立即按钮 ——
|
|
6633
|
-
|
|
6642
|
+
/* ⚡ 立即按钮 —— 每个 chip 内部都自带一颗,跟在文本和 × 删除之间。
|
|
6643
|
+
展开态可见、可点;折叠态隐起来不参与 hit-test。 */
|
|
6644
|
+
.queue-bar-item-promote {
|
|
6634
6645
|
flex-shrink: 0;
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6646
|
+
display: inline-flex;
|
|
6647
|
+
align-items: center;
|
|
6648
|
+
gap: 3px;
|
|
6649
|
+
height: 18px;
|
|
6650
|
+
padding: 0 7px 0 6px;
|
|
6638
6651
|
border: none;
|
|
6652
|
+
border-radius: 999px;
|
|
6639
6653
|
cursor: pointer;
|
|
6640
6654
|
color: #fff;
|
|
6641
|
-
background:
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
box-shadow: 0
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6655
|
+
background: rgba(255, 255, 255, 0.22);
|
|
6656
|
+
font-size: 0.65rem;
|
|
6657
|
+
font-weight: 600;
|
|
6658
|
+
letter-spacing: 0.02em;
|
|
6659
|
+
line-height: 1;
|
|
6660
|
+
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
|
|
6661
|
+
opacity: 0;
|
|
6662
|
+
pointer-events: none;
|
|
6663
|
+
transition: opacity 120ms ease 60ms, background var(--transition-fast),
|
|
6664
|
+
box-shadow var(--transition-fast), transform 120ms ease;
|
|
6650
6665
|
}
|
|
6651
|
-
.queue-bar-promote
|
|
6652
|
-
|
|
6653
|
-
|
|
6666
|
+
.queue-bar-item.expanded .queue-bar-item-promote,
|
|
6667
|
+
.queue-bar-item.dragging .queue-bar-item-promote {
|
|
6668
|
+
opacity: 1;
|
|
6669
|
+
pointer-events: auto;
|
|
6654
6670
|
}
|
|
6655
|
-
.queue-bar-promote:
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6671
|
+
.queue-bar-item-promote:hover {
|
|
6672
|
+
background: rgba(255, 255, 255, 0.36);
|
|
6673
|
+
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45);
|
|
6674
|
+
}
|
|
6675
|
+
.queue-bar-item-promote:active { transform: scale(0.94); }
|
|
6676
|
+
.queue-bar-item-promote:focus-visible {
|
|
6677
|
+
outline: 2px solid #fff;
|
|
6678
|
+
outline-offset: 1px;
|
|
6679
|
+
}
|
|
6680
|
+
.queue-bar-item-promote svg { flex-shrink: 0; }
|
|
6681
|
+
.queue-bar-item-promote-label {
|
|
6682
|
+
display: inline;
|
|
6659
6683
|
}
|
|
6660
|
-
.queue-bar-promote svg { flex-shrink: 0; }
|
|
6661
|
-
.queue-bar-promote-label { display: none; } /* label 留作 aria,视觉不展示 */
|
|
6662
6684
|
|
|
6663
6685
|
/* 容量满了的视觉提示 —— 整组颜色稍暗 */
|
|
6664
|
-
.queue-bar.queue-bar-capacity .queue-bar-item
|
|
6665
|
-
.queue-bar.queue-bar-capacity .queue-bar-promote {
|
|
6686
|
+
.queue-bar.queue-bar-capacity .queue-bar-item {
|
|
6666
6687
|
background: linear-gradient(180deg, #a8522f 0%, #8e4426 100%);
|
|
6667
6688
|
}
|
|
6668
6689
|
|
|
6669
|
-
/*
|
|
6690
|
+
/* 窄屏:宽度收紧 + 横杠加粗便于指 + ⚡ 文字省略 */
|
|
6670
6691
|
@media (max-width: 560px) {
|
|
6671
|
-
.queue-bar-host {
|
|
6692
|
+
.queue-bar-host { right: 8px; bottom: 8px; }
|
|
6672
6693
|
.queue-bar { max-width: calc(100vw - 20px); }
|
|
6673
6694
|
.queue-bar-item { width: 40px; height: 6px; }
|
|
6695
|
+
.queue-bar-item-promote-label { display: none; }
|
|
6696
|
+
.queue-bar-item-promote { padding: 0 6px; }
|
|
6674
6697
|
}
|
|
6675
6698
|
|
|
6676
|
-
/*
|
|
6677
|
-
|
|
6678
|
-
让排队这件事在视觉上和"已发出"清楚拉开。 */
|
|
6679
|
-
.chat-message.user.queued {
|
|
6680
|
-
opacity: 0.92;
|
|
6681
|
-
}
|
|
6682
|
-
.chat-message.user.queued .chat-message-bubble,
|
|
6683
|
-
.chat-message.user.queued .chat-message-content {
|
|
6684
|
-
box-shadow: 0 0 0 1.5px rgba(197, 101, 61, 0.55) inset,
|
|
6685
|
-
0 1px 0 rgba(197, 101, 61, 0.10);
|
|
6686
|
-
background: linear-gradient(180deg, rgba(255, 245, 235, 0.85) 0%, rgba(255, 235, 220, 0.65) 100%);
|
|
6687
|
-
border-radius: 14px;
|
|
6688
|
-
position: relative;
|
|
6689
|
-
}
|
|
6690
|
-
.queued-badge {
|
|
6691
|
-
display: inline-flex;
|
|
6692
|
-
align-items: center;
|
|
6693
|
-
gap: 5px;
|
|
6694
|
-
font-size: 0.75rem;
|
|
6695
|
-
color: #fff;
|
|
6696
|
-
background: linear-gradient(180deg, var(--accent) 0%, #a8522f 100%);
|
|
6697
|
-
padding: 3px 10px 3px 9px;
|
|
6698
|
-
border-radius: 999px;
|
|
6699
|
-
font-weight: 600;
|
|
6700
|
-
margin-top: 6px;
|
|
6701
|
-
letter-spacing: 0.04em;
|
|
6702
|
-
box-shadow: 0 2px 6px rgba(197, 101, 61, 0.30);
|
|
6703
|
-
animation: queuePulse 1.5s ease-in-out infinite;
|
|
6704
|
-
}
|
|
6705
|
-
.queued-badge::before {
|
|
6706
|
-
content: '';
|
|
6707
|
-
width: 7px;
|
|
6708
|
-
height: 7px;
|
|
6709
|
-
border-radius: 50%;
|
|
6710
|
-
background: #fff;
|
|
6711
|
-
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.45);
|
|
6712
|
-
animation: queueDotPulse 1.0s ease-in-out infinite;
|
|
6713
|
-
}
|
|
6699
|
+
/* .chat-message.user.queued 与 .queued-badge 的 CSS 已下线 —— 排队消息现在只在
|
|
6700
|
+
右下角的 .queue-bar 里展示,不再以"半透明气泡 + 排队中徽章"形式占据 chat 流。 */
|
|
6714
6701
|
|
|
6715
6702
|
.input-hint {
|
|
6716
6703
|
font-size: 0.5rem; /* 8px — 让位给同一行的按钮,桌面端仍清晰可读 */
|