增加i18n支持
This commit is contained in:
@@ -4,14 +4,14 @@ import Layout from "../layouts/Layout.astro";
|
||||
|
||||
<Layout>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${theme.config?.basic?.label_archives_title ?: '归档'} - ${site.title}|"></title>
|
||||
<title th:text="|${theme.config?.basic?.label_archives_title ?: #messages.msg('archives.title')} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
|
||||
<div class="wi-archives">
|
||||
<header class="wi-archives__header">
|
||||
<h1 class="wi-archives__title" th:text="${theme.config?.basic?.label_archives_title ?: '归档'}">归档</h1>
|
||||
<h1 class="wi-archives__title" th:text="${theme.config?.basic?.label_archives_title ?: #messages.msg('archives.title')}">归档</h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
<p class="wi-archives__subtitle" th:text="${#strings.replace(theme.config?.home?.home_label_post_count ?: '共 {total} 篇文章', '{total}', #strings.toString(archives.total))}"></p>
|
||||
<p class="wi-archives__subtitle" th:text="${#strings.replace(#messages.msg('common.postCount'), '{0}', #strings.toString(archives.total))}"></p>
|
||||
</header>
|
||||
|
||||
<section class="wi-archives__timeline" aria-label="Archive timeline">
|
||||
@@ -57,8 +57,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
<div
|
||||
th:if="${archives.total == 0}"
|
||||
class="wi-archives__empty"
|
||||
th:text="${theme.config?.home?.home_label_no_posts ?: '暂无文章。'}"
|
||||
>暂无文章。</div>
|
||||
th:text="${theme.config?.home?.home_label_no_posts ?: #messages.msg('common.noPosts')}"
|
||||
>No posts yet.</div>
|
||||
</section>
|
||||
|
||||
<nav
|
||||
@@ -70,8 +70,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:if="${archives.hasPrevious()}"
|
||||
th:href="@{${archives.prevUrl}}"
|
||||
class="wi-archives__page-link wi-archives__page-link--prev"
|
||||
th:text="${theme.config?.home?.home_label_newer ?: '较新'}"
|
||||
>← 较新</a>
|
||||
th:text="${theme.config?.home?.home_label_newer ?: #messages.msg('common.newer')}"
|
||||
>← Newer</a>
|
||||
<span
|
||||
class="wi-archives__page-info"
|
||||
th:text="|${archives.page} / ${archives.totalPages}|"
|
||||
@@ -80,8 +80,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:if="${archives.hasNext()}"
|
||||
th:href="@{${archives.nextUrl}}"
|
||||
class="wi-archives__page-link wi-archives__page-link--next"
|
||||
th:text="${theme.config?.home?.home_label_older ?: '较旧'}"
|
||||
>较旧 →</a>
|
||||
th:text="${theme.config?.home?.home_label_older ?: #messages.msg('common.older')}"
|
||||
>Older →</a>
|
||||
</nav>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
@@ -4,14 +4,14 @@ import Layout from "../layouts/Layout.astro";
|
||||
|
||||
<Layout>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|分类 - ${site.title}|"></title>
|
||||
<title th:text="|#{categories.title} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
|
||||
<div class="wi-categories">
|
||||
<header class="wi-categories__header">
|
||||
<h1 class="wi-categories__title">分类</h1>
|
||||
<h1 class="wi-categories__title" th:text="#{categories.title}">分类</h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
<p class="wi-categories__subtitle" th:text="|共 ${categories.size} 个分类|"></p>
|
||||
<p class="wi-categories__subtitle" th:text="${#messages.msg('common.categoryCount', ${categories.size})}"></p>
|
||||
</header>
|
||||
|
||||
<nav class="wi-categories__list" aria-label="Category list">
|
||||
|
||||
+135
-8
@@ -14,7 +14,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:text="${category.spec.displayName}"
|
||||
></h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
<p class="wi-category__subtitle" th:text="|共 ${posts.total} 篇文章|"></p>
|
||||
<p class="wi-category__subtitle" th:text="#{common.postCount(${posts.total})}"></p>
|
||||
<p
|
||||
th:if="${not #strings.isEmpty(category.spec.description)}"
|
||||
class="wi-category__description"
|
||||
@@ -22,13 +22,44 @@ import Layout from "../layouts/Layout.astro";
|
||||
></p>
|
||||
</header>
|
||||
|
||||
<th:block th:replace="~{fragments/post-list}"></th:block>
|
||||
<ul class="wi-category__list" role="list">
|
||||
<li
|
||||
th:each="post : ${posts.items}"
|
||||
class="wi-category__entry"
|
||||
>
|
||||
<a
|
||||
class="wi-category__entry-link"
|
||||
th:href="@{${post.status.permalink}}"
|
||||
>
|
||||
<div class="wi-category__entry-body">
|
||||
<time
|
||||
class="wi-category__entry-date"
|
||||
th:text="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd')}"
|
||||
datetime="${post.spec.publishTime}"
|
||||
></time>
|
||||
<h2 class="wi-category__entry-title" th:text="${post.spec.title}"></h2>
|
||||
<p
|
||||
class="wi-category__entry-excerpt"
|
||||
th:text="${post.status.excerpt}"
|
||||
></p>
|
||||
</div>
|
||||
<img
|
||||
th:unless="${#strings.isEmpty(post.spec.cover)}"
|
||||
class="wi-category__entry-image"
|
||||
th:src="${post.spec.cover}"
|
||||
alt=""
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div
|
||||
th:if="${posts.total == 0}"
|
||||
class="wi-category__empty"
|
||||
th:text="${theme.config?.home?.home_label_no_posts ?: '暂无文章。'}"
|
||||
>暂无文章。</div>
|
||||
th:text="${theme.config?.home?.home_label_no_posts ?: #messages.msg('common.noPosts')}"
|
||||
>No posts yet.</div>
|
||||
|
||||
<nav
|
||||
th:if="${posts.totalPages gt 1}"
|
||||
@@ -39,8 +70,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:if="${posts.hasPrevious()}"
|
||||
th:href="@{${posts.prevUrl}}"
|
||||
class="wi-category__page-link wi-category__page-link--prev"
|
||||
th:text="${theme.config?.home?.home_label_newer ?: '较新'}"
|
||||
>← 较新</a>
|
||||
th:text="${theme.config?.home?.home_label_newer ?: #messages.msg('common.newer')}"
|
||||
>← Newer</a>
|
||||
<span
|
||||
class="wi-category__page-info"
|
||||
th:text="|${posts.page} / ${posts.totalPages}|"
|
||||
@@ -49,8 +80,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:if="${posts.hasNext()}"
|
||||
th:href="@{${posts.nextUrl}}"
|
||||
class="wi-category__page-link wi-category__page-link--next"
|
||||
th:text="${theme.config?.home?.home_label_older ?: '较旧'}"
|
||||
>较旧 →</a>
|
||||
th:text="${theme.config?.home?.home_label_older ?: #messages.msg('common.older')}"
|
||||
>Older →</a>
|
||||
</nav>
|
||||
</div>
|
||||
</Layout>
|
||||
@@ -97,6 +128,90 @@ import Layout from "../layouts/Layout.astro";
|
||||
line-height: var(--leading-normal);
|
||||
}
|
||||
|
||||
.wi-category__list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
gap: var(--space-lg);
|
||||
}
|
||||
|
||||
.wi-category__entry {
|
||||
border-bottom: 1px dashed var(--rule);
|
||||
transition: background var(--duration-fast) var(--ease-out-quart);
|
||||
}
|
||||
|
||||
.wi-category__entry:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.wi-category__entry:hover {
|
||||
background: var(--bg-raised);
|
||||
margin: 0 calc(-1 * var(--space-md));
|
||||
padding-left: var(--space-md);
|
||||
padding-right: var(--space-md);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.wi-category__entry-link {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 200px;
|
||||
gap: var(--space-lg);
|
||||
padding: var(--space-lg) 0;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.wi-category__entry-body {
|
||||
display: grid;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.wi-category__entry-date {
|
||||
color: var(--ink-3);
|
||||
font-size: var(--text-sm);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.wi-category__entry-title {
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
line-height: var(--leading-snug);
|
||||
margin: 0.25rem 0;
|
||||
transition: color var(--duration-fast) var(--ease-out-quart);
|
||||
}
|
||||
|
||||
.wi-category__entry-link:hover .wi-category__entry-title {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.wi-category__entry-excerpt {
|
||||
margin: 0;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--ink-2);
|
||||
line-height: var(--leading-normal);
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wi-category__entry-image {
|
||||
width: 200px;
|
||||
height: 140px;
|
||||
object-fit: cover;
|
||||
border-radius: var(--radius-sm);
|
||||
align-self: center;
|
||||
transition: transform var(--duration-fast) var(--ease-out-quart);
|
||||
}
|
||||
|
||||
.wi-category__entry:hover .wi-category__entry-image {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.wi-category__empty {
|
||||
color: var(--ink-3);
|
||||
font-size: var(--text-md);
|
||||
@@ -127,4 +242,16 @@ import Layout from "../layouts/Layout.astro";
|
||||
.wi-category__page-info {
|
||||
color: var(--ink-3);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.wi-category__entry-link {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.wi-category__entry-image {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
order: -1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+25
-13
@@ -10,7 +10,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
<section class="wi-douban">
|
||||
<div class="wi-container">
|
||||
<div class="wi-douban__header">
|
||||
<h1 class="wi-douban__title" th:text="${title}">豆瓣</h1>
|
||||
<h1 class="wi-douban__title" th:text="${title ?: #messages.msg('douban.title')}">Douban</h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
</div>
|
||||
|
||||
@@ -32,63 +32,63 @@ import Layout from "../layouts/Layout.astro";
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type=${currentType},status='wish')}"
|
||||
th:classappend="${hasStatus and currentStatus == 'wish'} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>想看</a>
|
||||
th:text="#{douban.wish}">Wish</a>
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type=${currentType},status='done')}"
|
||||
th:classappend="${(!hasStatus and isDefaultType) or (hasStatus and currentStatus == 'done')} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>看过</a>
|
||||
th:text="#{douban.done}">Done</a>
|
||||
</th:block>
|
||||
<th:block th:if="${currentType == 'book'}">
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='book',status='wish')}"
|
||||
th:classappend="${hasStatus and currentStatus == 'wish'} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>想读</a>
|
||||
th:text="#{douban.wishRead}">Wish</a>
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='book',status='doing')}"
|
||||
th:classappend="${hasStatus and currentStatus == 'doing'} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>在读</a>
|
||||
th:text="#{douban.reading}">Reading</a>
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='book',status='done')}"
|
||||
th:classappend="${(!hasStatus and isDefaultType) or (hasStatus and currentStatus == 'done')} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>读过</a>
|
||||
th:text="#{douban.done}">Done</a>
|
||||
</th:block>
|
||||
<th:block th:if="${currentType == 'music'}">
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='music',status='wish')}"
|
||||
th:classappend="${hasStatus and currentStatus == 'wish'} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>想听</a>
|
||||
th:text="#{douban.wishListen}">Wish</a>
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='music',status='doing')}"
|
||||
th:classappend="${hasStatus and currentStatus == 'doing'} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>在听</a>
|
||||
th:text="#{douban.listening}">Listening</a>
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='music',status='done')}"
|
||||
th:classappend="${(!hasStatus and isDefaultType) or (hasStatus and currentStatus == 'done')} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>听过</a>
|
||||
th:text="#{douban.listened}">Listened</a>
|
||||
</th:block>
|
||||
<th:block th:if="${currentType == 'game'}">
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='game',status='wish')}"
|
||||
th:classappend="${hasStatus and currentStatus == 'wish'} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>想玩</a>
|
||||
th:text="#{douban.wishPlay}">Wish</a>
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='game',status='doing')}"
|
||||
th:classappend="${hasStatus and currentStatus == 'doing'} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>在玩</a>
|
||||
th:text="#{douban.playing}">Playing</a>
|
||||
<a
|
||||
class="wi-douban__filter-tag wi-douban__filter-tag--sm"
|
||||
th:href="@{/douban(type='game',status='done')}"
|
||||
th:classappend="${(!hasStatus and isDefaultType) or (hasStatus and currentStatus == 'done')} ? 'wi-douban__filter-tag--active' : ''"
|
||||
>玩过</a>
|
||||
th:text="#{douban.played}">Played</a>
|
||||
</th:block>
|
||||
</div>
|
||||
|
||||
@@ -120,6 +120,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
class="wi-douban__card"
|
||||
th:each="item : ${doubans.items}"
|
||||
th:if="${!hasGenre or #sets.contains(item.spec?.genres, currentGenre)}"
|
||||
th:attr="data-type=${currentType}"
|
||||
>
|
||||
<a
|
||||
class="wi-douban__card-link"
|
||||
@@ -161,7 +162,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
class="wi-douban__my-score"
|
||||
th:if="${!#strings.isEmpty(item.faves?.score)}"
|
||||
>
|
||||
我的:<th:block th:text="${item.faves?.score}"></th:block>
|
||||
<span th:text="#{douban.myRating}">My:</span><th:block th:text="${item.faves?.score}"></th:block>
|
||||
</span>
|
||||
<span
|
||||
class="wi-douban__year"
|
||||
@@ -299,6 +300,12 @@ import Layout from "../layouts/Layout.astro";
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.wi-douban__card[data-type="music"] .wi-douban__poster {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.wi-douban__poster-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -408,5 +415,10 @@ import Layout from "../layouts/Layout.astro";
|
||||
width: 64px;
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
.wi-douban__card[data-type="music"] .wi-douban__poster {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
---
|
||||
import Navbar from "../components/Navbar.astro";
|
||||
import MobileMenu from "../components/MobileMenu.astro";
|
||||
import "../styles/main.scss";
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="zh" th:lang="${theme.config?.basic?.language ?: #locale.language}" th:classappend="${theme.config?.animation?.animation_enabled == false} ? 'wi-no-animations'">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script is:inline th:attr="data-scheme=${theme.config?.style?.color_scheme}">
|
||||
(function () {
|
||||
var stored = localStorage.getItem("wi-theme");
|
||||
var prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
var scheme = null;
|
||||
if (document.currentScript && document.currentScript.getAttribute("data-scheme")) {
|
||||
scheme = document.currentScript.getAttribute("data-scheme");
|
||||
}
|
||||
var isDark = false;
|
||||
if (stored === "dark") { isDark = true; }
|
||||
else if (stored === "light") { isDark = false; }
|
||||
else if (scheme === "dark") { isDark = true; }
|
||||
else if (scheme === "light") { isDark = false; }
|
||||
else if (!stored && prefersDark) { isDark = true; }
|
||||
if (isDark) {
|
||||
document.documentElement.classList.add("dark");
|
||||
document.documentElement.setAttribute("data-color-scheme", "dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
document.documentElement.setAttribute("data-color-scheme", "light");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<title th:text="|${settings.title} - ${site.title}|"></title>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/plugins/footprint/assets/static/css/footprint.css(version=${version})}" />
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/plugins/footprint/assets/static/font/result.css(version=${version})}" />
|
||||
<script type="text/javascript" th:src="@{/plugins/footprint/assets/static/js/jquery-3.6.0.min.js}"></script>
|
||||
<script type="text/javascript">
|
||||
window._AMapSecurityConfig = {
|
||||
securityJsCode: /*[[${settings.gaoDeKey}]]*/''
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" th:src="|https://webapi.amap.com/maps?v=2.0&key=${settings.gaoDeKey}|"></script>
|
||||
<script type="text/javascript" th:src="@{/plugins/footprint/assets/static/js/footprint.js(version=${version})}"></script>
|
||||
<script th:inline="javascript">
|
||||
window.FOOTPRINT_CONFIG = {
|
||||
amapKey: /*[[${settings.gaoDeKey}]]*/'',
|
||||
footprints: [],
|
||||
title: /*[[${settings.title}]]*/ '足迹',
|
||||
logoName: /*[[${settings.logoName}]]*/ '足迹',
|
||||
describe: /*[[${settings.describe}]]*/ '描述',
|
||||
hsla: /*[[${settings.hsla}]]*/ '200, 100%, 50%',
|
||||
mapStyle: /*[[${settings.mapStyle}]]*/ 'amap://styles/normal'
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body id="footprint-page">
|
||||
<Navbar />
|
||||
<MobileMenu />
|
||||
|
||||
<div class="footprint-container">
|
||||
<div id="footprint-map"></div>
|
||||
|
||||
<div class="logo-container">
|
||||
<h1 class="footprint-logo" th:text="${settings.logoName}">足迹<span class="logo-version">2024</span></h1>
|
||||
<p class="footprint-slogan" th:text="${settings.describe}">每一处足迹都充满了故事,那是对人生的思考和无限的风光。</p>
|
||||
</div>
|
||||
|
||||
<div class="map-controls">
|
||||
<div class="likcc-layer-selector">
|
||||
<button class="likcc-layer-btn active" data-type="normal">
|
||||
<svg class="likcc-layer-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
||||
<path d="M9 9h6v6H9z"></path>
|
||||
</svg>
|
||||
<span>标准图</span>
|
||||
</button>
|
||||
<button class="likcc-layer-btn" data-type="satellite">
|
||||
<svg class="likcc-layer-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
|
||||
</svg>
|
||||
<span>卫星图</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="likcc-feature-toggles">
|
||||
<label class="likcc-toggle-item">
|
||||
<input type="checkbox" data-type="road">
|
||||
<div class="likcc-toggle-switch">
|
||||
<div class="likcc-toggle-slider"></div>
|
||||
</div>
|
||||
<div class="likcc-toggle-content">
|
||||
<svg class="likcc-toggle-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 7v10a4 4 0 004 4h10a4 4 0 004-4V7a4 4 0 00-4-4H7a4 4 0 00-4 4z"></path>
|
||||
<path d="M9 12h6"></path>
|
||||
</svg>
|
||||
<span class="likcc-toggle-label">路网</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="likcc-toggle-item">
|
||||
<input type="checkbox" data-type="traffic">
|
||||
<div class="likcc-toggle-switch">
|
||||
<div class="likcc-toggle-slider"></div>
|
||||
</div>
|
||||
<div class="likcc-toggle-content">
|
||||
<svg class="likcc-toggle-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path>
|
||||
</svg>
|
||||
<span class="likcc-toggle-label">路况</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="likcc-zoom-controls">
|
||||
<button class="likcc-zoom-btn" id="zoom-out">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<path d="M21 21l-4.35-4.35"></path>
|
||||
<line x1="8" y1="11" x2="14" y2="11"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="likcc-zoom-btn" id="zoom-in">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<path d="M21 21l-4.35-4.35"></path>
|
||||
<line x1="11" y1="8" x2="11" y2="14"></line>
|
||||
<line x1="8" y1="11" x2="14" y2="11"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="likcc-scale-display">
|
||||
<div class="likcc-scale-bar"></div>
|
||||
<span class="likcc-scale-text" id="scale-text">1000 公里</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style>
|
||||
#footprint-page {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#footprint-page .footprint-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100vh - 72px);
|
||||
margin-top: 72px;
|
||||
}
|
||||
|
||||
#footprint-page #footprint-map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
|
||||
<Layout wide>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${theme.config?.friends?.friends_page_title ?: '朋友圈'} - ${site.title}|"></title>
|
||||
<title th:text="|${theme.config?.friends?.friends_page_title ?: #messages.msg('friends.title')} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
|
||||
<section
|
||||
@@ -15,9 +15,9 @@ import Layout from "../layouts/Layout.astro";
|
||||
<div class="wi-friends-page__header">
|
||||
<h1
|
||||
class="wi-friends-page__title"
|
||||
th:text="${theme.config?.friends?.friends_page_title ?: '朋友圈'}"
|
||||
th:text="${theme.config?.friends?.friends_page_title ?: #messages.msg('friends.title')}"
|
||||
>
|
||||
朋友圈
|
||||
Friends Circle
|
||||
</h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
</div>
|
||||
@@ -87,8 +87,9 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:if="${friends.hasPrevious()}"
|
||||
th:href="@{${friends.prevUrl}}"
|
||||
class="wi-friends-page__page-link"
|
||||
th:text="#{common.newer}"
|
||||
>
|
||||
← 上一页
|
||||
← Newer
|
||||
</a>
|
||||
<span
|
||||
class="wi-friends-page__page-info"
|
||||
@@ -98,8 +99,9 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:if="${friends.hasNext()}"
|
||||
th:href="@{${friends.nextUrl}}"
|
||||
class="wi-friends-page__page-link"
|
||||
th:text="#{common.older}"
|
||||
>
|
||||
下一页 →
|
||||
Older →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -111,11 +113,11 @@ import Layout from "../layouts/Layout.astro";
|
||||
>
|
||||
<div class="wi-container">
|
||||
<div class="wi-friends-page__header">
|
||||
<h1 class="wi-friends-page__title">朋友圈</h1>
|
||||
<h1 class="wi-friends-page__title" th:text="#{friends.title}">Friends Circle</h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
</div>
|
||||
<div class="wi-friends-page__empty">
|
||||
<p>朋友圈功能需要安装「朋友圈」插件,<a href="https://www.halo.run/store/apps/app-friends">前往应用市场安装</a></p>
|
||||
<p th:utext="#{common.installPlugin('Friends Circle', 'https://www.halo.run/store/apps/app-friends')}">This feature requires the Friends Circle plugin</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
+76
-9
@@ -13,6 +13,7 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
<div
|
||||
class="wi-home-content"
|
||||
th:classappend="${theme.config?.hero?.hero_enabled != false} ? 'wi-home-content--with-hero'"
|
||||
th:attr="data-i18n-all-loaded=#{common.allLoaded},data-i18n-loading=#{common.loading},data-i18n-words=#{common.words},data-i18n-read-time=#{common.readTime},data-i18n-views=#{common.views}"
|
||||
>
|
||||
<section
|
||||
class="wi-home-pinned"
|
||||
@@ -20,7 +21,7 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
>
|
||||
<div class="wi-container">
|
||||
<div class="wi-section__header">
|
||||
<h2 class="wi-section__title" th:text="${theme.config?.home?.home_pinned_title ?: '置顶'}">置顶</h2>
|
||||
<h2 class="wi-section__title" th:text="${theme.config?.home?.home_pinned_title ?: #messages.msg('hero.pinned')}">置顶</h2>
|
||||
</div>
|
||||
<div class="wi-pinned">
|
||||
<a
|
||||
@@ -65,7 +66,7 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
<section class="wi-home-posts" id="wi-home-posts">
|
||||
<div class="wi-container">
|
||||
<div class="wi-section__header">
|
||||
<h2 class="wi-section__title" th:text="${theme.config?.home?.home_posts_title ?: '文章'}">文章</h2>
|
||||
<h2 class="wi-section__title" th:text="${theme.config?.home?.home_posts_title ?: #messages.msg('hero.posts')}">文章</h2>
|
||||
</div>
|
||||
<div class="wi-flow" id="wi-post-grid">
|
||||
<article
|
||||
@@ -128,7 +129,7 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
class="wi-flow__stat"
|
||||
th:if="${theme.config?.home?.home_card_show_visit ?: true}"
|
||||
>
|
||||
<th:block th:text="${post.stats?.visit ?: 0}"></th:block> 阅读
|
||||
<th:block th:text="${post.stats?.visit ?: 0}"></th:block> <th:block th:text="#{common.views}">阅读</th:block>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -152,7 +153,7 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
th:if="${posts.hasPrevious()}"
|
||||
th:href="@{${posts.prevUrl}}"
|
||||
class="wi-pagination__prev"
|
||||
th:text="${theme.config?.home?.home_label_newer ?: '较新'}"
|
||||
th:text="${theme.config?.home?.home_label_newer ?: #messages.msg('common.newer')}"
|
||||
>← 较新</a>
|
||||
<span
|
||||
class="wi-pagination__info"
|
||||
@@ -162,18 +163,18 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
th:if="${posts.hasNext()}"
|
||||
th:href="@{${posts.nextUrl}}"
|
||||
class="wi-pagination__next"
|
||||
th:text="${theme.config?.home?.home_label_older ?: '较旧'}"
|
||||
th:text="${theme.config?.home?.home_label_older ?: #messages.msg('common.older')}"
|
||||
>较旧 →</a>
|
||||
</nav>
|
||||
|
||||
<div
|
||||
th:if="${posts.hasNext() and theme.config?.home?.home_post_loading == 'infinite_scroll'}"
|
||||
id="wi-infinite-scroll-sentinel"
|
||||
th:attr="data-next-url=${posts.nextUrl}, data-all-loaded-text=${theme.config?.home?.home_label_all_loaded ?: '已加载全部文章'}"
|
||||
th:attr="data-next-url=${posts.nextUrl}, data-all-loaded-text=${theme.config?.home?.home_label_all_loaded ?: #messages.msg('common.allLoaded')}"
|
||||
>
|
||||
<div class="wi-infinite-scroll__loader">
|
||||
<div class="wi-infinite-scroll__spinner"></div>
|
||||
<span th:text="${theme.config?.home?.home_label_loading ?: '加载中...'}">加载中...</span>
|
||||
<span th:text="${theme.config?.home?.home_label_loading ?: #messages.msg('common.loading')}">加载中...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -181,7 +182,7 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
th:if="${!posts.hasNext() and posts.totalPages gt 1 and theme.config?.home?.home_post_loading == 'infinite_scroll'}"
|
||||
class="wi-infinite-scroll__end"
|
||||
>
|
||||
<span th:text="${theme.config?.home?.home_label_all_loaded ?: '已加载全部文章'}">已加载全部文章</span>
|
||||
<span th:text="${theme.config?.home?.home_label_all_loaded ?: #messages.msg('common.allLoaded')}">已加载全部文章</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -194,9 +195,10 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
if (!sentinel) return;
|
||||
|
||||
var grid = document.getElementById("wi-post-grid");
|
||||
var i18nEl = document.querySelector(".wi-home-content");
|
||||
var loading = false;
|
||||
var nextUrl = sentinel.getAttribute("data-next-url");
|
||||
var allLoadedText = sentinel.getAttribute("data-all-loaded-text") || "已加载全部文章";
|
||||
var allLoadedText = sentinel.getAttribute("data-all-loaded-text") || (i18nEl && i18nEl.getAttribute("data-i18n-all-loaded")) || "All posts loaded";
|
||||
|
||||
var observer = new IntersectionObserver(
|
||||
function (entries) {
|
||||
@@ -302,6 +304,71 @@ import HeroSection from "../components/HeroSection.astro";
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script is:inline>
|
||||
(function () {
|
||||
var hero = document.getElementById("wi-hero");
|
||||
var content = document.querySelector(".wi-home-content--with-hero");
|
||||
if (!hero || !content) return;
|
||||
|
||||
var isSnapping = false;
|
||||
var heroHeight = window.innerHeight;
|
||||
|
||||
window.addEventListener("resize", function () {
|
||||
heroHeight = window.innerHeight;
|
||||
}, { passive: true });
|
||||
|
||||
function snapTo(targetY) {
|
||||
if (isSnapping) return;
|
||||
isSnapping = true;
|
||||
window.scrollTo({ top: targetY, behavior: "smooth" });
|
||||
var timer = setTimeout(function () {
|
||||
isSnapping = false;
|
||||
}, 800);
|
||||
if ("onscrollend" in window) {
|
||||
window.addEventListener(
|
||||
"scrollend",
|
||||
function () {
|
||||
clearTimeout(timer);
|
||||
isSnapping = false;
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("wheel", function (e) {
|
||||
if (isSnapping) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
var y = window.scrollY;
|
||||
if (y < heroHeight && e.deltaY > 0) {
|
||||
e.preventDefault();
|
||||
snapTo(heroHeight);
|
||||
} else if (y > 0 && y <= heroHeight && e.deltaY < 0) {
|
||||
e.preventDefault();
|
||||
snapTo(0);
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
var touchStartY = 0;
|
||||
window.addEventListener("touchstart", function (e) {
|
||||
touchStartY = e.touches[0].clientY;
|
||||
}, { passive: true });
|
||||
|
||||
window.addEventListener("touchend", function (e) {
|
||||
if (isSnapping) return;
|
||||
var diff = touchStartY - e.changedTouches[0].clientY;
|
||||
var y = window.scrollY;
|
||||
if (y < heroHeight && diff > 30) {
|
||||
snapTo(heroHeight);
|
||||
} else if (y > 0 && y <= heroHeight && diff < -30) {
|
||||
snapTo(0);
|
||||
}
|
||||
}, { passive: true });
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.wi-home-content {
|
||||
position: relative;
|
||||
|
||||
@@ -4,7 +4,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
|
||||
<Layout wide>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${theme.config?.links?.links_page_title ?: '友情链接'} - ${site.title}|"></title>
|
||||
<title th:text="|${theme.config?.links?.links_page_title ?: #messages.msg('links.title')} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
|
||||
<section
|
||||
@@ -16,11 +16,11 @@ import Layout from "../layouts/Layout.astro";
|
||||
<div class="wi-links__header">
|
||||
<h1
|
||||
class="wi-links__title"
|
||||
th:text="${theme.config?.links?.links_page_title ?: '友情链接'}"
|
||||
th:text="${theme.config?.links?.links_page_title ?: #messages.msg('links.title')}"
|
||||
>
|
||||
友情链接
|
||||
</h1>
|
||||
<p class="wi-links__subtitle">山水一程,三生有幸</p>
|
||||
<p class="wi-links__subtitle" th:text="#{links.subtitle}">Mountains and rivers, a journey of a thousand miles</p>
|
||||
<span class="wi-page-accent"></span>
|
||||
</div>
|
||||
|
||||
@@ -154,6 +154,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.wi-links__card-glow {
|
||||
@@ -184,6 +185,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 16px;
|
||||
flex: 1;
|
||||
transition:
|
||||
transform var(--duration-normal) var(--ease-out-expo),
|
||||
box-shadow var(--duration-normal) var(--ease-out-expo),
|
||||
|
||||
+13
-11
@@ -5,13 +5,13 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
|
||||
<Layout>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${theme.config?.moments?.moments_page_title ?: '瞬间'} - ${site.title}|"></title>
|
||||
<title th:text="|${theme.config?.moments?.moments_page_title ?: #messages.msg('moments.title')} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
|
||||
<section class="wi-moments-page">
|
||||
<section class="wi-moments-page" th:attr="data-i18n-all-moments-loaded=#{common.allMomentsLoaded}">
|
||||
<div class="wi-container">
|
||||
<div class="wi-moments-page__header">
|
||||
<h1 class="wi-moments-page__title" th:text="${theme.config?.moments?.moments_page_title ?: '瞬间'}">瞬间</h1>
|
||||
<h1 class="wi-moments-page__title" th:text="${theme.config?.moments?.moments_page_title ?: #messages.msg('moments.title')}">瞬间</h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
</div>
|
||||
|
||||
@@ -77,7 +77,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
</th:block>
|
||||
<th:block th:if="${momentsResult == null or #lists.isEmpty(momentsResult.items)}">
|
||||
<div class="wi-moments-page__empty">
|
||||
<p>还没有瞬间,快去记录当下的心情吧 🌙</p>
|
||||
<p th:text="#{moments.noMoments}">No moments yet</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
@@ -133,7 +133,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
</th:block>
|
||||
<th:block th:if="${momentsResult == null or #lists.isEmpty(momentsResult.items)}">
|
||||
<div class="wi-moments-page__empty">
|
||||
<p>还没有瞬间,快去记录当下的心情吧 🌙</p>
|
||||
<p th:text="#{moments.noMoments}">No moments yet</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
@@ -189,7 +189,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
</th:block>
|
||||
<th:block th:if="${momentsResult == null or #lists.isEmpty(momentsResult.items)}">
|
||||
<div class="wi-moments-page__empty">
|
||||
<p>还没有瞬间,快去记录当下的心情吧 🌙</p>
|
||||
<p th:text="#{moments.noMoments}">No moments yet</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
@@ -204,13 +204,13 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
class="wi-moments-page__page-btn"
|
||||
th:if="${momentsResult.hasPrevious()}"
|
||||
th:href="${momentsResult.prevUrl}"
|
||||
>← 较新</a>
|
||||
th:text="#{common.newer}">Newer</a>
|
||||
<span class="wi-moments-page__page-spacer" th:if="${momentsResult.hasPrevious() and momentsResult.hasNext()}"></span>
|
||||
<a
|
||||
class="wi-moments-page__page-btn"
|
||||
th:if="${momentsResult.hasNext()}"
|
||||
th:href="${momentsResult.nextUrl}"
|
||||
>较旧 →</a>
|
||||
th:text="#{common.older}">Older</a>
|
||||
</nav>
|
||||
|
||||
<div
|
||||
@@ -220,7 +220,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
></div>
|
||||
<th:block th:if="${momentFinder == null}">
|
||||
<div class="wi-moments-page__empty">
|
||||
<p>瞬间插件加载异常,请检查插件状态</p>
|
||||
<p th:text="#{common.pluginError}">Plugin error</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
@@ -228,7 +228,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
|
||||
<th:block th:unless="${pluginFinder.available('PluginMoments')}">
|
||||
<div class="wi-moments-page__empty">
|
||||
<p>瞬间功能需要安装「瞬间」插件,<a href="https://www.halo.run/store/apps/app-hqbe">前往应用市场安装</a></p>
|
||||
<p th:utext="#{common.installPlugin('Moments', 'https://www.halo.run/store/apps/app-hqbe')}">This feature requires the Moments plugin</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
@@ -414,7 +414,9 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
sentinel.style.display = "none";
|
||||
var endMsg = document.createElement("div");
|
||||
endMsg.className = "wi-moments-page__empty";
|
||||
endMsg.innerHTML = "<p>已加载全部瞬间</p>";
|
||||
var momentsSection = document.querySelector(".wi-moments-page");
|
||||
var allMomentsText = momentsSection ? momentsSection.getAttribute("data-i18n-all-moments-loaded") : "All moments loaded";
|
||||
endMsg.innerHTML = "<p>" + allMomentsText + "</p>";
|
||||
sentinel.parentNode.appendChild(endMsg);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
<Layout>
|
||||
<Fragment slot="head">
|
||||
<title
|
||||
th:text="|${theme.config?.messageboard?.messageboard_title ?: '留言板'} - ${site.title}|"
|
||||
th:text="|${theme.config?.messageboard?.messageboard_title ?: #messages.msg('messageboard.title')} - ${site.title}|"
|
||||
></title>
|
||||
</Fragment>
|
||||
|
||||
@@ -14,12 +14,12 @@ import Layout from "../layouts/Layout.astro";
|
||||
<span class="wi-messageboard__deco">"</span>
|
||||
<h1
|
||||
class="wi-messageboard__title"
|
||||
th:text="${theme.config?.messageboard?.messageboard_title ?: '留言板'}"
|
||||
th:text="${theme.config?.messageboard?.messageboard_title ?: #messages.msg('messageboard.title')}"
|
||||
></h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
<p
|
||||
class="wi-messageboard__subtitle"
|
||||
th:text="${theme.config?.messageboard?.messageboard_subtitle}"
|
||||
th:text="${theme.config?.messageboard?.messageboard_subtitle ?: #messages.msg('messageboard.subtitle')}"
|
||||
></p>
|
||||
</header>
|
||||
|
||||
|
||||
+10
-14
@@ -5,7 +5,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
|
||||
<Layout wide>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${title ?: (theme.config?.photos?.photos_page_title ?: '图库')} - ${site.title}|"></title>
|
||||
<title th:text="|${title ?: (theme.config?.photos?.photos_page_title ?: #messages.msg('photos.title'))} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
|
||||
<section class="wi-photos-page">
|
||||
@@ -13,9 +13,9 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
<div class="wi-photos-page__header">
|
||||
<h1
|
||||
class="wi-photos-page__title"
|
||||
th:text="${theme.config?.photos?.photos_page_title ?: '图库'}"
|
||||
th:text="${theme.config?.photos?.photos_page_title ?: #messages.msg('photos.title')}"
|
||||
>
|
||||
图库
|
||||
Gallery
|
||||
</h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
</div>
|
||||
@@ -30,8 +30,9 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
th:href="@{${photoUrl.list()}}"
|
||||
class="wi-photos-page__group-link"
|
||||
th:classappend="${#strings.isEmpty(currentGroup)} ? 'wi-photos-page__group-link--active' : ''"
|
||||
th:text="#{common.all}"
|
||||
>
|
||||
全部
|
||||
All
|
||||
</a>
|
||||
<a
|
||||
th:each="group : ${groups}"
|
||||
@@ -48,7 +49,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
<div class="wi-photos-page__all-groups">
|
||||
<th:block th:if="${showUngrouped and photos != null and !#lists.isEmpty(photos.items)}">
|
||||
<div class="wi-photos-page__section">
|
||||
<h2 class="wi-photos-page__section-title">全部</h2>
|
||||
<h2 class="wi-photos-page__section-title" th:text="#{common.all}">All</h2>
|
||||
<div
|
||||
class="wi-photos-page__grid"
|
||||
th:attr="data-style=${theme.config?.photos?.photos_style ?: 'masonry'}, data-columns=${theme.config?.photos?.photos_columns ?: 3}"
|
||||
@@ -240,7 +241,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
</div>
|
||||
</div>
|
||||
<div class="wi-photos-page__empty" th:if="${#lists.isEmpty(group.photos)}">
|
||||
<p>该分组暂无图片</p>
|
||||
<p th:text="#{common.noPhotosInGroup}">No photos in this group.</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</th:block>
|
||||
@@ -248,25 +249,20 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
</th:block>
|
||||
|
||||
<div class="wi-photos-page__empty" th:if="${#lists.isEmpty(groups) and !(showUngrouped and photos != null and !#lists.isEmpty(photos.items))}">
|
||||
<p>暂无图片</p>
|
||||
<p th:text="#{common.noPhotos}">No photos yet.</p>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${groups == null}">
|
||||
<div class="wi-photos-page__empty">
|
||||
<p>图库插件加载异常,请检查插件状态</p>
|
||||
<p th:text="#{common.pluginError}">Plugin error</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
||||
<th:block th:unless="${pluginFinder.available('PluginPhotos')}">
|
||||
<div class="wi-photos-page__empty">
|
||||
<p>
|
||||
图库功能需要安装「图库」插件,<a
|
||||
href="https://www.halo.run/store/apps/app-PgHgw"
|
||||
>前往应用市场安装</a
|
||||
>
|
||||
</p>
|
||||
<p th:utext="#{common.installPlugin('Gallery', 'https://www.halo.run/store/apps/app-PgHgw')}">This feature requires the Gallery plugin</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
|
||||
+313
-16
@@ -3,14 +3,42 @@ import Layout from "../layouts/Layout.astro";
|
||||
import LightGallery from "../components/LightGallery.astro";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<Layout wide={true}>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${post.spec.title} - ${site.title}|"></title>
|
||||
<meta th:if="${post.spec.cover}" property="og:image" th:content="${post.spec.cover}" />
|
||||
<meta property="og:title" th:content="${post.spec.title}" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" th:content="${post.status.permalink}" />
|
||||
<meta th:if="${post.status.excerpt}" property="og:description" th:content="${post.status.excerpt}" />
|
||||
<meta property="og:site_name" th:content="${site.title}" />
|
||||
<meta name="twitter:card" content="summary_large_image" th:if="${post.spec.cover}" />
|
||||
<meta name="twitter:card" content="summary" th:unless="${post.spec.cover}" />
|
||||
<meta name="twitter:title" th:content="${post.spec.title}" />
|
||||
<meta th:if="${post.spec.cover}" name="twitter:image" th:content="${post.spec.cover}" />
|
||||
<meta th:if="${post.status.excerpt}" name="twitter:description" th:content="${post.status.excerpt}" />
|
||||
<meta property="article:published_time" th:content="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd')}" />
|
||||
<th:block th:if="${post.categories != null and !post.categories.isEmpty()}">
|
||||
<meta property="article:section" th:content="${post.categories[0].spec.displayName}" />
|
||||
</th:block>
|
||||
<th:block th:if="${post.tags != null and !post.tags.isEmpty()}">
|
||||
<meta th:each="tag : ${post.tags}" property="article:tag" th:content="${tag.spec.displayName}" />
|
||||
</th:block>
|
||||
<script type="application/ld+json" th:utext="${'{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Article",
|
||||
"headline": "' + post.spec.title + '",
|
||||
"datePublished": "' + #dates.format(post.spec.publishTime, "yyyy-MM-dd") + '",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "' + (post.contributors != null and !post.contributors.isEmpty() ? post.contributors[0].displayName : site.title) + '"
|
||||
}' + (!#strings.isEmpty(post.spec.cover) ? ', "image": "' + post.spec.cover + '"' : '') + (!#strings.isEmpty(post.status.excerpt) ? ', "description": "' + #strings.replace(post.status.excerpt, '"', '\\"') + '"' : '') + '
|
||||
}'}"></script>
|
||||
</Fragment>
|
||||
|
||||
<div class="wi-reading-progress" id="wi-reading-progress"></div>
|
||||
|
||||
<article class="wi-post">
|
||||
<article class="wi-post" th:attr="data-i18n-words=#{common.words},data-i18n-read-time=#{common.readTime}">
|
||||
<header class="wi-post__header">
|
||||
<div
|
||||
th:if="${theme.config?.article?.article_show_cover != false and !#strings.isEmpty(post.spec.cover)}"
|
||||
@@ -82,18 +110,18 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
th:if="${theme.config?.article?.article_show_word_count ?: true}"
|
||||
class="wi-post__stat-item"
|
||||
id="wi-word-count"
|
||||
>-- 字</span>
|
||||
>-- words</span>
|
||||
<span
|
||||
th:if="${theme.config?.article?.article_show_visit_count ?: true}"
|
||||
class="wi-post__stat-item"
|
||||
>
|
||||
<th:block th:text="${post.stats?.visit ?: 0}"></th:block> 阅读
|
||||
<th:block th:text="${post.stats?.visit ?: 0}"></th:block> <th:block th:text="#{common.views}"></th:block>
|
||||
</span>
|
||||
<span
|
||||
th:if="${theme.config?.article?.article_show_read_time ?: false}"
|
||||
class="wi-post__stat-item"
|
||||
id="wi-read-time"
|
||||
>-- 分钟</span>
|
||||
>-- min read</span>
|
||||
</span>
|
||||
</th:block>
|
||||
</div>
|
||||
@@ -109,10 +137,10 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
th:if="${theme.config?.article?.article_show_toc ?: true}"
|
||||
class="wi-toc"
|
||||
id="wi-toc"
|
||||
th:attr="data-position=${theme.config?.article?.article_toc_position ?: 'left'}"
|
||||
th:attr="data-position=${theme.config?.article?.article_toc_position ?: 'left'},data-expand=${theme.config?.article?.article_toc_expand ?: 'active'}"
|
||||
>
|
||||
<div class="wi-toc__header">
|
||||
<span class="wi-toc__title">目录</span>
|
||||
<span class="wi-toc__title" th:text="#{article.toc}">目录</span>
|
||||
</div>
|
||||
<nav class="wi-toc__nav" id="wi-toc-nav"></nav>
|
||||
</aside>
|
||||
@@ -128,6 +156,27 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="wi-post__share" th:if="${theme.config?.article?.article_show_share != false}" th:with="shareUrl=${post.status.permalink}, shareTitle=${post.spec.title}">
|
||||
<span class="wi-post__share-label" th:text="${theme.config?.article?.article_share_title ?: #messages.msg('share.title')}">分享</span>
|
||||
<div class="wi-post__share-buttons">
|
||||
<a class="wi-post__share-btn wi-post__share-btn--weibo" th:href="'https://service.weibo.com/share/share.php?url=' + ${shareUrl} + '&title=' + ${shareTitle}" target="_blank" rel="noopener noreferrer" title="Weibo">
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M10.098 20.323c-3.977.391-7.414-1.406-7.672-4.02-.259-2.609 2.759-5.047 6.74-5.441 3.979-.394 7.413 1.404 7.671 4.018.259 2.6-2.759 5.049-6.739 5.443zM9.05 17.219c-.384.616-1.208.884-1.829.602-.612-.279-.793-.991-.406-1.593.379-.595 1.176-.861 1.793-.583.631.283.822.997.442 1.574zm1.27-1.627c-.141.237-.449.353-.689.253-.236-.09-.307-.361-.164-.584.14-.227.44-.34.682-.246.24.085.318.352.171.577zm.176-2.719c-1.893-.494-4.033.45-4.857 2.118-.836 1.704-.026 3.591 1.886 4.21 1.983.642 4.318-.341 5.132-2.145.8-1.752-.145-3.681-2.161-4.183zM17.616 3.68c-.998-.27-1.652-.068-1.877.136-.225.207-.094.544.28.726.377.186.856.072 1.122-.258.268-.328.391-.545.475-.604zm2.471 1.947c-1.278-1.399-3.398-1.878-5.217-1.176-1.818.704-2.478 2.523-1.527 4.099.956 1.582 3.168 2.202 5.011 1.395 1.84-.804 2.977-2.899 1.733-4.318zM20.4 4.44c1.462 1.599.936 4.076-.878 5.478-1.816 1.402-4.556 1.402-6.128-.006-1.573-1.404-1.3-3.834.554-5.314 1.854-1.478 4.99-1.759 6.452-.158z"/></svg>
|
||||
</a>
|
||||
<a class="wi-post__share-btn wi-post__share-btn--twitter" th:href="'https://twitter.com/intent/tweet?url=' + ${shareUrl} + '&text=' + ${shareTitle}" target="_blank" rel="noopener noreferrer" title="X">
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
|
||||
</a>
|
||||
<a class="wi-post__share-btn wi-post__share-btn--facebook" th:href="'https://www.facebook.com/sharer/sharer.php?u=' + ${shareUrl}" target="_blank" rel="noopener noreferrer" title="Facebook">
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>
|
||||
</a>
|
||||
<a class="wi-post__share-btn wi-post__share-btn--telegram" th:href="'https://t.me/share/url?url=' + ${shareUrl} + '&text=' + ${shareTitle}" target="_blank" rel="noopener noreferrer" title="Telegram">
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.479.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>
|
||||
</a>
|
||||
<button class="wi-post__share-btn wi-post__share-btn--copy" type="button" th:attr="data-url=${shareUrl}" title="Copy Link">
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<th:block th:if="${theme.config?.article?.article_show_nav == true}">
|
||||
<nav class="wi-post__nav" aria-label="Post navigation">
|
||||
<th:block
|
||||
@@ -138,7 +187,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
th:href="@{${cursor.previous.status.permalink}}"
|
||||
class="wi-post__nav-link wi-post__nav-link--prev"
|
||||
>
|
||||
<span class="wi-post__nav-label">上一篇</span>
|
||||
<span class="wi-post__nav-label" th:text="#{article.previousPost}">上一篇</span>
|
||||
<span
|
||||
class="wi-post__nav-title"
|
||||
th:text="${cursor.previous.spec.title}"
|
||||
@@ -153,7 +202,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
th:href="@{${cursor.next.status.permalink}}"
|
||||
class="wi-post__nav-link wi-post__nav-link--next"
|
||||
>
|
||||
<span class="wi-post__nav-label">下一篇</span>
|
||||
<span class="wi-post__nav-label" th:text="#{article.nextPost}">下一篇</span>
|
||||
<span
|
||||
class="wi-post__nav-title"
|
||||
th:text="${cursor.next.spec.title}"
|
||||
@@ -167,6 +216,23 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
</nav>
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${theme.config?.article?.article_show_related == true}">
|
||||
<section class="wi-post__related" th:with="relatedCat=${post.categories != null and !post.categories.isEmpty()} ? ${post.categories[0].metadata.name} : null, relatedPosts=${relatedCat != null} ? ${postFinder.list({size: 3, categoryName: relatedCat})} : ${postFinder.list({size: 3})}">
|
||||
<h2 class="wi-post__related-title" th:text="${theme.config?.article?.article_related_title ?: #messages.msg('article.relatedPosts')}">相关推荐</h2>
|
||||
<div class="wi-post__related-grid">
|
||||
<a th:each="rp : ${relatedPosts.items}" th:if="${rp.metadata.name != post.metadata.name}" th:href="@{${rp.status.permalink}}" class="wi-post__related-card">
|
||||
<div class="wi-post__related-cover" th:if="${!#strings.isEmpty(rp.spec.cover)}">
|
||||
<img th:src="${rp.spec.cover}" th:alt="${rp.spec.title}" loading="lazy" decoding="async" />
|
||||
</div>
|
||||
<div class="wi-post__related-body">
|
||||
<h3 class="wi-post__related-name" th:text="${rp.spec.title}"></h3>
|
||||
<time class="wi-post__related-date" th:text="${#dates.format(rp.spec.publishTime, 'yyyy-MM-dd')}"></time>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</th:block>
|
||||
|
||||
<div class="wi-post__comment" th:attr="data-comment-style=${theme.config?.comment?.comment_style ?: 'warm'},data-show-avatar=${theme.config?.comment?.comment_show_avatar != false}">
|
||||
<halo:comment
|
||||
th:if="${haloCommentEnabled}"
|
||||
@@ -182,7 +248,7 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
class="wi-toc-fab"
|
||||
id="wi-toc-fab"
|
||||
type="button"
|
||||
aria-label="打开目录"
|
||||
th:aria-label="#{common.openToc}"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" x2="21" y1="6" y2="6"/><line x1="8" x2="21" y1="12" y2="12"/><line x1="8" x2="21" y1="18" y2="18"/><line x1="3" x2="3.01" y1="6" y2="6"/><line x1="3" x2="3.01" y1="12" y2="12"/><line x1="3" x2="3.01" y1="18" y2="18"/></svg>
|
||||
</button>
|
||||
@@ -195,8 +261,8 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
<div class="wi-toc-drawer__overlay"></div>
|
||||
<div class="wi-toc-drawer__panel">
|
||||
<div class="wi-toc-drawer__header">
|
||||
<span class="wi-toc-drawer__title">目录</span>
|
||||
<button class="wi-toc-drawer__close" type="button" aria-label="关闭目录">
|
||||
<span class="wi-toc-drawer__title" th:text="#{article.toc}">目录</span>
|
||||
<button class="wi-toc-drawer__close" type="button" th:aria-label="#{common.closeToc}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -263,6 +329,9 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
|
||||
var showWordCount = document.getElementById("wi-word-count");
|
||||
var showReadTime = document.getElementById("wi-read-time");
|
||||
var articleEl = document.querySelector(".wi-post");
|
||||
var wordsLabel = articleEl ? articleEl.getAttribute("data-i18n-words") : "words";
|
||||
var readTimeLabel = articleEl ? articleEl.getAttribute("data-i18n-read-time") : "min read";
|
||||
|
||||
if (showWordCount || showReadTime) {
|
||||
var text = (body.textContent || body.innerText || "").trim();
|
||||
@@ -270,10 +339,10 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
var readMinutes = Math.max(1, Math.ceil(charCount / 500));
|
||||
|
||||
if (showWordCount) {
|
||||
showWordCount.textContent = charCount + " 字";
|
||||
showWordCount.textContent = charCount + " " + wordsLabel;
|
||||
}
|
||||
if (showReadTime) {
|
||||
showReadTime.textContent = readMinutes + " 分钟";
|
||||
showReadTime.textContent = readMinutes + " " + readTimeLabel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +422,13 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
entries.forEach(function (entry) {
|
||||
if (entry.isIntersecting) {
|
||||
tocLinks.forEach(function (l) { l.classList.remove("wi-toc__link--active"); });
|
||||
tocGroups.forEach(function (g) { g.classList.remove("wi-toc__group--active"); g.classList.remove("wi-toc__group--expanded"); });
|
||||
var tocExpandMode = tocAside ? (tocAside.getAttribute("data-expand") || "active") : "active";
|
||||
tocGroups.forEach(function (g) {
|
||||
g.classList.remove("wi-toc__group--active");
|
||||
if (tocExpandMode !== "all") {
|
||||
g.classList.remove("wi-toc__group--expanded");
|
||||
}
|
||||
});
|
||||
|
||||
var activeLink = tocNav.querySelector('a[href="#' + entry.target.id + '"]');
|
||||
if (activeLink) {
|
||||
@@ -456,6 +531,28 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
});
|
||||
}
|
||||
|
||||
var copyBtn = document.querySelector(".wi-post__share-btn--copy");
|
||||
if (copyBtn) {
|
||||
copyBtn.addEventListener("click", function () {
|
||||
var url = copyBtn.getAttribute("data-url");
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(url).then(function () {
|
||||
copyBtn.classList.add("wi-post__share-btn--copied");
|
||||
setTimeout(function () { copyBtn.classList.remove("wi-post__share-btn--copied"); }, 2000);
|
||||
});
|
||||
} else {
|
||||
var ta = document.createElement("textarea");
|
||||
ta.value = url;
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(ta);
|
||||
copyBtn.classList.add("wi-post__share-btn--copied");
|
||||
setTimeout(function () { copyBtn.classList.remove("wi-post__share-btn--copied"); }, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var btn = document.querySelector(".wi-like-btn");
|
||||
if (!btn) return;
|
||||
var postName = btn.getAttribute("data-post-name");
|
||||
@@ -493,6 +590,21 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
console.error("Like error:", err);
|
||||
});
|
||||
});
|
||||
|
||||
var lazyImgs = document.querySelectorAll(".wi-post__content img[loading='lazy']");
|
||||
lazyImgs.forEach(function (img) {
|
||||
if (img.complete && img.naturalWidth > 0) {
|
||||
img.setAttribute("data-blur", "loaded");
|
||||
} else {
|
||||
img.setAttribute("data-blur", "true");
|
||||
img.addEventListener("load", function () {
|
||||
img.setAttribute("data-blur", "loaded");
|
||||
});
|
||||
img.addEventListener("error", function () {
|
||||
img.setAttribute("data-blur", "loaded");
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</Layout>
|
||||
@@ -680,7 +792,8 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
.wi-post__body .ai-summary,
|
||||
.wi-post__body [class*="ai-summary"],
|
||||
.wi-post__body [class*="ai-abstract"],
|
||||
.wi-post__body .abstract {
|
||||
.wi-post__body .abstract,
|
||||
.wi-post__body [class*="likcc-article-summary"] {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
@@ -693,6 +806,22 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
margin-block: 1.5em;
|
||||
}
|
||||
|
||||
.wi-post__content img {
|
||||
transition: filter 0.4s ease, opacity 0.4s ease;
|
||||
}
|
||||
|
||||
.wi-post__content img[data-blur="true"] {
|
||||
filter: blur(20px);
|
||||
opacity: 0.6;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.wi-post__content img[data-blur="loaded"] {
|
||||
filter: blur(0);
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.wi-post__body a {
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 1px;
|
||||
@@ -928,6 +1057,85 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.wi-post__share {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-md);
|
||||
padding-top: var(--space-md);
|
||||
}
|
||||
|
||||
.wi-post__share-label {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--ink-3);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.wi-post__share-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.wi-post__share-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--rule);
|
||||
background: var(--bg-raised);
|
||||
color: var(--ink-3);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.wi-post__share-btn:hover {
|
||||
color: var(--accent);
|
||||
border-color: var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 6%, var(--bg));
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.wi-post__share-btn--weibo:hover {
|
||||
color: #e6162d;
|
||||
border-color: #e6162d;
|
||||
background: color-mix(in srgb, #e6162d 6%, var(--bg));
|
||||
}
|
||||
|
||||
.wi-post__share-btn--facebook:hover {
|
||||
color: #1877f2;
|
||||
border-color: #1877f2;
|
||||
background: color-mix(in srgb, #1877f2 6%, var(--bg));
|
||||
}
|
||||
|
||||
.wi-post__share-btn--telegram:hover {
|
||||
color: #0088cc;
|
||||
border-color: #0088cc;
|
||||
background: color-mix(in srgb, #0088cc 6%, var(--bg));
|
||||
}
|
||||
|
||||
.wi-post__share-btn--copied {
|
||||
color: #22c55e;
|
||||
border-color: #22c55e;
|
||||
}
|
||||
|
||||
.wi-post__share-btn--copied::after {
|
||||
content: '✓';
|
||||
font-size: 14px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.wi-post__share-btn--copied svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wi-post__share-btn--copy {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wi-post__comment {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
@@ -985,6 +1193,90 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.wi-post__related {
|
||||
padding-top: var(--space-xl);
|
||||
border-top: 1px solid var(--rule);
|
||||
}
|
||||
|
||||
.wi-post__related-title {
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-lg);
|
||||
}
|
||||
|
||||
.wi-post__related-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.wi-post__related-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: var(--bg-raised);
|
||||
border: 1px solid var(--rule);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: transform var(--duration-fast) var(--ease-out-quart), box-shadow var(--duration-fast) var(--ease-out-quart);
|
||||
}
|
||||
|
||||
.wi-post__related-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.wi-post__related-cover {
|
||||
aspect-ratio: 16 / 9;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wi-post__related-cover img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform var(--duration-fast) var(--ease-out-quart);
|
||||
}
|
||||
|
||||
.wi-post__related-card:hover .wi-post__related-cover img {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
|
||||
.wi-post__related-body {
|
||||
padding: var(--space-md);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.wi-post__related-name {
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
line-height: var(--leading-snug);
|
||||
transition: color var(--duration-fast) var(--ease-out-quart);
|
||||
}
|
||||
|
||||
.wi-post__related-card:hover .wi-post__related-name {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.wi-post__related-date {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--ink-3);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.wi-post__related-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.wi-post__cover-wrap {
|
||||
margin-inline: calc(-1 * var(--space-md));
|
||||
@@ -1049,6 +1341,11 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.wi-toc[data-expand="all"] .wi-toc__sub {
|
||||
max-height: 600px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.wi-toc__link {
|
||||
display: block;
|
||||
padding: 4px 0;
|
||||
|
||||
+15
-15
@@ -55,35 +55,35 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:href="${profile.summary?.profileUrl}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Steam 主页 →</a>
|
||||
th:text="#{steam.homepage}">Steam Homepage →</a>
|
||||
</div>
|
||||
<div class="wi-steam__level" th:if="${profile.steamLevel != null}">
|
||||
<span class="wi-steam__level-num" th:text="${profile.steamLevel}"></span>
|
||||
<span class="wi-steam__level-label">等级</span>
|
||||
<span class="wi-steam__level-label" th:text="#{steam.level}">Level</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wi-steam__stats" th:if="${stats != null}">
|
||||
<div class="wi-steam__stat-card">
|
||||
<span class="wi-steam__stat-value" th:text="${stats.totalGames} ?: 0">0</span>
|
||||
<span class="wi-steam__stat-label">拥有游戏</span>
|
||||
<span class="wi-steam__stat-label" th:text="#{steam.ownedGames}">Owned Games</span>
|
||||
</div>
|
||||
<div class="wi-steam__stat-card">
|
||||
<span class="wi-steam__stat-value" th:text="${stats.totalPlaytimeFormatted} ?: '0 小时'">0 小时</span>
|
||||
<span class="wi-steam__stat-label">总游玩时长</span>
|
||||
<span class="wi-steam__stat-value" th:text="${stats.totalPlaytimeFormatted} ?: '0 hours'">0 hours</span>
|
||||
<span class="wi-steam__stat-label" th:text="#{steam.totalPlaytime}">Total Playtime</span>
|
||||
</div>
|
||||
<div class="wi-steam__stat-card">
|
||||
<span class="wi-steam__stat-value" th:text="${stats.recentPlaytimeFormatted} ?: '0 小时'">0 小时</span>
|
||||
<span class="wi-steam__stat-label">近两周</span>
|
||||
<span class="wi-steam__stat-value" th:text="${stats.recentPlaytimeFormatted} ?: '0 hours'">0 hours</span>
|
||||
<span class="wi-steam__stat-label" th:text="#{steam.recentPlaytime}">Recent 2 Weeks</span>
|
||||
</div>
|
||||
<div class="wi-steam__stat-card">
|
||||
<span class="wi-steam__stat-value" th:text="${badges != null and badges.totalBadges != null ? badges.totalBadges : 0}">0</span>
|
||||
<span class="wi-steam__stat-label">徽章</span>
|
||||
<span class="wi-steam__stat-label" th:text="#{steam.badges}">Badges</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wi-steam__section" th:if="${recentGames != null and !recentGames.isEmpty()}">
|
||||
<h3 class="wi-steam__section-title">最近游玩</h3>
|
||||
<h3 class="wi-steam__section-title" th:text="#{steam.recentlyPlayed}">Recently Played</h3>
|
||||
<div class="wi-steam__recent-scroll">
|
||||
<article class="wi-steam__recent-card" th:each="game : ${recentGames}">
|
||||
<a
|
||||
@@ -107,7 +107,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
<div class="wi-steam__recent-body">
|
||||
<h4 class="wi-steam__recent-name" th:text="${game.name}"></h4>
|
||||
<div class="wi-steam__recent-meta">
|
||||
<span class="wi-steam__recent-time" th:text="${game.playtime2WeeksFormatted} ?: '0 小时'"></span>
|
||||
<span class="wi-steam__recent-time" th:text="${game.playtime2WeeksFormatted} ?: #{steam.hours}"></span>
|
||||
<span
|
||||
class="wi-steam__recent-achievements"
|
||||
th:if="${game.achievementProgressText != null}"
|
||||
@@ -122,7 +122,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
</th:block>
|
||||
|
||||
<div class="wi-steam__section">
|
||||
<h3 class="wi-steam__section-title">游戏库</h3>
|
||||
<h3 class="wi-steam__section-title" th:text="#{steam.gameLibrary}">Game Library</h3>
|
||||
<div class="wi-steam__games-grid">
|
||||
<article class="wi-steam__game-card" th:each="game : ${games.items}">
|
||||
<a
|
||||
@@ -146,11 +146,11 @@ import Layout from "../layouts/Layout.astro";
|
||||
<div class="wi-steam__game-body">
|
||||
<h4 class="wi-steam__game-name" th:text="${game.name}"></h4>
|
||||
<div class="wi-steam__game-meta">
|
||||
<span class="wi-steam__game-time" th:text="${game.playtimeFormatted} ?: '0 小时'"></span>
|
||||
<span class="wi-steam__game-time" th:text="${game.playtimeFormatted} ?: #{steam.hours}"></span>
|
||||
<span
|
||||
class="wi-steam__game-last"
|
||||
th:if="${!#strings.isEmpty(game.lastPlayedFormatted)}"
|
||||
th:text="|最后游玩 ${game.lastPlayedFormatted}|"
|
||||
th:text="#{steam.lastPlayed(${game.lastPlayedFormatted})}"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -166,13 +166,13 @@ import Layout from "../layouts/Layout.astro";
|
||||
class="wi-steam__page-btn"
|
||||
th:if="${games.hasPrevious()}"
|
||||
th:href="${games.prevUrl}"
|
||||
>上一页</a>
|
||||
th:text="#{common.newer}">Previous</a>
|
||||
<span class="wi-steam__page-spacer" th:if="${games.hasPrevious() and games.hasNext()}"></span>
|
||||
<a
|
||||
class="wi-steam__page-btn"
|
||||
th:if="${games.hasNext()}"
|
||||
th:href="${games.nextUrl}"
|
||||
>下一页</a>
|
||||
th:text="#{common.older}">Next</a>
|
||||
</nav>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
+7
-7
@@ -11,7 +11,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
<header class="wi-tag__header">
|
||||
<h1 class="wi-tag__title" th:text="${tag.spec.displayName}"></h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
<p class="wi-tag__subtitle" th:text="|共 ${posts.total} 篇文章|"></p>
|
||||
<p class="wi-tag__subtitle" th:text="#{common.postCount(${posts.total})}"></p>
|
||||
<p
|
||||
th:if="${not #strings.isEmpty(tag.spec.description)}"
|
||||
class="wi-tag__description"
|
||||
@@ -55,8 +55,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
<div
|
||||
th:if="${posts.total == 0}"
|
||||
class="wi-tag__empty"
|
||||
th:text="${theme.config?.home?.home_label_no_posts ?: '暂无文章。'}"
|
||||
>暂无文章。</div>
|
||||
th:text="${theme.config?.home?.home_label_no_posts ?: #messages.msg('common.noPosts')}"
|
||||
>No posts yet.</div>
|
||||
|
||||
<nav
|
||||
th:if="${posts.totalPages gt 1}"
|
||||
@@ -67,8 +67,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:if="${posts.hasPrevious()}"
|
||||
th:href="@{${posts.prevUrl}}"
|
||||
class="wi-tag__page-link wi-tag__page-link--prev"
|
||||
th:text="${theme.config?.home?.home_label_newer ?: '较新'}"
|
||||
>← 较新</a>
|
||||
th:text="${theme.config?.home?.home_label_newer ?: #messages.msg('common.newer')}"
|
||||
>← Newer</a>
|
||||
<span
|
||||
class="wi-tag__page-info"
|
||||
th:text="|${posts.page} / ${posts.totalPages}|"
|
||||
@@ -77,8 +77,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
th:if="${posts.hasNext()}"
|
||||
th:href="@{${posts.nextUrl}}"
|
||||
class="wi-tag__page-link wi-tag__page-link--next"
|
||||
th:text="${theme.config?.home?.home_label_older ?: '较旧'}"
|
||||
>较旧 →</a>
|
||||
th:text="${theme.config?.home?.home_label_older ?: #messages.msg('common.older')}"
|
||||
>Older →</a>
|
||||
</nav>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
@@ -4,14 +4,14 @@ import Layout from "../layouts/Layout.astro";
|
||||
|
||||
<Layout>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|标签 - ${site.title}|"></title>
|
||||
<title th:text="|#{tags.title} - ${site.title}|"></title>
|
||||
</Fragment>
|
||||
|
||||
<div class="wi-tags">
|
||||
<header class="wi-tags__header">
|
||||
<h1 class="wi-tags__title">标签</h1>
|
||||
<h1 class="wi-tags__title" th:text="#{tags.title}">标签</h1>
|
||||
<span class="wi-page-accent"></span>
|
||||
<p class="wi-tags__subtitle" th:text="|共 ${tags.size} 个标签|"></p>
|
||||
<p class="wi-tags__subtitle" th:text="${#messages.msg('common.tagCount', ${tags.size})}"></p>
|
||||
</header>
|
||||
|
||||
<div class="wi-tags__cloud" role="list" aria-label="Tag list">
|
||||
|
||||
Reference in New Issue
Block a user