feat(artalk): 增强评论系统功能与多语言支持
- 引入 Artalk 多语言包支持中英文切换 - 配置评论区域支持多语言提示与界面文本 - 优化编辑器功能,启用 Markdown、表情、@提醒等 - 改进评论时间显示逻辑,支持相对时间与本地化格式 - 添加管理员评论徽章标识 - 增强暗色模式与移动端适配样式 - 优化 CSS 样式,包括链接、输入框、工具栏等视觉效果 - 完善 Artalk 实例销毁逻辑,提升稳定性 - 移除旧版语言更新方法,统一通过配置管理 - 删除冗余 Avatar 样式以简化维护
This commit is contained in:
@@ -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>
|
||||||
@@ -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 {
|
||||||
|
|||||||
137
js/about.js
137
js/about.js
@@ -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);
|
||||||
if (!isHttps || isLocal) {
|
|
||||||
const lang = getStoredLanguage();
|
const lang = getStoredLanguage();
|
||||||
|
if (!isHttps || isLocal) {
|
||||||
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) {
|
||||||
|
try {
|
||||||
Artalk.destroy();
|
Artalk.destroy();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Artalk destroy Error", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空容器
|
// 清空容器
|
||||||
@@ -590,15 +676,6 @@ 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;
|
||||||
|
|||||||
Reference in New Issue
Block a user