feat(artalk): 增强评论系统功能与多语言支持

- 引入 Artalk 多语言包支持中英文切换
- 配置评论区域支持多语言提示与界面文本
- 优化编辑器功能,启用 Markdown、表情、@提醒等
- 改进评论时间显示逻辑,支持相对时间与本地化格式
- 添加管理员评论徽章标识
- 增强暗色模式与移动端适配样式
- 优化 CSS 样式,包括链接、输入框、工具栏等视觉效果
- 完善 Artalk 实例销毁逻辑,提升稳定性
- 移除旧版语言更新方法,统一通过配置管理
- 删除冗余 Avatar 样式以简化维护
This commit is contained in:
hehh
2025-11-25 13:21:48 +08:00
parent 24e0aae3f3
commit f2644b4fe6
3 changed files with 124 additions and 59 deletions

View File

@@ -287,6 +287,9 @@
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="js/config.js?version=20251125"></script> <script src="js/config.js?version=20251125"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/artalk/2.9.1/Artalk.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/artalk/2.9.1/Artalk.js"></script>
<!-- 引入多语言包(按需) -->
<script src="https://cdn.jsdelivr.net/npm/artalk@latest/dist/i18n/zh-cn.js"></script>
<script src="https://cdn.jsdelivr.net/npm/artalk@latest/dist/i18n/en.js"></script>
<script src="js/about.js?version=20251125"></script> <script src="js/about.js?version=20251125"></script>
</body> </body>
</html> </html>

View File

