字体切全量、评论徽章优先级、友链自助申请卡片、友圈头像兜底
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
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:
1 parent
e12da91314
commit
5fcbd2a7b6
4 files changed
+139
-85
No files matched your search
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user