Files
halo-theme-WarmIsland/src/pages/moments.astro
T
nxxy335 cfd9b55a28 fix(v1.2.2): 移动端二级菜单/页脚遮挡/切换不同步/卡片边框;新增瞬间详情页;Steam 页适配
- 移动端抽屉菜单:子菜单 th:block 移入 th:each 循环,修复二级菜单从未渲染
- 页脚:去掉 z-index 抬升,overflow-x hidden 改 clip,评论区翻页等弹层不再被遮挡/裁切
- 深浅色切换:页脚渐变背景改为可过渡的 background-color + 遮罩色层,全站同步过渡
- 玻璃卡片:移除与悬浮位移冲突的 backdrop-filter(Chromium 合成层吃掉顶边框),
  影响瞬间/友链页/友链圈/订阅页卡片;瞬间卡悬浮加描边
- 新增瞬间详情页主题化模板 moment.html(卡片视觉/九宫格/点赞恢复/空态兜底/灯箱)
- Steam 页:统计数据恒显示并兜底 '-',失败原因提示;成就进度移至右侧并加奖杯标识;
  修复容器查询写在被查询元素上导致失效的存量问题
- 评论聚焦环改用 color-mix(var(--accent)),跟随配色;订阅页圆角补兜底
- 已通过 ocr review 全量审查(22 文件),采纳其中有效发现
2026-10-01 16:54:52 +08:00

