Files
halo-theme-WarmIsland/src/pages/moments.astro
T
nxxy335 9f677a9f0d feat: Hero 背景图完整显示、导航二级菜单、瞬间朋友圈化、友链申请表单 (v1.1.9)
- Hero:背景图 opacity 0.15 -> 1 完整显示(此前近乎透明的背景图是"蒙灰"观感的
  主因);标题/副标题/一言按明暗模式补轻投影保证复杂图片上的可读性
- 导航栏二级菜单:桌面端纯 CSS 悬停/聚焦展开(零 JS),带悬停桥防误关、
  下拉箭头旋转反馈;移动端菜单以缩进子项形式呈现
- 瞬间页朋友圈化:头像(moment.owner.avatar,缺省回退站点名首字占位)+ 昵称
  + 正文 + 九宫格图片 + 时间操作;九宫格遵循微信规则(单图原比例、2/4 图两列、
  其余三列)
- 友情链接页适配 plugin-links 友链申请:同源表单(POST /links/apply/submit +
  csrfToken + GET /links/apply/captcha 验证码图,点击刷新),支持名称/链接/
  Logo/描述/邮箱/反链/RSS 字段、提交结果与错误提示;插件未开放申请时验证码
  加载失败自动隐藏表单;新增 links_apply_form_enabled 开关(默认开启)
2026-09-26 16:14:20 +08:00

811 lines
28 KiB
Plaintext

---
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);
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: blur(16px);
-webkit-backdrop-filter: blur(16px);
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);
}
.wi-moments-page__card-item:hover {
box-shadow: var(--shadow-md);
transform: translateY(-3px);
}
/* 朋友圈式布局:头像在左,昵称/正文/九宫格在右 */
.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);
}
.wi-moments-page__masonry-media:has(.wi-moments-page__masonry-image:nth-child(4)) {
grid-template-columns: repeat(3, 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>