From 98126cafe6a218fec6ff58555e62ddad5df7038c Mon Sep 17 00:00:00 2001 From: zqlit Date: Sat, 3 Oct 2026 16:59:34 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=84=E8=AE=BA=E5=BE=BD=E7=AB=A0DOM/?= =?UTF-8?q?=E5=B0=BA=E5=AF=B8=E7=BB=9F=E4=B8=80(=E6=8B=86badge-wrap+?= =?UTF-8?q?=E5=8D=95=E4=B8=80=E7=B1=BB=E5=90=8D)=E3=80=81=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dmain.css!important=E5=8A=AB=E6=8C=81=E5=BE=BD=E7=AB=A0?= =?UTF-8?q?=E5=B0=BA=E5=AF=B8=E3=80=81=E5=8F=8B=E9=93=BE=E5=8D=A1=E7=89=87?= =?UTF-8?q?=E6=8C=82=E5=88=B0comment=E7=BA=A7=E4=B8=8E=E8=BE=93=E5=85=A5?= =?UTF-8?q?=E6=A1=86=E5=AF=B9=E9=BD=90=E3=80=81=E5=8D=A1=E7=89=87=E5=8A=A8?= =?UTF-8?q?=E6=95=88+=E6=89=93=E5=AD=97=E6=9C=BA=E3=80=81=E7=94=B3?= =?UTF-8?q?=E8=AF=B7=E5=BC=B9=E7=AA=97=E6=8C=89=E9=92=AE=E9=94=99=E4=BD=8D?= =?UTF-8?q?=E4=B8=8E=E6=BB=9A=E5=8A=A8=E6=9D=A1=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/Ying/assets/css/main.css | 14 +-- themes/Ying/assets/js/modules/artalk.js | 85 ++++++++++++---- themes/Ying/layouts/page/comment.html | 15 ++- themes/Ying/layouts/partials/artalk.html | 120 +++++++++++++++-------- 4 files changed, 161 insertions(+), 73 deletions(-) diff --git a/themes/Ying/assets/css/main.css b/themes/Ying/assets/css/main.css index e780c329..ee9e5123 100644 --- a/themes/Ying/assets/css/main.css +++ b/themes/Ying/assets/css/main.css @@ -4607,19 +4607,15 @@ input[type=submit] { box-shadow: 0 2px 5px rgba(0,0,0,0.1); } +/* 评论徽章(博主/置顶等)的尺寸与配色统一由 layouts/partials/artalk.html 里的 + .atk-cmt-badge 规则管理。这里保留兼容但不再强制 padding/font-size,避免 + !important 覆盖导致博主/置顶徽章比其他徽章高 2px、宽 2px。 */ .atk-pinned-badge { - background-color: var(--text-highlight-color) !important; - color: #fff !important; - border-radius: 3px !important; - font-size: 12px !important; - padding: 1px 5px !important; + border-radius: 3px; } .atk-badge { - background-color: #999 !important; /* 普通徽章颜色 */ - color: #fff !important; - border-radius: 3px !important; - padding: 1px 5px !important; + border-radius: 3px; } /* Emoticons & Images */ diff --git a/themes/Ying/assets/js/modules/artalk.js b/themes/Ying/assets/js/modules/artalk.js index 38ae2995..68f88983 100644 --- a/themes/Ying/assets/js/modules/artalk.js +++ b/themes/Ying/assets/js/modules/artalk.js @@ -672,8 +672,10 @@ artalk.on('comment-rendered', function(node) { var linkMatch = matchBadge(linkMap, host, nickLower); var feedMatch = matchBadge(feedMap, host, nickLower); - // 官方系统徽章(博主等)由 Artalk 渲染在 .atk-badge-wrap,把它挪进 - // 昵称元素内,保证视觉顺序:系统徽章 > 头衔 > 友链 > 友圈 > 官职 + // 系统徽章(博主/置顶)由 Artalk 渲染在 .atk-badge-wrap 里,头衔/友链/友圈/官职 + // 则是直接插进昵称的 —— 两套 DOM 会导致尺寸与垂直对齐都不一致。这里把包装层 + // 拆掉,让所有徽章都成为昵称的直接子元素,视觉顺序: + // 系统徽章 > 头衔 > 友链 > 友圈 > 官职 var badgeWrap = el.querySelector('.atk-badge-wrap'); if (badgeWrap && badgeWrap.parentNode !== nickEl) nickEl.appendChild(badgeWrap); @@ -691,6 +693,20 @@ artalk.on('comment-rendered', function(node) { if (data.rank_count != null) tip += ' (' + data.rank_count + '条评论)'; injectBadge(nickEl, 'atk-rank-badge', data.rank_name, tip, data.rank_color || '', data.rank_bg || ''); } + + // 5) 拆掉 .atk-badge-wrap 包装层:把 博主/置顶 提成昵称的直接子元素(保持原顺序) + var wrap = nickEl.querySelector('.atk-badge-wrap'); + if (wrap && wrap.parentNode) { + var wrapParent = wrap.parentNode; + while (wrap.firstChild) wrapParent.insertBefore(wrap.firstChild, wrap); + wrapParent.removeChild(wrap); + } + // 6) 所有徽章挂同一个类,几何样式(尺寸/内边距/圆角/字重/对齐)只由 + // .atk-cmt-badge 一处定义,从此不会有"两种徽章尺寸不一致"的问题 + var allBadges = nickEl.querySelectorAll( + '.atk-badge, .atk-pinned-badge, .atk-title-badge, .atk-link-badge, .atk-feed-badge, .atk-rank-badge' + ); + for (var bi = 0; bi < allBadges.length; bi++) allBadges[bi].classList.add('atk-cmt-badge'); } catch (e) { /* 徽章注入失败不影响评论 */ } // ── 友链申请入口卡片:评论内容就是约定 URL(https://usj.cc/link-apply)时, @@ -716,7 +732,9 @@ artalk.on('comment-rendered', function(node) { var avImg = el2.querySelector('.atk-avatar img'); var avatarSrc = avImg ? avImg.getAttribute('src') : ''; var nickEl2 = el2.querySelector('.atk-nick'); - var sysBadge = (nickEl2 || el2).querySelector('.atk-badge-wrap'); + // wrap 已在上面拆掉,博主徽章现在是昵称的直接子元素 + var sysBadge = (nickEl2 || el2).querySelector('.atk-badge') || + el2.querySelector('.atk-badge'); var nickText = String(d2.nick || '博主'); // 隐藏评论常规元素(头像列/昵称行/页脚操作),整条变成一张卡片 @@ -730,40 +748,67 @@ artalk.on('comment-rendered', function(node) { if (meta) meta.style.display = 'none'; var main = el2.querySelector('.atk-main') || el2; - main.style.marginLeft = '0'; // 卡片占满整行,原头像列不再占位(修复错位) - var contentEl = main.querySelector('.atk-content'); + // 卡片挂在 .atk-comment 这一级,而不是塞进 .atk-content 里: + // .atk-main 被主题锁了 margin-left:34px !important(头像缩进),塞在里面 + // 卡片永远比评论输入框窄一圈;提到 .atk-comment 这一级就能和输入框同宽对齐。 + var commentEl = el2.querySelector('.atk-comment') || main.parentElement || el2; + if (main && main !== el2) main.style.display = 'none'; // 常规内容整块隐藏 + + var FL_DESC = '想和我交换友链?点击申请,审核结果会邮件通知你'; var card = document.createElement('div'); - card.className = 'atk-fl-apply'; + card.className = 'atk-fl-card'; // 独立类名:容器用的是 atk-fl-apply 做标记 // 跟随评论列表原生观感:白底 + 细边框,只有按钮带主题色 card.style.cssText = 'display:flex;align-items:center;gap:12px;padding:12px 14px;margin:2px 0;' + 'background:var(--bg-card,#fff);border:1px solid var(--border-main,#eeeeee);' + 'border-radius:10px;transition:border-color .2s,background .2s;'; card.innerHTML = - '' + + '' + '' + - '' + + '' + '' + nickText.replace(/' + '' + - '想和我交换友链?点击申请,审核结果会邮件通知你' + + '' + + '' + + '' + '' + - '申请友链'; + '申请友链'; // 昵称行追加官方徽章(博主),样式与评论区徽章一致 if (sysBadge) { var bw = sysBadge.cloneNode(true); - bw.style.marginLeft = '2px'; + bw.style.marginLeft = '0'; var nickRow = card.querySelector('span > span'); nickRow.appendChild(bw); } - if (contentEl) { - contentEl.innerHTML = ''; - contentEl.appendChild(card); - contentEl.style.cursor = 'pointer'; - } else { - main.appendChild(card); - } + // 卡片直接挂在评论节点(.atk-comment)下:宽度与评论输入框一致 + if (contentEl) contentEl.innerHTML = ''; + commentEl.appendChild(card); + + // ── 打字机效果(PJAX 安全:卡片被移除/替换时定时器自动停止) ── + // 注意:不要用 prefers-reduced-motion 跳过打字 —— Windows 关闭"动画效果" + // 或部分浏览器默认就会报告 reduce,会导致效果完全不出现。这里始终打字。 + try { + var typedEl = card.querySelector('.atk-fl-typed'); + var caretEl = card.querySelector('.atk-fl-caret'); + var alive = function () { return card.isConnected !== undefined ? card.isConnected : document.body.contains(card); }; + if (typedEl) { + var ti = 0; + setTimeout(function () { + if (!alive()) return; + var timer = setInterval(function () { + if (!alive()) { clearInterval(timer); return; } // PJAX 切页后自动停止 + ti += 1; + typedEl.textContent = FL_DESC.slice(0, ti); + if (ti >= FL_DESC.length) { + clearInterval(timer); + if (caretEl) caretEl.style.display = 'none'; + } + }, 42); + }, 320); // 等入场动画播完再打字,观感更自然 + } + } catch (e) {} el2.addEventListener('click', function () { if (window.flApplyOpenModal) window.flApplyOpenModal(); diff --git a/themes/Ying/layouts/page/comment.html b/themes/Ying/layouts/page/comment.html index 4b1de925..44ab980e 100644 --- a/themes/Ying/layouts/page/comment.html +++ b/themes/Ying/layouts/page/comment.html @@ -46,10 +46,19 @@ 'background:var(--bg-input,#fff);color:inherit;font-family:inherit}' + '#flApplyBox input:focus,#flApplyBox textarea:focus{outline:none;border-color:var(--theme-main,#07c160);' + 'box-shadow:0 0 0 3px var(--theme-main-20,rgba(7,193,96,.2))}' + - '#flSubmit{width:100%;background:var(--theme-main,#07c160);border:none;color:#fff;padding:10px;' + - 'border-radius:6px;font-size:14px;cursor:pointer;transition:filter .2s}' + + /* 主题 main.css 有一条全局 button 归一化规则(margin-left:23%; margin-top:10px; + border:1px solid; background:#222),会把提交按钮推右溢出弹窗 → 这里用 id 选择器压过它 */ + '#flSubmit{display:block;width:100%;margin:0;background:var(--theme-main,#07c160);border:none;color:#fff;' + + 'padding:11px 0;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:filter .2s}' + '#flSubmit:hover{filter:brightness(1.06)}' + - '#flSubmit:disabled{opacity:.6;cursor:default}'; + '#flSubmit:disabled{opacity:.6;cursor:default}' + + /* 弹窗滚动条:细一点、跟随主题色,别用系统那根粗滚动条 */ + '#flApplyBox{overflow-x:hidden;scrollbar-width:thin;scrollbar-color:rgba(140,150,160,.45) transparent}' + + '#flApplyBox::-webkit-scrollbar{width:6px;height:6px}' + + '#flApplyBox::-webkit-scrollbar-track{background:transparent}' + + '#flApplyBox::-webkit-scrollbar-thumb{background:rgba(140,150,160,.45);border-radius:3px}' + + '[data-theme="dark"] #flApplyBox{scrollbar-color:rgba(200,205,212,.35) transparent}' + + '[data-theme="dark"] #flApplyBox::-webkit-scrollbar-thumb{background:rgba(200,205,212,.35)}'; document.head.appendChild(style); mask = document.createElement('div'); diff --git a/themes/Ying/layouts/partials/artalk.html b/themes/Ying/layouts/partials/artalk.html index 5c919c23..367522a6 100644 --- a/themes/Ying/layouts/partials/artalk.html +++ b/themes/Ying/layouts/partials/artalk.html @@ -15,24 +15,30 @@ border-color: var(--frame-dark-color); background: transparent; } - /* ================= 评论徽章规格 ================= - 几何完全沿用原设计:inline-block + margin-left:4px + padding 0 6px - + 12px/500 字重 + line-height:18px + 1px 描边 + 3px 圆角。 - 注意:不要覆盖 Artalk 自带的 margin-right:6px,否则徽章会挤在一起。 */ - .atk-comment>.atk-main>.atk-header .atk-badge, - .atk-comment>.atk-main>.atk-header .atk-pinned-badge, - .atk-comment>.atk-main>.atk-header .atk-title-badge, - .atk-comment>.atk-main>.atk-header .atk-link-badge, - .atk-comment>.atk-main>.atk-header .atk-feed-badge, - .atk-comment>.atk-main>.atk-header .atk-rank-badge { - display: inline-block; - margin-left: 4px; - padding: 0 6px; - font-size: 12px; - font-weight: 500; - border-radius: 3px; - line-height: 18px; - vertical-align: middle; + /* ================= 评论徽章统一规格(单一来源) ================= + 几何沿用原设计:inline-block + margin-left:4px + padding 0 6px + 12px/500 + + line-height:18px + 1px 描边 + 3px 圆角。 + artalk.js 会把所有徽章(博主/置顶/头衔/友链/友圈/官职)都挂上 .atk-cmt-badge + 并拆掉 Artalk 的 .atk-badge-wrap 包装层,所以几何只在这里定义一次, + 不会再出现两种 DOM / 两种尺寸。各类型只保留配色差异。 + 注:margin-right 清零是为了不叠加 Artalk 给"非最后一个徽章"的 6px 右间距 + (否则 徽章→徽章 间距一宽一窄,看起来不齐)。 */ + .atk-comment .atk-cmt-badge, + .atk-comment .atk-badge, + .atk-comment .atk-pinned-badge, + .atk-comment .atk-title-badge, + .atk-comment .atk-link-badge, + .atk-comment .atk-feed-badge, + .atk-comment .atk-rank-badge { + display: inline-block !important; + margin-left: 4px !important; + margin-right: 0 !important; + padding: 0 6px !important; + font-size: 12px !important; + font-weight: 600 !important; + border-radius: 3px !important; + line-height: 18px !important; + vertical-align: middle !important; pointer-events: none; white-space: nowrap; } @@ -50,37 +56,24 @@ color: #6b7280; background: rgba(107,114,128,0.08); border: 1px solid rgba(107,114,128,0.15); - font-weight: 600; } .atk-title-badge { - font-weight: 600; color: #b8860b; background: rgba(184,134,11,0.08); border: 1px solid rgba(184,134,11,0.22); } - /* 博主(.atk-badge):浅底描边(与友链/友圈/官职同风格) + /* 博主(.atk-badge):实底 —— 白字 + 浅黑底 (!important 是为了盖掉 Artalk 写在元素上的内联背景色) */ - .atk-comment>.atk-main>.atk-header .atk-badge { - border: 1px solid rgba(55,65,81,0.18); - font-weight: 600; - color: #374151 !important; - background: rgba(55,65,81,0.06) !important; + .atk-comment .atk-badge { + border: 1px solid #333333; + color: #ffffff !important; + background: #333333 !important; } - [data-theme="dark"] .atk-comment>.atk-main>.atk-header .atk-badge { - border-color: rgba(229,231,235,0.2); - color: #e5e7eb !important; - background: rgba(229,231,235,0.08) !important; - } - /* 置顶徽章:浅底红字描边(与友链/友圈同风格,比实底红更协调、不刺眼) */ - .atk-comment>.atk-main>.atk-header .atk-pinned-badge { - border: 1px solid rgba(217,83,79,0.18); - color: #d9534f !important; - background: rgba(217,83,79,0.08) !important; - } - [data-theme="dark"] .atk-comment>.atk-main>.atk-header .atk-pinned-badge { - border-color: rgba(217,83,79,0.28); - color: #f0918d !important; - background: rgba(217,83,79,0.14) !important; + /* 置顶徽章:实底 —— 白字 + 浅红底(比 #d9534f / #ff6262 更浅,不刺眼) */ + .atk-comment .atk-pinned-badge { + border: 1px solid #e05a5a; + color: #ffffff !important; + background: #e05a5a !important; } /* ---- 暗色模式配色 ---- */ [data-theme="dark"] .atk-link-badge { @@ -103,6 +96,51 @@ background: rgba(251,191,36,0.12); border-color: rgba(251,191,36,0.2); } + /* ================= 友链申请入口卡片 ================= + PJAX 下每次切页评论区都会重建卡片 → 入场动画与打字机自然重播; + 打字机定时器在 artalk.js 里会检测卡片是否还在文档中(切页后自动停)。 */ + .atk-fl-card { + animation: flApplyIn .5s cubic-bezier(.22, 1, .36, 1) both; + } + @keyframes flApplyIn { + from { opacity: 0; transform: translateY(12px) scale(.98); } + to { opacity: 1; transform: none; } + } + .atk-fl-card:hover { + border-color: var(--theme-main-30, rgba(7,193,96,.3)) !important; + } + /* 打字机光标 */ + .atk-fl-card .atk-fl-caret { + display: inline-block; + width: 1px; + height: 1em; + margin-left: 2px; + vertical-align: -2px; + background: currentColor; + animation: flCaret .9s steps(1, end) infinite; + } + @keyframes flCaret { + 0%, 49% { opacity: 1; } + 50%, 100% { opacity: 0; } + } + /* 申请友链按钮:轻微上浮 + 主题色投影 */ + .atk-fl-card .atk-fl-btn { + transition: transform .2s ease, box-shadow .2s ease; + } + .atk-fl-card:hover .atk-fl-btn { + transform: translateY(-1px); + box-shadow: 0 4px 12px var(--theme-main-20, rgba(7,193,96,.2)); + } + .atk-fl-card .atk-fl-btn:active { + transform: translateY(0); + } + /* 尊重系统"减弱动态效果":只关掉入场动画和按钮位移, + 打字机与光标保留(打字机是文字渐显,不属于会造成不适的位移类动效) */ + @media (prefers-reduced-motion: reduce) { + .atk-fl-card { animation: none; } + .atk-fl-card .atk-fl-btn { transition: none; } + .atk-fl-card:hover .atk-fl-btn { transform: none; box-shadow: none; } + } .atk-main { backface-visibility: hidden; will-change: transform;