优化一下博客的性能

This commit is contained in:
zqlit committed 2026-05-20 14:33:05 +08:00
1 parent 15421ff0ac
commit 427b17d7a0
24 files changed
+2045 -148

No files matched your search

+46 -23
View File
@@ -513,8 +513,8 @@ ul {
z-index: 10;
position: relative;
text-align: center;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
/* Smoother transition */
transition: background-color 0.5s cubic-bezier(0.4, 0, 0.2, 1),
color 0.5s cubic-bezier(0.4, 0, 0.2, 1);
@@ -528,15 +528,26 @@ ul {
contain-intrinsic-size: 1000px;
} */
/* Mobile Optimization: Remove expensive effects */
@media (max-width: 767px) {
.main,
[data-theme="dark"] .main,
.artalk-related,
.floating-tools {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
box-shadow: none !important;
@media (min-width: 768px) {
.main {
background: rgba(255, 255, 255, 0.88);
-webkit-backdrop-filter: blur(6px);
backdrop-filter: blur(6px);
}
[data-theme="dark"] #pjax-loading-skeleton {
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
}
.floating-tools a {
-webkit-backdrop-filter: blur(4px) saturate(140%);
backdrop-filter: blur(4px) saturate(140%);
}
.atk-loading {
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
}
@@ -1825,7 +1836,8 @@ darkb-text:active {
[data-theme="dark"] #pjax-loading-skeleton {
background: rgba(15, 23, 42, 0.94) !important;
box-shadow: var(--card-shadow-dark) !important;
backdrop-filter: blur(18px);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
}
[data-theme="dark"] .skeleton-line {
@@ -2969,6 +2981,17 @@ input[type=submit] {
.lazyload {
width: 100%;
max-width: 100%;
height: auto;
}
.post-content img,
.entry-content img {
display: block;
max-width: 100%;
height: auto;
content-visibility: auto;
contain-intrinsic-size: 700px auto;
}
/* 设置进度条的背景色 */
@@ -3504,8 +3527,8 @@ input[type=submit] {
/* Optimized transition: specific properties instead of all */
transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease, border-color 0.3s ease;
/* Restored backdrop-filter */
backdrop-filter: blur(10px) saturate(180%);
-webkit-backdrop-filter: blur(10px) saturate(180%);
backdrop-filter: blur(4px) saturate(140%);
-webkit-backdrop-filter: blur(4px) saturate(140%);
border: 1px solid rgba(255, 255, 255, 0.4);
/* GPU Acceleration for individual items */
transform: translate3d(0, 0, 0);
@@ -4060,8 +4083,8 @@ img[atk-emoticon] {
background: rgba(255, 255, 255, 0.8) !important;
box-shadow: none !important; /* 去除阴影,更简洁 */
border-radius: 8px !important;
backdrop-filter: blur(4px); /* 轻微模糊 */
-webkit-backdrop-filter: blur(4px);
backdrop-filter: none;
-webkit-backdrop-filter: none;
/* display: flex !important; <-- 移除这个强制显示 */
align-items: center;
justify-content: center;
@@ -4747,17 +4770,17 @@ html[data-theme="light"] .atk-loading-spinner svg circle {
/* Lazy Load Animation */
.lazyload {
opacity: 0;
transform: translateY(30px); /* 稍微增加位移距离,增强上浮感 */
filter: blur(5px); /* 减少模糊,避免过于影响性能 */
transition: opacity 0.8s ease-out, transform 0.8s cubic-bezier(0.215, 0.61, 0.355, 1), filter 0.8s ease-out; /* 使用 ease-out 和自定义贝塞尔曲线,模拟自然惯性 */
will-change: opacity, transform; /* 移除 filter 的 will-change 以节省内存 */
opacity: 1;
transform: none;
filter: none;
transition: none;
will-change: auto;
}
.lazyload.lazy-loaded {
opacity: 1;
transform: translateY(0);
filter: blur(0);
transform: none;
filter: none;
}
[data-theme="dark"] .ai-comment-card .atk-content p {
+202
View File
@@ -0,0 +1,202 @@
window.BrowserCache = (function () {
var PREFIX = 'ying-cache:';
var DEBUG_KEY = PREFIX + 'debug';
var DEBUG = detectDebug();
function detectDebug() {
try {
if (typeof window === 'undefined' || !window.location) return false;
var loc = window.location;
var host = loc.hostname || '';
var protocol = loc.protocol || '';
var search = loc.search || '';
// Explicit URL override wins over everything.
if (/(^|[?&])debug-cache=1(&|$)/.test(search)) return true;
if (/(^|[?&])debug-cache=0(&|$)/.test(search)) return false;
// Persisted toggle (set via setDebug) wins over auto-detection.
try {
var stored = localStorage.getItem(DEBUG_KEY);
if (stored === '1') return true;
if (stored === '0') return false;
} catch (e) {}
// Auto-enable on local dev origins.
if (protocol === 'file:') return true;
if (host === 'localhost' || host === '127.0.0.1' || host === '0.0.0.0') return true;
} catch (e) {}
return false;
}
function setDebug(enabled) {
DEBUG = !!enabled;
try {
localStorage.setItem(DEBUG_KEY, DEBUG ? '1' : '0');
} catch (e) {}
return DEBUG;
}
function isDebug() {
return DEBUG;
}
function isStorageAvailable() {
try {
var key = PREFIX + '__test__';
localStorage.setItem(key, '1');
localStorage.removeItem(key);
return true;
} catch (e) {
return false;
}
}
function buildKey(key) {
return PREFIX + key;
}
function log(tagOrEvent, payload) {
if (!DEBUG || typeof console === 'undefined' || !console.info) return;
var label = tagOrEvent && tagOrEvent.charAt(0) === '[' ? tagOrEvent : '[BrowserCache][' + tagOrEvent + ']';
console.info(label, payload || {});
}
function formatDuration(ms) {
if (!ms || ms <= 0) return '0s';
var totalSeconds = Math.floor(ms / 1000);
var hours = Math.floor(totalSeconds / 3600);
var minutes = Math.floor((totalSeconds % 3600) / 60);
var seconds = totalSeconds % 60;
if (hours > 0) return hours + 'h ' + minutes + 'm';
if (minutes > 0) return minutes + 'm ' + seconds + 's';
return seconds + 's';
}
function remove(key) {
if (!isStorageAvailable()) return;
try {
localStorage.removeItem(buildKey(key));
log('remove', { key: buildKey(key) });
} catch (e) {}
}
function read(key, options) {
options = options || {};
if (!isStorageAvailable()) {
log('storage-unavailable', { key: buildKey(key) });
return null;
}
var fullKey = buildKey(key);
try {
var raw = localStorage.getItem(fullKey);
if (!raw) {
log('miss', { key: fullKey });
return null;
}
var payload = JSON.parse(raw);
if (!payload || typeof payload !== 'object') {
remove(key);
log('invalid-payload', { key: fullKey });
return null;
}
if (payload.version !== options.version) {
remove(key);
log('version-mismatch', { key: fullKey, expected: options.version, actual: payload.version });
return null;
}
if (typeof payload.cachedAt !== 'number' || !('data' in payload)) {
remove(key);
log('invalid-shape', { key: fullKey });
return null;
}
if (typeof options.validate === 'function' && !options.validate(payload.data)) {
remove(key);
log('validate-failed', { key: fullKey });
return null;
}
var now = Date.now();
var age = now - payload.cachedAt;
var softTtl = options.softTtl || 0;
var hardTtl = options.hardTtl || softTtl;
if (hardTtl > 0 && age > hardTtl) {
remove(key);
log('expired', { key: fullKey, age: formatDuration(age), hardTtl: formatDuration(hardTtl) });
return null;
}
var result = {
key: fullKey,
data: payload.data,
cachedAt: payload.cachedAt,
age: age,
ageText: formatDuration(age),
softTtl: softTtl,
softTtlText: formatDuration(softTtl),
hardTtl: hardTtl,
hardTtlText: formatDuration(hardTtl),
isFresh: softTtl <= 0 || age <= softTtl,
isStale: softTtl > 0 && age > softTtl
};
log(result.isFresh ? 'hit-fresh' : 'hit-stale', {
key: fullKey,
age: result.ageText,
softTtl: result.softTtlText,
hardTtl: result.hardTtlText
});
return result;
} catch (e) {
remove(key);
log('parse-failed', { key: fullKey, message: e && e.message ? e.message : e });
return null;
}
}
function write(key, options, data) {
options = options || {};
if (!isStorageAvailable()) {
log('storage-unavailable', { key: buildKey(key) });
return;
}
var fullKey = buildKey(key);
try {
localStorage.setItem(fullKey, JSON.stringify({
version: options.version,
cachedAt: Date.now(),
data: data
}));
log('write', {
key: fullKey,
softTtl: formatDuration(options.softTtl || 0),
hardTtl: formatDuration(options.hardTtl || options.softTtl || 0)
});
} catch (e) {
if (DEBUG && typeof console !== 'undefined' && console.warn) {
console.warn('BrowserCache write failed:', e);
}
}
}
return {
read: read,
write: write,
remove: remove,
buildKey: buildKey,
formatDuration: formatDuration,
log: log,
setDebug: setDebug,
isDebug: isDebug
};
})();
@@ -198,16 +198,21 @@ window.initFloatingTools = function() {
}
if (container) {
window.lightboxObserver = new MutationObserver(function(mutations) {
var syncLightboxState = function() {
var lightbox = document.querySelector('.view-image');
if (lightbox) {
container.classList.add('hidden');
} else {
container.classList.remove('hidden');
}
};
window.lightboxObserver = new MutationObserver(function() {
syncLightboxState();
});
window.lightboxObserver.observe(document.body, { childList: true });
window.lightboxObserver.observe(document.body, { childList: true, subtree: true });
syncLightboxState();
}
} catch (e) {
+31 -59
View File
@@ -1,77 +1,59 @@
(function() {
// Default configuration
var defaults = {
offsetBottom: 100, // Distance from bottom to start loading
showTime: 1100, // Transition duration (ms)
queueInterval: 200 // Time between showing successive images in queue
offsetBottom: 100,
showTime: 1100,
queueInterval: 200
};
var observer;
var imageQueue = []; // Queue for images waiting to be shown
var isProcessingQueue = false;
function init(setting) {
// Merge settings
defaults = Object.assign({}, defaults, setting || {});
// Reset queue
imageQueue = [];
isProcessingQueue = false;
// Disconnect previous observer if exists (for PJAX)
if (observer) {
observer.disconnect();
observer = null;
}
// Check for IntersectionObserver support
if (!window.IntersectionObserver) {
loadAllImages();
return;
}
// Initialize IntersectionObserver
observer = new IntersectionObserver(function(entries, self) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var img = entry.target;
// Load immediately without queue
loadImage(img);
// Stop observing this image once it's triggered
self.unobserve(img);
}
if (!entry.isIntersecting) return;
var img = entry.target;
loadImage(img);
self.unobserve(img);
});
}, {
rootMargin: "0px 0px " + defaults.offsetBottom + "px 0px",
threshold: 0.01
rootMargin: "0px 0px " + defaults.offsetBottom + "px 0px",
threshold: 0.01
});
observeImages();
}
// Removed addToQueue and processQueue functions as we want instant loading
function getPendingImages() {
return document.querySelectorAll('img.lazyload[data-lazy-src], .post-content img[data-lazy-src]:not(.lazy-loaded)');
}
function observeImages() {
var images = document.querySelectorAll('img.lazyload, .post-content img:not(.lazy-loaded)');
var images = getPendingImages();
images.forEach(function(img) {
if (img.classList.contains('lazy-loaded')) return;
// Update transition duration based on settings
if (defaults.showTime) {
// We'll set this via inline style or rely on CSS class if it matches default
// But for full control, let's set it
img.style.transitionDuration = (defaults.showTime / 1000) + 's';
}
if (img.getAttribute('data-lazy-src')) {
observer.observe(img);
}
observer.observe(img);
});
}
function markLoaded(img, callback) {
img.classList.add('lazy-loaded');
img.removeAttribute('data-lazy-src');
if (callback) callback();
}
function loadImage(img, callback) {
var src = img.getAttribute('data-lazy-src');
if (!src) {
@@ -79,37 +61,28 @@
return;
}
img.decoding = 'async';
var temp = new Image();
var onComplete = function() {
// Swap source
temp.decoding = 'async';
temp.onload = function() {
img.src = src;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
img.classList.add('lazy-loaded');
img.removeAttribute('data-lazy-src');
// Execute callback immediately after starting animation logic
if (callback) callback();
});
requestAnimationFrame(function() {
markLoaded(img, callback);
});
};
temp.onload = onComplete;
temp.onerror = function() {
// Fallback
img.src = src;
requestAnimationFrame(() => {
img.classList.add('lazy-loaded');
if (callback) callback();
});
markLoaded(img, callback);
};
temp.src = src;
}
function loadAllImages() {
var images = document.querySelectorAll('img.lazyload');
var images = getPendingImages();
images.forEach(function(img) {
loadImage(img);
});
@@ -117,5 +90,4 @@
window.lazyLoadInit = init;
window.lazyLoadRefresh = observeImages;
})();
+12
View File
@@ -50,6 +50,16 @@ function pjax_reload() {
}
}
function refreshHeatmap() {
if (typeof renderHeatmap === 'function') {
try {
renderHeatmap();
} catch (e) {
console.error('renderHeatmap error:', e);
}
}
}
// pjax发送时期
document.addEventListener("pjax:send", function () {
// pjax动画减少圆圈动画
@@ -141,4 +151,6 @@ document.addEventListener("pjax:complete", function () {
window.initSearch();
} catch(e) { console.error('initSearch error:', e); }
}
refreshHeatmap();
});
@@ -1,10 +1,17 @@
{{ $src := .Destination }}
{{ $alt := .Text }}
{{ $width := "" }}
{{ $height := "" }}
{{ $srcset := "" }}
{{- if not (strings.HasPrefix $src "http") -}}
{{- $img := .Page.Resources.GetMatch $src -}}
{{- if $img -}}
{{- $src = $img.RelPermalink -}}
{{- $width = printf "%d" $img.Width -}}
{{- $height = printf "%d" $img.Height -}}
{{- else -}}
{{- $src = $src | relURL -}}
{{- end -}}
{{- end -}}
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-lazy-src="{{ $src }}" alt="{{ .Text }}" class="lazyload" uk-scrollspy="cls: uk-animation-fade; delay: 200">
<img src="{{ $src }}" alt="{{ $alt }}" class="lazyload lazy-loaded" loading="lazy" decoding="async"{{ with $width }} width="{{ . }}"{{ end }}{{ with $height }} height="{{ . }}"{{ end }}>
+1 -1
View File
@@ -6,7 +6,7 @@
{{ range $paginator.Pages }}
<div class="post">
<div class="time">{{ .Date.Format "January 2, 2006" }}</div>
<a href="{{ .Permalink }}">{{ .Title }}</a>
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
</div>
{{ end }}
</div>
-1
View File
@@ -90,6 +90,5 @@
{{ end }}
<!-- 评论区内容结束 -->
</div>
<script async src="/js/bsz.js"></script>
</div>
{{ end }}
+1 -1
View File
@@ -41,7 +41,7 @@
{{ range $paginator.Pages }}
<div class="post">
<div class="time">{{ .Date.Format "January 2, 2006" }}</div>
<a href="{{ .Permalink }}">{{ .Title }}</a>
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
<!-- 计算每篇文章的发布时间与当前时间的差值 -->
{{ $publishDate := .Date }}
+1 -1
View File
@@ -1,5 +1,5 @@
{{ define "main" }}
<div id="pjax-container">
<div id="pjax-container" data-needs-echarts="true">
<div class="post-content" itemprop="articleBody" uk-scrollspy="target: > *; cls: uk-animation-slide-bottom-small; delay: 100">
{{ .Content }}
+1 -1
View File
@@ -38,7 +38,7 @@
<li data-date="{{ $year }}{{ printf "%02d" $month }}{{ .Date.Day }}">
<span class="articles_date_time">{{ .Date.Format "01/02" }}</span>
<a class="a-archives" href="{{ .Permalink }}">{{ .Title }}</a>
<a class="a-archives" href="{{ .RelPermalink }}">{{ .Title }}</a>
</li>
{{ end }}
+112 -36
View File
@@ -337,6 +337,15 @@
allPosts: [],
currentIndex: 0,
BATCH_SIZE: 10,
CACHE_KEY: 'friend-circle-v1',
CACHE_OPTIONS: {
version: 2,
softTtl: 5 * 60 * 1000,
hardTtl: 60 * 60 * 1000,
validate: function(data) {
return !!data && Array.isArray(data.posts);
}
},
timeAgo: function (dateStr) {
const date = new Date(dateStr);
@@ -403,6 +412,74 @@
});
},
renderEmpty: function () {
const container = document.getElementById("friend-circle-container");
if (!container) return;
container.innerHTML = '<div class="empty" style="grid-column: 1/-1; text-align:center; padding:20px;">暂无动态</div>';
},
renderError: function () {
const container = document.getElementById("friend-circle-container");
if (!container) return;
container.innerHTML = '<div class="error" style="grid-column: 1/-1; text-align:center; padding:20px; color:#d9534f;">加载失败,请稍后刷新重试</div>';
},
applyData: function (data) {
const container = document.getElementById("friend-circle-container");
if (!container) return;
if (!data.posts || data.posts.length === 0) {
this.renderEmpty();
return;
}
window.FriendCircle.allPosts = data.posts;
window.fcUpdateTime = new Date(data.updated).toLocaleString();
window.FriendCircle.currentIndex = 0;
container.innerHTML = "";
window.FriendCircle.loadMore();
},
fetchData: function () {
if (window.BrowserCache && typeof window.BrowserCache.log === 'function') {
window.BrowserCache.log('[FriendCircleCache][fetch]', {
key: window.BrowserCache ? window.BrowserCache.buildKey(window.FriendCircle.CACHE_KEY) : window.FriendCircle.CACHE_KEY,
softTtl: window.BrowserCache ? window.BrowserCache.formatDuration(window.FriendCircle.CACHE_OPTIONS.softTtl) : window.FriendCircle.CACHE_OPTIONS.softTtl,
hardTtl: window.BrowserCache ? window.BrowserCache.formatDuration(window.FriendCircle.CACHE_OPTIONS.hardTtl) : window.FriendCircle.CACHE_OPTIONS.hardTtl
});
}
return fetch("https://rssapi.usj.cc/api/articles?limit=50")
.then(function(res) {
if (!res.ok) throw new Error("Network response was not ok");
return res.json();
})
.then(function(apiData) {
const posts = (apiData.articles || []).map(function(a) {
return {
title: a.title || '',
link: a.link || '',
date: a.pubDate || '',
author: a.feedName || a.author || '',
avatar: a.favicon || '',
blogUrl: a.siteUrl || '',
image: null,
description: ''
};
});
const data = {
posts: posts,
updated: apiData.timestamp || new Date().toISOString()
};
if (window.BrowserCache) {
window.BrowserCache.write(window.FriendCircle.CACHE_KEY, window.FriendCircle.CACHE_OPTIONS, data);
}
return data;
});
},
initTooltip: function() {
if (this.tooltipInitialized) return;
this.tooltipInitialized = true;
@@ -476,42 +553,35 @@
if (this.isFetching) return;
this.isFetching = true;
// 从 RSS API 拉取按时间排序的文章
fetch("https://rssapi.usj.cc/api/articles?limit=50&t=" + new Date().getTime())
.then(function(res) {
if (!res.ok) throw new Error("Network response was not ok");
return res.json();
})
.then(function(apiData) {
// 将 API 格式转换为友圈格式
const posts = (apiData.articles || []).map(function(a) {
return {
title: a.title || '',
link: a.link || '',
date: a.pubDate || '',
author: a.feedName || a.author || '',
avatar: a.favicon || '',
blogUrl: a.siteUrl || '',
image: null,
description: ''
};
const cached = window.BrowserCache && window.BrowserCache.read(this.CACHE_KEY, this.CACHE_OPTIONS);
if (cached) {
if (window.BrowserCache && typeof window.BrowserCache.log === 'function') {
window.BrowserCache.log('[FriendCircleCache][render]', {
key: cached.key,
age: cached.ageText,
isFresh: cached.isFresh,
softTtl: cached.softTtlText,
hardTtl: cached.hardTtlText
});
const data = { posts: posts, updated: apiData.timestamp || new Date().toISOString() };
}
this.applyData(cached.data);
if (cached.isFresh) {
this.isFetching = false;
return;
}
}
if (!data.posts || data.posts.length === 0) {
container.innerHTML = '<div class="empty" style="grid-column: 1/-1; text-align:center; padding:20px;">暂无动态</div>';
return;
}
window.FriendCircle.allPosts = data.posts;
window.fcUpdateTime = new Date(data.updated).toLocaleString();
window.FriendCircle.currentIndex = 0;
container.innerHTML = "";
window.FriendCircle.loadMore();
this.fetchData()
.then(function(data) {
window.FriendCircle.applyData(data);
})
.catch(function(err) {
console.error("Friend Circle Error:", err);
container.innerHTML = '<div class="error" style="grid-column: 1/-1; text-align:center; padding:20px; color:#d9534f;">加载失败,请稍后刷新重试</div>';
if (window.BrowserCache && window.BrowserCache.isDebug && window.BrowserCache.isDebug()) {
console.error("Friend Circle Error:", err);
}
if (!cached) {
window.FriendCircle.renderError();
}
})
.finally(function() {
window.FriendCircle.isFetching = false;
@@ -519,12 +589,18 @@
}
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function() {
function initFriendCirclePage() {
if (window.FriendCircle && typeof window.FriendCircle.init === 'function') {
window.FriendCircle.init();
});
}
}
document.addEventListener('pjax:complete', initFriendCirclePage);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initFriendCirclePage);
} else {
window.FriendCircle.init();
initFriendCirclePage();
}
</script>
</div>
+88 -10
View File
@@ -78,18 +78,96 @@
var list = document.getElementById('links-list');
if (!list) return;
fetch('https://rssapi.usj.cc/api/links?t=' + new Date().getTime())
.then(function(res) { return res.json(); })
.then(function(data) {
var links = data.links || [];
if (links.length === 0) return;
var html = '';
links.forEach(function(l) {
html += '<li><a href="' + l.url + '" class="url-name" target="_blank">' + l.name + '</a><span style="margin-left: 13px;">' + (l.description || '') + '</span></li>';
var CACHE_KEY = 'friend-links-v1';
var CACHE_OPTIONS = {
version: 2,
softTtl: 6 * 60 * 60 * 1000,
hardTtl: 24 * 60 * 60 * 1000,
validate: function(data) {
return !!data && Array.isArray(data.links);
}
};
function escapeHtml(value) {
return String(value || '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function renderState(message, className) {
list.innerHTML = '<li class="' + className + '">' + escapeHtml(message) + '</li>';
}
function renderLinks(links) {
if (!Array.isArray(links) || links.length === 0) {
renderState('暂无友链数据', 'links-empty');
return;
}
var html = '';
links.forEach(function(l) {
html += '<li><a href="' + escapeHtml(l.url) + '" class="url-name" target="_blank" rel="noopener noreferrer">' + escapeHtml(l.name) + '</a><span style="margin-left: 13px;">' + escapeHtml(l.description || '') + '</span></li>';
});
list.innerHTML = html;
}
function logCache(event, payload) {
if (window.BrowserCache && typeof window.BrowserCache.log === 'function') {
window.BrowserCache.log('[LinksCache][' + event + ']', payload);
}
}
function fetchLinks() {
logCache('fetch', {
key: window.BrowserCache ? window.BrowserCache.buildKey(CACHE_KEY) : CACHE_KEY,
softTtl: window.BrowserCache ? window.BrowserCache.formatDuration(CACHE_OPTIONS.softTtl) : CACHE_OPTIONS.softTtl,
hardTtl: window.BrowserCache ? window.BrowserCache.formatDuration(CACHE_OPTIONS.hardTtl) : CACHE_OPTIONS.hardTtl
});
return fetch('https://rssapi.usj.cc/api/links')
.then(function(res) {
if (!res.ok) throw new Error('Failed to fetch links');
return res.json();
})
.then(function(data) {
var links = Array.isArray(data.links) ? data.links : [];
var payload = { links: links };
window.BrowserCache.write(CACHE_KEY, CACHE_OPTIONS, payload);
return payload;
});
list.innerHTML = html;
}
var cached = window.BrowserCache && window.BrowserCache.read(CACHE_KEY, CACHE_OPTIONS);
if (cached) {
logCache('render', {
key: cached.key,
age: cached.ageText,
isFresh: cached.isFresh,
softTtl: cached.softTtlText,
hardTtl: cached.hardTtlText
});
renderLinks(cached.data.links);
if (cached.isFresh) {
return;
}
} else {
renderState('友链加载中...', 'links-loading');
}
fetchLinks()
.then(function(payload) {
renderLinks(payload.links);
})
.catch(function() {});
.catch(function(err) {
if (window.BrowserCache && window.BrowserCache.isDebug && window.BrowserCache.isDebug()) {
console.error('Links Error:', err);
}
if (!cached) {
renderState('友链加载失败,请稍后刷新重试', 'links-error');
}
});
})();
</script>
</div>
+5 -4
View File
@@ -52,19 +52,20 @@
{{ $uikit := resources.Get "js/libs/uikit.min.js" }}
{{ $easylazyload := resources.Get "js/modules/lazyload.js" }}
{{ $viewimage := resources.Get "js/libs/view-image.min.js" }}
{{ $artalk := resources.Get "js/libs/Artalk.js" }}
{{ $barrage := resources.Get "js/modules/barrage.js" }}
{{ $main := resources.Get "js/main.js" }}
{{ $mypjax := resources.Get "js/modules/mypjax.js" }}
{{ $nprogress := resources.Get "js/libs/nprogress.js" }}
{{ $message := resources.Get "js/libs/message.min.js" }}
{{ $echarts := resources.Get "js/libs/echarts.min.js" }}
{{ $tiaozhuan := resources.Get "js/modules/tiaozhuan.js" }}
{{ $reward := resources.Get "js/modules/reward.js" }}
{{ $echarts := resources.Get "js/libs/echarts.min.js" }}
{{ $artalk := resources.Get "js/libs/Artalk.js" }}
{{/* Modules */}}
{{ $utils := resources.Get "js/modules/utils.js" }}
{{ $loader := resources.Get "js/modules/loader.js" }}
{{ $cache := resources.Get "js/modules/cache.js" }}
{{ $search := resources.Get "js/modules/search.js" }}
{{ $floatingTools := resources.Get "js/modules/floating-tools.js" }}
{{ $paragraphComments := resources.Get "js/modules/paragraph-comments.js" }}
@@ -72,9 +73,9 @@
{{ $artalkModule := resources.Get "js/modules/artalk.js" }}
{{ $pjaxLib := resources.Get "js/libs/pjax.js" }}
{{ $scripts := slice $iconfont $lightgallery $uikit $easylazyload $viewimage $artalk $barrage $utils $loader $search $floatingTools $paragraphComments $infiniteScroll $artalkModule $nprogress $pjaxLib $main $mypjax $message $echarts $tiaozhuan $reward | resources.Concat "js/bundle.js" | resources.Minify | resources.Fingerprint }}
{{ $scripts := slice $iconfont $lightgallery $uikit $easylazyload $viewimage $barrage $utils $loader $cache $search $floatingTools $paragraphComments $infiniteScroll $artalkModule $nprogress $pjaxLib $main $mypjax $message $tiaozhuan $reward $echarts $artalk | resources.Concat "js/bundle.js" | resources.Minify | resources.Fingerprint }}
<script src="{{ $scripts.RelPermalink }}"></script>
<script defer src="{{ $scripts.RelPermalink }}"></script>
<script>
// Global configuration from Hugo
window.enableInfiniteScroll = {{ .Site.Params.infiniteScroll.enable | default false }};
+6 -4
View File
@@ -1,10 +1,9 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>{{ .Title }}</title>
<!-- SEO & Meta Tags -->
<meta name="description" content="{{ if .IsHome }}{{ .Site.Params.description }}{{ else }}{{ .Description | default .Summary | plainify | truncate 160 }}{{ end }}" />
<link rel="canonical" href="{{ .Permalink }}" />
<link rel="canonical" href="{{ .RelPermalink | absURL }}" />
{{- $keywords := slice "大学" "教程" "blog" "优世界" "优设计" "博客" "大学生博客" "生活" "文案" -}}
{{- if .Params.tags -}}
@@ -72,6 +71,7 @@
</script>
<!-- Preload Fonts -->
<link rel="preload" href="{{ "font/zql-v2.woff2" | relURL }}" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="{{ "font/remixicon.woff2" | relURL }}" as="font" type="font/woff2" crossorigin>
<!-- Site Configuration -->
<script>
@@ -98,12 +98,14 @@
{{ $remixicon := resources.Get "css/libs/remixicon.css" }}
{{ $uikit := resources.Get "css/libs/uikit.min.css" }}
{{ $nprogress := resources.Get "css/libs/nprogress.min.css" }}
{{ $artalk := resources.Get "css/libs/Artalk.css" }}
{{ $message := resources.Get "css/libs/message.min.css" }}
{{ $main := resources.Get "css/main.css" }}
{{ $style := slice $normalize $remixicon $uikit $nprogress $artalk $message $main | resources.Concat "css/style.css" | resources.Minify | resources.Fingerprint }}
{{ $style := slice $normalize $remixicon $uikit $nprogress $message $main | resources.Concat "css/style.css" | resources.Minify | resources.Fingerprint }}
{{ $artalk := resources.Get "css/libs/Artalk.css" | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $style.RelPermalink }}">
<link rel="stylesheet" href="{{ $artalk.RelPermalink }}">
{{- if and .Site.Params.style.enableBackgroundImage .Site.Params.style.backgroundImageUrl -}}
<style>
+1 -1
View File
@@ -5,7 +5,7 @@
<div class="header">
<div class="header-top">
<div class="header-avatar load-memos-editor" id="theme-toggle-avatar">
<img src="{{ .Site.Params.author.avatar }}" class="blog-img" width="80" height="80" alt="{{ .Site.Title }}" />
<img src="{{ .Site.Params.author.avatar }}" class="blog-img" width="80" height="80" alt="{{ .Site.Title }}" decoding="async" fetchpriority="high" />
<div class="avatar-theme-tip">
点击头像切换昼夜
</div>