fix(polish): 视觉复核二轮六项——网格单一高度源/导航i18n/热力图缓存等

- 图库:li 去 aspect-ratio(与行跨度双高度约束竞争=列洞根因面),
  img 改 object-fit cover 填满;截图前整页滚动触发懒加载
- Header:导航标签按 locale 取字典(en 页曾是中文);图标钮暗色
  提色去底块(视觉复核 02/12 的灰块)
- 热力图:构建期模块级缓存,zh/en 两页共享一次抓取(en 页曾空格)
- en 首页移除机器翻译横幅(文章级标注才是本意);面板居中;计数器
  文字投影
- Artalk E2E 报 fetch 失败定性为测试环境跨域(127.0.0.1 页面拉
  wait4x.online API),生产同源不受影响——上线后专项验证

验证: pnpm astro build 21 页 exit 0;node tests/e2e.mjs 30/30 PASS
      (新构建全链重跑,含滚动后 21/21 图库断言)

Spec: 2026-10-25_fix-site-polish

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-10-25 10:57:16 +08:00
1 parent 7a2880b65d
commit e21fac7e1d
6 files changed
+36 -9

No files matched your search

+1
View File
@@ -276,6 +276,7 @@ const navItems = [
<style>
.search-dialog {
margin: 12vh auto auto;
margin-top: 12vh;
width: min(560px, calc(100vw - 32px));
border: 1px solid var(--line);
+9 -5
View File
@@ -1,18 +1,19 @@
---
import { localeOf, localePath } from '../lib/locale';
import { t } from '../i18n/ui';
// 顶部导航:≤4 项纪律(防 higan 十项复发);当前页 aria-current
const nav = [
{ href: '/archives/', label: '文章' },
{ href: '/gallery/', label: '图库' },
{ href: '/about/', label: '关于' },
];
const path = Astro.url.pathname;
const isCurrent = (href: string) =>
path === href || path === href.replace(/\/$/, '') || path.startsWith(href);
// 语言切换:同路径跨前缀跳转(zh 无前缀 ↔ /en/),预构建双语毫秒级
const curLocale = localeOf(path);
const nav = [
{ href: '/archives/', label: t('nav_posts', curLocale) },
{ href: '/gallery/', label: t('nav_gallery', curLocale) },
{ href: '/about/', label: t('nav_about', curLocale) },
];
const switchHref = localePath(path, curLocale === 'zh' ? 'en' : 'zh');
const switchLabel = curLocale === 'zh' ? 'EN' : '中';
---
@@ -114,6 +115,9 @@ const switchLabel = curLocale === 'zh' ? 'EN' : '中';
.nav-link:hover { color: var(--ink-1); }
.nav-link[aria-current='page'] { color: var(--accent); }
.nav-lang { font-family: var(--font-mono); font-size: 13px; }
/* 暗色下图标钮发灰难辨(视觉复核 02/12):图标链接统一提一档并去底块感 */
.nav-link:has(svg) { color: var(--ink-2); background: transparent; }
.nav-link:has(svg):hover { color: var(--ink-1); }
@media (max-width: 560px) {
.nav-link { font-size: 14px; padding-inline: var(--space-1); }
}
+9 -1
View File
@@ -86,7 +86,7 @@ const first = cards[0];
<li
class="shot"
data-group={card.group}
style={`aspect-ratio:${card.w}/${card.h}; --s3:${card.s3}; --s2:${card.s2}`}
style={`--s3:${card.s3}; --s2:${card.s2}`}
>
<button
type="button"
@@ -279,6 +279,13 @@ const first = cards[0];
border-radius: 10px;
overflow: hidden;
}
/* 高度唯一来源=行跨度;图片封面式填满格子——消除 aspect-ratio 与
span 的双约束竞争(视觉复核发现的列洞/丢图根因面) */
.shot img {
width: 100%;
height: 100%;
object-fit: cover;
}
@media (min-width: 820px) {
.shot { grid-row-end: span var(--s3, 12); }
}
@@ -365,6 +372,7 @@ const first = cards[0];
flex-direction: column;
gap: 2px;
}
.lb-meta { text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6); }
.lb-meta strong {
color: #fff;
font-size: 13px;
+10 -1
View File
@@ -41,7 +41,7 @@ function toDateString(tsSec: number): string {
* 聚合原始贡献点为 53 周年历:起点为「今天所在周的周一」前推 52 周,
* 网格尾部未来的日子填 0(格渲染为空档),首列可能含早于窗口的 0 天。
*/
export async function loadHeatmap(): Promise<HeatmapYear> {
async function loadHeatmapInternal(): Promise<HeatmapYear> {
let raw: RawHeat[] = [];
try {
const res = await fetch(HEATMAP_API, {
@@ -81,3 +81,12 @@ export async function loadHeatmap(): Promise<HeatmapYear> {
}
return { weeks, total };
}
// 构建期模块级缓存:zh/en 两个首页各渲染一次,若各自直连远端会抓两遍;
// 缓存后第二个页面复用同一份结果(视觉复核发现 en 页数据偶发为空)
let _cache: Promise<HeatmapYear> | null = null;
export function loadHeatmap(): Promise<HeatmapYear> {
_cache ??= loadHeatmapInternal();
return _cache;
}
-2
View File
@@ -2,7 +2,6 @@
// /en/ 首页:英文 UI + 双语内容(postsEn 优先,缺则中文回退)
import { getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import AiTranslatedBadge from '../../components/AiTranslatedBadge.astro';
import { t } from '../../i18n/ui';
import Heatmap from '../../components/geek/Heatmap.astro';
import { POST_TRACKS, trackOf } from '../../content.config';
@@ -20,7 +19,6 @@ const t9 = (cat: keyof typeof POST_TRACKS) => trackOf(cat);
---
<BaseLayout title="wait4x" description="wait4x's blog: reading · code · photography" track="tech">
<AiTranslatedBadge />
<h1 class="visually-hidden">wait4x</h1>
{years.map((year) => (
<section class="year">