817 lines
29 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
import Layout from "../layouts/Layout.astro";
import LightGallery from "../components/LightGallery.astro";
---
<Layout>
<Fragment slot="head">
<title th:text="|${theme.config?.moments?.moments_page_title ?: '动态'} - ${site.title}|"></title>
</Fragment>
<section class="wi-moments-page">
<div class="wi-moments-page__hero" th:if="${theme.config?.moments?.moments_cover}">
<img
class="wi-moments-page__cover"
th:src="${theme.config?.moments?.moments_cover}"
alt=""
loading="eager"
decoding="async"
/>
</div>
<div class="wi-container">
<div class="wi-moments-page__header" th:unless="${theme.config?.moments?.moments_cover}">
<h1 class="wi-moments-page__title" th:text="${theme.config?.moments?.moments_page_title ?: '动态'}">瞬间</h1>
<span class="wi-page-accent"></span>
</div>
<th:block th:if="${pluginFinder.available('PluginMoments')}">
<div class="wi-moments-page__content">
<th:block th:if="${momentFinder != null}">
<th:block th:with="pageSize = ${theme.config?.moments?.moments_page_size ?: 10}, momentsResult = ${momentFinder.list(1, pageSize)}">
<div class="wi-moments-page__cards" th:if="${theme.config?.moments?.moments_style == 'cards' or theme.config?.moments?.moments_style == null or theme.config?.moments?.moments_style == 'timeline'}">
<th:block th:if="${momentsResult != null and not #lists.isEmpty(momentsResult.items)}">
<div class="wi-moments-page__card-item" th:each="moment : ${momentsResult.items}">
<div class="wi-moments-page__card-layout">
<img
th:if="${moment.owner != null and !#strings.isEmpty(moment.owner.avatar)}"
class="wi-moments-page__avatar"
th:src="${moment.owner.avatar}"
th:alt="''"
loading="lazy"
decoding="async"
/>
<div
th:unless="${moment.owner != null and !#strings.isEmpty(moment.owner.avatar)}"
class="wi-moments-page__avatar wi-moments-page__avatar--fallback"
aria-hidden="true"
>
<span th:text="${#strings.substring(site.title, 0, 1)}"></span>
</div>
<div class="wi-moments-page__main">
<div
class="wi-moments-page__name"
th:text="${moment.owner != null and !#strings.isEmpty(moment.owner.displayName) ? moment.owner.displayName : site.title}"
></div>
<div class="wi-moments-page__card-text" th:utext="${moment.spec?.content?.html ?: moment.spec?.content?.raw ?: moment.spec?.content}"></div>
<div class="wi-moments-page__card-media" th:if="${moment.spec.content.medium != null and !#lists.isEmpty(moment.spec.content.medium)}">
<th:block th:each="media : ${moment.spec.content.medium}">
<img
th:if="${media.type.name == 'PHOTO'}"
th:src="${media.url}"
th:alt="''"
class="wi-moments-page__card-image"
loading="lazy"
decoding="async"
/>
</th:block>
</div>
<div class="wi-moments-page__card-footer">
<time
class="wi-moments-page__card-date"
th:text="${#dates.format(moment.spec?.releaseTime ?: moment.metadata?.creationTimestamp, 'yyyy-MM-dd HH:mm')}"
></time>
<div class="wi-moments-page__actions">
<button
class="wi-moments-page__like-btn"
type="button"
th:attr="data-moment-name=${moment.metadata.name}"
>
<svg class="wi-moments-page__like-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/></svg>
<span class="wi-moments-page__like-count" th:text="${moment.stats?.upvote ?: 0}">0</span>
</button>
<button
class="wi-moments-page__comment-btn"
type="button"
th:attr="data-moment-name=${moment.metadata.name}"
>
<svg class="wi-moments-page__comment-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
<span class="wi-moments-page__comment-count" th:text="${moment.stats?.approvedComment ?: 0}">0</span>
</button>
</div>
</div>
<div class="wi-moments-page__comment-area" th:attr="data-moment-name=${moment.metadata.name}" style="display:none;">
<halo:comment
group="moment.halo.run"
kind="Moment"
th:attr="name=${moment.metadata.name}"
/>
</div>
</div> <!-- /__main -->
</div> <!-- /__card-layout -->
</div>
</th:block>
<th:block th:if="${momentsResult == null or #lists.isEmpty(momentsResult.items)}">
<div class="wi-moments-page__empty">
<p th:text="'还没有瞬间,快去记录当下的心情吧 🌙'">还没有瞬间,快去记录当下的心情吧 🌙</p>
</div>
</th:block>
</div>
<div class="wi-moments-page__masonry" th:if="${theme.config?.moments?.moments_style == 'masonry'}">
<th:block th:if="${momentsResult != null and not #lists.isEmpty(momentsResult.items)}">
<div class="wi-moments-page__masonry-item" th:each="moment : ${momentsResult.items}">
<div class="wi-moments-page__masonry-text" th:utext="${moment.spec?.content?.html ?: moment.spec?.content?.raw ?: moment.spec?.content}"></div>
<div class="wi-moments-page__masonry-media" th:if="${moment.spec.content.medium != null and !#lists.isEmpty(moment.spec.content.medium)}">
<th:block th:each="media : ${moment.spec.content.medium}">
<img
th:if="${media.type.name == 'PHOTO'}"
th:src="${media.url}"
th:alt="''"
class="wi-moments-page__masonry-image"
loading="lazy"
decoding="async"
/>
</th:block>
</div>
<div class="wi-moments-page__masonry-footer">
<time
class="wi-moments-page__masonry-date"
th:text="${#dates.format(moment.spec?.releaseTime ?: moment.metadata?.creationTimestamp, 'yyyy-MM-dd HH:mm')}"
></time>
<div class="wi-moments-page__actions">
<button
class="wi-moments-page__like-btn"
type="button"
th:attr="data-moment-name=${moment.metadata.name}"
>
<svg class="wi-moments-page__like-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/></svg>
<span class="wi-moments-page__like-count" th:text="${moment.stats?.upvote ?: 0}">0</span>
</button>
<button
class="wi-moments-page__comment-btn"
type="button"
th:attr="data-moment-name=${moment.metadata.name}"
>
<svg class="wi-moments-page__comment-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
<span class="wi-moments-page__comment-count" th:text="${moment.stats?.approvedComment ?: 0}">0</span>
</button>
</div>
</div>
<div class="wi-moments-page__comment-area" th:attr="data-moment-name=${moment.metadata.name}" style="display:none;">
<halo:comment
group="moment.halo.run"
kind="Moment"
th:attr="name=${moment.metadata.name}"
/>
</div>
</div>
</th:block>
<th:block th:if="${momentsResult == null or #lists.isEmpty(momentsResult.items)}">
<div class="wi-moments-page__empty">
<p th:text="'还没有瞬间,快去记录当下的心情吧 🌙'">还没有瞬间,快去记录当下的心情吧 🌙</p>
</div>
</th:block>
</div>
</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}"
th:text="'较新'">较新</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}"
th:text="'较旧'">较旧</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}">
<div class="wi-moments-page__empty">
<p th:text="'插件加载异常,请检查插件状态'">插件加载异常,请检查插件状态</p>
</div>
</th:block>
</div>
</th:block>
<th:block th:unless="${pluginFinder.available('PluginMoments')}">
<div class="wi-moments-page__empty">
<p>该功能需要安装「瞬间」插件,<a href="https://www.halo.run/store/apps/app-SnwWD" target="_blank" rel="noopener noreferrer">前往应用市场安装</a></p>
</div>
</th:block>
</div>
</section>
<LightGallery />
</Layout>
<script is:inline th:inline="none">
(function () {
document.addEventListener("click", function (e) {
var likeBtn = e.target.closest(".wi-moments-page__like-btn");
if (likeBtn) {
handleLike(likeBtn);
return;
}
var commentBtn = e.target.closest(".wi-moments-page__comment-btn");
if (commentBtn) {
toggleComment(commentBtn);
return;
}
});
function handleLike(btn) {
var momentName = btn.getAttribute("data-moment-name");
var likedKey = "wi-moment-liked-" + momentName;
var countEl = btn.querySelector(".wi-moments-page__like-count");
if (localStorage.getItem(likedKey)) return;
if (btn.classList.contains("wi-moments-page__like-btn--liked")) return;
fetch("/apis/api.halo.run/v1alpha1/trackers/upvote", {
method: "POST",
headers: { "Content-Type": "application/json;charset=UTF-8" },
body: JSON.stringify({
group: "moment.halo.run",
plural: "moments",
name: momentName,
}),
})
.then(function (res) {
if (!res.ok) throw new Error("Like failed");
btn.classList.add("wi-moments-page__like-btn--liked");
if (countEl) {
countEl.textContent = parseInt(countEl.textContent || "0") + 1;
}
localStorage.setItem(likedKey, "1");
})
.catch(function (err) {
console.error("Like error:", err);
});
}
function toggleComment(btn) {
var momentName = btn.getAttribute("data-moment-name");
var commentArea = document.querySelector(
'.wi-moments-page__comment-area[data-moment-name="' + momentName + '"]'
);
if (!commentArea) return;
if (commentArea.style.display === "none") {
commentArea.style.display = "block";
btn.classList.add("wi-moments-page__comment-btn--active");
} else {
commentArea.style.display = "none";
btn.classList.remove("wi-moments-page__comment-btn--active");
}
}
document.querySelectorAll(".wi-moments-page__like-btn").forEach(function (btn) {
var momentName = btn.getAttribute("data-moment-name");
var likedKey = "wi-moment-liked-" + momentName;
if (localStorage.getItem(likedKey)) {
btn.classList.add("wi-moments-page__like-btn--liked");
}
});
function loadMomentStats() {
fetch("/apis/api.moment.halo.run/v1alpha1/moments")
.then(function (res) {
if (!res.ok) return null;
return res.json();
})
.then(function (data) {
if (!data || !data.items) return;
data.items.forEach(function (moment) {
var name = moment.metadata.name;
var stats = moment.stats || {};
document.querySelectorAll(".wi-moments-page__like-btn").forEach(function (btn) {
if (btn.getAttribute("data-moment-name") === name) {
var countEl = btn.querySelector(".wi-moments-page__like-count");
if (countEl) countEl.textContent = stats.upvote || 0;
}
});
document.querySelectorAll(".wi-moments-page__comment-btn").forEach(function (btn) {
if (btn.getAttribute("data-moment-name") === name) {
var countEl = btn.querySelector(".wi-moments-page__comment-count");
if (countEl) countEl.textContent = stats.approvedComment || 0;
}
});
});
})
.catch(function () {});
}
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__cards"
)
: null;
var container = null;
var selectors = [
".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>
<style>
.wi-moments-page {
padding-block: 1rem;
}
.wi-moments-page__hero {
position: relative;
width: 100%;
height: clamp(220px, 30vw, 380px);
/* 顶图与首条瞬间的卡片边框不能贴死:留出与页面头部一致的呼吸间距 */
margin-bottom: var(--space-2xl);
overflow: hidden;
background: var(--bg-raised);
}
.wi-moments-page__cover {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.wi-moments-page__header {
text-align: center;
margin-bottom: var(--space-3xl);
}
.wi-moments-page__title {
font-size: var(--text-4xl);
margin-bottom: var(--space-sm);
}
.wi-page-accent {
display: block;
width: 48px;
height: 3px;
margin: var(--space-sm) auto 0;
border-radius: 9999px;
background: var(--accent);
}
.wi-moments-page__empty {
text-align: center;
padding: var(--space-4xl) var(--space-xl);
color: var(--ink-3);
font-size: var(--text-md);
}
.wi-moments-page__empty a {
color: var(--accent);
}
.wi-moments-page__content {
content-visibility: auto;
contain-intrinsic-size: auto 800px;
}
.wi-moments-page__actions {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.wi-moments-page__like-btn,
.wi-moments-page__comment-btn {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
border: 1px solid var(--rule);
border-radius: 9999px;
background: transparent;
color: var(--ink-3);
font-size: var(--text-xs);
font-family: var(--font-body);
cursor: pointer;
transition:
color 0.2s ease,
border-color 0.2s ease,
background 0.2s ease;
}
.wi-moments-page__like-btn:hover,
.wi-moments-page__comment-btn:hover {
color: var(--accent);
border-color: var(--accent);
}
.wi-moments-page__like-btn--liked {
color: var(--accent);
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 8%, var(--bg));
cursor: default;
}
.wi-moments-page__like-btn--liked .wi-moments-page__like-icon {
fill: var(--accent);
}
.wi-moments-page__comment-btn--active {
color: var(--accent);
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 8%, var(--bg));
}
.wi-moments-page__like-icon,
.wi-moments-page__comment-icon {
flex-shrink: 0;
}
.wi-moments-page__like-count,
.wi-moments-page__comment-count {
line-height: 1;
}
.wi-moments-page__comment-area {
margin-top: var(--space-md);
padding-top: var(--space-md);
border-top: 1px solid var(--rule);
}
.wi-moments-page__comment-area halo\:comment {
display: block;
width: 100%;
}
.wi-moments-page__cards {
display: flex;
flex-direction: column;
gap: var(--space-lg);
max-width: 720px;
margin: 0 auto;
}
.wi-moments-page__card-item {
background: var(--glass-bg);
/* 不用 backdrop-filter:Chromium 下带 backdrop-filter 的元素一发生
transform(悬浮上移),合成层就会吃掉顶部 1px 边框;卡片背后是
纯页面背景,毛玻璃模糊本身没有可见效果,去掉即可修复 */
border: 1px solid var(--glass-border);
border-radius: 16px;
padding: var(--space-xl);
transition:
box-shadow var(--duration-normal) var(--ease-out-expo),
transform var(--duration-normal) var(--ease-out-expo),
border-color var(--duration-normal) var(--ease-out-expo);
}
.wi-moments-page__card-item:hover {
box-shadow: var(--shadow-md);
transform: translateY(-3px);
border-color: var(--accent);
}
/* 朋友圈式布局:头像在左,昵称/正文/九宫格在右 */
.wi-moments-page__card-layout {
display: flex;
gap: var(--space-md);
align-items: flex-start;
}
.wi-moments-page__avatar {
flex-shrink: 0;
width: 44px;
height: 44px;
border-radius: 10px;
object-fit: cover;
}
.wi-moments-page__avatar--fallback {
display: flex;
align-items: center;
justify-content: center;
background: color-mix(in srgb, var(--accent) 14%, transparent);
color: var(--accent);
font-weight: 700;
font-size: var(--text-lg);
}
.wi-moments-page__main {
flex: 1;
min-width: 0;
}
.wi-moments-page__name {
font-size: var(--text-base);
font-weight: 600;
color: var(--accent);
margin-bottom: var(--space-xs);
}
.wi-moments-page__card-text {
font-size: var(--text-base);
line-height: var(--leading-relaxed);
color: var(--ink);
margin-bottom: var(--space-md);
}
.wi-moments-page__card-media {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
margin-bottom: var(--space-md);
}
.wi-moments-page__card-image {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border-radius: 8px;
cursor: pointer;
transition: transform 0.2s ease;
}
.wi-moments-page__card-image:hover {
transform: scale(1.03);
}
.wi-moments-page__card-media:has(.wi-moments-page__card-image:only-child) {
grid-template-columns: 1fr;
}
.wi-moments-page__card-media:has(.wi-moments-page__card-image:only-child) .wi-moments-page__card-image {
aspect-ratio: auto;
max-height: 300px;
max-width: 400px;
}
.wi-moments-page__card-media:has(.wi-moments-page__card-image:nth-child(2):last-child) {
grid-template-columns: repeat(2, 1fr);
}
/* 微信九宫格规则:4 张时 2x2 排布 */
.wi-moments-page__card-media:has(.wi-moments-page__card-image:nth-child(4)):not(:has(.wi-moments-page__card-image:nth-child(5))) {
grid-template-columns: repeat(2, 1fr);
max-width: 72%;
}
/* 三列九宫格限制宽度,避免大屏下图片单元过大 */
.wi-moments-page__card-media:has(.wi-moments-page__card-image:nth-child(3)) {
max-width: 100%;
}
.wi-moments-page__card-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-md);
}
.wi-moments-page__card-date {
font-size: var(--text-xs);
color: var(--ink-3);
letter-spacing: var(--tracking-wide);
}
.wi-moments-page__masonry {
columns: 2;
column-gap: var(--space-lg);
}
.wi-moments-page__masonry-item {
break-inside: avoid;
margin-bottom: var(--space-lg);
background: var(--bg-raised);
border: 1px solid var(--rule);
border-radius: 16px;
padding: var(--space-xl);
transition:
box-shadow var(--duration-normal) var(--ease-out-expo),
transform var(--duration-normal) var(--ease-out-expo);
}
.wi-moments-page__masonry-item:hover {
box-shadow: var(--shadow-md);
transform: translateY(-2px);
}
.wi-moments-page__masonry-text {
font-size: var(--text-base);
line-height: var(--leading-relaxed);
color: var(--ink);
margin-bottom: var(--space-md);
}
.wi-moments-page__masonry-media {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
margin-bottom: var(--space-md);
}
.wi-moments-page__masonry-image {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border-radius: 8px;
cursor: pointer;
transition: transform 0.2s ease;
}
.wi-moments-page__masonry-image:hover {
transform: scale(1.03);
}
.wi-moments-page__masonry-media:has(.wi-moments-page__masonry-image:only-child) {
grid-template-columns: 1fr;
}
.wi-moments-page__masonry-media:has(.wi-moments-page__masonry-image:only-child) .wi-moments-page__masonry-image {
aspect-ratio: auto;
max-height: 300px;
}
.wi-moments-page__masonry-media:has(.wi-moments-page__masonry-image:nth-child(2):last-child) {
grid-template-columns: repeat(2, 1fr);
}
/* 微信九宫格规则:4 张时 2x2 排布 */
.wi-moments-page__masonry-media:has(.wi-moments-page__masonry-image:nth-child(4)):not(:has(.wi-moments-page__masonry-image:nth-child(5))) {
grid-template-columns: repeat(2, 1fr);
}
.wi-moments-page__masonry-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-md);
}
.wi-moments-page__masonry-date {
font-size: var(--text-xs);
color: var(--ink-3);
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) {
.wi-moments-page__hero {
height: clamp(180px, 36vw, 260px);
}
.wi-moments-page__masonry {
columns: 1;
}
.wi-moments-page__card-item {
padding: var(--space-md);
}
.wi-moments-page__card-text {
font-size: var(--text-base);
}
}
@media (max-width: 480px) {
.wi-moments-page__card-media,
.wi-moments-page__masonry-media {
grid-template-columns: repeat(3, 1fr);
gap: 4px;
}
.wi-moments-page__like-btn,
.wi-moments-page__comment-btn {
padding: 8px 14px;
}
.wi-moments-page__card-item,
.wi-moments-page__masonry-item {
padding: var(--space-md) var(--space-sm);
}
.wi-moments-page__card-text,
.wi-moments-page__masonry-text {
font-size: var(--text-base);
}
}
</style>