完善页脚

This commit is contained in:
nxxy335top
2026-05-19 14:18:09 +08:00
parent 1bf7107966
commit 93dc21e69b
18 changed files with 550 additions and 137 deletions
+16 -8
View File
@@ -79,6 +79,7 @@ spec:
name: layout_sidebar name: layout_sidebar
label: 启用侧边栏 label: 启用侧边栏
value: false value: false
help: 侧边栏功能开发中,暂不可用
- $formkit: switch - $formkit: switch
name: animation_enabled name: animation_enabled
label: 启用动效 label: 启用动效
@@ -132,6 +133,7 @@ spec:
label: 副标题(留空则使用站点副标题) label: 副标题(留空则使用站点副标题)
- $formkit: select - $formkit: select
name: hero_description_mode name: hero_description_mode
id: hero_description_mode
label: 描述文案来源 label: 描述文案来源
options: options:
- label: - label:
@@ -178,6 +180,7 @@ spec:
- $formkit: textarea - $formkit: textarea
name: hero_custom_description name: hero_custom_description
label: 自定义描述文案 label: 自定义描述文案
key: hero_custom_description
if: "$get(hero_description_mode).value === 'custom'" if: "$get(hero_description_mode).value === 'custom'"
- $formkit: attachment - $formkit: attachment
name: hero_background_image name: hero_background_image
@@ -238,14 +241,6 @@ spec:
name: home_label_all_loaded name: home_label_all_loaded
label: 无限滚动-全部加载文案 label: 无限滚动-全部加载文案
value: 已加载全部文章 value: 已加载全部文章
- $formkit: text
name: home_latest_title
label: 最新文章模块标题
value: 最新文章
- $formkit: text
name: home_label_view_all
label: 查看全部标签
value: 查看全部
- $formkit: text - $formkit: text
name: home_label_no_posts name: home_label_no_posts
label: 暂无文章文案 label: 暂无文章文案
@@ -329,6 +324,19 @@ spec:
- label: Masonry - label: Masonry
value: masonry value: masonry
value: timeline value: timeline
- $formkit: select
name: moments_loading_mode
label: 加载方式
options:
- label: 下滑加载
value: infinite_scroll
- label: 分页
value: pagination
value: infinite_scroll
- $formkit: number
name: moments_page_size
label: 每页显示数量
value: 10
- group: photos - group: photos
label: 图库 label: 图库
formSchema: formSchema:
+1 -8
View File
@@ -10,7 +10,7 @@ const today = new Date();
<span class="footer-copyright" th:if="${theme.config?.footer?.footer_copyright}" th:text="${theme.config?.footer?.footer_copyright}"></span> <span class="footer-copyright" th:if="${theme.config?.footer?.footer_copyright}" th:text="${theme.config?.footer?.footer_copyright}"></span>
<span class="footer-copyright" th:unless="${theme.config?.footer?.footer_copyright}"> <span class="footer-copyright" th:unless="${theme.config?.footer?.footer_copyright}">
© {today.getFullYear()} © {today.getFullYear()}
<th:block th:text="${site.title}"></th:block> <th:block th:text="${theme.config?.basic?.owner_name ?: site.title}"></th:block>
</span> </span>
<span class="footer-icp" th:if="${theme.config?.footer?.footer_icp}"> <span class="footer-icp" th:if="${theme.config?.footer?.footer_icp}">
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer" th:text="${theme.config?.footer?.footer_icp}"></a> <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer" th:text="${theme.config?.footer?.footer_icp}"></a>
@@ -172,7 +172,6 @@ const today = new Date();
.footer-custom :global(img) { .footer-custom :global(img) {
display: inline-block; display: inline-block;
max-height: 26px;
vertical-align: middle; vertical-align: middle;
border-radius: 4px; border-radius: 4px;
} }
@@ -208,7 +207,6 @@ const today = new Date();
.footer-injected :global(img) { .footer-injected :global(img) {
display: inline-block; display: inline-block;
max-height: 26px;
vertical-align: middle; vertical-align: middle;
border-radius: 4px; border-radius: 4px;
} }
@@ -236,10 +234,5 @@ const today = new Date();
.footer-injected { .footer-injected {
font-size: 0.75rem; font-size: 0.75rem;
} }
.footer-custom :global(img),
.footer-injected :global(img) {
max-height: 20px;
}
} }
</style> </style>
+4 -2
View File
@@ -44,14 +44,16 @@ import ThemeSwitcher from "./ThemeSwitcher.vue";
th:if="${pluginFinder.available('PluginSearchWidget') and theme.config?.navbar?.navbar_show_search != false}" th:if="${pluginFinder.available('PluginSearchWidget') and theme.config?.navbar?.navbar_show_search != false}"
class="wi-navbar__action-btn" class="wi-navbar__action-btn"
type="button" type="button"
aria-label="Search" th:aria-label="${theme.config?.basic?.label_search ?: '搜索'}"
onclick="SearchWidget.open()" onclick="SearchWidget.open()"
> >
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
</button> </button>
<th:block th:if="${theme.config?.navbar?.navbar_show_theme_switch != false}"> <th:block th:if="${theme.config?.navbar?.navbar_show_theme_switch != false}">
<ThemeSwitcher client:idle /> <span th:attr="data-label=${theme.config?.basic?.label_theme_switch ?: '切换主题'}" style="display:inline-flex">
<ThemeSwitcher client:idle />
</span>
</th:block> </th:block>
<button <button
+7 -2
View File
@@ -4,9 +4,14 @@ import MingcuteMoonLine from "~icons/mingcute/moon-line";
import MingcuteSunLine from "~icons/mingcute/sun-line"; import MingcuteSunLine from "~icons/mingcute/sun-line";
const isDark = ref(false); const isDark = ref(false);
const label = ref("切换主题");
onMounted(() => { onMounted(() => {
isDark.value = document.documentElement.classList.contains("dark"); isDark.value = document.documentElement.classList.contains("dark");
const parent = document.querySelector("[data-label]");
if (parent) {
label.value = parent.getAttribute("data-label") || "切换主题";
}
}); });
function toggle() { function toggle() {
@@ -24,10 +29,10 @@ function toggle() {
<button <button
class="theme-toggle" class="theme-toggle"
type="button" type="button"
:aria-label="isDark ? 'Switch to light mode' : 'Switch to dark mode'" :aria-label="label"
:title="label"
@click="toggle" @click="toggle"
> >
<!-- Moon: shown in light mode -->
<MingcuteSunLine v-if="isDark" /> <MingcuteSunLine v-if="isDark" />
<MingcuteMoonLine v-else /> <MingcuteMoonLine v-else />
</button> </button>
+9 -2
View File
@@ -21,6 +21,7 @@ const { pageTitle, contentClass, wide, home } = Astro.props;
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta th:if="${theme.config?.basic?.site_description}" name="description" th:content="${theme.config?.basic?.site_description}" />
<script is:inline th:attr="data-scheme=${theme.config?.style?.color_scheme}"> <script is:inline th:attr="data-scheme=${theme.config?.style?.color_scheme}">
(function () { (function () {
var stored = localStorage.getItem("wi-theme"); var stored = localStorage.getItem("wi-theme");
@@ -56,6 +57,12 @@ const { pageTitle, contentClass, wide, home } = Astro.props;
/> />
<link rel="alternate" type="application/rss+xml" th:title="${site.title}" th:href="@{/feed.xml}" /> <link rel="alternate" type="application/rss+xml" th:title="${site.title}" th:href="@{/feed.xml}" />
<style th:if="${theme.config?.style?.accent_color}" th:utext="${':root { --accent: ' + theme.config?.style?.accent_color + '; --accent-hover: ' + theme.config?.style?.accent_color + '; }'}"></style> <style th:if="${theme.config?.style?.accent_color}" th:utext="${':root { --accent: ' + theme.config?.style?.accent_color + '; --accent-hover: ' + theme.config?.style?.accent_color + '; }'}"></style>
<style th:if="${theme.config?.style?.border_radius == 'small'}" th:utext="${':root { --radius-sm: 4px; --radius-md: 8px; --radius-lg: 16px; }'}"></style>
<style th:if="${theme.config?.style?.border_radius == 'medium' or theme.config?.style?.border_radius == null}" th:utext="${':root { --radius-sm: 8px; --radius-md: 12px; --radius-lg: 24px; }'}"></style>
<style th:if="${theme.config?.style?.border_radius == 'large'}" th:utext="${':root { --radius-sm: 12px; --radius-md: 20px; --radius-lg: 36px; }'}"></style>
<style th:if="${theme.config?.style?.layout_container_width == 'narrow'}" th:utext="${'.wi-content-wrap { max-width: 680px; } .wi-content-wrap--wide { max-width: 1000px; } .wi-main--wide { max-width: 1200px; }'}"></style>
<style th:if="${theme.config?.style?.layout_container_width == 'medium' or theme.config?.style?.layout_container_width == null}" th:utext="${'.wi-content-wrap { max-width: 800px; } .wi-content-wrap--wide { max-width: 1200px; } .wi-main--wide { max-width: 1400px; }'}"></style>
<style th:if="${theme.config?.style?.layout_container_width == 'wide'}" th:utext="${'.wi-content-wrap { max-width: 900px; } .wi-content-wrap--wide { max-width: 1400px; } .wi-main--wide { max-width: 1600px; }'}"></style>
<style th:if="${theme.config?.style?.custom_css}" th:utext="${theme.config?.style?.custom_css}"></style> <style th:if="${theme.config?.style?.custom_css}" th:utext="${theme.config?.style?.custom_css}"></style>
<slot name="head" /> <slot name="head" />
</head> </head>
@@ -72,8 +79,8 @@ const { pageTitle, contentClass, wide, home } = Astro.props;
</main> </main>
<Footer /> <Footer />
<MobileMenu /> <MobileMenu />
<ScrollReveal client:visible /> <ScrollReveal th:if="${theme.config?.animation?.animation_enabled != false and theme.config?.animation?.animation_scroll_reveal != false}" client:visible />
<CursorGlow th:if="${theme.config?.animation?.animation_cursor_glow}" client:idle /> <CursorGlow th:if="${theme.config?.animation?.animation_enabled != false and theme.config?.animation?.animation_cursor_glow == true}" client:idle />
</body> </body>
</html> </html>
+3 -3
View File
@@ -4,14 +4,14 @@ import Layout from "../layouts/Layout.astro";
<Layout> <Layout>
<Fragment slot="head"> <Fragment slot="head">
<title th:text="|归档 - ${site.title}|"></title> <title th:text="|${theme.config?.basic?.label_archives_title ?: '归档'} - ${site.title}|"></title>
</Fragment> </Fragment>
<div class="wi-archives"> <div class="wi-archives">
<header class="wi-archives__header"> <header class="wi-archives__header">
<h1 class="wi-archives__title">归档</h1> <h1 class="wi-archives__title" th:text="${theme.config?.basic?.label_archives_title ?: '归档'}">归档</h1>
<span class="wi-page-accent"></span> <span class="wi-page-accent"></span>
<p class="wi-archives__subtitle" th:text="|共 ${archives.total} 篇文章|"></p> <p class="wi-archives__subtitle" th:text="${#strings.replace(theme.config?.home?.home_label_post_count ?: '共 {total} 篇文章', '{total}', #strings.toString(archives.total))}"></p>
</header> </header>
<section class="wi-archives__timeline" aria-label="Archive timeline"> <section class="wi-archives__timeline" aria-label="Archive timeline">
+76 -29
View File
@@ -20,21 +20,41 @@ import Layout from "../layouts/Layout.astro";
class="wi-categories__item" class="wi-categories__item"
th:href="@{${category.status.permalink}}" th:href="@{${category.status.permalink}}"
> >
<div
class="wi-categories__cover"
th:if="${category.spec.cover != null and !#strings.isEmpty(category.spec.cover)}"
>
<img
th:src="${category.spec.cover}"
th:alt="${category.spec.displayName}"
class="wi-categories__cover-img"
loading="lazy"
decoding="async"
/>
</div>
<div
class="wi-categories__cover wi-categories__cover--placeholder"
th:if="${category.spec.cover == null or #strings.isEmpty(category.spec.cover)}"
>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="24" height="24"><path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"/></svg>
</div>
<div class="wi-categories__item-content"> <div class="wi-categories__item-content">
<span <div class="wi-categories__name-row">
class="wi-categories__name" <span
th:text="${category.spec.displayName}" class="wi-categories__name"
></span> th:text="${category.spec.displayName}"
></span>
<span
class="wi-categories__count"
th:text="${category.postCount}"
></span>
</div>
<p <p
th:if="${not #strings.isEmpty(category.spec.description)}" th:if="${not #strings.isEmpty(category.spec.description)}"
class="wi-categories__desc" class="wi-categories__desc"
th:text="${category.spec.description}" th:text="${category.spec.description}"
></p> ></p>
</div> </div>
<span
class="wi-categories__count"
th:text="${category.postCount}"
></span>
</a> </a>
</nav> </nav>
</div> </div>
@@ -76,35 +96,67 @@ import Layout from "../layouts/Layout.astro";
.wi-categories__list { .wi-categories__list {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: var(--space-md); gap: var(--space-md);
} }
.wi-categories__item { .wi-categories__item {
display: grid; display: flex;
grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-md);
gap: var(--space-lg);
padding: var(--space-lg); padding: var(--space-lg);
border-radius: $border-radius-sm; border-radius: 16px;
border: 1px solid var(--rule); border: 1px solid var(--rule);
background: var(--bg); background: var(--bg-raised);
text-decoration: none; text-decoration: none;
color: inherit; color: inherit;
align-items: start; align-items: center;
transition: all var(--duration-fast) var(--ease-out-quart); transition: all var(--duration-fast) var(--ease-out-quart);
} }
.wi-categories__item:hover { .wi-categories__item:hover {
border-color: var(--accent); border-color: var(--accent);
background: var(--bg-raised);
transform: translateY(-2px); transform: translateY(-2px);
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-md);
}
.wi-categories__cover {
flex-shrink: 0;
width: 56px;
height: 56px;
border-radius: 12px;
overflow: hidden;
background: var(--bg);
}
.wi-categories__cover-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.wi-categories__cover--placeholder {
display: flex;
align-items: center;
justify-content: center;
background: var(--accent-bg);
color: var(--accent);
} }
.wi-categories__item-content { .wi-categories__item-content {
display: grid; flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.25rem; gap: 0.25rem;
} }
.wi-categories__name-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-sm);
}
.wi-categories__name { .wi-categories__name {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: var(--text-lg); font-size: var(--text-lg);
@@ -128,14 +180,14 @@ import Layout from "../layouts/Layout.astro";
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-width: 2rem; min-width: 1.75rem;
height: 2rem; height: 1.75rem;
padding: 0 0.5rem; padding: 0 0.4rem;
border-radius: 999px; border-radius: 999px;
background: var(--bg-raised); background: var(--bg);
border: 1px solid var(--rule); border: 1px solid var(--rule);
color: var(--ink-3); color: var(--ink-3);
font-size: var(--text-sm); font-size: var(--text-xs);
font-weight: 600; font-weight: 600;
white-space: nowrap; white-space: nowrap;
flex-shrink: 0; flex-shrink: 0;
@@ -147,14 +199,9 @@ import Layout from "../layouts/Layout.astro";
border-color: var(--accent); border-color: var(--accent);
} }
@media (max-width: 768px) { @media (max-width: 640px) {
.wi-categories__item { .wi-categories__list {
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: var(--space-sm);
}
.wi-categories__count {
align-self: flex-start;
} }
} }
</style> </style>
+51 -46
View File
@@ -15,62 +15,96 @@ import Layout from "../layouts/Layout.astro";
</div> </div>
<div class="wi-douban__filters"> <div class="wi-douban__filters">
<th:block th:with="urlType = ${param.type}, isDefaultType = ${urlType == null or #strings.isEmpty(urlType.toString())}, currentType = ${isDefaultType ? 'movie' : urlType.toString()}"> <th:block th:with="urlType = ${param.type}, isDefaultType = ${urlType == null or #strings.isEmpty(urlType.toString())}, currentType = ${isDefaultType ? 'music' : urlType.toString()}, urlStatus = ${param.status}, hasStatus = ${urlStatus != null and !#strings.isEmpty(urlStatus.toString())}, currentStatus = ${hasStatus ? urlStatus.toString() : (isDefaultType ? 'done' : null)}">
<div class="wi-douban__filter-group" th:if="${types != null and !#lists.isEmpty(types)}"> <div class="wi-douban__filter-group" th:if="${types != null and !#lists.isEmpty(types)}">
<a <a
th:each="t : ${types}" th:each="t : ${types}"
class="wi-douban__filter-tag" class="wi-douban__filter-tag"
th:href="@{/douban(type=${t.key})}" th:href="@{/douban(type=${t.key})}"
th:text="${t.name}" th:text="${t.name}"
th:classappend="${(isDefaultType and t.key == 'movie') or (!isDefaultType and urlType.toString() == t.key) ? 'wi-douban__filter-tag--active' : ''}" th:classappend="${(isDefaultType and t.key == 'music') or (!isDefaultType and urlType.toString() == t.key) ? 'wi-douban__filter-tag--active' : ''}"
></a> ></a>
</div> </div>
<div class="wi-douban__filter-group wi-douban__status-filters"> <div class="wi-douban__filter-group wi-douban__status-filters">
<th:block th:if="${currentType == 'movie'}"> <th:block th:if="${currentType == 'movie' or currentType == 'drama'}">
<a <a
class="wi-douban__filter-tag wi-douban__filter-tag--sm" class="wi-douban__filter-tag wi-douban__filter-tag--sm"
th:href="@{/douban(type='movie',status='wish')}" th:href="@{/douban(type=${currentType},status='wish')}"
th:classappend="${param.status != null and param.status.toString() == 'wish' ? 'wi-douban__filter-tag--active' : ''}" th:classappend="${hasStatus and currentStatus == 'wish'} ? 'wi-douban__filter-tag--active' : ''"
>想看</a> >想看</a>
<a <a
class="wi-douban__filter-tag wi-douban__filter-tag--sm" class="wi-douban__filter-tag wi-douban__filter-tag--sm"
th:href="@{/douban(type='movie',status='done')}" th:href="@{/douban(type=${currentType},status='done')}"
th:classappend="${param.status != null and param.status.toString() == 'done' ? 'wi-douban__filter-tag--active' : ''}" th:classappend="${(!hasStatus and isDefaultType) or (hasStatus and currentStatus == 'done')} ? 'wi-douban__filter-tag--active' : ''"
>看过</a> >看过</a>
</th:block> </th:block>
<th:block th:if="${currentType == 'book'}"> <th:block th:if="${currentType == 'book'}">
<a <a
class="wi-douban__filter-tag wi-douban__filter-tag--sm" class="wi-douban__filter-tag wi-douban__filter-tag--sm"
th:href="@{/douban(type='book',status='wish')}" th:href="@{/douban(type='book',status='wish')}"
th:classappend="${param.status != null and param.status.toString() == 'wish' ? 'wi-douban__filter-tag--active' : ''}" th:classappend="${hasStatus and currentStatus == 'wish'} ? 'wi-douban__filter-tag--active' : ''"
>想</a> >想</a>
<a <a
class="wi-douban__filter-tag wi-douban__filter-tag--sm" class="wi-douban__filter-tag wi-douban__filter-tag--sm"
th:href="@{/douban(type='book',status='doing')}" th:href="@{/douban(type='book',status='doing')}"
th:classappend="${param.status != null and param.status.toString() == 'doing' ? 'wi-douban__filter-tag--active' : ''}" th:classappend="${hasStatus and currentStatus == 'doing'} ? 'wi-douban__filter-tag--active' : ''"
>在</a> >在</a>
<a <a
class="wi-douban__filter-tag wi-douban__filter-tag--sm" class="wi-douban__filter-tag wi-douban__filter-tag--sm"
th:href="@{/douban(type='book',status='done')}" th:href="@{/douban(type='book',status='done')}"
th:classappend="${param.status != null and param.status.toString() == 'done' ? 'wi-douban__filter-tag--active' : ''}" th:classappend="${(!hasStatus and isDefaultType) or (hasStatus and currentStatus == 'done')} ? 'wi-douban__filter-tag--active' : ''"
>过</a> >过</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>
<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>
<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: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>
<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>
<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:block> </th:block>
</div> </div>
<div class="wi-douban__filter-group" th:if="${genres != null and !#lists.isEmpty(genres)}"> <div class="wi-douban__filter-group" th:if="${genres != null and !#lists.isEmpty(genres)}">
<th:block th:each="g : ${genres}" th:with="urlStatus = ${param.status}, hasStatus = ${urlStatus != null and !#strings.isEmpty(urlStatus.toString())}"> <th:block th:each="g : ${genres}">
<a <a
th:if="${hasStatus}" th:if="${hasStatus}"
class="wi-douban__filter-tag wi-douban__filter-tag--sm" class="wi-douban__filter-tag wi-douban__filter-tag--sm"
th:href="@{/douban(type=${currentType}, status=${urlStatus.toString()}, genre=${g.name})}" th:href="@{/douban(type=${currentType}, status=${currentStatus}, genre=${g.name})}"
th:text="|${g.name}(${g.doubanCount})|" th:text="|${g.name}(${g.doubanCount})|"
th:classappend="${param.genre != null and param.genre.toString() == g.name ? 'wi-douban__filter-tag--active' : ''}" th:classappend="${param.genre != null and param.genre.toString() == g.name ? 'wi-douban__filter-tag--active' : ''}"
></a> ></a>
<a <a
th:unless="${hasStatus}" th:unless="${hasStatus}"
class="wi-douban__filter-tag wi-douban__filter-tag--sm" class="wi-douban__filter-tag wi-douban__filter-tag--sm"
th:href="@{/douban(type=${currentType}, genre=${g.name})}" th:href="@{/douban(type=${currentType}, status='done', genre=${g.name})}"
th:text="|${g.name}(${g.doubanCount})|" th:text="|${g.name}(${g.doubanCount})|"
th:classappend="${param.genre != null and param.genre.toString() == g.name ? 'wi-douban__filter-tag--active' : ''}" th:classappend="${param.genre != null and param.genre.toString() == g.name ? 'wi-douban__filter-tag--active' : ''}"
></a> ></a>
@@ -79,7 +113,7 @@ import Layout from "../layouts/Layout.astro";
</th:block> </th:block>
</div> </div>
<th:block th:with="urlType = ${param.type}, isDefaultType = ${urlType == null or #strings.isEmpty(urlType.toString())}, currentType = ${isDefaultType ? 'movie' : urlType.toString()}, urlStatus = ${param.status}, hasStatus = ${urlStatus != null and !#strings.isEmpty(urlStatus.toString())}, currentStatus = ${hasStatus ? urlStatus.toString() : null}, urlGenre = ${param.genre}, hasGenre = ${urlGenre != null and !#strings.isEmpty(urlGenre.toString())}, currentGenre = ${hasGenre ? urlGenre.toString() : null}, doubans = ${hasStatus ? doubanFinder.list(1, 100, currentType, currentStatus) : doubanFinder.listByType(1, 100, currentType)}"> <th:block th:with="urlType = ${param.type}, isDefaultType = ${urlType == null or #strings.isEmpty(urlType.toString())}, currentType = ${isDefaultType ? 'music' : urlType.toString()}, urlStatus = ${param.status}, hasStatus = ${urlStatus != null and !#strings.isEmpty(urlStatus.toString())}, currentStatus = ${hasStatus ? urlStatus.toString() : 'done'}, urlGenre = ${param.genre}, hasGenre = ${urlGenre != null and !#strings.isEmpty(urlGenre.toString())}, currentGenre = ${hasGenre ? urlGenre.toString() : null}, doubans = ${doubanFinder.list(1, 100, currentType, currentStatus)}">
<div class="wi-douban__grid"> <div class="wi-douban__grid">
<article <article
@@ -134,11 +168,6 @@ import Layout from "../layouts/Layout.astro";
th:if="${!#strings.isEmpty(item.spec?.year)}" th:if="${!#strings.isEmpty(item.spec?.year)}"
th:text="${item.spec?.year}" th:text="${item.spec?.year}"
></span> ></span>
<span
class="wi-douban__type-badge"
th:if="${!#strings.isEmpty(item.spec?.type)}"
th:text="${item.spec?.type}"
></span>
</div> </div>
<div class="wi-douban__tags" th:if="${item.spec?.genres != null and !#sets.isEmpty(item.spec?.genres)}"> <div class="wi-douban__tags" th:if="${item.spec?.genres != null and !#sets.isEmpty(item.spec?.genres)}">
<span <span
@@ -152,11 +181,6 @@ import Layout from "../layouts/Layout.astro";
th:if="${!#strings.isEmpty(item.faves?.remark)}" th:if="${!#strings.isEmpty(item.faves?.remark)}"
th:text="${item.faves?.remark}" th:text="${item.faves?.remark}"
></p> ></p>
<span
class="wi-douban__status"
th:if="${!#strings.isEmpty(item.faves?.status)}"
th:text="${item.faves?.status == 'done' ? '看过' : (item.faves?.status == 'doing' ? '在看' : '想看')}"
></span>
</div> </div>
</article> </article>
</div> </div>
@@ -343,14 +367,6 @@ import Layout from "../layouts/Layout.astro";
font-weight: 500; font-weight: 500;
} }
.wi-douban__type-badge {
padding: 1px 6px;
border-radius: 4px;
background: var(--accent-bg);
color: var(--accent);
font-weight: 500;
}
.wi-douban__tags { .wi-douban__tags {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -379,17 +395,6 @@ import Layout from "../layouts/Layout.astro";
z-index: 2; z-index: 2;
} }
.wi-douban__status {
display: inline-block;
font-size: 11px;
padding: 2px 8px;
border-radius: 4px;
background: color-mix(in srgb, var(--accent) 10%, transparent);
color: var(--accent);
font-weight: 500;
width: fit-content;
}
@media (max-width: 640px) { @media (max-width: 640px) {
.wi-douban__grid { .wi-douban__grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
+3 -2
View File
@@ -33,7 +33,7 @@ import HeroSection from "../components/HeroSection.astro";
class="wi-pinned__cover" class="wi-pinned__cover"
th:if="${!#strings.isEmpty(post.spec.cover)}" th:if="${!#strings.isEmpty(post.spec.cover)}"
> >
<img th:src="${post.spec.cover}" th:alt="${post.spec.title}" class="wi-pinned__image" /> <img th:src="${post.spec.cover}" th:alt="${post.spec.title}" class="wi-pinned__image" loading="lazy" decoding="async" />
</div> </div>
<div class="wi-pinned__body"> <div class="wi-pinned__body">
<div class="wi-pinned__meta"> <div class="wi-pinned__meta">
@@ -137,7 +137,7 @@ import HeroSection from "../components/HeroSection.astro";
class="wi-flow__cover" class="wi-flow__cover"
th:if="${!#strings.isEmpty(post.spec.cover)}" th:if="${!#strings.isEmpty(post.spec.cover)}"
> >
<img th:src="${post.spec.cover}" th:alt="${post.spec.title}" class="wi-flow__image" /> <img th:src="${post.spec.cover}" th:alt="${post.spec.title}" class="wi-flow__image" loading="lazy" decoding="async" />
</div> </div>
</article> </article>
</div> </div>
@@ -196,6 +196,7 @@ import HeroSection from "../components/HeroSection.astro";
var grid = document.getElementById("wi-post-grid"); var grid = document.getElementById("wi-post-grid");
var loading = false; var loading = false;
var nextUrl = sentinel.getAttribute("data-next-url"); var nextUrl = sentinel.getAttribute("data-next-url");
var allLoadedText = sentinel.getAttribute("data-all-loaded-text") || "已加载全部文章";
var observer = new IntersectionObserver( var observer = new IntersectionObserver(
function (entries) { function (entries) {
+27
View File
@@ -10,6 +10,7 @@ import Layout from "../layouts/Layout.astro";
<section <section
class="wi-links" class="wi-links"
th:if="${pluginFinder.available('PluginLinks')}" th:if="${pluginFinder.available('PluginLinks')}"
th:attr="data-style=${theme.config?.links?.links_style ?: 'cards'}"
> >
<div class="wi-container"> <div class="wi-container">
<div class="wi-links__header"> <div class="wi-links__header">
@@ -121,6 +122,32 @@ import Layout from "../layouts/Layout.astro";
margin-bottom: var(--space-2xl); margin-bottom: var(--space-2xl);
} }
.wi-links[data-style="list"] .wi-links__grid {
grid-template-columns: 1fr;
max-width: 720px;
}
.wi-links[data-style="list"] .wi-links__card-inner {
border-radius: 12px;
padding: var(--space-md) var(--space-lg);
}
.wi-links[data-style="grid"] .wi-links__grid {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: var(--space-sm);
}
.wi-links[data-style="grid"] .wi-links__card-inner {
flex-direction: column;
align-items: center;
text-align: center;
padding: var(--space-xl) var(--space-lg);
}
.wi-links[data-style="grid"] .wi-links__arrow {
display: none;
}
.wi-links__card { .wi-links__card {
position: relative; position: relative;
border-radius: 16px; border-radius: 16px;
+151 -1
View File
@@ -18,7 +18,7 @@ import LightGallery from "../components/LightGallery.astro";
<th:block th:if="${pluginFinder.available('PluginMoments')}"> <th:block th:if="${pluginFinder.available('PluginMoments')}">
<div class="wi-moments-page__content"> <div class="wi-moments-page__content">
<th:block th:if="${momentFinder != null}"> <th:block th:if="${momentFinder != null}">
<th:block th:with="momentsResult = ${momentFinder.list(1, 50)}"> <th:block th:with="pageSize = ${theme.config?.moments?.moments_page_size ?: 10}, momentsResult = ${momentFinder.list(1, pageSize)}">
<div <div
class="wi-moments-page__timeline" class="wi-moments-page__timeline"
th:if="${theme.config?.moments?.moments_style == 'timeline' or theme.config?.moments?.moments_style == null}" th:if="${theme.config?.moments?.moments_style == 'timeline' or theme.config?.moments?.moments_style == null}"
@@ -195,6 +195,29 @@ import LightGallery from "../components/LightGallery.astro";
</div> </div>
</th:block> </th:block>
</th:block> </th:block>
<nav
class="wi-moments-page__pagination"
th:if="${theme.config?.moments?.moments_loading_mode == 'pagination' and momentsResult != null and momentsResult.hasPrevious()}"
>
<a
class="wi-moments-page__page-btn"
th:if="${momentsResult.hasPrevious()}"
th:href="${momentsResult.prevUrl}"
>← 较新</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>
</nav>
<div
class="wi-moments-page__infinite-sentinel"
th:if="${theme.config?.moments?.moments_loading_mode != 'pagination' and momentsResult != null and momentsResult.hasNext()}"
th:attr="data-next-url=${momentsResult.nextUrl}"
></div>
<th:block th:if="${momentFinder == null}"> <th:block th:if="${momentFinder == null}">
<div class="wi-moments-page__empty"> <div class="wi-moments-page__empty">
<p>瞬间插件加载异常,请检查插件状态</p> <p>瞬间插件加载异常,请检查插件状态</p>
@@ -315,6 +338,98 @@ import LightGallery from "../components/LightGallery.astro";
} }
loadMomentStats(); loadMomentStats();
var sentinel = document.querySelector(".wi-moments-page__infinite-sentinel");
if (sentinel) {
var momentsContent = document.querySelector(".wi-moments-page__content");
var infiniteLoading = false;
var infiniteNextUrl = sentinel.getAttribute("data-next-url");
var infiniteObserver = new IntersectionObserver(
function (entries) {
if (entries[0].isIntersecting && !infiniteLoading && infiniteNextUrl) {
infiniteLoading = true;
fetch(infiniteNextUrl)
.then(function (res) {
if (!res.ok) throw new Error("Fetch failed");
return res.text();
})
.then(function (html) {
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
var style = sentinel.closest(".wi-moments-page__content")
? sentinel.closest(".wi-moments-page__content").querySelector(
sentinel.previousElementSibling
? sentinel.previousElementSibling.className.split(" ")[0]
: ".wi-moments-page__timeline"
)
: null;
var container = null;
var selectors = [
".wi-moments-page__timeline",
".wi-moments-page__cards",
".wi-moments-page__masonry"
];
for (var s = 0; s < selectors.length; s++) {
container = doc.querySelector(selectors[s]);
if (container) break;
}
if (!container) {
infiniteLoading = false;
return;
}
var currentContainer = document.querySelector(selectors[0]) ||
document.querySelector(selectors[1]) ||
document.querySelector(selectors[2]);
if (!currentContainer) {
infiniteLoading = false;
return;
}
var newItems = container.children;
for (var i = 0; i < newItems.length; i++) {
var item = newItems[i].cloneNode(true);
item.style.opacity = "0";
item.style.transform = "translateY(20px)";
currentContainer.appendChild(item);
(function (el) {
requestAnimationFrame(function () {
el.style.transition = "opacity 0.4s ease, transform 0.4s ease";
el.style.opacity = "1";
el.style.transform = "translateY(0)";
});
})(item);
}
var newSentinel = doc.querySelector(".wi-moments-page__infinite-sentinel");
if (newSentinel && newSentinel.getAttribute("data-next-url")) {
infiniteNextUrl = newSentinel.getAttribute("data-next-url");
sentinel.setAttribute("data-next-url", infiniteNextUrl);
} else {
infiniteNextUrl = null;
infiniteObserver.disconnect();
sentinel.style.display = "none";
var endMsg = document.createElement("div");
endMsg.className = "wi-moments-page__empty";
endMsg.innerHTML = "<p>已加载全部瞬间</p>";
sentinel.parentNode.appendChild(endMsg);
}
infiniteLoading = false;
})
.catch(function () {
infiniteLoading = false;
});
}
},
{ rootMargin: "300px" }
);
infiniteObserver.observe(sentinel);
}
})(); })();
</script> </script>
@@ -693,6 +808,41 @@ import LightGallery from "../components/LightGallery.astro";
letter-spacing: var(--tracking-wide); letter-spacing: var(--tracking-wide);
} }
.wi-moments-page__pagination {
display: flex;
justify-content: center;
align-items: center;
gap: var(--space-lg);
margin-top: var(--space-3xl);
}
.wi-moments-page__page-btn {
display: inline-block;
padding: 10px 24px;
border-radius: 12px;
background: var(--bg-raised);
border: 1px solid var(--rule);
color: var(--ink);
font-size: var(--text-sm);
text-decoration: none;
transition: border-color var(--duration-fast) var(--ease-out-quart),
color var(--duration-fast) var(--ease-out-quart);
}
.wi-moments-page__page-btn:hover {
border-color: var(--accent);
color: var(--accent);
}
.wi-moments-page__page-spacer {
flex: 1;
}
.wi-moments-page__infinite-sentinel {
height: 1px;
width: 100%;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.wi-moments-page__timeline { .wi-moments-page__timeline {
padding-left: var(--space-xl); padding-left: var(--space-xl);
+1 -1
View File
@@ -30,7 +30,7 @@ import Layout from "../layouts/Layout.astro";
></div> ></div>
</div> </div>
<div class="wi-messageboard__comment"> <div class="wi-messageboard__comment" th:attr="data-comment-style=${theme.config?.comment?.comment_style ?: 'warm'},data-show-avatar=${theme.config?.comment?.comment_show_avatar != false}">
<halo:comment <halo:comment
th:if="${haloCommentEnabled}" th:if="${haloCommentEnabled}"
group="content.halo.run" group="content.halo.run"
+64 -11
View File
@@ -13,13 +13,15 @@ import LightGallery from "../components/LightGallery.astro";
<article class="wi-post"> <article class="wi-post">
<header class="wi-post__header"> <header class="wi-post__header">
<div <div
th:if="${!#strings.isEmpty(post.spec.cover)}" th:if="${theme.config?.article?.article_show_cover != false and !#strings.isEmpty(post.spec.cover)}"
class="wi-post__cover-wrap" class="wi-post__cover-wrap"
> >
<img <img
class="wi-post__cover" class="wi-post__cover"
th:src="${post.spec.cover}" th:src="${post.spec.cover}"
th:alt="${post.spec.title}" th:alt="${post.spec.title}"
loading="lazy"
decoding="async"
/> />
</div> </div>
@@ -31,7 +33,7 @@ import LightGallery from "../components/LightGallery.astro";
<div class="wi-post__meta"> <div class="wi-post__meta">
<time <time
th:if="${theme.config?.article?.article_show_date}" th:if="${theme.config?.article?.article_show_date != false}"
th:datetime="${post.spec.publishTime}" th:datetime="${post.spec.publishTime}"
th:text="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd')}" th:text="${#dates.format(post.spec.publishTime, 'yyyy-MM-dd')}"
></time> ></time>
@@ -48,7 +50,7 @@ import LightGallery from "../components/LightGallery.astro";
</span> </span>
</th:block> </th:block>
<th:block <th:block
th:if="${theme.config?.article?.article_show_category && post.categories != null && post.categories.size() > 0}" th:if="${theme.config?.article?.article_show_category != false && post.categories != null && post.categories.size() > 0}"
> >
<span class="wi-post__meta-sep">·</span> <span class="wi-post__meta-sep">·</span>
<span class="wi-post__meta-categories"> <span class="wi-post__meta-categories">
@@ -60,7 +62,7 @@ import LightGallery from "../components/LightGallery.astro";
</span> </span>
</th:block> </th:block>
<th:block <th:block
th:if="${theme.config?.article?.article_show_tags && post.tags != null && post.tags.size() > 0}" th:if="${theme.config?.article?.article_show_tags != false && post.tags != null && post.tags.size() > 0}"
> >
<span class="wi-post__meta-sep">·</span> <span class="wi-post__meta-sep">·</span>
<span class="wi-post__meta-tags"> <span class="wi-post__meta-tags">
@@ -126,7 +128,7 @@ import LightGallery from "../components/LightGallery.astro";
</button> </button>
</div> </div>
<th:block th:if="${theme.config?.article?.article_show_nav}"> <th:block th:if="${theme.config?.article?.article_show_nav == true}">
<nav class="wi-post__nav" aria-label="Post navigation"> <nav class="wi-post__nav" aria-label="Post navigation">
<th:block <th:block
th:with="cursor = ${postFinder.cursor(post.metadata.name)}" th:with="cursor = ${postFinder.cursor(post.metadata.name)}"
@@ -165,7 +167,7 @@ import LightGallery from "../components/LightGallery.astro";
</nav> </nav>
</th:block> </th:block>
<div class="wi-post__comment"> <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 <halo:comment
th:if="${haloCommentEnabled}" th:if="${haloCommentEnabled}"
group="content.halo.run" group="content.halo.run"
@@ -204,6 +206,35 @@ import LightGallery from "../components/LightGallery.astro";
<LightGallery /> <LightGallery />
<link
th:if="${theme.config?.article?.article_code_theme == 'cold'}"
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism-tomorrow.min.css"
/>
<link
th:if="${theme.config?.article?.article_code_theme != 'cold'}"
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"
/>
<script is:inline src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
<script is:inline src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
<script is:inline>
(function () {
if (typeof Prism !== "undefined") {
Prism.plugins.autoloader.languages_path = "https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/";
var body = document.getElementById("wi-post-body");
if (body) {
body.querySelectorAll("pre code").forEach(function (block) {
if (!block.classList.contains("language-")) {
Prism.highlightElement(block);
}
});
}
}
})();
</script>
<script is:inline> <script is:inline>
(function () { (function () {
var progressBar = document.getElementById("wi-reading-progress"); var progressBar = document.getElementById("wi-reading-progress");
@@ -603,6 +634,32 @@ import LightGallery from "../components/LightGallery.astro";
overflow-x: auto; overflow-x: auto;
} }
.wi-post__body pre {
margin-block: 1.5em;
padding: 1.25em;
border-radius: 12px;
border: 1px solid var(--rule);
background: var(--bg-raised);
font-size: 0.875em;
line-height: 1.6;
}
.wi-post__body pre code {
background: none;
padding: 0;
border: none;
border-radius: 0;
font-size: inherit;
}
.wi-post__body code {
background: var(--bg-raised);
padding: 0.15em 0.4em;
border-radius: 4px;
font-size: 0.875em;
border: 1px solid var(--rule);
}
.wi-post__body :is(h1, h2, h3, h4, h5, h6) { .wi-post__body :is(h1, h2, h3, h4, h5, h6) {
font-family: var(--font-sans); font-family: var(--font-sans);
margin-top: 1.8em; margin-top: 1.8em;
@@ -652,10 +709,6 @@ import LightGallery from "../components/LightGallery.astro";
margin-block-end: 0.6em; margin-block-end: 0.6em;
} }
.wi-post__body pre {
margin-block: 1.5em;
}
.wi-post__body blockquote { .wi-post__body blockquote {
margin-block: 2em; margin-block: 2em;
} }
@@ -956,7 +1009,7 @@ import LightGallery from "../components/LightGallery.astro";
color: #545164; color: #545164;
font-size: 0.875rem; font-size: 0.875rem;
text-align: center; text-align: center;
margin-top: -0.8em; margin-top: 0.5em;
margin-bottom: 1.2em; margin-bottom: 1.2em;
line-height: 1.5; line-height: 1.5;
} }
+66 -16
View File
@@ -16,15 +16,23 @@ import Layout from "../layouts/Layout.astro";
<th:block th:with="profile = ${steamFinder.getProfile()}, stats = ${steamFinder.getStats()}, badges = ${steamFinder.getBadges()}, recentGames = ${steamFinder.getRecentGames(recentGamesLimit)}"> <th:block th:with="profile = ${steamFinder.getProfile()}, stats = ${steamFinder.getStats()}, badges = ${steamFinder.getBadges()}, recentGames = ${steamFinder.getRecentGames(recentGamesLimit)}">
<div class="wi-steam__profile" th:if="${profile != null and profile.summary != null}"> <div class="wi-steam__profile" th:if="${profile != null}">
<div class="wi-steam__avatar"> <div class="wi-steam__avatar">
<img <img
th:if="${profile.summary != null and !#strings.isEmpty(profile.summary?.avatarFull) and !#strings.contains(profile.summary?.avatarFull, '00000000000000000')}"
th:src="${profile.summary?.avatarFull}" th:src="${profile.summary?.avatarFull}"
th:alt="${profile.summary?.personaName}" th:alt="${profile.summary?.personaName ?: 'Steam'}"
class="wi-steam__avatar-img" class="wi-steam__avatar-img"
loading="lazy"
decoding="async" decoding="async"
/> />
<span
class="wi-steam__avatar-placeholder"
th:if="${profile.summary == null or #strings.isEmpty(profile.summary?.avatarFull) or #strings.contains(profile.summary?.avatarFull, '00000000000000000')}"
>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="36" height="36">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
</svg>
</span>
<span <span
class="wi-steam__status-dot wi-steam__status-dot--playing" class="wi-steam__status-dot wi-steam__status-dot--playing"
th:if="${profile.playing}" th:if="${profile.playing}"
@@ -39,11 +47,11 @@ import Layout from "../layouts/Layout.astro";
></span> ></span>
</div> </div>
<div class="wi-steam__info"> <div class="wi-steam__info">
<h2 class="wi-steam__name" th:text="${profile.summary?.personaName}"></h2> <h2 class="wi-steam__name" th:if="${profile.summary != null}" th:text="${profile.summary?.personaName}"></h2>
<span class="wi-steam__status-text" th:text="${profile.statusText}"></span> <span class="wi-steam__status-text" th:if="${!#strings.isEmpty(profile.statusText)}" th:text="${profile.statusText}"></span>
<a <a
class="wi-steam__profile-link" class="wi-steam__profile-link"
th:if="${!#strings.isEmpty(profile.summary?.profileUrl)}" th:if="${profile.summary != null and !#strings.isEmpty(profile.summary?.profileUrl)}"
th:href="${profile.summary?.profileUrl}" th:href="${profile.summary?.profileUrl}"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -57,19 +65,19 @@ import Layout from "../layouts/Layout.astro";
<div class="wi-steam__stats" th:if="${stats != null}"> <div class="wi-steam__stats" th:if="${stats != null}">
<div class="wi-steam__stat-card"> <div class="wi-steam__stat-card">
<span class="wi-steam__stat-value" th:text="${stats.totalGames}"></span> <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">拥有游戏</span>
</div> </div>
<div class="wi-steam__stat-card"> <div class="wi-steam__stat-card">
<span class="wi-steam__stat-value" th:text="${stats.totalPlaytimeFormatted}"></span> <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-label">总游玩时长</span>
</div> </div>
<div class="wi-steam__stat-card"> <div class="wi-steam__stat-card">
<span class="wi-steam__stat-value" th:text="${stats.recentPlaytimeFormatted}"></span> <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-label">近两周</span>
</div> </div>
<div class="wi-steam__stat-card" th:if="${badges != null}"> <div class="wi-steam__stat-card">
<span class="wi-steam__stat-value" th:text="${badges.totalBadges}"></span> <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">徽章</span>
</div> </div>
</div> </div>
@@ -99,7 +107,7 @@ import Layout from "../layouts/Layout.astro";
<div class="wi-steam__recent-body"> <div class="wi-steam__recent-body">
<h4 class="wi-steam__recent-name" th:text="${game.name}"></h4> <h4 class="wi-steam__recent-name" th:text="${game.name}"></h4>
<div class="wi-steam__recent-meta"> <div class="wi-steam__recent-meta">
<span class="wi-steam__recent-time" th:text="${game.playtime2WeeksFormatted}"></span> <span class="wi-steam__recent-time" th:text="${game.playtime2WeeksFormatted} ?: '0 小时'"></span>
<span <span
class="wi-steam__recent-achievements" class="wi-steam__recent-achievements"
th:if="${game.achievementProgressText != null}" th:if="${game.achievementProgressText != null}"
@@ -138,7 +146,7 @@ import Layout from "../layouts/Layout.astro";
<div class="wi-steam__game-body"> <div class="wi-steam__game-body">
<h4 class="wi-steam__game-name" th:text="${game.name}"></h4> <h4 class="wi-steam__game-name" th:text="${game.name}"></h4>
<div class="wi-steam__game-meta"> <div class="wi-steam__game-meta">
<span class="wi-steam__game-time" th:text="${game.playtimeFormatted}"></span> <span class="wi-steam__game-time" th:text="${game.playtimeFormatted} ?: '0 小时'"></span>
<span <span
class="wi-steam__game-last" class="wi-steam__game-last"
th:if="${!#strings.isEmpty(game.lastPlayedFormatted)}" th:if="${!#strings.isEmpty(game.lastPlayedFormatted)}"
@@ -216,6 +224,19 @@ import Layout from "../layouts/Layout.astro";
border-radius: 50%; border-radius: 50%;
object-fit: cover; object-fit: cover;
border: 3px solid var(--rule); border: 3px solid var(--rule);
display: block;
}
.wi-steam__avatar-placeholder {
display: flex;
align-items: center;
justify-content: center;
width: 80px;
height: 80px;
border-radius: 50%;
background: var(--accent-bg);
border: 3px solid var(--rule);
color: var(--ink-3);
} }
.wi-steam__status-dot { .wi-steam__status-dot {
@@ -340,6 +361,7 @@ import Layout from "../layouts/Layout.astro";
font-size: var(--text-xs); font-size: var(--text-xs);
color: var(--ink-3); color: var(--ink-3);
margin-top: 4px; margin-top: 4px;
white-space: nowrap;
} }
.wi-steam__section { .wi-steam__section {
@@ -450,7 +472,7 @@ import Layout from "../layouts/Layout.astro";
.wi-steam__games-grid { .wi-steam__games-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-columns: repeat(4, 1fr);
gap: var(--space-md); gap: var(--space-md);
} }
@@ -499,6 +521,7 @@ import Layout from "../layouts/Layout.astro";
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 4px;
min-height: 72px;
} }
.wi-steam__game-name { .wi-steam__game-name {
@@ -513,13 +536,26 @@ import Layout from "../layouts/Layout.astro";
.wi-steam__game-meta { .wi-steam__game-meta {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
gap: 8px;
font-size: var(--text-xs); font-size: var(--text-xs);
color: var(--ink-3); color: var(--ink-3);
flex-wrap: wrap;
} }
.wi-steam__game-time { .wi-steam__game-time {
color: var(--accent); color: var(--accent);
font-weight: 500; font-weight: 500;
white-space: nowrap;
flex-shrink: 0;
}
.wi-steam__game-last {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 1;
min-width: 0;
} }
.wi-steam__pagination { .wi-steam__pagination {
@@ -552,10 +588,20 @@ import Layout from "../layouts/Layout.astro";
flex: 1; flex: 1;
} }
@media (max-width: 1200px) {
.wi-steam__games-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 1024px) { @media (max-width: 1024px) {
.wi-steam__stats { .wi-steam__stats {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
} }
.wi-steam__games-grid {
grid-template-columns: repeat(2, 1fr);
}
} }
@media (max-width: 768px) { @media (max-width: 768px) {
@@ -565,7 +611,8 @@ import Layout from "../layouts/Layout.astro";
padding: var(--space-lg); padding: var(--space-lg);
} }
.wi-steam__avatar-img { .wi-steam__avatar-img,
.wi-steam__avatar-placeholder {
width: 64px; width: 64px;
height: 64px; height: 64px;
} }
@@ -584,7 +631,7 @@ import Layout from "../layouts/Layout.astro";
} }
.wi-steam__games-grid { .wi-steam__games-grid {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); grid-template-columns: repeat(2, 1fr);
gap: var(--space-sm); gap: var(--space-sm);
} }
@@ -598,6 +645,9 @@ import Layout from "../layouts/Layout.astro";
.wi-steam__game-meta { .wi-steam__game-meta {
font-size: 10px; font-size: 10px;
flex-direction: column;
align-items: flex-start;
gap: 2px;
} }
.wi-steam__recent-card { .wi-steam__recent-card {
+14
View File
@@ -20,6 +20,7 @@ import Layout from "../layouts/Layout.astro";
class="wi-tags__pill" class="wi-tags__pill"
role="listitem" role="listitem"
th:href="@{${tag.status.permalink}}" th:href="@{${tag.status.permalink}}"
th:style="${tag.postCount > 10 ? 'font-size:1.25em' : (tag.postCount > 5 ? 'font-size:1.1em' : '')}"
> >
<span class="wi-tags__pill-name" th:text="${tag.spec.displayName}"></span> <span class="wi-tags__pill-name" th:text="${tag.spec.displayName}"></span>
<span class="wi-tags__pill-count" th:text="${tag.postCount}"></span> <span class="wi-tags__pill-count" th:text="${tag.postCount}"></span>
@@ -66,6 +67,8 @@ import Layout from "../layouts/Layout.astro";
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: var(--space-sm); gap: var(--space-sm);
justify-content: center;
padding: var(--space-lg) 0;
} }
.wi-tags__pill { .wi-tags__pill {
@@ -116,4 +119,15 @@ import Layout from "../layouts/Layout.astro";
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
color: var(--bg); color: var(--bg);
} }
@media (max-width: 640px) {
.wi-tags__cloud {
gap: 8px;
}
.wi-tags__pill {
padding: 0.4rem 0.8rem;
font-size: var(--text-xs);
}
}
</style> </style>
+46
View File
@@ -208,3 +208,49 @@ html.dark .halo-comment-widget {
} }
} }
} }
[data-comment-style="minimal"] .halo-comment-widget {
background: transparent;
backdrop-filter: none;
-webkit-backdrop-filter: none;
border: none;
border-top: 1px solid var(--rule);
border-radius: 0;
padding: var(--space-lg) 0;
.comment-item {
background: transparent;
border: none;
border-bottom: 1px solid var(--rule);
border-radius: 0;
padding: var(--space-md) 0;
&:hover {
box-shadow: none;
transform: none;
}
}
.comment-reply-item {
background: transparent;
border: none;
border-radius: 0;
padding: var(--space-xs) 0;
&:hover {
box-shadow: none;
transform: none;
}
}
.comment-form {
background: transparent;
border: 1px solid var(--rule);
border-radius: $border-radius-md;
padding: var(--space-md);
}
}
[data-show-avatar="false"] .halo-comment-widget .comment-avatar {
display: none;
}
+5 -1
View File
@@ -78,11 +78,15 @@ a {
img, img,
video, video,
svg { svg {
display: block;
max-width: 100%; max-width: 100%;
height: auto; height: auto;
} }
.wi-main img,
.wi-main video {
display: block;
}
img { img {
border-radius: $border-radius-md; border-radius: $border-radius-md;
} }
+6 -5
View File
@@ -5,12 +5,13 @@ metadata:
spec: spec:
displayName: WarmIsland 暖屿 displayName: WarmIsland 暖屿
author: author:
name: WarmIsland name: 暖心向阳335
website: https://github.com/warm-island website: https://nxxy335.top/
description: 一座深夜里温暖、安静、治愈的小岛 — 具有独特气质的生活博客主题 description: 具有独特气质的生活博客主题
logo: /themes/warm-island/assets/logo.png logo: /themes/warm-island/assets/logo.png
homepage: https://github.com/warm-island/theme-warm-island homepage: https://nxxy335.top/
issues: https://github.com/warm-island/theme-warm-island/issues repo: https://github.com/nxxy335top/halo-theme-WarmIsland
issues: https://github.com/nxxy335top/halo-theme-WarmIsland/issues
settingName: "warm-island-setting" settingName: "warm-island-setting"
configMapName: "warm-island-configMap" configMapName: "warm-island-configMap"
customTemplates: customTemplates: