feat: 图库重做/瞬间详情/重要日子适配页/全站灯箱,修复豆瓣页白屏(v0.2.0)

- 图库页重做:首屏按相册分组展示,封面自动取相册第一张图,可在设置中按相册手动配置封面;点击相册进入 ?group= 瀑布流视图(一行三张、页面加宽),支持预览模式(lightgallery 放大,默认值可配置、前台可切换)
- 瞬间页:新增 /moments/{name} 详情页(完整内容、媒体、标签、作者信息、评论区);列表页发布人与发布时间同行对齐;补充单条标签
- 新增 plugin-important-dates 适配页 important-dates.html(即将到来提醒、全部日期倒计时、重要标记、人员生日)
- 全站集成 lightgallery.js 灯箱(动态模式、按需加载、挂载 body 避免层叠上下文遮挡),可在设置中关闭
- 友链页:「全部」视图按分组展示并显示分组标题(空分组自动隐藏);卡片简介限制两行,统一卡片高度与尺寸
- 修复 /douban 白屏:SpEL 不支持 th:with 中的嵌套 map 字面量(EL1041E),改为四段显式区块
- 版本号升至 0.2.0;README 同步更新

Co-Authored-By: WorkBuddy <noreply@workbuddy.ai>
This commit is contained in:
2026-09-30 09:10:32 +08:00
co-authored by WorkBuddy
parent c0ea6ec0df
commit 4e3001674a
17 changed files with 1125 additions and 160 deletions
+155 -43
View File
@@ -80,52 +80,164 @@
<th:block th:if="${pluginFinder.available('plugin-douban')}">
<th:block
th:with="collections=${{ {'type':'book','status':'done','label':'读过'}, {'type':'book','status':'doing','label':'在读'}, {'type':'movie','status':'done','label':'看过'}, {'type':'drama','status':'doing','label':'在追'} }}"
th:with="movies=${doubanFinder.getMovies(24, 0, 'book', 'done')}"
>
<th:block th:each="col : ${collections}">
<th:block
th:with="movies=${doubanFinder.getMovies(24, 0, col.type, col.status)}"
>
<div
class="douban-section"
th:if="${not #lists.isEmpty(movies)}"
<div
class="douban-section"
th:if="${not #lists.isEmpty(movies)}"
>
<h2 class="douban-section-title">读过</h2>
<div class="douban-grid">
<a
th:each="m : ${movies}"
class="douban-card"
th:href="${m.spec.link}"
target="_blank"
rel="noopener noreferrer"
>
<h2 class="douban-section-title" th:text="${col.label}">
读过
</h2>
<div class="douban-grid">
<a
th:each="m : ${movies}"
class="douban-card"
th:href="${m.spec.link}"
target="_blank"
rel="noopener noreferrer"
<img
class="douban-cover"
th:src="${m.spec.poster}"
th:alt="${m.spec.name}"
loading="lazy"
/>
<p class="douban-name" th:text="${m.spec.name}">名称</p>
<p class="douban-meta">
<span
th:if="${not #strings.isEmpty(m.spec.year)}"
th:text="${m.spec.year}"
>年份</span
>
<img
class="douban-cover"
th:src="${m.spec.poster}"
th:alt="${m.spec.name}"
loading="lazy"
/>
<p class="douban-name" th:text="${m.spec.name}">名称</p>
<p class="douban-meta">
<span
th:if="${not #strings.isEmpty(m.spec.year)}"
th:text="${m.spec.year}"
>年份</span
>
<span
th:if="${not #strings.isEmpty(m.spec.douban_score)}"
class="douban-score"
th:text="'★ ' + ${m.spec.douban_score}"
>评分</span
>
</p>
</a>
</div>
</div>
</th:block>
</th:block>
<span
th:if="${not #strings.isEmpty(m.spec.douban_score)}"
class="douban-score"
th:text="'★ ' + ${m.spec.douban_score}"
>评分</span
>
</p>
</a>
</div>
</div>
</th:block>
<th:block
th:with="movies=${doubanFinder.getMovies(24, 0, 'book', 'doing')}"
>
<div
class="douban-section"
th:if="${not #lists.isEmpty(movies)}"
>
<h2 class="douban-section-title">在读</h2>
<div class="douban-grid">
<a
th:each="m : ${movies}"
class="douban-card"
th:href="${m.spec.link}"
target="_blank"
rel="noopener noreferrer"
>
<img
class="douban-cover"
th:src="${m.spec.poster}"
th:alt="${m.spec.name}"
loading="lazy"
/>
<p class="douban-name" th:text="${m.spec.name}">名称</p>
<p class="douban-meta">
<span
th:if="${not #strings.isEmpty(m.spec.year)}"
th:text="${m.spec.year}"
>年份</span
>
<span
th:if="${not #strings.isEmpty(m.spec.douban_score)}"
class="douban-score"
th:text="'★ ' + ${m.spec.douban_score}"
>评分</span
>
</p>
</a>
</div>
</div>
</th:block>
<th:block
th:with="movies=${doubanFinder.getMovies(24, 0, 'movie', 'done')}"
>
<div
class="douban-section"
th:if="${not #lists.isEmpty(movies)}"
>
<h2 class="douban-section-title">看过</h2>
<div class="douban-grid">
<a
th:each="m : ${movies}"
class="douban-card"
th:href="${m.spec.link}"
target="_blank"
rel="noopener noreferrer"
>
<img
class="douban-cover"
th:src="${m.spec.poster}"
th:alt="${m.spec.name}"
loading="lazy"
/>
<p class="douban-name" th:text="${m.spec.name}">名称</p>
<p class="douban-meta">
<span
th:if="${not #strings.isEmpty(m.spec.year)}"
th:text="${m.spec.year}"
>年份</span
>
<span
th:if="${not #strings.isEmpty(m.spec.douban_score)}"
class="douban-score"
th:text="'★ ' + ${m.spec.douban_score}"
>评分</span
>
</p>
</a>
</div>
</div>
</th:block>
<th:block
th:with="movies=${doubanFinder.getMovies(24, 0, 'drama', 'doing')}"
>
<div
class="douban-section"
th:if="${not #lists.isEmpty(movies)}"
>
<h2 class="douban-section-title">在追</h2>
<div class="douban-grid">
<a
th:each="m : ${movies}"
class="douban-card"
th:href="${m.spec.link}"
target="_blank"
rel="noopener noreferrer"
>
<img
class="douban-cover"
th:src="${m.spec.poster}"
th:alt="${m.spec.name}"
loading="lazy"
/>
<p class="douban-name" th:text="${m.spec.name}">名称</p>
<p class="douban-meta">
<span
th:if="${not #strings.isEmpty(m.spec.year)}"
th:text="${m.spec.year}"
>年份</span
>
<span
th:if="${not #strings.isEmpty(m.spec.douban_score)}"
class="douban-score"
th:text="'★ ' + ${m.spec.douban_score}"
>评分</span
>
</p>
</a>
</div>
</div>
</th:block>
</th:block>