- 修复 /categories、/tags 因变量为 List 误用 .items 导致的 500 - 新增 layout.html 布局契约,消除插件页面 fallback 警告 - 适配 plugin-moments / plugin-photos / plugin-links(含友链申请表单与 RSS 订阅页) - 适配 halo-weread-plugin(书架页)、留言板单页模板 - 适配 plugin-extra-api 的代码高亮与暗色样式 - 修复暗黑模式评论区不可见(补充 color-scheme 与兜底样式) - 更新元数据:作者暖心向阳335、版本 0.1.0、requires >=2.26.0
83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
/**
|
|
* whitespace 留白主题 - 文章页脚本
|
|
* 代码块复制 + 阅读进度条
|
|
*/
|
|
|
|
// ========================================
|
|
// 代码块复制
|
|
// ========================================
|
|
|
|
function initCodeCopy(): void {
|
|
const codeBlocks = document.querySelectorAll<HTMLElement>(
|
|
".article-content pre",
|
|
);
|
|
|
|
codeBlocks.forEach((pre) => {
|
|
const copyBtn = document.createElement("button");
|
|
copyBtn.className = "code-copy-btn";
|
|
copyBtn.type = "button";
|
|
copyBtn.textContent = "复制";
|
|
|
|
pre.style.position = "relative";
|
|
pre.appendChild(copyBtn);
|
|
|
|
copyBtn.addEventListener("click", async () => {
|
|
const code = pre.querySelector("code");
|
|
const text = code ? (code.textContent ?? "") : (pre.textContent ?? "");
|
|
try {
|
|
await navigator.clipboard.writeText(text);
|
|
copyBtn.textContent = "已复制";
|
|
copyBtn.classList.add("copied");
|
|
setTimeout(() => {
|
|
copyBtn.textContent = "复制";
|
|
copyBtn.classList.remove("copied");
|
|
}, 2000);
|
|
} catch {
|
|
console.error("复制失败");
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// ========================================
|
|
// 阅读进度条
|
|
// ========================================
|
|
|
|
function initReadingProgress(): void {
|
|
const article = document.querySelector<HTMLElement>(".article-content");
|
|
if (!article) return;
|
|
|
|
const progressBar = document.createElement("div");
|
|
progressBar.className = "reading-progress";
|
|
document.body.appendChild(progressBar);
|
|
|
|
const updateProgress = () => {
|
|
const articleTop = article.offsetTop;
|
|
const articleHeight = article.offsetHeight;
|
|
const windowHeight = window.innerHeight;
|
|
const scrollY = window.scrollY;
|
|
|
|
const start = articleTop - windowHeight;
|
|
const end = articleTop + articleHeight;
|
|
const current = scrollY;
|
|
|
|
let progress = ((current - start) / (end - start)) * 100;
|
|
progress = Math.max(0, Math.min(100, progress));
|
|
progressBar.style.width = `${progress}%`;
|
|
};
|
|
|
|
window.addEventListener("scroll", updateProgress, { passive: true });
|
|
updateProgress();
|
|
}
|
|
|
|
function init(): void {
|
|
initCodeCopy();
|
|
initReadingProgress();
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
} else {
|
|
init();
|
|
}
|