release v1.2.6: AskUserQuestion preview panel, 401 atomic write fix, mobile scrollbar

This commit is contained in:
cc-dan
2026-03-11 00:40:37 +00:00
parent 6860f9a341
commit 96dbb81914
4 changed files with 194 additions and 16 deletions

View File

@@ -528,29 +528,98 @@
card.appendChild(body);
if (Array.isArray(q.options) && q.options.length > 0) {
const hasDesc = q.options.some(o => o.description);
// 左右分栏容器
const layout = document.createElement('div');
layout.className = 'ask-options-layout' + (hasDesc ? ' has-preview' : '');
const opts = document.createElement('div');
opts.className = 'ask-question-options';
// 右侧预览区(仅在有 description 时创建)
const preview = hasDesc ? document.createElement('div') : null;
if (preview) {
preview.className = 'ask-option-preview';
// 默认显示第一项
preview.textContent = q.options[0].description || '';
}
// 当前选中项(移动端 tap-to-preview 状态)
let selectedOpt = null;
let selectedBtn = null;
q.options.forEach((opt, i) => {
const item = document.createElement('button');
item.type = 'button';
item.className = 'ask-option-item';
item.addEventListener('click', () => appendAskOptionToInput(q, opt));
const title = document.createElement('div');
title.className = 'ask-option-label';
title.textContent = `${i + 1}. ${opt.label || ''}`;
item.appendChild(title);
if (opt.description) {
const desc = document.createElement('div');
desc.className = 'ask-option-desc';
desc.textContent = opt.description;
item.appendChild(desc);
// 桌面hover 切换预览
if (preview) {
item.addEventListener('mouseenter', () => {
preview.textContent = opt.description || '';
});
}
item.addEventListener('click', (e) => {
const isTouch = item.dataset.touchActivated === '1';
item.dataset.touchActivated = '';
if (isTouch) {
// 移动端:第一次 tap = 选中预览,不发送
if (selectedBtn !== item) {
if (selectedBtn) selectedBtn.classList.remove('ask-option-selected');
selectedBtn = item;
selectedOpt = opt;
item.classList.add('ask-option-selected');
if (preview) preview.textContent = opt.description || '';
return;
}
// 第二次 tap 同一项 = 发送
}
// 桌面直接发送
appendAskOptionToInput(q, opt);
});
item.addEventListener('touchstart', () => {
item.dataset.touchActivated = '1';
}, { passive: true });
opts.appendChild(item);
});
card.appendChild(opts);
layout.appendChild(opts);
if (preview) {
layout.appendChild(preview);
// 预览区最小高度 = 左侧选项列表总高度(渲染后同步)
requestAnimationFrame(() => {
preview.style.minHeight = opts.offsetHeight + 'px';
});
}
// 移动端确认按钮
if (hasDesc) {
const confirmBtn = document.createElement('button');
confirmBtn.type = 'button';
confirmBtn.className = 'ask-confirm-btn';
confirmBtn.textContent = '确认选择';
confirmBtn.addEventListener('click', () => {
if (selectedOpt) {
appendAskOptionToInput(q, selectedOpt);
} else if (q.options.length > 0) {
appendAskOptionToInput(q, q.options[0]);
}
});
layout.appendChild(confirmBtn);
}
card.appendChild(layout);
}
wrapper.appendChild(card);
@@ -681,7 +750,15 @@
thumbEl.style.top = thumbTop + 'px';
}
messagesDiv.addEventListener('scroll', () => updateScrollbar(), { passive: true });
messagesDiv.addEventListener('scroll', () => {
updateScrollbar();
// 移动端:滚动时短暂显示滑块,停止后淡出
scrollbarEl.classList.add('scrolling');
clearTimeout(scrollbarEl._hideTimer);
scrollbarEl._hideTimer = setTimeout(() => {
if (!isDragging) scrollbarEl.classList.remove('scrolling');
}, 1200);
}, { passive: true });
new ResizeObserver(updateScrollbar).observe(messagesDiv);
// Drag logic

View File

@@ -49,11 +49,9 @@ body {
-webkit-tap-highlight-color: transparent;
}
/* Scrollbar */
::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: var(--scrollbar-track); }
::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: #b0a090; }
/* 全局隐藏原生滚动条,聊天区由 custom-scrollbar 接管 */
::-webkit-scrollbar { display: none; }
* { scrollbar-width: none; }
/* === Login === */
.login-overlay {
@@ -369,6 +367,16 @@ body {
.custom-scrollbar.active {
opacity: 1;
}
/* 移动端触摸后 hover 会粘滞 — 完全禁用 hover 触发,只靠 .active拖动时显示 */
@media (pointer: coarse) {
.messages-wrap:hover .custom-scrollbar {
opacity: 0;
}
/* 移动端滚动时用独立的类显示滑块,不走 .active */
.custom-scrollbar.scrolling {
opacity: 1;
}
}
.custom-scrollbar-thumb {
position: absolute;
right: 0;
@@ -388,6 +396,28 @@ body {
cursor: grab;
}
.custom-scrollbar-thumb.dragging { cursor: grabbing; }
/* 移动端触摸设备:加宽滑块与轨道,便于手指操作;默认隐藏,拖动时显示 */
@media (pointer: coarse) {
.custom-scrollbar {
width: 18px;
right: 0;
opacity: 0;
}
.custom-scrollbar.active {
opacity: 1;
}
.custom-scrollbar-thumb {
width: 8px;
right: 5px;
min-height: 40px;
border-radius: 4px;
}
.custom-scrollbar-thumb:hover,
.custom-scrollbar-thumb.dragging {
width: 14px;
right: 2px;
}
}
.welcome-msg {
text-align: center;
margin: auto;
@@ -640,10 +670,64 @@ body {
color: var(--text-primary);
margin-bottom: 8px;
}
/* 左右分栏布局 */
.ask-options-layout {
display: flex;
flex-direction: column;
gap: 6px;
}
.ask-options-layout.has-preview {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto;
gap: 8px;
align-items: start;
}
.ask-question-options {
display: flex;
flex-direction: column;
gap: 6px;
grid-row: 1;
grid-column: 1;
}
/* 右侧预览区 */
.ask-option-preview {
grid-row: 1;
grid-column: 2;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 10px 12px;
font-size: 12px;
line-height: 1.6;
color: var(--text-secondary);
min-height: 60px;
transition: background 0.15s;
white-space: pre-wrap;
word-break: break-word;
}
/* 确认按钮 — 仅移动端 */
.ask-confirm-btn {
display: none;
grid-row: 2;
grid-column: 1 / -1;
width: 100%;
padding: 9px 0;
border: 1.5px solid var(--accent);
border-radius: 8px;
background: transparent;
color: var(--accent);
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: background 0.12s, color 0.12s;
}
.ask-confirm-btn:active {
background: var(--accent);
color: #fff;
}
@media (pointer: coarse) {
.ask-confirm-btn { display: block; }
}
.ask-option-item {
border: 1px solid var(--border-color);
@@ -659,6 +743,10 @@ body {
background: var(--accent-light);
border-color: var(--accent);
}
.ask-option-item.ask-option-selected {
background: var(--accent-light);
border-color: var(--accent);
}
.ask-option-label {
font-size: 12px;
font-weight: 600;