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 文件),采纳其中有效发现
This commit is contained in:
1 parent
c1b08ad915
commit
cfd9b55a28
24 files changed
+531
-43
No files matched your search
@@ -98,18 +98,31 @@ const THEME_VERSION = readThemeVersion();
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
/*
|
||||
* 页脚不要创建高于内容的绘制层级:
|
||||
* - 之前 z-index:1 与 .wi-main 同级且靠后,会盖住内容区的弹层(如评论区翻页下拉)
|
||||
* - 渐变背景(background-image)无法参与过渡,导致深浅色切换时页脚瞬变、
|
||||
* 内容区还在渐变,看起来"不同步";改为 background-color + 遮罩渐隐的
|
||||
* 伪色层,两者都能随 .wi-theme-transition 平滑过渡
|
||||
*/
|
||||
footer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border-top: 1px solid var(--rule);
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
var(--bg),
|
||||
color-mix(in srgb, var(--bg) 97%, var(--accent) 3%)
|
||||
);
|
||||
background-color: var(--bg);
|
||||
}
|
||||
|
||||
footer::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background-color: color-mix(in srgb, var(--bg) 97%, var(--accent) 3%);
|
||||
-webkit-mask-image: linear-gradient(to bottom, transparent, #000);
|
||||
mask-image: linear-gradient(to bottom, transparent, #000);
|
||||
}
|
||||
|
||||
.footer-inner {
|
||||
position: relative;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -57,8 +57,6 @@
|
||||
gap: var(--space-md);
|
||||
padding: var(--space-lg);
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 12px;
|
||||
text-decoration: none;
|
||||
|
||||
@@ -13,23 +13,24 @@
|
||||
<th:block th:if="${menuFinder != null}">
|
||||
<th:block th:with="menu = ${menuFinder.getPrimary()}">
|
||||
<th:block th:if="${menu != null and menu.menuItems != null and not #lists.isEmpty(menu.menuItems)}">
|
||||
<a
|
||||
th:each="menuItem : ${menu.menuItems}"
|
||||
th:href="@{${menuItem.status.href}}"
|
||||
th:target="${menuItem.spec?.target?.value == '_blank'} ? '_blank' : '_self'"
|
||||
th:text="${menuItem.status.displayName}"
|
||||
class="wi-mobile-menu__link"
|
||||
th:data-href="${menuItem.status.href}"
|
||||
></a>
|
||||
<th:block th:if="${not #lists.isEmpty(menuItem.children)}">
|
||||
<th:block th:each="menuItem : ${menu.menuItems}">
|
||||
<a
|
||||
th:each="child : ${menuItem.children}"
|
||||
th:href="@{${child.status.href}}"
|
||||
th:target="${child.spec?.target?.value == '_blank'} ? '_blank' : '_self'"
|
||||
th:text="${'| ' + child.status.displayName}"
|
||||
class="wi-mobile-menu__link wi-mobile-menu__link--sub"
|
||||
th:data-href="${child.status.href}"
|
||||
th:href="@{${menuItem.status.href}}"
|
||||
th:target="${menuItem.spec?.target?.value == '_blank'} ? '_blank' : '_self'"
|
||||
th:text="${menuItem.status.displayName}"
|
||||
class="wi-mobile-menu__link"
|
||||
th:data-href="${menuItem.status.href}"
|
||||
></a>
|
||||
<th:block th:if="${not #lists.isEmpty(menuItem.children)}">
|
||||
<a
|
||||
th:each="child : ${menuItem.children}"
|
||||
th:href="@{${child.status.href}}"
|
||||
th:target="${child.spec?.target?.value == '_blank'} ? '_blank' : '_self'"
|
||||
th:text="${child.status.displayName}"
|
||||
class="wi-mobile-menu__link wi-mobile-menu__link--sub"
|
||||
th:data-href="${child.status.href}"
|
||||
></a>
|
||||
</th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
||||
@@ -168,8 +168,6 @@ import Layout from "../layouts/Layout.astro";
|
||||
|
||||
.wi-friends-page__card {
|
||||
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);
|
||||
|
||||
@@ -551,8 +551,6 @@ import Layout from "../layouts/Layout.astro";
|
||||
gap: var(--space-md);
|
||||
padding: var(--space-lg);
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 16px;
|
||||
flex: 1;
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
---
|
||||
/**
|
||||
* 瞬间详情页(templates/moment.html,覆盖 plugin-moments 默认模板)
|
||||
* ---------------------------------------------------------------
|
||||
* 插件默认模板没有套主题样式,排版松散。这里复用瞬间列表页的
|
||||
* 「朋友圈式卡片」视觉:头像 + 昵称 + 时间 + 正文 + 九宫格媒体 + 点赞,
|
||||
* 评论区默认展开,底部保留返回列表入口。
|
||||
*
|
||||
* 插件路由传入的模型变量:moment(MomentVo)、title、haloCommentEnabled。
|
||||
* moment 取不到(已删除/链接错误)时显示空态,避免 SpEL 取 null 属性 500。
|
||||
*/
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import LightGallery from "../components/LightGallery.astro";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<Fragment slot="head">
|
||||
<title th:text="|${title} - ${site.title}|">瞬间</title>
|
||||
</Fragment>
|
||||
|
||||
<section class="wi-moment-detail">
|
||||
<h1 class="wi-moment-detail__sr-only" th:text="'瞬间详情'">瞬间详情</h1>
|
||||
<div class="wi-moment-detail__topbar">
|
||||
<a class="wi-moment-detail__back" href="/moments" th:href="@{/moments}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12 19-7-7 7-7"/><path d="M19 12H5"/></svg>
|
||||
<span th:text="'返回瞬间列表'">返回瞬间列表</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<th:block th:if="${moment != null}">
|
||||
<article class="wi-moment-detail__card" th:with="detailContent=${moment.spec?.content}">
|
||||
<div class="wi-moment-detail__layout">
|
||||
<img
|
||||
th:if="${moment.owner != null and !#strings.isEmpty(moment.owner.avatar)}"
|
||||
class="wi-moment-detail__avatar"
|
||||
th:src="${moment.owner.avatar}"
|
||||
th:alt="''"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
/>
|
||||
<div
|
||||
th:unless="${moment.owner != null and !#strings.isEmpty(moment.owner.avatar)}"
|
||||
class="wi-moment-detail__avatar wi-moment-detail__avatar--fallback"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span th:text="${#strings.substring(site.title, 0, 1)}"></span>
|
||||
</div>
|
||||
|
||||
<div class="wi-moment-detail__main">
|
||||
<div class="wi-moment-detail__head">
|
||||
<span
|
||||
class="wi-moment-detail__name"
|
||||
th:text="${moment.owner != null and !#strings.isEmpty(moment.owner.displayName) ? moment.owner.displayName : site.title}"
|
||||
></span>
|
||||
<time
|
||||
class="wi-moment-detail__date"
|
||||
th:datetime="${moment.spec?.releaseTime ?: moment.metadata?.creationTimestamp}"
|
||||
th:text="${#dates.format(moment.spec?.releaseTime ?: moment.metadata?.creationTimestamp, 'yyyy-MM-dd HH:mm')}"
|
||||
></time>
|
||||
</div>
|
||||
|
||||
<div class="wi-moment-detail__text" th:utext="${detailContent?.html ?: detailContent?.raw ?: ''}"></div>
|
||||
|
||||
<div
|
||||
class="wi-moment-detail__media wi-moments-page__card-media"
|
||||
th:if="${detailContent != null and detailContent.medium != null and !#lists.isEmpty(detailContent.medium)}"
|
||||
>
|
||||
<th:block th:each="medium : ${detailContent.medium}">
|
||||
<img
|
||||
th:if="${medium.type.name == 'PHOTO'}"
|
||||
class="wi-moment-detail__image"
|
||||
th:src="${medium.url}"
|
||||
th:alt="''"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
<video
|
||||
th:if="${medium.type.name == 'VIDEO'}"
|
||||
class="wi-moment-detail__video"
|
||||
th:src="${medium.url}"
|
||||
controls
|
||||
preload="metadata"
|
||||
></video>
|
||||
<audio
|
||||
th:if="${medium.type.name == 'AUDIO'}"
|
||||
class="wi-moment-detail__audio"
|
||||
th:src="${medium.url}"
|
||||
controls
|
||||
preload="metadata"
|
||||
></audio>
|
||||
</th:block>
|
||||
</div>
|
||||
|
||||
<div class="wi-moment-detail__actions">
|
||||
<button
|
||||
class="wi-moment-detail__like-btn"
|
||||
type="button"
|
||||
aria-label="点赞"
|
||||
th:attr="data-moment-name=${moment.metadata.name}"
|
||||
>
|
||||
<svg 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" aria-hidden="true"><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-moment-detail__like-count" th:text="${moment.stats?.upvote ?: 0}">0</span>
|
||||
</button>
|
||||
<span class="wi-moment-detail__comment-hint">
|
||||
<svg 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" aria-hidden="true"><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 th:text="${moment.stats?.approvedComment ?: 0}">0</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<section class="wi-moment-detail__comments" th:if="${haloCommentEnabled}">
|
||||
<halo:comment
|
||||
group="moment.halo.run"
|
||||
kind="Moment"
|
||||
th:attr="name=${moment.metadata.name}"
|
||||
/>
|
||||
</section>
|
||||
</th:block>
|
||||
|
||||
<th:block th:if="${moment == null}">
|
||||
<div class="wi-moment-detail__empty">
|
||||
<p th:text="'这条瞬间不存在,或已经被删除了 🌙'">这条瞬间不存在,或已经被删除了 🌙</p>
|
||||
</div>
|
||||
</th:block>
|
||||
</section>
|
||||
|
||||
<LightGallery />
|
||||
</Layout>
|
||||
|
||||
<script is:inline th:inline="none">
|
||||
(function () {
|
||||
/* 页面加载时恢复已点赞状态(与 moments.astro 列表页一致) */
|
||||
document.querySelectorAll(".wi-moment-detail__like-btn").forEach(function (btn) {
|
||||
var name = btn.getAttribute("data-moment-name");
|
||||
if (name && localStorage.getItem("wi-moment-liked-" + name)) {
|
||||
btn.classList.add("wi-moment-detail__like-btn--liked");
|
||||
btn.setAttribute("aria-pressed", "true");
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("click", function (e) {
|
||||
var likeBtn = e.target.closest(".wi-moment-detail__like-btn");
|
||||
if (!likeBtn) return;
|
||||
var momentName = likeBtn.getAttribute("data-moment-name");
|
||||
if (!momentName) return;
|
||||
var likedKey = "wi-moment-liked-" + momentName;
|
||||
var countEl = likeBtn.querySelector(".wi-moment-detail__like-count");
|
||||
if (localStorage.getItem(likedKey)) return;
|
||||
if (likeBtn.classList.contains("wi-moment-detail__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");
|
||||
likeBtn.classList.add("wi-moment-detail__like-btn--liked");
|
||||
likeBtn.setAttribute("aria-pressed", "true");
|
||||
if (countEl) {
|
||||
countEl.textContent = parseInt(countEl.textContent || "0", 10) + 1;
|
||||
}
|
||||
localStorage.setItem(likedKey, "1");
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error("Like error:", err);
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.wi-moment-detail {
|
||||
padding-block: 1rem;
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* 仅供屏幕阅读器的页面级标题 */
|
||||
.wi-moment-detail__sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.wi-moment-detail__topbar {
|
||||
margin-bottom: var(--space-lg);
|
||||
}
|
||||
|
||||
.wi-moment-detail__back {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.375rem 0.875rem;
|
||||
border-radius: 9999px;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--ink-2);
|
||||
text-decoration: none;
|
||||
background: var(--bg-raised);
|
||||
transition:
|
||||
color var(--duration-fast) var(--ease-out-quart),
|
||||
background var(--duration-fast) var(--ease-out-quart);
|
||||
}
|
||||
|
||||
.wi-moment-detail__back:hover {
|
||||
color: var(--accent);
|
||||
background: var(--accent-bg);
|
||||
}
|
||||
|
||||
.wi-moment-detail__card {
|
||||
background: var(--glass-bg);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 16px;
|
||||
padding: var(--space-xl);
|
||||
}
|
||||
|
||||
.wi-moment-detail__layout {
|
||||
display: flex;
|
||||
gap: var(--space-md);
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.wi-moment-detail__avatar {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.wi-moment-detail__avatar--fallback {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--accent-bg);
|
||||
color: var(--accent);
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-md);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.wi-moment-detail__main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wi-moment-detail__head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: var(--space-sm);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.wi-moment-detail__name {
|
||||
font-size: var(--text-md);
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.wi-moment-detail__date {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--ink-3);
|
||||
}
|
||||
|
||||
.wi-moment-detail__text {
|
||||
margin-top: var(--space-sm);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-relaxed);
|
||||
color: var(--ink);
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.wi-moment-detail__text :global(img) {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.wi-moment-detail__media {
|
||||
margin-top: var(--space-md);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* 与列表页一致的微信九宫格规则:单图自然比例,2 图两列,4 图 2x2 */
|
||||
.wi-moment-detail__media:has(.wi-moment-detail__image:only-child) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.wi-moment-detail__media:has(.wi-moment-detail__image:only-child) .wi-moment-detail__image {
|
||||
aspect-ratio: auto;
|
||||
max-height: 300px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.wi-moment-detail__media:has(.wi-moment-detail__image:nth-child(2):last-child) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.wi-moment-detail__media:has(.wi-moment-detail__image:nth-child(4)):not(:has(.wi-moment-detail__image:nth-child(5))) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
max-width: 72%;
|
||||
}
|
||||
|
||||
.wi-moment-detail__media:has(.wi-moment-detail__image:nth-child(3)) {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.wi-moment-detail__image {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
cursor: zoom-in;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.wi-moment-detail__image:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.wi-moment-detail__video {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.wi-moment-detail__audio {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wi-moment-detail__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
margin-top: var(--space-md);
|
||||
padding-top: var(--space-md);
|
||||
border-top: 1px solid var(--rule);
|
||||
}
|
||||
|
||||
.wi-moment-detail__like-btn,
|
||||
.wi-moment-detail__comment-hint {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.375rem 0.875rem;
|
||||
border: 1px solid var(--rule);
|
||||
border-radius: 9999px;
|
||||
background: transparent;
|
||||
color: var(--ink-2);
|
||||
font-size: var(--text-xs);
|
||||
transition:
|
||||
color var(--duration-fast) var(--ease-out-quart),
|
||||
border-color var(--duration-fast) var(--ease-out-quart),
|
||||
background var(--duration-fast) var(--ease-out-quart);
|
||||
}
|
||||
|
||||
.wi-moment-detail__like-btn {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wi-moment-detail__comment-hint {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.wi-moment-detail__like-btn:hover,
|
||||
.wi-moment-detail__like-btn--liked {
|
||||
color: var(--accent);
|
||||
border-color: var(--accent);
|
||||
background: var(--accent-bg);
|
||||
}
|
||||
|
||||
.wi-moment-detail__comments {
|
||||
margin-top: var(--space-xl);
|
||||
}
|
||||
|
||||
.wi-moment-detail__empty {
|
||||
text-align: center;
|
||||
padding: var(--space-4xl) var(--space-xl);
|
||||
color: var(--ink-3);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.wi-moment-detail__card {
|
||||
padding: var(--space-lg);
|
||||
}
|
||||
|
||||
.wi-moment-detail__avatar {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -538,19 +538,22 @@ import LightGallery from "../components/LightGallery.astro";
|
||||
|
||||
.wi-moments-page__card-item {
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
/* 不用 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);
|
||||
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);
|
||||
}
|
||||
|
||||
/* 朋友圈式布局:头像在左,昵称/正文/九宫格在右 */
|
||||
|
||||
@@ -118,5 +118,5 @@ import Layout from "../layouts/Layout.astro";
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
.wi-subs{padding-block:1rem}.wi-subs__header{text-align:center;margin-bottom:var(--space-3xl)}.wi-subs__title{font-size:var(--text-4xl);margin-bottom:var(--space-sm)}.wi-subs__subtitle{font-size:var(--text-sm);color:var(--ink-3);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-subs__flow{display:flex;flex-direction:column;gap:var(--space-lg);max-width:720px;margin-inline:auto}.wi-subs[data-layout=grid] .wi-subs__flow{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-lg);max-width:1200px}.wi-subs[data-layout=grid] .wi-subs__card{padding:var(--space-lg);display:flex;flex-direction:column;gap:var(--space-md)}.wi-subs[data-layout=grid] .wi-subs__author{flex-direction:column;align-items:center;text-align:center;gap:var(--space-xs);margin-bottom:0}.wi-subs[data-layout=grid] .wi-subs__avatar{width:44px;height:44px}.wi-subs[data-layout=grid] .wi-subs__author-info{align-items:center;gap:2px}.wi-subs[data-layout=grid] .wi-subs__author-name{font-size:var(--text-sm);white-space:normal;text-align:center;line-height:var(--leading-tight);-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.wi-subs[data-layout=grid] .wi-subs__date{font-size:var(--text-xs)}.wi-subs[data-layout=grid] .wi-subs__body{margin-bottom:0;flex:1;display:flex;flex-direction:column;gap:var(--space-xs)}.wi-subs[data-layout=grid] .wi-subs__post-title{font-size:var(--text-md);line-height:var(--leading-snug);-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden;margin:0}.wi-subs[data-layout=grid] .wi-subs__summary{font-size:var(--text-sm);-webkit-line-clamp:3;line-clamp:3}@media(max-width:768px){.wi-subs[data-layout=grid] .wi-subs__flow{grid-template-columns:repeat(2,1fr)}}@media(max-width:480px){.wi-subs[data-layout=grid] .wi-subs__flow{grid-template-columns:1fr}.wi-subs[data-layout=grid] .wi-subs__card{padding:var(--space-md)}.wi-subs[data-layout=grid] .wi-subs__author{flex-direction:row;text-align:left}.wi-subs[data-layout=grid] .wi-subs__author-info{align-items:flex-start}.wi-subs[data-layout=grid] .wi-subs__author-name{text-align:left}}.wi-subs__card{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),border-color var(--duration-normal) var(--ease-out-expo)}.wi-subs__card:hover{box-shadow:var(--shadow-md);transform:translateY(-2px);border-color:var(--accent)}.wi-subs__author{display:flex;align-items:center;gap:var(--space-md);margin-bottom:var(--space-md)}.wi-subs__avatar{width:44px;height:44px;border-radius:9999px;object-fit:cover;flex-shrink:0;box-shadow:var(--shadow-sm)}.wi-subs__avatar--placeholder{display:flex;align-items:center;justify-content:center;background:var(--accent-bg);color:var(--accent);font-family:var(--font-sans);font-size:var(--text-md);font-weight:700;box-shadow:none}.wi-subs__author-info{display:flex;flex-direction:column;gap:2px;min-width:0}.wi-subs__author-name{font-size:var(--text-md);font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-decoration:none;transition:color var(--duration-fast) var(--ease-out-quart)}a.wi-subs__author-name:hover{color:var(--accent)}.wi-subs__date{font-size:var(--text-xs);color:var(--ink-3);letter-spacing:.02em}.wi-subs__body{margin-bottom:var(--space-sm)}.wi-subs__title-link{text-decoration:none;display:block}.wi-subs__post-title{font-size:var(--text-lg);font-weight:600;color:var(--ink);line-height:var(--leading-snug);margin:0 0 var(--space-xs);transition:color var(--duration-fast) var(--ease-out-quart)}.wi-subs__title-link:hover .wi-subs__post-title{color:var(--accent)}.wi-subs__summary{font-size:var(--text-sm);color:var(--ink-2);line-height:var(--leading-relaxed);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;margin-block-end:0}.wi-subs__pagination{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-top:var(--space-2xl);padding-top:var(--space-xl);border-top:1px solid var(--rule)}.wi-subs__page-link{display:inline-flex;align-items:center;padding:var(--space-sm) var(--space-md);min-height:44px;color:var(--accent);text-decoration:none;font-size:var(--text-sm);font-weight:500;border-radius:var(--radius-sm);transition:opacity var(--duration-fast) var(--ease-out-quart),background var(--duration-fast) var(--ease-out-quart)}.wi-subs__page-link:hover{opacity:.8;background:var(--bg-raised)}.wi-subs__page-link--placeholder{visibility:hidden;pointer-events:none}.wi-subs__page-info{color:var(--ink-3);font-size:var(--text-sm)}.wi-subs__empty{text-align:center;padding:var(--space-4xl) var(--space-xl);color:var(--ink-3);font-size:var(--text-md)}.wi-subs__empty a{color:var(--accent)}.wLine truncated
|
||||
.wi-subs{padding-block:1rem}.wi-subs__header{text-align:center;margin-bottom:var(--space-3xl)}.wi-subs__title{font-size:var(--text-4xl);margin-bottom:var(--space-sm)}.wi-subs__subtitle{font-size:var(--text-sm);color:var(--ink-3);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-subs__flow{display:flex;flex-direction:column;gap:var(--space-lg);max-width:720px;margin-inline:auto}.wi-subs[data-layout=grid] .wi-subs__flow{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-lg);max-width:1200px}.wi-subs[data-layout=grid] .wi-subs__card{padding:var(--space-lg);display:flex;flex-direction:column;gap:var(--space-md)}.wi-subs[data-layout=grid] .wi-subs__author{flex-direction:column;align-items:center;text-align:center;gap:var(--space-xs);margin-bottom:0}.wi-subs[data-layout=grid] .wi-subs__avatar{width:44px;height:44px}.wi-subs[data-layout=grid] .wi-subs__author-info{align-items:center;gap:2px}.wi-subs[data-layout=grid] .wi-subs__author-name{font-size:var(--text-sm);white-space:normal;text-align:center;line-height:var(--leading-tight);-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.wi-subs[data-layout=grid] .wi-subs__date{font-size:var(--text-xs)}.wi-subs[data-layout=grid] .wi-subs__body{margin-bottom:0;flex:1;display:flex;flex-direction:column;gap:var(--space-xs)}.wi-subs[data-layout=grid] .wi-subs__post-title{font-size:var(--text-md);line-height:var(--leading-snug);-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden;margin:0}.wi-subs[data-layout=grid] .wi-subs__summary{font-size:var(--text-sm);-webkit-line-clamp:3;line-clamp:3}@media(max-width:768px){.wi-subs[data-layout=grid] .wi-subs__flow{grid-template-columns:repeat(2,1fr)}}@media(max-width:480px){.wi-subs[data-layout=grid] .wi-subs__flow{grid-template-columns:1fr}.wi-subs[data-layout=grid] .wi-subs__card{padding:var(--space-md)}.wi-subs[data-layout=grid] .wi-subs__author{flex-direction:row;text-align:left}.wi-subs[data-layout=grid] .wi-subs__author-info{align-items:flex-start}.wi-subs[data-layout=grid] .wi-subs__author-name{text-align:left}}.wi-subs__card{background:var(--glass-bg);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-subs__card:hover{box-shadow:var(--shadow-md);transform:translateY(-2px);border-color:var(--accent)}.wi-subs__author{display:flex;align-items:center;gap:var(--space-md);margin-bottom:var(--space-md)}.wi-subs__avatar{width:44px;height:44px;border-radius:9999px;object-fit:cover;flex-shrink:0;box-shadow:var(--shadow-sm)}.wi-subs__avatar--placeholder{display:flex;align-items:center;justify-content:center;background:var(--accent-bg);color:var(--accent);font-family:var(--font-sans);font-size:var(--text-md);font-weight:700;box-shadow:none}.wi-subs__author-info{display:flex;flex-direction:column;gap:2px;min-width:0}.wi-subs__author-name{font-size:var(--text-md);font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-decoration:none;transition:color var(--duration-fast) var(--ease-out-quart)}a.wi-subs__author-name:hover{color:var(--accent)}.wi-subs__date{font-size:var(--text-xs);color:var(--ink-3);letter-spacing:.02em}.wi-subs__body{margin-bottom:var(--space-sm)}.wi-subs__title-link{text-decoration:none;display:block}.wi-subs__post-title{font-size:var(--text-lg);font-weight:600;color:var(--ink);line-height:var(--leading-snug);margin:0 0 var(--space-xs);transition:color var(--duration-fast) var(--ease-out-quart)}.wi-subs__title-link:hover .wi-subs__post-title{color:var(--accent)}.wi-subs__summary{font-size:var(--text-sm);color:var(--ink-2);line-height:var(--leading-relaxed);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;margin-block-end:0}.wi-subs__pagination{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-top:var(--space-2xl);padding-top:var(--space-xl);border-top:1px solid var(--rule)}.wi-subs__page-link{display:inline-flex;align-items:center;padding:var(--space-sm) var(--space-md);min-height:44px;color:var(--accent);text-decoration:none;font-size:var(--text-sm);font-weight:500;border-radius:var(--radius-sm, 8px);transition:opacity var(--duration-fast) var(--ease-out-quart),background var(--duration-fast) var(--ease-out-quart)}.wi-subs__page-link:hover{opacity:.8;background:var(--bg-raised)}.wi-subs__page-link--placeholder{visibility:hidden;pointer-events:none}.wi-subs__page-info{color:var(--ink-3);font-size:var(--text-sm)}.wi-subs__empty{text-align:center;padding:var(--space-4xl) var(--space-xl);color:var(--ink-3);font-size:var(--text-md)}.wi-subs__empty a{color:var(--accent)}.wi-subs__infinite-sentinel{height:1px;width:100%}.wi-subs_Line truncated
|
||||
</style>
|
||||
+36
-8
@@ -63,24 +63,29 @@ import Layout from "../layouts/Layout.astro";
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wi-steam__stats" th:if="${stats != null}">
|
||||
<div class="wi-steam__stats">
|
||||
<div class="wi-steam__stat-card">
|
||||
<span class="wi-steam__stat-value" th:text="${stats.totalGames} ?: 0">0</span>
|
||||
<span class="wi-steam__stat-value" th:text="${stats != null and stats.totalGames != null ? stats.totalGames : '-'}">-</span>
|
||||
<span class="wi-steam__stat-label" th:text="'拥有游戏'">拥有游戏</span>
|
||||
</div>
|
||||
<div class="wi-steam__stat-card">
|
||||
<span class="wi-steam__stat-value" th:text="${stats.totalPlaytimeFormatted} ?: '0 hours'">0 hours</span>
|
||||
<span class="wi-steam__stat-value" th:text="${stats != null and stats.totalPlaytimeFormatted != null ? stats.totalPlaytimeFormatted : '-'}">-</span>
|
||||
<span class="wi-steam__stat-label" th:text="'总游玩时长'">总游玩时长</span>
|
||||
</div>
|
||||
<div class="wi-steam__stat-card">
|
||||
<span class="wi-steam__stat-value" th:text="${stats.recentPlaytimeFormatted} ?: '0 hours'">0 hours</span>
|
||||
<span class="wi-steam__stat-value" th:text="${stats != null and stats.recentPlaytimeFormatted != null ? stats.recentPlaytimeFormatted : '-'}">-</span>
|
||||
<span class="wi-steam__stat-label" th:text="'近两周'">近两周</span>
|
||||
</div>
|
||||
<div class="wi-steam__stat-card">
|
||||
<span class="wi-steam__stat-value" th:text="${badges != null and badges.totalBadges != null ? badges.totalBadges : 0}">0</span>
|
||||
<span class="wi-steam__stat-value" th:text="${badges != null and badges.totalBadges != null ? badges.totalBadges : '-'}">-</span>
|
||||
<span class="wi-steam__stat-label" th:text="'徽章'">徽章</span>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
class="wi-steam__stats-hint"
|
||||
th:if="${stats == null or badges == null}"
|
||||
th:text="'Steam 统计数据暂时没有加载成功:可能是 Steam 接口超时、游戏库隐私设置为私密或插件配置有误,稍后刷新重试。'"
|
||||
></p>
|
||||
|
||||
<div class="wi-steam__section" th:if="${recentGames != null and !recentGames.isEmpty()}">
|
||||
<h3 class="wi-steam__section-title" th:text="'最近游玩'">最近游玩</h3>
|
||||
@@ -111,8 +116,10 @@ import Layout from "../layouts/Layout.astro";
|
||||
<span
|
||||
class="wi-steam__recent-achievements"
|
||||
th:if="${game.achievementProgressText != null}"
|
||||
th:text="${game.achievementProgressText}"
|
||||
></span>
|
||||
>
|
||||
<svg class="wi-steam__achieve-icon" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2Z"/></svg>
|
||||
<span th:text="${game.achievementProgressText}"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
@@ -331,6 +338,9 @@ import Layout from "../layouts/Layout.astro";
|
||||
border: 1px solid var(--rule);
|
||||
border-radius: 12px;
|
||||
min-height: 80px;
|
||||
/* 容器查询的容器必须是被查询元素的祖先:
|
||||
放在 .wi-steam__stat-value 自身上时 @container 永远不命中 */
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.wi-steam__stat-value {
|
||||
@@ -342,7 +352,6 @@ import Layout from "../layouts/Layout.astro";
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
@container (max-width: 120px) {
|
||||
@@ -456,6 +465,8 @@ import Layout from "../layouts/Layout.astro";
|
||||
|
||||
.wi-steam__recent-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
font-size: var(--text-xs);
|
||||
color: var(--ink-3);
|
||||
@@ -466,8 +477,25 @@ import Layout from "../layouts/Layout.astro";
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 成就进度固定靠右展示,带奖杯标识 */
|
||||
.wi-steam__recent-achievements {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #f59e0b;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.wi-steam__achieve-icon {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
/* 统计数据加载失败时的提示 */
|
||||
.wi-steam__stats-hint {
|
||||
margin: calc(-1 * var(--space-sm)) 0 var(--space-2xl);
|
||||
font-size: var(--text-xs);
|
||||
color: var(--ink-3);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wi-steam__games-grid {
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 3px rgba(212, 118, 78, 0.15);
|
||||
/* 跟随当前配色/自定义强调色,不再硬编码默认赤陶色 */
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
@@ -198,7 +199,7 @@ html.dark .halo-comment-widget {
|
||||
.comment-input,
|
||||
.comment-textarea {
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 3px rgba(232, 149, 95, 0.15);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +196,10 @@ table {
|
||||
z-index: 1;
|
||||
background-color: var(--bg);
|
||||
width: 100%;
|
||||
/* clip 与 hidden 同样裁掉横向溢出,但不会把元素变成滚动容器,
|
||||
避免内容底部的弹层(如评论区翻页下拉)被纵向裁掉 */
|
||||
overflow-x: hidden;
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
.wi-main--wide.wi-main--home {
|
||||
@@ -207,6 +210,7 @@ table {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
.wi-content-wrap {
|
||||
@@ -214,6 +218,7 @@ table {
|
||||
margin: 0 auto;
|
||||
padding-inline: clamp(1rem, 3vw, 2rem);
|
||||
overflow-x: hidden;
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
.wi-content-wrap--wide {
|
||||
|
||||
Reference in new issue
Block a user