175 lines
5.5 KiB
HTML
175 lines
5.5 KiB
HTML
{{ define "main" }}
|
|
<div id="pjax-container">
|
|
<style>
|
|
.links ul>li {
|
|
position: relative;
|
|
padding-left: 1.75em;
|
|
}
|
|
|
|
.links a {
|
|
color: var(--link-color-light);
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.links li {
|
|
margin-top: .5em;
|
|
margin-bottom: .5em;
|
|
}
|
|
|
|
.links ul>li:before {
|
|
content: "";
|
|
position: absolute;
|
|
background-color: #d1d5db;
|
|
border-radius: 50%;
|
|
width: .375em;
|
|
height: .375em;
|
|
top: .6875em;
|
|
left: .25em;
|
|
}
|
|
|
|
.url-name {
|
|
position: relative;
|
|
display: inline-block;
|
|
}
|
|
|
|
.url-name::before {
|
|
content: "";
|
|
position: absolute;
|
|
height: 12px;
|
|
bottom: 3px;
|
|
left: -4px;
|
|
z-index: -1;
|
|
background-color: #5d5d5d;
|
|
opacity: .3;
|
|
transform: skew(-35deg);
|
|
transition: opacity .2s ease;
|
|
border-radius: 3px 8px 10px 6px;
|
|
transition: 0.1s ease background-color;
|
|
width: 112%;
|
|
}
|
|
|
|
.url-name:hover::before {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
[data-theme="dark"] .links a {
|
|
color: var(--link-color-dark);
|
|
}
|
|
|
|
[data-theme="dark"] .url-name::before {
|
|
background-color: #e5e7eb;
|
|
opacity: 0.18;
|
|
}
|
|
|
|
[data-theme="dark"] .url-name:hover::before {
|
|
opacity: 0.35;
|
|
}
|
|
</style>
|
|
<div class="post-content" itemprop="articleBody">
|
|
<div class="links">
|
|
<ul id="links-list" uk-scrollspy="target: > li; cls: uk-animation-slide-bottom-small; delay: 50">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
var list = document.getElementById('links-list');
|
|
if (!list) return;
|
|
|
|
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, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
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;
|
|
});
|
|
}
|
|
|
|
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(err) {
|
|
if (window.BrowserCache && window.BrowserCache.isDebug && window.BrowserCache.isDebug()) {
|
|
console.error('Links Error:', err);
|
|
}
|
|
if (!cached) {
|
|
renderState('友链加载失败,请稍后刷新重试', 'links-error');
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</div>
|
|
{{ end }}
|