字体切全量、评论徽章优先级、友链自助申请卡片、友圈头像兜底
Deploy to Production / pre-check (push) Successful in 1m27s
Deploy to Production / build (push) Successful in 4m49s
Deploy to Production / deploy-edgeone (push) Successful in 3m50s
Deploy to Production / finalize (push) Successful in 21s
Deploy to Production / notify-failure (push) Skipped

- 字体:zql 从 subset(776K) 切换到全量(1.2MB woff2),subset 覆盖
  不足导致大量字回退系统字体,视觉不一致;全量一次加载彻底解决
- 评论徽章统一 comment-rendered 注入,优先级互斥:友链 > 友圈 >
  官职(后端 rank 字段),官方系统徽章(博主)独立显示
- 留言页新增友链自助申请入口卡片 + 弹窗表单(名称/链接/订阅/邮箱
  必填),提交进 api.200181.xyz 待审队列,审核结果邮件通知申请人
- 友圈头像:favicon 抓取失败时兜底第三方 favicon 服务
This commit is contained in:
QunLIn committed 2026-10-03 12:13:45 +08:00
1 parent e12da91314
commit 5fcbd2a7b6
4 files changed
+139 -85

No files matched your search

+5 -3
View File
@@ -1,6 +1,8 @@
@font-face {
font-family: 'zql';
src: url('/font/zql-v2-subset.woff2') format('woff2'),
url('/font/zql-v2-subset.woff') format('woff');
/* 2026-10-03 从 subset 切换到全量字体(1.2MB woff2):subset 覆盖不足,
很多字回退系统字体导致视觉不一致。全量仅比子集大 ~460KB,一次加载永久解决。 */
src: url('/font/zql-v2.woff2') format('woff2'),
url('/font/zql-v2.woff') format('woff');
font-display: swap;
}
}
+47 -81
View File
@@ -550,7 +550,6 @@ window.initArtalk = function() {
setTimeout(saveConf, 5000);
// ── Badge system: 友链 / 友圈 / 评论等级 ──
var badgesInjected = false;
var normalizeHost = function(h) {
return (h || '').replace(/^www\./, '');
@@ -621,108 +620,75 @@ var getPageKey = function() {
return window.artalkConfig ? (window.artalkConfig.pageKey || window.location.pathname) : window.location.pathname;
};
var processBadges = function() {
if (!linkMap && !feedMap) return;
// 友链 / 友圈徽章:数据来自 window.friendLinks / window.friendFeeds
// (评论等级官职徽章已迁到 comment-rendered 处理,见下方)
document.querySelectorAll('.atk-comment-wrap').forEach(function(wrap) {
var nickEl = wrap.querySelector('.atk-nick');
var avatarEl = wrap.querySelector('.atk-avatar');
if (!nickEl) return;
var nickText = (nickEl.textContent || '').trim();
var nickLower = nickText.toLowerCase();
var nickLink = nickEl.querySelector('a[href]');
var commentHost = null;
if (nickLink) {
try { commentHost = normalizeHost(new URL(nickLink.getAttribute('href')).hostname); } catch(e) {}
}
// 1. 友链 badge (green gradient) — from /api/links?all=1
if (linkMap && !nickEl.querySelector('.atk-link-badge')) {
var linkMatch = null;
if (commentHost && linkMap.hosts.has(commentHost)) {
linkMatch = linkMap.hosts.get(commentHost);
} else if (linkMap.names.has(nickLower)) {
linkMatch = linkMap.names.get(nickLower);
}
if (linkMatch) {
var lb = document.createElement('span');
lb.className = 'atk-link-badge';
lb.textContent = '友链';
lb.title = '友链: ' + linkMatch;
nickEl.appendChild(lb);
}
}
// 2. 友圈 badge (gold gradient) — from /api/feeds
if (feedMap && !nickEl.querySelector('.atk-feed-badge')) {
var feedMatch = null;
if (commentHost && feedMap.hosts.has(commentHost)) {
feedMatch = feedMap.hosts.get(commentHost);
} else if (feedMap.names.has(nickLower)) {
feedMatch = feedMap.names.get(nickLower);
}
if (feedMatch) {
var fb = document.createElement('span');
fb.className = 'atk-feed-badge';
fb.textContent = '友圈';
fb.title = '友圈: ' + feedMatch;
nickEl.appendChild(fb);
}
}
// 3. 评论等级徽章已由后端下发(badge_name/badge_color 官方槽渲染),不再本地注入
});
// ── 评论区徽章统一注入(comment-rendered 每条触发)──
// 优先级:官方系统徽章(博主等,Artalk 自渲染)独立显示;
// 主题徽章互斥取最高一级:友链 > 友圈 > 评论官职。
// 数据源:window.friendLinks/friendFeeds(友链、友圈)+ 后端 rank_* 字段(官职)。
var ensureBadgeMaps = function() {
if (!linkMap && window.friendLinks) linkMap = buildMap(window.friendLinks);
if (!feedMap && window.friendFeeds) feedMap = buildMap(window.friendFeeds);
return !!(linkMap || feedMap);
};
var injectAllBadges = function() {
if (badgesInjected) return;
badgesInjected = true;
var matchBadge = function(map, host, nickLower) {
if (!map) return null;
if (host && map.hosts.has(host)) return map.hosts.get(host);
if (map.names.has(nickLower)) return map.names.get(nickLower);
return null;
};
if (window.friendLinks) linkMap = buildMap(window.friendLinks);
if (window.friendFeeds) feedMap = buildMap(window.friendFeeds);
if (linkMap || feedMap) {
processBadges();
}
var injectBadge = function(nickEl, cls, text, title, color, bg) {
if (nickEl.querySelector('.' + cls)) return;
var b = document.createElement('span');
b.className = cls;
b.textContent = text;
if (title) b.title = title;
if (color) b.style.color = color;
if (bg) b.style.backgroundColor = bg;
nickEl.appendChild(b);
};
// 评论等级官职徽章——后端按全站真实评论数计算,随评论 API 下发
// rank_name/rank_title/rank_count/rank_color/rank_bg(不占用官方 badge 槽,
// 官方徽章如「博主」保留,官职徽章接在其后面)。配色沿用主题原版。
artalk.on('comment-rendered', function(node) {
try {
var data = null;
if (node && typeof node.getData === 'function') data = node.getData();
else if (node && node.comment && typeof node.comment.getData === 'function') data = node.comment.getData();
else data = node;
if (!data || !data.rank_name) return;
if (!data) return;
var el = null;
if (node && node.$el) el = node.$el;
else if (node && typeof node.getEl === 'function') el = node.getEl();
if (!el || !el.querySelector) return;
var nickEl = el.querySelector('.atk-nick');
if (!nickEl || nickEl.querySelector('.atk-rank-badge')) return;
var rb = document.createElement('span');
rb.className = 'atk-rank-badge';
rb.textContent = data.rank_name;
var tip = data.rank_title || data.rank_name;
if (data.rank_count != null) tip += ' (' + data.rank_count + '条评论)';
rb.title = tip;
rb.style.color = data.rank_color || '';
rb.style.backgroundColor = data.rank_bg || '';
nickEl.appendChild(rb);
if (!nickEl) return;
if (!ensureBadgeMaps()) return;
var nickLower = (data.nick || '').toLowerCase();
var host = null;
try { if (data.link) host = normalizeHost(new URL(data.link).hostname); } catch (e) {}
// 优先级:友链 > 友圈 > 官职(互斥,只注入一枚主题徽章)
var linkMatch = matchBadge(linkMap, host, nickLower);
if (linkMatch) {
injectBadge(nickEl, 'atk-link-badge', '友链', '友链: ' + linkMatch);
return;
}
var feedMatch = matchBadge(feedMap, host, nickLower);
if (feedMatch) {
injectBadge(nickEl, 'atk-feed-badge', '友圈', '友圈: ' + feedMatch);
return;
}
if (data.rank_name && !nickEl.querySelector('.atk-rank-badge')) {
var tip = data.rank_title || data.rank_name;
if (data.rank_count != null) tip += ' (' + data.rank_count + '条评论)';
injectBadge(nickEl, 'atk-rank-badge', data.rank_name, tip, data.rank_color || '', data.rank_bg || '');
}
} catch (e) { /* 徽章注入失败不影响评论 */ }
});
artalk.on('list-loaded', function() {
// Badge injection
badgesInjected = false;
setTimeout(injectAllBadges, 300);
// Add staggered animation to the comment list
var list = document.querySelector('.atk-list');
if (list) {