diff --git a/assets/css/app.css b/assets/css/app.css index a884e0f..408371c 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -7000,33 +7000,42 @@ h6.md-h { font-size: 17px; color: var(--muted); } /* #78:评论里的「添加附件」。 用原生 file input(视觉隐藏),点 label 触发 —— 与站内其它上传入口同一手法。 */ +/* 🔴 #81(用户 2026-11-05):「评论里面拖文件上传附件,那个地方太小了。」 + + 原来是一个 `padding:4px 10px` 的小胶囊(高约 26px)+ 一行小字, + 拖动落点太小:触屏上不好瞄,桌面上也容易拖偏。 + ⇒ 改用与「任务附件」同一套 `.upbox`(96px 高的虚线大框)。 + 这里只做评论特有的微调,不去覆盖 `.upbox` 本体 —— + 那一套是站点级组件,改它会影响所有上传入口。 */ .cmt-attach-row { - display: flex; align-items: center; gap: 8px; - margin-top: 6px; + display: flex; flex-direction: column; gap: 8px; + margin-top: 8px; } -.cmt-attach-pick { - display: inline-flex; align-items: center; gap: 5px; - font-size: 12.5px; color: var(--muted); cursor: pointer; - padding: 4px 10px; border-radius: 999px; - border: 1px dashed var(--line); background: transparent; +/* 评论里的上传框比「任务附件」矮一点:评论框本身已经在下方, + 96px 会把整块讨论区推得太长;72px 在触屏上仍然好点。 */ +.cmt-upbox { min-height: 72px; padding: 10px 14px; gap: 3px; } +.cmt-upbox .upbox-ico { font-size: 18px; } +.cmt-upbox .upbox-msg { font-size: 13px; } +.cmt-upbox-sub { + font-size: 11.5px; color: var(--faint); margin-top: 1px; } -.cmt-attach-pick:hover { color: var(--brand); border-color: var(--brand); } -.cmt-attach-name { - font-size: 12px; color: var(--faint); - max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; +/* 拖拽经过时整框高亮(`.is-over` 由 task_panel.js 加在 `.cmt-attach-row` 上, + 而 `.upbox.is-over` 是站点级规则 —— 这里补一条子选择器把它传导下去) */ +.cmt-attach-row.is-over .cmt-upbox { + border-color: var(--brand); border-style: solid; + background: #FDF3EC; color: var(--brand); } -/* #79:评论附件区支持拖拽 —— 高亮用虚线框 + 浅主题底色,和上面那块 - 「任务附件」的 is-over 观感一致(同一个交互不该长两个样子)。 */ -.cmt-attach-row { - padding: 6px 8px; border-radius: 8px; - border: 1px dashed transparent; - transition: background-color .12s, border-color .12s; +/* 已选文件列表:一行一个,前面带个圆点;超长名截断 */ +.cmt-file-list { + display: flex; flex-direction: column; gap: 3px; + padding: 6px 10px; border-radius: var(--radius-s); + background: var(--surface-2, #F2F0EC); + font-size: 12px; color: var(--muted); } -.cmt-attach-row.is-over { - border-color: var(--brand); - background: color-mix(in srgb, var(--brand) 8%, transparent); +.cmt-file-list span { + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.cmt-attach-row.is-over .cmt-attach-pick { color: var(--brand); border-color: var(--brand); } +.cmt-file-list span::before { content: '📎 '; } .tk-sec-lb { flex: 0 0 34px; font-size: 12.5px; color: var(--faint); } .tk-seg { display: flex; gap: 6px; flex-wrap: wrap; } /* 面板里的状态徽标比卡片上的大一档(这里是要点的按钮,不是标签) */ diff --git a/assets/js/task_panel.js b/assets/js/task_panel.js index 201d7aa..8ae2b7f 100644 --- a/assets/js/task_panel.js +++ b/assets/js/task_panel.js @@ -576,17 +576,35 @@ try { input.files = dt.files; } catch (e) { /* 个别内核只读:下面提示照旧 */ } - /* 更新提示文字(用户要能确认"确实加上了哪几个") */ - var nameEl = zone.querySelector('[data-cmt-file-name]'); - if (nameEl) { - var names = []; - if (input.files) { - for (var k = 0; k < input.files.length; k++) { names.push(input.files[k].name); } - } - nameEl.textContent = names.length - ? names.join('、') - : '可点击选择,也可把文件拖进来'; + /* 更新已选文件列表(用户要能确认"确实加上了哪几个")。 + #81:从"一行逗号拼接"改成"一行一个" —— 拖 5 个文件时 + 逗号拼起来读不清,也看不出到底几个。 */ + cmtRenderNames(zone, input); + } + + /** + * 把 `input.files` 渲染成一行一个的列表(#81)。 + * + * ⚠️ 用 `textContent` 逐个 append,**不要** `innerHTML +=` 拼字符串 —— + * 文件名是用户可控的(`.jpg` 这种),拼进 innerHTML + * 就是 XSS。用 `document.createElement('span')` + `textContent` 才安全。 + * ⚠️ 列表为空时 `hidden`,非空才显示 —— 否则评论区永远挂着一块空灰条。 + */ + function cmtRenderNames(zone, input) { + var box = zone.querySelector('[data-cmt-file-name]'); + if (!box) { return; } + while (box.firstChild) { box.removeChild(box.firstChild); } + var n = input && input.files ? input.files.length : 0; + if (!n) { + box.hidden = true; + return; } + for (var i = 0; i < n; i++) { + var sp = document.createElement('span'); + sp.textContent = input.files[i].name; + box.appendChild(sp); + } + box.hidden = false; } /* dragover:必须 preventDefault,否则浏览器把文件当"打开"处理(页面跳走) */ @@ -618,17 +636,26 @@ cmtAddFiles(zone, files); }); - /* 点选也要更新提示(原生 onchange) */ + /* #81:新的上传框带 `role="button" tabindex="0"`(`.upbox` 的既有约定), + 键盘 Enter/Space 也要能打开文件选择 —— 只做鼠标的话键盘用户点不动。 */ + document.addEventListener('keydown', function (e) { + var t = e.target; + if (!t || !t.closest) { return; } + var zone = t.closest('[data-cmt-drop]'); + if (!zone) { return; } + if (e.key !== 'Enter' && e.key !== ' ') { return; } + e.preventDefault(); + var inp = zone.querySelector('[data-cmt-file-input]'); + if (inp) { inp.click(); } + }); + + /* 点选也要更新列表(原生 onchange)—— 与拖拽共用同一个渲染函数 */ document.addEventListener('change', function (e) { var t = e.target; if (!t || !t.hasAttribute || !t.hasAttribute('data-cmt-file-input')) { return; } var zone = t.closest ? t.closest('[data-cmt-drop]') : null; if (!zone) { return; } - var nameEl = zone.querySelector('[data-cmt-file-name]'); - if (!nameEl) { return; } - var names = []; - for (var i = 0; i < (t.files ? t.files.length : 0); i++) { names.push(t.files[i].name); } - nameEl.textContent = names.length ? names.join('、') : '可点击选择,也可把文件拖进来'; + cmtRenderNames(zone, t); }); /* 拖到框上要给 dragover preventDefault,否则浏览器不认这是落点(还会当"打开文件") */ diff --git a/templates/tasks/_panel.php b/templates/tasks/_panel.php index 6ed7ef4..5bcb9a3 100644 --- a/templates/tasks/_panel.php +++ b/templates/tasks/_panel.php @@ -436,22 +436,29 @@ $tpLate = $tpDue !== '' && $tpStatus !== 'done' && \App\Task::isOverdue($tpD ⚠️ 用原生 `` 而不是拖拽框:评论是一次性提交, 拖拽框那套(`data-tk-drop-box`)是"点了立刻上传",两者语义不同。 */ ?> `** —— - `` 的 `files` 是只读的,得用 `DataTransfer` 重建 - 一个 FileList 赋回去。这样表单提交时浏览器才会真的带上文件, - 否则只是"看起来加上了",提交是空的。 */ ?> + ⇒ 原来是一个 `padding:4px 10px` 的小胶囊 + 一行小字提示, + 拖动落点只有 ~26px 高,触屏上根本不好瞄,桌面上也经常拖偏。 + ⇒ 改成与**「任务附件」那块完全一样**的 `.upbox`: + 高 96px、虚线大框、加号图标 + 说明文字。 + 同一个交互在一个页面里不该长两个样子,也不该一个大一个小。 + + ⚠️ 这块的语义是"挂到评论表单、点发表才一起提交", + 而上面「任务附件」是"拖上去立刻上传" —— 外观一致但行为不同, + 所以说明文字要写清"随这条评论一起发出",避免用户以为已经传上去了。 + ⚠️ `data-cmt-drop` 仍是拖拽落点标记(task_panel.js 认它), + 不要改成 `data-tk-drop-box`(那是立刻上传那条路)。 */ ?>
-