]> acesimba.cloud Git - codebuddy-web.git/commitdiff
feat: 粘贴弹窗整窗支持拖拽上传 + 拖拽高亮反馈
authorCodebuddy <codebuddy@localhost>
Sat, 29 Aug 2026 01:58:45 +0000 (09:58 +0800)
committerCodebuddy <codebuddy@localhost>
Sat, 29 Aug 2026 01:58:45 +0000 (09:58 +0800)
- 拖拽监听从 textarea 移到 #paste-modal 整层遮罩,modal 内任意位置都能接住拖放
  (事件冒泡同样覆盖 textarea,不会重复上传)
- dragover 统一 preventDefault,避免拖到非 textarea 区域时被浏览器默认行为接管
  (会直接打开文件/导航离开,可能中断会话)
- 设置 dropEffect='copy',光标显示复制而非禁止图标
- 拖拽进入时 dialog 加绿色外发光、输入框变虚线绿框;用 dragDepth 计数器避免
  子元素间移动时高亮闪烁,关闭弹窗时清理状态
- 仅在检测到文件时 preventDefault,保留拖文本进 textarea 正常插入
- 输入框下方新增拖拽提示文字

Co-Authored-By: CodeBuddy <noreply@codebuddy.ai>
frontend/index.html

index 41019695068840dc84880a90e9eb4414d2e7c584..fa2f39e687c9779009dfe330503fc4960bf4bd93 100644 (file)
@@ -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
           <button class="send-btn" id="paste-send">发送</button>
         </div>
       </div>
+      <div class="paste-drop-hint">也可把文件<b>拖到这里</b>上传(图片 / 视频 / zip / 任意格式,单个 ≤20MB)</div>
       <div style="font-size:11px; color:#666; margin-top:6px; text-align:right;">Ctrl+Enter 发送到终端输入行(不自动提交,需自行回车)</div>
       <div style="margin-top:12px; border-top:1px solid rgba(255,255,255,0.1); padding-top:10px;">
         <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:6px;">
@@ -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) {