fixed bug
This commit is contained in:
1 parent
23eab42bd7
commit
d73ec8bdc1
16 files changed
+1134
-97
No files matched your search
@@ -3,3 +3,39 @@
|
||||
image: "/album/青梅酒.jpg"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "/album/青梅酒.jpg"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "/album/青梅酒.jpg"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "/album/青梅酒.jpg"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "/album/青梅酒.jpg"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "/album/青梅酒.jpg"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "/album/青梅酒.jpg"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "https://immmmm.com/goods/mxkeys.webp"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "/album/青梅酒.jpg"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
- title: "青梅酒不错"
|
||||
image: "https://immmmm.com/goods/mxkeys.webp"
|
||||
date: "2026-01-29"
|
||||
description: "青梅酒还不错"
|
||||
@@ -87,13 +87,6 @@ hasCJKLanguage = true
|
||||
# 站点参数配置 (Site Parameters)
|
||||
# ==============================================================================
|
||||
[params]
|
||||
# ----------------------------------------------------------------------------
|
||||
# 关于页面配置 (About Page Configuration)
|
||||
# ----------------------------------------------------------------------------
|
||||
[params.about]
|
||||
enableheatmap = false # 开启热力图 (Enable Heatmap)
|
||||
enableskills = false # 开启技能栈 (Enable Skills)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 社交链接 (Social Links)
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -103,6 +96,13 @@ hasCJKLanguage = true
|
||||
{ title = "Rss订阅", url = "/rss.xml", icon = "ri-rss-fill" }
|
||||
]
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 关于页面配置 (About Page Configuration)
|
||||
# ----------------------------------------------------------------------------
|
||||
[params.about]
|
||||
enableheatmap = false # 开启热力图 (Enable Heatmap)
|
||||
enableskills = false # 开启技能栈 (Enable Skills)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 作者信息 (Author Info)
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -126,6 +126,7 @@ hasCJKLanguage = true
|
||||
[params.artalk]
|
||||
server = "https://artalk.usj.cc"
|
||||
site = "优世界"
|
||||
ai_badge = "捧场王" # 自定义 AI 评论标识
|
||||
emoticons = "/emotion/OwO.json"
|
||||
gravatar = "https://cravatar.cn/avatar/"
|
||||
|
||||
|
||||
+188
-50
@@ -46,10 +46,11 @@
|
||||
}
|
||||
|
||||
[data-theme="dark"] .main {
|
||||
background: rgba(15, 23, 42, 0.96);
|
||||
background: rgba(15, 23, 42, 0.99); /* Increased opacity for readability */
|
||||
box-shadow: var(--card-shadow-dark);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
/* Removed glassmorphism blur as requested */
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .header nav {
|
||||
@@ -505,7 +506,7 @@ ul {
|
||||
overflow: hidden;
|
||||
margin: 60px auto;
|
||||
padding: 50px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
box-shadow: var(--card-shadow-light);
|
||||
border-radius: 8px;
|
||||
z-index: 10;
|
||||
@@ -740,93 +741,153 @@ ul {
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
/* Simplified Search Styles for Essay/Shuoshuo */
|
||||
.search-input-group {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
border-bottom: 2px solid #e5e7eb;
|
||||
transition: border-color 0.3s ease;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08); /* Very subtle border for minimalism */
|
||||
border-radius: 99px; /* Fully rounded pill */
|
||||
padding: 2px 15px;
|
||||
background: transparent; /* No background by default */
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.search-input-group:hover {
|
||||
border-color: rgba(0, 0, 0, 0.15);
|
||||
background: rgba(0, 0, 0, 0.01);
|
||||
}
|
||||
|
||||
.search-input-group:focus-within {
|
||||
border-color: #111827;
|
||||
background: #fff;
|
||||
border-color: transparent;
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08); /* Soft diffuse shadow */
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .search-input-group {
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .search-input-group:hover {
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .search-input-group:focus-within {
|
||||
border-color: #e5e7eb;
|
||||
background: #1f2933;
|
||||
border-color: transparent;
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.search-input-group input {
|
||||
width: 100%;
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 8px 35px 8px 45px; /* Increased left padding to separate from icon */
|
||||
font-size: 1rem;
|
||||
padding: 10px 10px 10px 30px;
|
||||
font-size: 0.95rem;
|
||||
color: var(--text-title-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .search-input-group input {
|
||||
color: var(--text-title-dark-color);
|
||||
}
|
||||
|
||||
.search-icon, .close-icon {
|
||||
position: absolute;
|
||||
font-size: 1.2rem;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
left: 5px;
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
font-size: 1.1rem;
|
||||
color: #9ca3af;
|
||||
pointer-events: none;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.search-input-group:focus-within .search-icon {
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .search-input-group:focus-within .search-icon {
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
right: 5px;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
font-size: 1.1rem;
|
||||
color: #9ca3af;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
transition: all 0.2s;
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
.search-input-group.has-value .close-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.close-icon:hover {
|
||||
color: var(--text-title-color);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .close-icon:hover {
|
||||
color: var(--text-title-dark-color);
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.search-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
||||
z-index: 100;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
margin-top: 10px;
|
||||
display: none; /* Hidden by default */
|
||||
}
|
||||
|
||||
[data-theme="dark"] .search-dropdown {
|
||||
background: rgba(30, 41, 59, 0.98);
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.5);
|
||||
right: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
margin-top: 12px;
|
||||
overflow: hidden;
|
||||
z-index: 50;
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
visibility: hidden;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.search-dropdown.show {
|
||||
display: block;
|
||||
animation: slideDown 0.2s ease;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .search-dropdown {
|
||||
background: rgba(31, 41, 51, 0.9);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.search-result-item {
|
||||
padding: 12px 15px;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.05);
|
||||
transition: background 0.2s;
|
||||
text-align: left; /* Align text left */
|
||||
cursor: pointer;
|
||||
padding: 10px 15px;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.03);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.search-result-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.8rem;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.search-result-summary-text {
|
||||
max-width: 70%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.no-result {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
padding: 15px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .search-result-item {
|
||||
@@ -1001,6 +1062,83 @@ ul {
|
||||
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Code Block Controls */
|
||||
.code-controls {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
z-index: 10;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.highlight:hover .code-controls {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.code-btn {
|
||||
background: rgba(0,0,0,0.5);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.code-btn:hover {
|
||||
background: rgba(0,0,0,0.7);
|
||||
}
|
||||
|
||||
/* Expandable Code Blocks */
|
||||
.highlight.collapsed {
|
||||
max-height: 300px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.highlight.collapsed::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
background: linear-gradient(to bottom, transparent, #f6f8fa);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .highlight.collapsed::after {
|
||||
background: linear-gradient(to bottom, transparent, #282a36);
|
||||
}
|
||||
|
||||
.expand-btn-container {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
z-index: 5;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.highlight.collapsed .expand-btn-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.expand-btn {
|
||||
background: var(--link-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 15px;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .highlight {
|
||||
background: #282a36; /* Night Mode: Dark BG (Dracula) */
|
||||
color: #f8f8f2; /* Night Mode: Light Text */
|
||||
|
||||
@@ -5,13 +5,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
ViewImage.init('.post-content img');
|
||||
}
|
||||
|
||||
// 初始化各个模块
|
||||
if (window.initLoader) window.initLoader();
|
||||
if (window.initFloatingTools) window.initFloatingTools();
|
||||
if (window.initSearch) window.initSearch();
|
||||
if (window.initArtalk) window.initArtalk();
|
||||
|
||||
// 文章图片懒加载
|
||||
// 文章图片懒加载 (优先初始化,防止其他模块调用时出错)
|
||||
if (typeof lazyLoadInit === 'function') {
|
||||
lazyLoadInit({
|
||||
offsetBottom: 800,
|
||||
@@ -21,4 +15,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
} else {
|
||||
console.warn('lazyLoadInit is not defined');
|
||||
}
|
||||
|
||||
// 初始化各个模块
|
||||
if (window.initLoader) window.initLoader();
|
||||
if (window.initFloatingTools) window.initFloatingTools();
|
||||
if (window.initSearch) window.initSearch();
|
||||
if (window.initArtalk) window.initArtalk();
|
||||
|
||||
// New Utils Init
|
||||
if (window.initThemeToggle) window.initThemeToggle();
|
||||
if (window.initCodeFold) window.initCodeFold();
|
||||
if (window.initCodeCopy) window.initCodeCopy();
|
||||
if (window.initParagraphComments) window.initParagraphComments();
|
||||
});
|
||||
@@ -33,7 +33,7 @@ window.initArtalk = function() {
|
||||
<div class="atk-main" uk-scrollspy="cls: uk-animation-slide-right-small; delay: 300">
|
||||
<div class="atk-header">
|
||||
<span class="atk-nick" uk-scrollspy="cls: uk-animation-slide-top-small; delay: 350">${ai.name}</span>
|
||||
<span class="atk-badge">AI</span>
|
||||
<span class="atk-badge">${window.artalkConfig.aiBadge || 'AI'}</span>
|
||||
<span class="atk-date">${ai.date}</span>
|
||||
</div>
|
||||
<div class="atk-body">
|
||||
@@ -71,20 +71,30 @@ window.initArtalk = function() {
|
||||
});
|
||||
|
||||
// Find all avatars in the comment list
|
||||
var avatars = document.querySelectorAll('.atk-list .atk-avatar img');
|
||||
avatars.forEach(function(img) {
|
||||
var src = img.getAttribute('src');
|
||||
if (src) {
|
||||
img.setAttribute('data-lazy-src', src);
|
||||
img.removeAttribute('src');
|
||||
img.classList.add('lazyload');
|
||||
}
|
||||
});
|
||||
// We let lazyload.js handle the avatars automatically by calling lazyLoadAgain()
|
||||
// which will find these new images, set the placeholder, and observe them.
|
||||
|
||||
// Trigger lazy load update
|
||||
if (window.lazyLoadAgain) {
|
||||
window.lazyLoadAgain();
|
||||
}
|
||||
|
||||
// Force hide "No Comment" if AI comment exists
|
||||
if (window.artalkConfig.aiComment) {
|
||||
var checkNoComment = setInterval(function() {
|
||||
var noComment = document.querySelector('.atk-list-no-comment');
|
||||
var aiComment = document.querySelector('.atk-ai-comment');
|
||||
if (aiComment && noComment && noComment.style.display !== 'none') {
|
||||
noComment.style.display = 'none';
|
||||
}
|
||||
if (!document.querySelector('#Comments')) {
|
||||
clearInterval(checkNoComment);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Clear interval after 10 seconds to save resources
|
||||
setTimeout(function() { clearInterval(checkNoComment); }, 10000);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
|
||||
@@ -12,26 +12,34 @@
|
||||
function init(setting) {
|
||||
defaults = Object.assign({}, defaults, setting || {});
|
||||
|
||||
// Initialize IntersectionObserver
|
||||
if (!observer) {
|
||||
observer = new IntersectionObserver(function(entries, self) {
|
||||
entries.forEach(function(entry) {
|
||||
if (entry.isIntersecting) {
|
||||
var img = entry.target;
|
||||
showImg(img);
|
||||
self.unobserve(img);
|
||||
}
|
||||
});
|
||||
}, {
|
||||
rootMargin: defaults.offsetTopm + "px 0px " + defaults.offsetBottom + "px 0px"
|
||||
});
|
||||
// Reset observer for PJAX support
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
observer = null;
|
||||
}
|
||||
|
||||
// Initialize IntersectionObserver
|
||||
observer = new IntersectionObserver(function(entries, self) {
|
||||
entries.forEach(function(entry) {
|
||||
if (entry.isIntersecting) {
|
||||
var img = entry.target;
|
||||
showImg(img);
|
||||
self.unobserve(img);
|
||||
}
|
||||
});
|
||||
}, {
|
||||
rootMargin: defaults.offsetTopm + "px 0px " + defaults.offsetBottom + "px 0px"
|
||||
});
|
||||
|
||||
processImages();
|
||||
}
|
||||
|
||||
function processImages() {
|
||||
var images = document.querySelectorAll('img:not(.blog-img):not([data-comp])');
|
||||
if (!observer) {
|
||||
init(); // Auto-initialize if not ready
|
||||
}
|
||||
// Expanded selector to catch more images
|
||||
var images = document.querySelectorAll('img.lazyload, img:not(.blog-img):not([data-comp])');
|
||||
images.forEach(function(img) {
|
||||
// Check if already processed or has data-lazy-src
|
||||
if (img.getAttribute('data-lazy-src')) {
|
||||
|
||||
@@ -0,0 +1,564 @@
|
||||
// Paragraph Comments Module
|
||||
(function() {
|
||||
var POPUP_ID = 'selection-popup';
|
||||
|
||||
// CSS for Paragraph Comments
|
||||
var style = document.createElement('style');
|
||||
style.innerHTML = `
|
||||
/* Selection Popup */
|
||||
#${POPUP_ID} {
|
||||
position: absolute;
|
||||
display: none;
|
||||
background: var(--artalk-editer-color, #333);
|
||||
color: #fff;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
z-index: 2147483647;
|
||||
transform: translate(-50%, -120%);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
transition: opacity 0.2s, transform 0.2s;
|
||||
pointer-events: auto;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
white-space: nowrap;
|
||||
animation: popIn 0.2s cubic-bezier(0.18, 0.89, 0.32, 1.28);
|
||||
}
|
||||
#${POPUP_ID}::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: var(--artalk-editer-color, #333) transparent transparent transparent;
|
||||
}
|
||||
@keyframes popIn {
|
||||
0% { transform: translate(-50%, -100%) scale(0.9); opacity: 0; }
|
||||
100% { transform: translate(-50%, -120%) scale(1); opacity: 1; }
|
||||
}
|
||||
|
||||
/* Paragraph Comment Marker - Pure Text, No Styles */
|
||||
.paragraph-comment-marker {
|
||||
text-decoration: none !important;
|
||||
border-bottom: none !important;
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
cursor: text;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* Comment Count Bubble - Minimal SVG Style */
|
||||
.paragraph-comment-count {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 16px;
|
||||
padding: 0 4px;
|
||||
background: transparent;
|
||||
color: var(--erji-color, #999);
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-left: 2px;
|
||||
vertical-align: top;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
user-select: none;
|
||||
z-index: 10;
|
||||
transition: all 0.2s ease;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.paragraph-comment-count svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
fill: currentColor;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.paragraph-comment-count:hover {
|
||||
color: var(--theme-color, #4a90e2);
|
||||
background: rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.paragraph-comment-count:hover svg {
|
||||
opacity: 1;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* Comments Preview Modal */
|
||||
.pc-modal {
|
||||
position: fixed;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
.pc-modal.show {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.pc-modal-content {
|
||||
background: var(--background-color, #fff);
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
max-height: 80vh;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.2);
|
||||
transform: translateY(20px);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
.pc-modal.show .pc-modal-content {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.pc-header {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid var(--frame-color, #eee);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.pc-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
.pc-close {
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.pc-close:hover { opacity: 1; }
|
||||
.pc-quote-text {
|
||||
padding: 10px;
|
||||
background: var(--bankuai-color, #f6f6f6);
|
||||
border-left: 3px solid var(--text-highlight-color, #666);
|
||||
margin-bottom: 15px;
|
||||
font-size: 0.9em;
|
||||
color: var(--erji-color, #666);
|
||||
}
|
||||
.pc-comment-item {
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid var(--frame-color, #eee);
|
||||
}
|
||||
.pc-comment-item:last-child { border-bottom: none; margin-bottom: 0; }
|
||||
.pc-user { font-weight: bold; font-size: 0.9em; margin-bottom: 5px; }
|
||||
.pc-content { font-size: 0.95em; }
|
||||
|
||||
[data-theme="dark"] .pc-modal-content {
|
||||
background: var(--frame-dark-color, #1f2933);
|
||||
color: var(--text-content-dark-color, #d1d5db);
|
||||
}
|
||||
[data-theme="dark"] .pc-quote-text {
|
||||
background: rgba(0,0,0,0.2);
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Create Popup Element
|
||||
var popup = document.createElement('div');
|
||||
popup.id = POPUP_ID;
|
||||
popup.innerHTML = '<span class="icon" style="width:14px;height:14px;fill:currentColor;display:inline-block;"><svg viewBox="0 0 1024 1024" width="100%" height="100%"><path d="M576 128v298.666667h298.666667c0 164.906667-133.76 298.666667-298.666667 298.666666v170.666667c259.2 0 469.333333-210.133333 469.333333-469.333333H576zM149.333333 725.333333c0-164.906667 133.76-298.666667 298.666667-298.666666V128C188.8 128 0 338.133333 0 597.333333h469.333333v-298.666666H170.666667A298.666667 298.666667 0 0 0 149.333333 725.333333z"></path></svg></span> 评论';
|
||||
document.body.appendChild(popup);
|
||||
|
||||
// Create Modal Element
|
||||
var modal = document.createElement('div');
|
||||
modal.className = 'pc-modal';
|
||||
modal.innerHTML = `
|
||||
<div class="pc-modal-content">
|
||||
<div class="pc-header">
|
||||
<span>引用评论</span>
|
||||
<span class="pc-close">×</span>
|
||||
</div>
|
||||
<div class="pc-body"></div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// State
|
||||
var selectedText = '';
|
||||
var range = null;
|
||||
var isInitialized = false;
|
||||
|
||||
// Initialization
|
||||
function init() {
|
||||
if (!isInitialized) {
|
||||
document.addEventListener('mouseup', handleSelection);
|
||||
document.addEventListener('touchend', handleSelection); // Mobile support
|
||||
|
||||
popup.addEventListener('click', handleQuoteClick);
|
||||
modal.querySelector('.pc-close').addEventListener('click', closeModal);
|
||||
modal.addEventListener('click', function(e) {
|
||||
if (e.target === modal) closeModal();
|
||||
});
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
// Hook into Artalk
|
||||
tryHookArtalk();
|
||||
}
|
||||
|
||||
function tryHookArtalk() {
|
||||
if (window.artalk) {
|
||||
setupArtalkHook(window.artalk);
|
||||
} else {
|
||||
// Performance: Check less frequently (1s) and stop after 10s
|
||||
var checkCount = 0;
|
||||
var checkArtalk = setInterval(function() {
|
||||
checkCount++;
|
||||
if (window.artalk) {
|
||||
clearInterval(checkArtalk);
|
||||
setupArtalkHook(window.artalk);
|
||||
}
|
||||
if (checkCount > 10) clearInterval(checkArtalk); // 10s timeout
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function setupArtalkHook(artalk) {
|
||||
// Initial load
|
||||
var list = artalk.getCommentList();
|
||||
if (list && list.length > 0) {
|
||||
processComments();
|
||||
}
|
||||
|
||||
// Listen for updates
|
||||
artalk.on('list-loaded', function() {
|
||||
setTimeout(processComments, 500);
|
||||
});
|
||||
}
|
||||
|
||||
// Performance Optimized: Build Index Once
|
||||
function buildDocumentIndex(root) {
|
||||
var textNodes = [];
|
||||
var allText = "";
|
||||
var nodeOffsets = [];
|
||||
|
||||
var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
|
||||
var node;
|
||||
while (node = walker.nextNode()) {
|
||||
if (node.parentNode && (
|
||||
node.parentNode.tagName === 'SCRIPT' ||
|
||||
node.parentNode.tagName === 'STYLE' ||
|
||||
node.parentNode.classList.contains('paragraph-comment-marker') ||
|
||||
node.parentNode.classList.contains('paragraph-comment-count')
|
||||
)) continue;
|
||||
|
||||
// Skip code blocks
|
||||
if (node.parentElement.closest('pre') || node.parentElement.closest('code')) continue;
|
||||
|
||||
nodeOffsets.push(allText.length);
|
||||
textNodes.push(node);
|
||||
allText += node.nodeValue;
|
||||
}
|
||||
return { textNodes, allText, nodeOffsets };
|
||||
}
|
||||
|
||||
function processComments() {
|
||||
if (!window.artalk) return;
|
||||
|
||||
// Cleanup old markers
|
||||
document.querySelectorAll('.paragraph-comment-marker').forEach(el => {
|
||||
var parent = el.parentNode;
|
||||
if (parent) {
|
||||
parent.replaceChild(document.createTextNode(el.innerText), el);
|
||||
parent.normalize();
|
||||
}
|
||||
});
|
||||
document.querySelectorAll('.paragraph-comment-count').forEach(el => el.remove());
|
||||
|
||||
var comments = window.artalk.getCommentList();
|
||||
var quoteMap = {};
|
||||
|
||||
// Group comments by quote
|
||||
comments.forEach(c => {
|
||||
var content = c.content_marked || c.content;
|
||||
|
||||
// Extract text from HTML blockquotes
|
||||
var tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = content;
|
||||
var blockquotes = tempDiv.querySelectorAll('blockquote');
|
||||
|
||||
blockquotes.forEach(bq => {
|
||||
var quoteText = bq.textContent.trim();
|
||||
if (quoteText) {
|
||||
if (!quoteMap[quoteText]) quoteMap[quoteText] = [];
|
||||
if (!quoteMap[quoteText].some(existing => existing.id === c.id)) {
|
||||
quoteMap[quoteText].push(c);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Regex fallback
|
||||
if (!blockquotes.length && c.content && !c.content.includes('<')) {
|
||||
var match = c.content.match(/^> (.*?)(?:\n|$)/gm);
|
||||
if (match) {
|
||||
match.forEach(m => {
|
||||
var q = m.replace(/^> /, '').trim();
|
||||
if (q) {
|
||||
if (!quoteMap[q]) quoteMap[q] = [];
|
||||
if (!quoteMap[q].some(existing => existing.id === c.id)) {
|
||||
quoteMap[q].push(c);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var postContent = document.querySelector('.post-content') ||
|
||||
document.querySelector('.article-content') ||
|
||||
document.querySelector('article');
|
||||
|
||||
if (!postContent) return;
|
||||
|
||||
// Build Index ONCE
|
||||
var docData = buildDocumentIndex(postContent);
|
||||
|
||||
Object.keys(quoteMap).forEach(quote => {
|
||||
if (quote.length < 2) return;
|
||||
highlightQuote(docData, quote, quoteMap[quote]);
|
||||
});
|
||||
}
|
||||
|
||||
// Improved Highlight Logic using Pre-built Index
|
||||
function highlightQuote(docData, quote, comments) {
|
||||
if (!quote || quote.length < 5) return;
|
||||
|
||||
var { allText, textNodes, nodeOffsets } = docData;
|
||||
|
||||
// Fuzzy Match
|
||||
var cleanQuote = quote.trim().replace(/\s+/g, ' ');
|
||||
var cleanAllText = allText.replace(/\s+/g, ' ');
|
||||
|
||||
var matchIndex = cleanAllText.indexOf(cleanQuote);
|
||||
|
||||
if (matchIndex === -1) {
|
||||
matchIndex = allText.indexOf(quote);
|
||||
if (matchIndex === -1) matchIndex = allText.indexOf(quote.trim());
|
||||
}
|
||||
|
||||
if (matchIndex === -1) return;
|
||||
|
||||
// Map back to raw index
|
||||
var currentCleanIndex = 0;
|
||||
var rawStart = -1;
|
||||
var rawEnd = -1;
|
||||
var inWhitespace = false;
|
||||
|
||||
for (var i = 0; i < allText.length; i++) {
|
||||
var char = allText[i];
|
||||
var isSpace = /\s/.test(char);
|
||||
|
||||
if (isSpace) {
|
||||
if (!inWhitespace) {
|
||||
if (currentCleanIndex === matchIndex) rawStart = i;
|
||||
currentCleanIndex++;
|
||||
}
|
||||
inWhitespace = true;
|
||||
} else {
|
||||
if (currentCleanIndex === matchIndex) rawStart = i;
|
||||
currentCleanIndex++;
|
||||
inWhitespace = false;
|
||||
}
|
||||
|
||||
if (rawStart !== -1 && currentCleanIndex === matchIndex + cleanQuote.length) {
|
||||
rawEnd = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rawStart !== -1 && rawEnd !== -1) {
|
||||
rangeFromOffsets(textNodes, nodeOffsets, rawStart, rawEnd - rawStart, comments);
|
||||
}
|
||||
}
|
||||
|
||||
function rangeFromOffsets(textNodes, nodeOffsets, start, length, comments) {
|
||||
var end = start + length;
|
||||
var range = document.createRange();
|
||||
|
||||
var startNode = null, startOffset = 0;
|
||||
var endNode = null, endOffset = 0;
|
||||
|
||||
for (var i = 0; i < textNodes.length; i++) {
|
||||
var nodeStart = nodeOffsets[i];
|
||||
var nodeEnd = nodeStart + textNodes[i].nodeValue.length;
|
||||
|
||||
if (!startNode && start >= nodeStart && start < nodeEnd) {
|
||||
startNode = textNodes[i];
|
||||
startOffset = start - nodeStart;
|
||||
}
|
||||
|
||||
if (!endNode && end > nodeStart && end <= nodeEnd) {
|
||||
endNode = textNodes[i];
|
||||
endOffset = end - nodeStart;
|
||||
}
|
||||
|
||||
if (startNode && endNode) break;
|
||||
}
|
||||
|
||||
if (startNode && endNode) {
|
||||
try {
|
||||
range.setStart(startNode, startOffset);
|
||||
range.setEnd(endNode, endOffset);
|
||||
wrapRange(range, comments);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function wrapRange(range, comments) {
|
||||
try {
|
||||
var contents = range.extractContents();
|
||||
var span = document.createElement('span');
|
||||
span.className = 'paragraph-comment-marker';
|
||||
|
||||
span.appendChild(contents);
|
||||
range.insertNode(span);
|
||||
addBubble(span, comments.length, comments);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
function addBubble(marker, count, comments) {
|
||||
var bubble = document.createElement('sup');
|
||||
bubble.className = 'paragraph-comment-count';
|
||||
// Simple Chat Icon SVG
|
||||
bubble.innerHTML = `<svg viewBox="0 0 24 24"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"></path></svg> <span>${count}</span>`;
|
||||
|
||||
marker.appendChild(bubble);
|
||||
|
||||
bubble.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
showCommentsModal(null, comments);
|
||||
});
|
||||
}
|
||||
|
||||
function handleSelection(e) {
|
||||
setTimeout(function() {
|
||||
var sel = window.getSelection();
|
||||
if (sel.rangeCount > 0) {
|
||||
var r = sel.getRangeAt(0);
|
||||
var text = sel.toString().trim();
|
||||
|
||||
var postContent = document.querySelector('.post-content') ||
|
||||
document.querySelector('.article-content') ||
|
||||
document.querySelector('article');
|
||||
|
||||
if (!postContent) return;
|
||||
|
||||
var isInside = postContent.contains(r.commonAncestorContainer);
|
||||
|
||||
if (text.length > 0 && isInside) {
|
||||
selectedText = text;
|
||||
range = r;
|
||||
showPopup(r);
|
||||
} else {
|
||||
hidePopup();
|
||||
}
|
||||
} else {
|
||||
hidePopup();
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function showPopup(r) {
|
||||
var rect = r.getBoundingClientRect();
|
||||
popup.style.display = 'flex';
|
||||
var top = rect.top + window.scrollY - 40;
|
||||
var left = rect.left + window.scrollX + (rect.width / 2);
|
||||
|
||||
popup.style.top = top + 'px';
|
||||
popup.style.left = left + 'px';
|
||||
popup.style.opacity = 1;
|
||||
}
|
||||
|
||||
function hidePopup() {
|
||||
popup.style.display = 'none';
|
||||
popup.style.opacity = 0;
|
||||
}
|
||||
|
||||
function handleQuoteClick() {
|
||||
if (!window.artalk) return;
|
||||
|
||||
var commentsEl = document.getElementById('Comments');
|
||||
if (commentsEl) commentsEl.scrollIntoView({ behavior: 'smooth' });
|
||||
|
||||
var quoteContent = `> ${selectedText}\n\n`;
|
||||
var editor = window.artalk.editor;
|
||||
|
||||
if (editor && typeof editor.setContent === 'function' && typeof editor.getContent === 'function') {
|
||||
editor.setContent(quoteContent + editor.getContent());
|
||||
editor.focus();
|
||||
} else {
|
||||
var textarea = document.querySelector('.atk-textarea');
|
||||
if (textarea) {
|
||||
textarea.value = quoteContent + textarea.value;
|
||||
textarea.focus();
|
||||
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
textarea.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
|
||||
hidePopup();
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
|
||||
function showCommentsModal(quote, comments) {
|
||||
var body = modal.querySelector('.pc-body');
|
||||
body.innerHTML = '';
|
||||
|
||||
if (!quote && comments.length > 0) {
|
||||
var firstContent = comments[0].content_marked || comments[0].content;
|
||||
var match = firstContent.match(/<blockquote>(.*?)<\/blockquote>/) || firstContent.match(/^> (.*?)(?:\n|$)/);
|
||||
if (match) quote = match[1];
|
||||
}
|
||||
|
||||
if (quote) {
|
||||
body.innerHTML += `<div class="pc-quote-text">${quote}</div>`;
|
||||
}
|
||||
|
||||
comments.forEach(c => {
|
||||
var item = document.createElement('div');
|
||||
item.className = 'pc-comment-item';
|
||||
var cleanContent = c.content.replace(/^> .*?\n+/g, '').replace(/<blockquote>.*?<\/blockquote>/g, '');
|
||||
|
||||
var badgeHtml = '';
|
||||
if (c.badge) {
|
||||
badgeHtml = `<span style="background:${c.badge_color || '#000'};color:#fff;padding:1px 4px;border-radius:4px;font-size:0.8em;margin-left:5px;">${c.badge}</span>`;
|
||||
}
|
||||
|
||||
item.innerHTML = `
|
||||
<div class="pc-user">${c.nick}${badgeHtml} <span style="font-weight:normal;font-size:0.8em;color:#999;float:right">${c.date}</span></div>
|
||||
<div class="pc-content">${cleanContent}</div>
|
||||
`;
|
||||
body.appendChild(item);
|
||||
});
|
||||
|
||||
modal.classList.add('show');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
modal.classList.remove('show');
|
||||
}
|
||||
|
||||
window.initParagraphComments = init;
|
||||
init();
|
||||
|
||||
})();
|
||||
@@ -121,12 +121,24 @@ function initInlineSearch() {
|
||||
searchContainer.style.display = 'block';
|
||||
input.focus();
|
||||
loadSearchIndex();
|
||||
// Add Esc key listener
|
||||
document.addEventListener('keydown', escListener);
|
||||
} else {
|
||||
header.style.display = 'inline-flex';
|
||||
searchContainer.style.display = 'none';
|
||||
input.value = '';
|
||||
// Remove .has-value class
|
||||
searchContainer.querySelector('.search-input-group').classList.remove('has-value');
|
||||
resultsContainer.classList.remove('show');
|
||||
resultsContainer.innerHTML = '';
|
||||
// Remove Esc key listener
|
||||
document.removeEventListener('keydown', escListener);
|
||||
}
|
||||
};
|
||||
|
||||
var escListener = function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
window.toggleSearchMode(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -137,8 +149,41 @@ function initInlineSearch() {
|
||||
input.parentNode.replaceChild(newInput, input);
|
||||
input = newInput;
|
||||
|
||||
// Handle Close Icon Logic
|
||||
var closeIcon = searchContainer.querySelector('.close-icon');
|
||||
if (closeIcon) {
|
||||
// Remove inline onclick handler if present
|
||||
closeIcon.onclick = null;
|
||||
closeIcon.removeAttribute('onclick');
|
||||
|
||||
// Add new custom handler
|
||||
closeIcon.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (input.value.trim().length > 0) {
|
||||
// Clear input
|
||||
input.value = '';
|
||||
input.focus();
|
||||
// Trigger input event to update UI
|
||||
input.dispatchEvent(new Event('input'));
|
||||
} else {
|
||||
// Close search
|
||||
window.toggleSearchMode(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
input.addEventListener('input', function() {
|
||||
var query = this.value.trim().toLowerCase();
|
||||
var inputGroup = this.closest('.search-input-group');
|
||||
|
||||
// Toggle has-value class
|
||||
if (this.value.length > 0) {
|
||||
inputGroup.classList.add('has-value');
|
||||
} else {
|
||||
inputGroup.classList.remove('has-value');
|
||||
}
|
||||
|
||||
if (query.length === 0) {
|
||||
resultsContainer.classList.remove('show');
|
||||
@@ -156,10 +201,11 @@ function initInlineSearch() {
|
||||
if (results.length > 0) {
|
||||
var html = results.slice(0, 5).map(function(item) {
|
||||
return `
|
||||
<a href="${item.permalink}" class="search-result-item" style="display:block; text-decoration:none;" onclick="window.toggleSearchMode(false)">
|
||||
<a href="${item.permalink}" class="search-result-item" onclick="window.toggleSearchMode(false)">
|
||||
<span class="search-result-title">${item.title}</span>
|
||||
<div style="display:flex; align-items:center;">
|
||||
<div class="search-result-meta">
|
||||
<span class="search-result-date">${item.date}</span>
|
||||
<span class="search-result-summary-text">${item.summary || ''}</span>
|
||||
</div>
|
||||
</a>
|
||||
`;
|
||||
@@ -173,7 +219,7 @@ function initInlineSearch() {
|
||||
window.pjax.refresh(resultsContainer);
|
||||
}
|
||||
} else {
|
||||
resultsContainer.innerHTML = '<div class="search-result-item" style="text-align:center;color:#999;cursor:default;">无搜索结果</div>';
|
||||
resultsContainer.innerHTML = '<div class="search-result-item no-result">暂无相关内容</div>';
|
||||
resultsContainer.classList.add('show');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,3 +6,173 @@ window.isMobile = function() {
|
||||
return false; // PC端
|
||||
}
|
||||
};
|
||||
|
||||
// Toast Message Helper
|
||||
window.showToast = function(text) {
|
||||
if (typeof Qmsg !== 'undefined') {
|
||||
Qmsg.info(text);
|
||||
} else {
|
||||
// Fallback custom toast
|
||||
let toast = document.querySelector('.custom-toast');
|
||||
if (!toast) {
|
||||
toast = document.createElement('div');
|
||||
toast.className = 'custom-toast';
|
||||
toast.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
z-index: 9999;
|
||||
font-size: 14px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
`;
|
||||
document.body.appendChild(toast);
|
||||
}
|
||||
toast.innerText = text;
|
||||
toast.style.opacity = '1';
|
||||
|
||||
if (window.toastTimeout) clearTimeout(window.toastTimeout);
|
||||
window.toastTimeout = setTimeout(() => {
|
||||
toast.style.opacity = '0';
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
|
||||
// Theme Toggle Logic
|
||||
window.initThemeToggle = function() {
|
||||
const avatar = document.getElementById('theme-toggle-avatar');
|
||||
if (!avatar) return;
|
||||
|
||||
// Remove existing listeners to avoid duplicates (if any)
|
||||
const newAvatar = avatar.cloneNode(true);
|
||||
avatar.parentNode.replaceChild(newAvatar, avatar);
|
||||
|
||||
newAvatar.addEventListener('click', function(e) {
|
||||
// Prevent if clicking on something interactive inside (unlikely for avatar)
|
||||
e.preventDefault();
|
||||
|
||||
const html = document.documentElement;
|
||||
const currentTheme = html.getAttribute('data-theme');
|
||||
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
|
||||
html.setAttribute('data-theme', newTheme);
|
||||
localStorage.setItem('theme', newTheme);
|
||||
|
||||
window.showToast('已切换至 ' + (newTheme === 'dark' ? '深色' : '浅色') + '模式');
|
||||
|
||||
// Trigger generic resize event to force charts/etc to redraw if needed
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
});
|
||||
};
|
||||
|
||||
// Code Folding Logic
|
||||
window.initCodeFold = function() {
|
||||
const codeBlocks = document.querySelectorAll('.highlight');
|
||||
codeBlocks.forEach(block => {
|
||||
// Check height (approx 300px)
|
||||
if (block.offsetHeight > 360) {
|
||||
// Check if already processed
|
||||
if (block.parentNode.classList.contains('code-fold-container')) return;
|
||||
|
||||
// Wrap
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'code-fold-container collapsed';
|
||||
block.parentNode.insertBefore(wrapper, block);
|
||||
wrapper.appendChild(block);
|
||||
|
||||
// Add Button
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'code-expand-btn';
|
||||
btn.innerHTML = '<span><i class="ri-arrow-down-s-line" style="margin-right:4px;"></i> 展开代码 / Expand</span>';
|
||||
btn.onclick = function() {
|
||||
wrapper.classList.remove('collapsed');
|
||||
// Hide button after expand, or change to collapse?
|
||||
// Usually just expand is enough.
|
||||
btn.style.display = 'none';
|
||||
};
|
||||
wrapper.appendChild(btn);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Code Copy Logic
|
||||
window.initCodeCopy = function() {
|
||||
// Target pre tags that contain code, or .highlight containers
|
||||
const codeBlocks = document.querySelectorAll('pre');
|
||||
|
||||
codeBlocks.forEach(pre => {
|
||||
// Avoid double init
|
||||
if (pre.parentNode.querySelector('.copy-code-btn')) return;
|
||||
if (pre.querySelector('.copy-code-btn')) return;
|
||||
|
||||
// Check if it's inside a highlight block (Hugo usually does .highlight > pre)
|
||||
// We attach button to the pre or the highlight container?
|
||||
// Attaching to pre is safer for positioning.
|
||||
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'copy-code-btn';
|
||||
btn.innerHTML = '<i class="ri-file-copy-line"></i>';
|
||||
btn.title = "复制代码 / Copy Code";
|
||||
btn.style.cssText = `
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
opacity: 0;
|
||||
z-index: 10;
|
||||
`;
|
||||
|
||||
// Show on hover
|
||||
pre.addEventListener('mouseenter', () => btn.style.opacity = '1');
|
||||
pre.addEventListener('mouseleave', () => btn.style.opacity = '0');
|
||||
|
||||
// Handle touch devices
|
||||
if (window.isMobile()) {
|
||||
btn.style.opacity = '1';
|
||||
}
|
||||
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const code = pre.querySelector('code') ? pre.querySelector('code').innerText : pre.innerText;
|
||||
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(code).then(() => {
|
||||
window.showToast('代码已复制 / Copied!');
|
||||
btn.innerHTML = '<i class="ri-check-line"></i>';
|
||||
setTimeout(() => btn.innerHTML = '<i class="ri-file-copy-line"></i>', 2000);
|
||||
}).catch(err => {
|
||||
console.error('Copy failed', err);
|
||||
window.showToast('复制失败 / Failed');
|
||||
});
|
||||
} else {
|
||||
// Fallback
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = code;
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
window.showToast('代码已复制 / Copied!');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure relative positioning
|
||||
if (getComputedStyle(pre).position === 'static') {
|
||||
pre.style.position = 'relative';
|
||||
}
|
||||
|
||||
pre.appendChild(btn);
|
||||
});
|
||||
};
|
||||
@@ -94,6 +94,11 @@ document.addEventListener("pjax:complete", function () {
|
||||
// 初始化代码折叠
|
||||
if (typeof initCodeFold === 'function') initCodeFold();
|
||||
|
||||
// 初始化段落评论
|
||||
if (typeof window.initParagraphComments === 'function') {
|
||||
window.initParagraphComments();
|
||||
}
|
||||
|
||||
// 初始化友链状态
|
||||
if (typeof window.initLinkStatus === 'function') {
|
||||
window.initLinkStatus();
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
{{- $src = $src | relURL -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
<img data-lazy-src="{{ $src }}" alt="{{ .Text }}" class="lazyload">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-lazy-src="{{ $src }}" alt="{{ .Text }}" class="lazyload">
|
||||
@@ -39,9 +39,9 @@
|
||||
height: 160px;
|
||||
justify-content: space-between;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
/* Removed backdrop-filter for performance */
|
||||
/* backdrop-filter: blur(16px) saturate(180%); */
|
||||
/* -webkit-backdrop-filter: blur(16px) saturate(180%); */
|
||||
/* Enhanced Glassmorphism for non-mobile */
|
||||
backdrop-filter: blur(12px) saturate(120%);
|
||||
-webkit-backdrop-filter: blur(12px) saturate(120%);
|
||||
border: 1px solid #111827;
|
||||
box-shadow: none;
|
||||
transition:
|
||||
@@ -55,6 +55,18 @@
|
||||
overflow: hidden; /* 防止背景图溢出 */
|
||||
}
|
||||
|
||||
/* Mobile Optimization: Remove expensive effects */
|
||||
@media (max-width: 767px) {
|
||||
.fc-item {
|
||||
backdrop-filter: none !important;
|
||||
-webkit-backdrop-filter: none !important;
|
||||
background: rgba(255, 255, 255, 0.8); /* Higher opacity fallback */
|
||||
}
|
||||
[data-theme="dark"] .fc-item {
|
||||
background: rgba(30, 30, 30, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.friend-circle-list a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,17 @@
|
||||
.atk-loading{
|
||||
background: #FFFFFF;
|
||||
}
|
||||
.atk-loading-editor-box {
|
||||
margin-bottom: 30px;
|
||||
border: 1px solid var(--frame-color);
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
[data-theme="dark"] .atk-loading-editor-box {
|
||||
border-color: var(--frame-dark-color);
|
||||
background: transparent;
|
||||
}
|
||||
/*对artalk评论暗夜模式进行微调*/
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.atk-pinned-badge {
|
||||
@@ -20,6 +31,21 @@
|
||||
<div id="Comments" uk-scrollspy="target: > *; cls: uk-animation-slide-bottom-small; delay: 100">
|
||||
<!-- Loading Skeleton -->
|
||||
<div class="atk-loading-placeholder">
|
||||
<!-- Editor Skeleton -->
|
||||
<div class="atk-loading-editor-box">
|
||||
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
|
||||
<div class="atk-loading-line" style="width: 32%; height: 34px; border-radius: 4px; margin-bottom: 0;"></div>
|
||||
<div class="atk-loading-line" style="width: 32%; height: 34px; border-radius: 4px; margin-bottom: 0;"></div>
|
||||
<div class="atk-loading-line" style="width: 32%; height: 34px; border-radius: 4px; margin-bottom: 0;"></div>
|
||||
</div>
|
||||
<div class="atk-loading-line" style="width: 100%; height: 120px; border-radius: 4px; margin-bottom: 10px;"></div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div class="atk-loading-line" style="width: 120px; height: 20px; margin-bottom: 0;"></div>
|
||||
<div class="atk-loading-line" style="width: 80px; height: 34px; border-radius: 4px; margin-bottom: 0;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Comment List Skeleton -->
|
||||
<div class="atk-loading-item">
|
||||
<div class="atk-loading-avatar"></div>
|
||||
<div class="atk-loading-content">
|
||||
@@ -45,6 +71,7 @@
|
||||
el: '#Comments',
|
||||
server: '{{ .Site.Params.artalk.server }}',
|
||||
site: '{{ .Site.Params.artalk.site }}',
|
||||
aiBadge: '{{ .Site.Params.artalk.ai_badge | default "AI" }}',
|
||||
pageKey: '{{ .RelPermalink }}',
|
||||
emoticons: '{{ .Site.Params.artalk.emoticons | relURL }}',
|
||||
aiComment: {{ if .Params.ai_comment }}
|
||||
|
||||
@@ -66,10 +66,11 @@
|
||||
{{ $loader := resources.Get "js/modules/loader.js" }}
|
||||
{{ $search := resources.Get "js/modules/search.js" }}
|
||||
{{ $floatingTools := resources.Get "js/modules/floating-tools.js" }}
|
||||
{{ $paragraphComments := resources.Get "js/modules/paragraph-comments.js" }}
|
||||
{{ $artalkModule := resources.Get "js/modules/artalk.js" }}
|
||||
{{ $pjaxLib := resources.Get "js/pjax.js" }}
|
||||
|
||||
{{ $scripts := slice $iconfont $lightgallery $uikit $easylazyload $viewimage $artalk $barrage $utils $loader $search $floatingTools $artalkModule $nprogress $pjaxLib $main $mypjax $message $echarts $tiaozhuan | resources.Concat "js/bundle.js" | resources.Minify | resources.Fingerprint }}
|
||||
{{ $scripts := slice $iconfont $lightgallery $uikit $easylazyload $viewimage $artalk $barrage $utils $loader $search $floatingTools $paragraphComments $artalkModule $nprogress $pjaxLib $main $mypjax $message $echarts $tiaozhuan | resources.Concat "js/bundle.js" | resources.Minify | resources.Fingerprint }}
|
||||
<script src="{{ $scripts.RelPermalink }}"></script>
|
||||
<script async src="/js/bsz.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -52,6 +52,19 @@
|
||||
}
|
||||
}
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
|
||||
// Listen for system changes
|
||||
if (window.matchMedia) {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
|
||||
// Only switch if user hasn't manually set a preference
|
||||
// Or maybe we should respect system change if user hasn't explicitly locked it?
|
||||
// Common behavior: manual override sticks.
|
||||
if (!localStorage.getItem('theme')) {
|
||||
var newTheme = event.matches ? "dark" : "light";
|
||||
document.documentElement.setAttribute('data-theme', newTheme);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="header-top">
|
||||
<div class="head_author_img load-memos-editor">
|
||||
<div class="head_author_img load-memos-editor" id="theme-toggle-avatar">
|
||||
<img src="{{ .Site.Params.author.avatar }}" class="blog-img" width="80" height="80" alt="{{ .Site.Title }}" />
|
||||
<div class="avatar-theme-tip">
|
||||
点击头像切换昼夜
|
||||
|
||||
Reference in new issue
Block a user