From: Codebuddy Date: Sat, 29 Aug 2026 01:58:45 +0000 (+0800) Subject: feat: 粘贴弹窗整窗支持拖拽上传 + 拖拽高亮反馈 X-Git-Url: http://acesimba.cloud/gitweb/?a=commitdiff_plain;h=e33800af9a313862b3c84c0ca62a024066f1fc58;p=codebuddy-web.git feat: 粘贴弹窗整窗支持拖拽上传 + 拖拽高亮反馈 - 拖拽监听从 textarea 移到 #paste-modal 整层遮罩,modal 内任意位置都能接住拖放 (事件冒泡同样覆盖 textarea,不会重复上传) - dragover 统一 preventDefault,避免拖到非 textarea 区域时被浏览器默认行为接管 (会直接打开文件/导航离开,可能中断会话) - 设置 dropEffect='copy',光标显示复制而非禁止图标 - 拖拽进入时 dialog 加绿色外发光、输入框变虚线绿框;用 dragDepth 计数器避免 子元素间移动时高亮闪烁,关闭弹窗时清理状态 - 仅在检测到文件时 preventDefault,保留拖文本进 textarea 正常插入 - 输入框下方新增拖拽提示文字 Co-Authored-By: CodeBuddy --- diff --git a/frontend/index.html b/frontend/index.html index 4101969..fa2f39e 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -123,6 +123,14 @@ body { position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%; heigh border-radius: 6px; color: #ff8585; font-size: 16px; line-height: 1; cursor: pointer; } .paste-close:hover { background: rgba(255,90,90,0.18); color: #fff; border-color: rgba(255,90,90,0.5); } +/* 拖拽文件到粘贴弹窗时的高亮反馈 */ +#paste-dialog.paste-drag-over { box-shadow: 0 0 0 3px rgba(78,204,163,0.28); } +#paste-dialog.paste-drag-over .input-row { + border-color: #4ecca3 !important; + background: rgba(78,204,163,0.10) !important; +} +.paste-drop-hint { font-size: 11px; color: #666; margin-top: 6px; text-align: center; } +.paste-drop-hint b { color: #4ecca3; font-weight: 600; } .picker-body { flex: 1; overflow: auto; padding: 28px; } .picker-main { display: flex; flex: 1; min-height: 0; } #skills-sidebar { @@ -372,6 +380,7 @@ body { position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%; heigh +
也可把文件拖到这里上传(图片 / 视频 / zip / 任意格式,单个 ≤20MB)
Ctrl+Enter 发送到终端输入行(不自动提交,需自行回车)
@@ -925,6 +934,7 @@ body { position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%; heigh // ========== 粘贴 modal(右上角 📋 粘贴按钮触发) ========== const pasteModal = document.getElementById('paste-modal'); + const pasteDialog = document.getElementById('paste-dialog'); const pasteInput = document.getElementById('paste-input'); const pasteSend = document.getElementById('paste-send'); const pasteAttach = document.getElementById('paste-attach'); @@ -994,6 +1004,9 @@ body { position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%; heigh } function closePasteModal() { pasteModal.style.display = 'none'; + // 清理拖拽高亮状态,避免下次打开时残留 + pasteDialog.classList.remove('paste-drag-over'); + dragDepth = 0; if (term && term.focus) term.focus(); } // 关闭并清空:清除已输入文本与待发送文件,再关闭窗口 @@ -1037,11 +1050,34 @@ body { position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%; heigh // 文字:浏览器默认插入 }); - // 拖拽文件到 modal(图片/视频/zip/任意) - pasteInput.addEventListener('dragover', (e) => { e.preventDefault(); }); - pasteInput.addEventListener('drop', async (e) => { + // 拖拽文件到粘贴弹窗(图片/视频/zip/任意) + // 监听整层遮罩而非只监听 textarea:拖到 modal 任意位置都能接住(事件冒泡同样覆盖 + // textarea,不会重复上传),且避免拖到非 textarea 区域时被浏览器默认行为接管 + // (浏览器会直接打开该文件 / 导航离开,可能中断当前会话)。 + let dragDepth = 0; // 计数器:避免鼠标在子元素间移动时高亮闪烁 + const setDragOver = (on) => { pasteDialog.classList.toggle('paste-drag-over', on); }; + + pasteModal.addEventListener('dragenter', (e) => { + if (!e.dataTransfer) return; + e.preventDefault(); + dragDepth++; + setDragOver(true); + }); + pasteModal.addEventListener('dragover', (e) => { + if (!e.dataTransfer) return; + e.preventDefault(); // 必须阻止默认,否则浏览器会直接打开文件 + e.dataTransfer.dropEffect = 'copy'; // 光标显示“复制”,而非禁止图标 + }); + pasteModal.addEventListener('dragleave', (e) => { + dragDepth = Math.max(0, dragDepth - 1); + if (dragDepth === 0) setDragOver(false); + }); + pasteModal.addEventListener('drop', async (e) => { + dragDepth = 0; + setDragOver(false); if (!e.dataTransfer || !e.dataTransfer.files) return; const files = Array.from(e.dataTransfer.files); + // 拖入的是文本:不阻止默认行为,保证 textarea 仍能正常插入文字 if (!files.length) return; e.preventDefault(); for (const f of files) {