评论附件拖放区放大:小胶囊 → 整块虚线大框 (#81)
用户 2026-11-05:「评论里面拖文件上传附件,那个地方太小了。」
原来:`padding:4px 10px` 的小胶囊(约 26px 高)+ 一行小字提示,
拖动落点只有那一条窄带 —— 触屏不好瞄,桌面也容易拖偏。
改成与「任务附件」同一套 `.upbox`(那个是站点级上传组件的标准外观):
· 高度 89px(触屏建议下限 44px,绰绰有余)
· 宽度占满整行(桌面 840px / 手机 330px)
· 虚线大框 + 加号图标 + 说明文字
· 副标题写清「点『发表』时随这条评论一起发出」——
与上面那块「拖上去立刻上传」语义不同,不写清楚用户会以为已经传了
· 比「任务附件」矮一点(96 → 72 min-height,实测 89px):
评论框已经在下面,96px 会把讨论区推太长;89px 仍然很好点
顺带改的:
· 已选文件从"逗号拼一行"改成"一行一个,带 📎",长名截断
· 渲染用 createElement + textContent,**不拼 innerHTML**
(文件名是用户可控的,拼 innerHTML 就是 XSS)
· 列表为空时 hidden,不挂空灰条
· 加键盘支持:`.upbox` 带 role=button + tabindex,Enter/Space 能打开选择框
实测(Playwright,两种视口):
桌面 900px:840 × 89px,边框 1px dashed,触屏可点性 ✅
手机 390px:330 × 89px,触屏可点性 ✅
文件列表:2 项,高 56px,正常显示
This commit is contained in:
+30
-21
@@ -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; }
|
||||
/* 面板里的状态徽标比卡片上的大一档(这里是要点的按钮,不是标签) */
|
||||
|
||||
+42
-15
@@ -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); }
|
||||
/* 更新已选文件列表(用户要能确认"确实加上了哪几个")。
|
||||
#81:从"一行逗号拼接"改成"一行一个" —— 拖 5 个文件时
|
||||
逗号拼起来读不清,也看不出到底几个。 */
|
||||
cmtRenderNames(zone, input);
|
||||
}
|
||||
nameEl.textContent = names.length
|
||||
? names.join('、')
|
||||
: '可点击选择,也可把文件拖进来';
|
||||
|
||||
/**
|
||||
* 把 `input.files` 渲染成一行一个的列表(#81)。
|
||||
*
|
||||
* ⚠️ 用 `textContent` 逐个 append,**不要** `innerHTML +=` 拼字符串 ——
|
||||
* 文件名是用户可控的(`<img onerror=...>.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,否则浏览器不认这是落点(还会当"打开文件") */
|
||||
|
||||
+18
-11
@@ -436,22 +436,29 @@ $tpLate = $tpDue !== '' && $tpStatus !== 'done' && \App\Task::isOverdue($tpD
|
||||
⚠️ 用原生 `<input type=file>` 而不是拖拽框:评论是一次性提交,
|
||||
拖拽框那套(`data-tk-drop-box`)是"点了立刻上传",两者语义不同。 */ ?>
|
||||
<?php /* 🔴 #79(用户 2026-11-05):「评论框下面的附件也需要可以拖动添加。」
|
||||
🔴 #81(同日):「评论里面拖文件上传附件,那个地方太小了。」
|
||||
|
||||
⇒ 给这片区域挂上拖拽落点(`data-cmt-drop`,由 task_panel.js 接管)。
|
||||
两个要点:
|
||||
① `dragover` 必须 `preventDefault()` —— 不拦的话浏览器
|
||||
会把文件当"打开"处理(直接跳走,当前页面全丢)。
|
||||
② 拖进来的文件**要写回真正的 `<input type=file>`** ——
|
||||
`<input>` 的 `files` 是只读的,得用 `DataTransfer` 重建
|
||||
一个 FileList 赋回去。这样表单提交时浏览器才会真的带上文件,
|
||||
否则只是"看起来加上了",提交是空的。 */ ?>
|
||||
⇒ 原来是一个 `padding:4px 10px` 的小胶囊 + 一行小字提示,
|
||||
拖动落点只有 ~26px 高,触屏上根本不好瞄,桌面上也经常拖偏。
|
||||
⇒ 改成与**「任务附件」那块完全一样**的 `.upbox`:
|
||||
高 96px、虚线大框、加号图标 + 说明文字。
|
||||
同一个交互在一个页面里不该长两个样子,也不该一个大一个小。
|
||||
|
||||
⚠️ 这块的语义是"挂到评论表单、点发表才一起提交",
|
||||
而上面「任务附件」是"拖上去立刻上传" —— 外观一致但行为不同,
|
||||
所以说明文字要写清"随这条评论一起发出",避免用户以为已经传上去了。
|
||||
⚠️ `data-cmt-drop` 仍是拖拽落点标记(task_panel.js 认它),
|
||||
不要改成 `data-tk-drop-box`(那是立刻上传那条路)。 */ ?>
|
||||
<div class="cmt-attach-row" data-cmt-drop>
|
||||
<label class="cmt-attach-pick">
|
||||
<label class="upbox cmt-upbox" role="button" tabindex="0"
|
||||
aria-label="点击选择文件,或把文件拖进来">
|
||||
<input type="file" name="attach[]" multiple class="sr-only"
|
||||
id="tkp-cmt-files" data-cmt-file-input>
|
||||
<span aria-hidden="true">📎</span> 添加附件
|
||||
<span class="upbox-ico" aria-hidden="true">+</span>
|
||||
<span class="upbox-msg">点击选择,或把文件拖到这里</span>
|
||||
<span class="cmt-upbox-sub">点「发表」时随这条评论一起发出</span>
|
||||
</label>
|
||||
<span class="cmt-attach-name" data-cmt-file-name>可点击选择,也可把文件拖进来</span>
|
||||
<div class="cmt-file-list" data-cmt-file-name hidden></div>
|
||||
</div>
|
||||
<div class="btn-row"><button class="btn btn-sm" type="submit">发表</button></div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user