@@ -124,7 +124,6 @@
transform: translateY(0) !important; transform: translateY(0) !important;
} }
/* 修改发送按钮默认显示为"发送" */
.atk-send-btn:before { .atk-send-btn:before {
content: "发送" !important; content: "发送" !important;
} }
@@ -173,12 +172,6 @@
border-bottom: 1px solid rgba(108, 92, 231, 0.2) !important; border-bottom: 1px solid rgba(108, 92, 231, 0.2) !important;
} }
.atk-avatar {
border-radius: 50% !important;
box-shadow: 0 0 10px rgba(108, 92, 231, 0.2) !important;
transition: all 0.3s ease;
object-fit: cover; /* 修复头像拉伸问题 */
}
.atk-comment .atk-header { .atk-comment .atk-header {
padding: 0 !important; padding: 0 !important;
@@ -336,11 +329,6 @@
color: #00cec9 !important; color: #00cec9 !important;
} }
[data-theme="night"] .atk-avatar {
border: 2px solid #00cec9 !important;
box-shadow: 0 0 10px rgba(0, 206, 201, 0.3) !important;
}
/* Mobile specific styles */ /* Mobile specific styles */
.atk-mobile .atk-main-editor { .atk-mobile .atk-main-editor {
border-radius: 16px !important; border-radius: 16px !important;
@@ -514,6 +502,33 @@
color: #ef4444 !important; color: #ef4444 !important;
} }
/* 评论内容链接样式 */
.atk-comment-content a {
color: #3498db;
text-decoration: underline;
}
.atk-comment-content a:hover {
color: #2980b9;
}
/* 更圆润的输入框 */
.atk-editor-wrap .atk-editor-textarea {
border-radius: 12px !important;
padding: 12px !important;
}
/* 工具栏图标间距优化 */
.atk-editor-toolbar .atk-btn {
margin: 2px !important;
}
/* 暗色模式下聚焦边框 */
.atk-dark .atk-editor-textarea:focus {
box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.5) !important;
}
/* Responsive adjustments */ /* Responsive adjustments */
@media (max-width: 768px) { @media (max-width: 768px) {
.atk-header { .atk-header {

View File

@@ -528,31 +528,112 @@ class UIManager {
initArtalk() { initArtalk() {
const isHttps = location.protocol === 'https:'; const isHttps = location.protocol === 'https:';
const isLocal = !!(window.SiteConfig?.dev?.isLocal); const isLocal = !!(window.SiteConfig?.dev?.isLocal);
const lang = getStoredLanguage();
if (!isHttps || isLocal) { if (!isHttps || isLocal) {
const lang = getStoredLanguage();
const msg = lang === 'zh' ? '当前评论区已关闭' : 'Comments are closed'; const msg = lang === 'zh' ? '当前评论区已关闭' : 'Comments are closed';
$('#artalk-container').html(`<div style="text-align:center;color:#999;padding:20px;">${msg}</div>`); $('#artalk-container').html(`<div style="text-align:center;color:#999;padding:20px;">${msg}</div>`);
return; return;
} }
if (typeof Artalk !== 'undefined' && window.SiteConfig?.artalk) { if (typeof Artalk !== 'undefined' && window.SiteConfig?.artalk) {
try { try {
Artalk.init({ const artalkConfig = {
el: '#artalk-container', el: '#artalk-container',
pageKey: '/about.html', pageKey: '/about.html',
pageTitle: '关于我 - Honesty', pageTitle: '关于我 - Honesty',
server: window.SiteConfig.artalk.server, server: window.SiteConfig.artalk.server,
site: window.SiteConfig.artalk.site, site: window.SiteConfig.artalk.site,
darkMode: document.documentElement.getAttribute('data-theme') === 'night' // 多语言支持
}); locale: lang === 'zh' ? 'zh-CN' : 'en-US',
// 主题支持
darkMode: document.documentElement.getAttribute('data-theme') === 'night',
// 编辑器增强配置
editor: {
// 启用 Markdown
markdown: true,
// 自定义占位符(支持多语言)
placeholder: lang === 'zh' ? '说点什么吧...支持 Markdown 语法,可 @用户、发送表情' : 'Leave a comment... Supports Markdown, @mentions, and Send 😊',
// 发送按钮文字(多语言)
sendBtn: lang === 'zh' ? '发送' : 'Send',
// 表情面板
emoji: {
// 使用默认表情包
preset: 'twemoji'
},
// 启用 @ 用户提醒功能
mention: true,
// 自动聚焦(仅桌面端)
autoFocus: !('ontouchstart' in window),
// 限制编辑器高度
maxHeight: 200,
// 工具栏
toolbar: [
'bold', 'italic', 'strike', 'link',
'blockquote', 'code', 'codeblock',
'ol', 'ul', 'hr',
'emoji', 'mention'
]
},
// 评论格式化函数
commentFormatter: (comment) => {
// 美化时间显示
const formatTime = (dateStr) => {
const date = new Date(dateStr);
const now = new Date();
const diffSec = Math.floor((now - date) / 1000);
if (diffSec < 60) return lang === 'zh' ? '刚刚' : 'Just now';
if (diffSec < 3600) return lang === 'zh' ? `${Math.floor(diffSec / 60)}分钟前` : `${Math.floor(diffSec / 60)} minutes ago`;
if (diffSec < 86400) return lang === 'zh' ? `${Math.floor(diffSec / 3600)}小时前` : `${Math.floor(diffSec / 3600)} hours ago`;
const isToday = date.toDateString() === now.toDateString();
if (isToday) return lang === 'zh' ?
`今天 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}` :
`Today ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
const isYesterday = new Date(now - 86400000).toDateString() === date.toDateString();
if (isYesterday) return lang === 'zh' ?
`昨天 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}` :
`Yesterday ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
return date.toLocaleString(lang === 'zh' ? 'zh-CN' : 'en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
}).replace(/\//g, '-');
};
// 如果是管理员,添加徽章
if (comment.is_admin) {
comment.nick = `👑${comment.nick}`;
}
// 更新显示时间
comment.create_date_formatted = formatTime(comment.date || comment.created_at || comment.create_date);
return comment;
}
};
Artalk.init(artalkConfig);
this.enhanceArtalkUI(); this.enhanceArtalkUI();
} catch (e) { } catch (e) {
console.error("Artalk Error", e); console.error("Artalk Error", e);
const lang = getStoredLanguage();
const msg = lang === 'zh' ? '当前评论区已关闭' : 'Comments are closed'; const msg = lang === 'zh' ? '当前评论区已关闭' : 'Comments are closed';
$('#artalk-container').html(`<div style="text-align:center;color:#999;padding:20px;">${msg}</div>`); $('#artalk-container').html(`<div style="text-align:center;color:#999;padding:20px;">${msg}</div>`);
} }
} else { } else {
const lang = getStoredLanguage();
const msg = lang === 'zh' ? '当前评论区已关闭' : 'Comments are closed'; const msg = lang === 'zh' ? '当前评论区已关闭' : 'Comments are closed';
$('#artalk-container').html(`<div style="text-align:center;color:#999;padding:20px;">${msg}</div>`); $('#artalk-container').html(`<div style="text-align:center;color:#999;padding:20px;">${msg}</div>`);
} }
@@ -562,7 +643,12 @@ class UIManager {
reloadArtalk() { reloadArtalk() {
// 销毁现有的 Artalk 实例 // 销毁现有的 Artalk 实例
if (typeof Artalk !== 'undefined' && Artalk.instances) { if (typeof Artalk !== 'undefined' && Artalk.instances) {
Artalk.destroy(); try {
Artalk.destroy();
} catch (e) {
console.error("Artalk destroy Error", e);
}
} }
// 清空容器 // 清空容器
@@ -589,16 +675,7 @@ class UIManager {
// 获取当前主题 // 获取当前主题
const currentTheme = document.documentElement.getAttribute('data-theme'); const currentTheme = document.documentElement.getAttribute('data-theme');
// 设置主题
if (typeof Artalk !== 'undefined') {
try {
Artalk.setDarkMode(currentTheme === 'night');
} catch (e) {
console.warn('Failed to set Artalk dark mode:', e);
}
}
// 移动端增强功能 // 移动端增强功能
if (isMobile) { if (isMobile) {
this.enhanceMobileArtalk(container, lang); this.enhanceMobileArtalk(container, lang);
@@ -685,36 +762,6 @@ class UIManager {
container.classList.add(`atk-theme-${theme || 'day'}`); container.classList.add(`atk-theme-${theme || 'day'}`);
} }
updateArtalkLanguage(container, lang, isMobile) {
// 更新展开/收起按钮文本
if (isMobile) {
const expandButtons = container.querySelectorAll('.atk-expand-btn');
const expandText = lang === 'zh' ? '展开' : 'Expand';
const collapseText = lang === 'zh' ? '收起' : 'Collapse';
expandButtons.forEach(btn => {
// 如果按钮当前显示的是展开文本,保持不变
// 如果显示的是收起文本,则更新为对应语言的收起文本
if (btn.textContent === '展开' || btn.textContent === 'Expand') {
btn.textContent = expandText;
} else if (btn.textContent === '收起' || btn.textContent === 'Collapse') {
btn.textContent = collapseText;
}
});
}
// 如果有 Artalk 实例,可以在这里更新其实例的语言设置
if (typeof Artalk !== 'undefined') {
try {
// 注意Artalk 的语言设置通常在初始化时确定,
// 动态更改语言需要重新初始化或者使用其API如果支持
console.log('Would update Artalk language to:', lang);
} catch (e) {
console.warn('Failed to update Artalk language:', e);
}
}
}
initTechCloud() { initTechCloud() {
const container = document.getElementById('tech-container'); const container = document.getElementById('tech-container');
if (!container) return; if (!container) return;