added 工具栏

This commit is contained in:
Vaica committed 2026-01-24 18:35:57 +08:00
1 parent f087f75fd4
commit b9fd4cb7f6
8 files changed
+295 -240

No files matched your search

+208 -208
View File
@@ -67,13 +67,17 @@ $('#libabys').eq(1).attr("style", "margin-left: -5px");
$('.itp-index:odd').attr("style", "float: right;width:48%;");
//文章图片懒加载
lazyLoadInit({
// coverColor: "white",
// coverDiv: "<div style='display: flex; justify-content: center; align-items: center; height: 200px; color: #000000;'><span>优世界·一个记录生活点滴的小站</span></div>",
offsetBottom: 800,
offsetTopm: 800,
showTime: 1100
});
if (typeof lazyLoadInit === 'function') {
lazyLoadInit({
// coverColor: "white",
// coverDiv: "<div style='display: flex; justify-content: center; align-items: center; height: 200px; color: #000000;'><span>优世界·一个记录生活点滴的小站</span></div>",
offsetBottom: 800,
offsetTopm: 800,
showTime: 1100
});
} else {
console.warn('lazyLoadInit is not defined');
}
async function loadBarrager() {
try {
@@ -101,223 +105,123 @@ function initArtalkAndGetComments() {
}
});
});
Artalk.init({
el: '#Comments', // 绑定元素的 Selector
server: window.siteConfig.artalk.server, // 后端地址
site: window.siteConfig.artalk.site, // 你的站点名
flatMode: true,
emoticons: window.siteConfig.artalk.emoticons
});
});
}
// 异步创建弹幕
// 从 Artalk 评论数据生成弹幕
async function createBarragerFromArtalk(commentsData) {
const looperTime = 1000; // 每条弹幕的发送间隔,单位毫秒
// 1. 处理评论数据(扁平化、乱序)
const flattenedComments = flattenComments(commentsData);
shuffleArray(flattenedComments); // 随机打乱评论顺序
const selectedComments = flattenedComments; // 使用所有评论
// 2. 构建弹幕列表
let barrageList = selectedComments.map(comment => ({
type: 'comment',
content: stripHTML(comment.content_marked) || 'No comment',
// 修复头像模糊:请求 200px 的图片 (s=200)
headImg: window.siteConfig.artalk.gravatar + comment.email_encrypted + "?s=200" || 'static/default-avatar.png',
href: comment.link || '#',
speed: 35
}));
// 确保弹幕容器存在
const barragerContainer = document.querySelector('.barrager');
if (!barragerContainer) {
console.warn('未找到弹幕容器 .barrager');
return;
}
// 3. 尝试获取在线一言并插入
if (window.siteConfig.barrage && window.siteConfig.barrage.enableHitokoto) {
try {
const hitokoto = await fetchHitokoto();
if (hitokoto) {
const insertIndex = Math.floor(Math.random() * (barrageList.length + 1));
barrageList.splice(insertIndex, 0, {
type: 'hitokoto',
content: `『一言』${hitokoto}`,
headImg: window.siteConfig.author.avatar,
href: 'https://hitokoto.cn',
speed: 35
});
}
} catch (e) {
console.error('获取一言失败:', e);
// 1. 过滤和处理评论数据 (只保留昵称和内容)
const barrageList = commentsData.map(comment => {
// 简单清理 HTML 标签,保留纯文本 (可选)
const contentText = comment.content.replace(/<[^>]+>/g, "").substring(0, 50); // 限制长度
return {
info: contentText, // 弹幕内容
href: '#', // 链接 (可选,点击弹幕跳转)
speed: 10 + Math.random() * 5, // 随机速度
color: '#fff', // 字体颜色 (白色)
old_ie_color: '#000000', // 旧版 IE 颜色
};
}).filter(item => item.info.trim() !== ""); // 过滤空评论
// 如果没有评论,则不显示弹幕
if (barrageList.length === 0) {
return;
}
}
// 初始化弹幕插件
let barrage = new Barrage.default({
el: 'body',
backColor: "#000000b5",
fontSize: "13px", // 字体稍微改小一点点以适配小头像
isLeft: true,
speed: 0,
height: "30px" // 整体高度稍微减小
});
const totalItems = barrageList.length;
let currentIndex = 0;
if (totalItems !== 0) {
while (currentIndex < totalItems) {
const item = barrageList[currentIndex];
// 发送弹幕
barrage.start(item.content, {
speed: item.speed,
headImg: item.headImg,
href: item.href
});
currentIndex++;
await delay(looperTime); // 等待指定的时间再发送下一条弹幕
}
}
}
// 数组乱序算法 (Fisher-Yates Shuffle)
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
// 获取一言
async function fetchHitokoto() {
const url = window.siteConfig.barrage.hitokotoUrl || 'https://v1.hitokoto.cn?c=a&c=b&c=c&c=d&c=i';
try {
const response = await fetch(url);
const data = await response.json();
return data.hitokoto;
} catch (error) {
return null;
}
}
// 延迟函数,返回一个 Promise,用于等待指定的毫秒数
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 去除 HTML 标签的函数
function stripHTML(html) {
return html.replace(/<\/?[^>]+(>|$)/g, "");
}
// 展平评论数据结构的函数
function flattenComments(comments) {
let result = [];
comments.forEach(function (comment) {
result.push(comment);
if (comment.children && comment.children.length > 0) {
result = result.concat(flattenComments(comment.children));
}
});
return result;
}
// 调用异步的弹幕加载函数
if (document.querySelector("#Comments") && !isMobile()) {
loadBarrager()
}
function getCurrentTheme() {
var theme = document.documentElement.getAttribute('data-theme');
if (!theme) {
theme = 'light';
}
return theme;
}
function applyTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
try {
localStorage.setItem('theme', theme);
} catch (e) {}
}
function updateThemeToggle(theme) {
var button = document.getElementById('theme-toggle');
if (theme === 'dark') {
if (button) {
button.textContent = '日间';
}
} else {
if (button) {
button.textContent = '夜间';
}
}
}
function toggleTheme() {
var current = getCurrentTheme();
var next = current === 'dark' ? 'light' : 'dark';
applyTheme(next);
updateThemeToggle(next);
if (window.Artalk && window.Artalk.get) {
try {
var ctx = Artalk.get('#Comments');
if (ctx && ctx.setDarkMode) {
ctx.setDarkMode(next === 'dark');
}
} catch (e) {}
}
}
document.addEventListener('DOMContentLoaded', function () {
var theme = getCurrentTheme();
updateThemeToggle(theme);
var button = document.getElementById('theme-toggle');
if (button) {
button.addEventListener('click', toggleTheme);
}
var avatarWrapper = document.querySelector('.head_author_img');
var avatarTip = document.querySelector('.avatar-theme-tip');
if (avatarWrapper) {
avatarWrapper.style.cursor = 'pointer';
avatarWrapper.addEventListener('click', toggleTheme);
}
if (avatarTip) {
avatarTip.classList.add('is-visible');
var hideOnce = function () {
avatarTip.classList.add('is-hidden');
// 2. 初始化 jQuery.barrager (如果尚未初始化)
// 注意:这里假设 jquery.barrager.js 已经加载并挂载到 jQuery 对象上
// 由于 barrager 插件通常是直接操作 DOM,我们可能需要循环添加
// 简单的循环发送弹幕示例 (每隔一段时间发送一条)
let index = 0;
const sendBarrage = () => {
if (index >= barrageList.length) {
index = 0; // 循环播放
}
const item = barrageList[index];
// 使用 jQuery 选择器调用 barrager
$('body').barrager(item);
index++;
};
setTimeout(hideOnce, 9000);
if (avatarWrapper) {
avatarWrapper.addEventListener('click', hideOnce);
// 每 2 秒发送一条弹幕
setInterval(sendBarrage, 2000);
}
async function fetchHitokoto() {
try {
const response = await fetch('https://v1.hitokoto.cn/?c=d&c=i'); // 获取句子
const data = await response.json();
return data.hitokoto;
} catch (error) {
console.error('获取一言失败:', error);
return null;
}
}
});
}
// 代码复制功能
// 代码块复制功能
function initCodeCopy() {
var codeBlocks = document.querySelectorAll('.highlight');
codeBlocks.forEach(function(block) {
if (block.querySelector('.copy-code-btn')) return;
const codeBlocks = document.querySelectorAll('.post-content pre code');
codeBlocks.forEach(codeBlock => {
// 检查是否已经添加了复制按钮,避免重复添加
if (codeBlock.parentNode.querySelector('.copy-code-btn')) return;
var btn = document.createElement('button');
btn.className = 'copy-code-btn';
btn.innerHTML = '<i class="ri-file-copy-line"></i>';
block.appendChild(btn);
const pre = codeBlock.parentNode;
pre.style.position = 'relative';
btn.addEventListener('click', function() {
var code = block.querySelector('code').innerText;
navigator.clipboard.writeText(code).then(function() {
btn.innerHTML = '<i class="ri-check-line"></i>';
setTimeout(function() {
btn.innerHTML = '<i class="ri-file-copy-line"></i>';
const copyBtn = document.createElement('button');
copyBtn.className = 'copy-code-btn';
copyBtn.innerHTML = '<i class="fa fa-copy"></i>'; // 使用 FontAwesome 图标
copyBtn.title = '复制代码';
// 样式 (建议放到 CSS 文件中)
copyBtn.style.position = 'absolute';
copyBtn.style.top = '5px';
copyBtn.style.right = '5px';
copyBtn.style.border = 'none';
copyBtn.style.background = 'transparent';
copyBtn.style.color = '#999';
copyBtn.style.cursor = 'pointer';
copyBtn.style.padding = '5px';
copyBtn.style.borderRadius = '4px';
copyBtn.style.transition = 'all 0.3s';
// Hover 效果
copyBtn.addEventListener('mouseenter', () => {
copyBtn.style.color = '#333';
copyBtn.style.background = 'rgba(0,0,0,0.1)';
});
copyBtn.addEventListener('mouseleave', () => {
copyBtn.style.color = '#999';
copyBtn.style.background = 'transparent';
});
copyBtn.addEventListener('click', () => {
const code = codeBlock.innerText;
navigator.clipboard.writeText(code).then(() => {
copyBtn.innerHTML = '<i class="fa fa-check"></i>';
setTimeout(() => {
copyBtn.innerHTML = '<i class="fa fa-copy"></i>';
}, 2000);
}).catch(function(err) {
console.error('Failed to copy: ', err);
btn.innerText = 'Error';
Qmsg.success("代码复制成功");
}).catch(err => {
console.error('复制失败:', err);
copyBtn.innerHTML = '<i class="fa fa-times"></i>';
Qmsg.error("复制失败");
});
});
pre.appendChild(copyBtn);
});
}
@@ -371,3 +275,99 @@ function typeWriter(element, text, speed = 100) {
type();
}
// 友链信息一键复制
function copySzhContent() {
var szhElement = document.getElementById('szh');
if (szhElement) {
var textToCopy = szhElement.innerText;
navigator.clipboard.writeText(textToCopy).then(function() {
Qmsg.success("复制成功");
}).catch(function(err) {
console.error('Could not copy text: ', err);
Qmsg.error("复制失败");
});
}
}
// Theme Toggle Logic
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
// Notify Artalk if present
if (window.Artalk) {
Artalk.setDarkMode(newTheme === 'dark');
}
}
// Update Floating Tools Visibility based on current page
function updateFloatingToolsVisibility() {
const tools = document.querySelector('.floating-tools');
if (!tools) return;
// Hide on Homepage
const isHome = window.location.pathname === '/' || window.location.pathname === '/index.html';
if (isHome) {
tools.style.display = 'none';
} else {
tools.style.display = 'flex';
}
// Hide Comment button if no comments section
const commentBtn = document.getElementById('to-comments');
if (commentBtn) {
const commentsSection = document.getElementById('Comments');
commentBtn.style.display = commentsSection ? 'flex' : 'none';
}
}
// Floating Tools Initialization
function initFloatingTools() {
// Initial visibility check
updateFloatingToolsVisibility();
// Prevent multiple event bindings
if (window.floatingToolsInitialized) return;
window.floatingToolsInitialized = true;
// Use Event Delegation for robust handling
document.addEventListener('click', function(e) {
// Theme Toggle
const toggleBtn = e.target.closest('#theme-toggle');
if (toggleBtn) {
e.preventDefault();
toggleTheme();
}
// Jump to Comments
const commentBtn = e.target.closest('#to-comments');
if (commentBtn) {
e.preventDefault();
const commentsSection = document.getElementById('Comments');
if (commentsSection) {
commentsSection.scrollIntoView({ behavior: 'smooth' });
}
}
});
// Theme Toggle (Avatar)
const avatar = document.querySelector('.head_author_img');
if (avatar) {
avatar.addEventListener('click', function(e) {
e.preventDefault();
toggleTheme();
});
}
}
// Listen for PJAX complete to update visibility
document.addEventListener('pjax:complete', function() {
updateFloatingToolsVisibility();
});
document.addEventListener('DOMContentLoaded', function() {
initFloatingTools();
});