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:
1 parent
7a2880b65d
commit
e21fac7e1d
6 files changed
+36
-9
No files matched your search
@@ -276,6 +276,7 @@ const navItems = [
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.search-dialog {
|
.search-dialog {
|
||||||
|
margin: 12vh auto auto;
|
||||||
margin-top: 12vh;
|
margin-top: 12vh;
|
||||||
width: min(560px, calc(100vw - 32px));
|
width: min(560px, calc(100vw - 32px));
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
---
|
---
|
||||||
import { localeOf, localePath } from '../lib/locale';
|
import { localeOf, localePath } from '../lib/locale';
|
||||||
|
import { t } from '../i18n/ui';
|
||||||
|
|
||||||
// 顶部导航:≤4 项纪律(防 higan 十项复发);当前页 aria-current
|
// 顶部导航:≤4 项纪律(防 higan 十项复发);当前页 aria-current
|
||||||
const nav = [
|
|
||||||
{ href: '/archives/', label: '文章' },
|
|
||||||
{ href: '/gallery/', label: '图库' },
|
|
||||||
{ href: '/about/', label: '关于' },
|
|
||||||
];
|
|
||||||
const path = Astro.url.pathname;
|
const path = Astro.url.pathname;
|
||||||
const isCurrent = (href: string) =>
|
const isCurrent = (href: string) =>
|
||||||
path === href || path === href.replace(/\/$/, '') || path.startsWith(href);
|
path === href || path === href.replace(/\/$/, '') || path.startsWith(href);
|
||||||
|
|
||||||
// 语言切换:同路径跨前缀跳转(zh 无前缀 ↔ /en/),预构建双语毫秒级
|
// 语言切换:同路径跨前缀跳转(zh 无前缀 ↔ /en/),预构建双语毫秒级
|
||||||
const curLocale = localeOf(path);
|
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 switchHref = localePath(path, curLocale === 'zh' ? 'en' : 'zh');
|
||||||
const switchLabel = curLocale === 'zh' ? 'EN' : '中';
|
const switchLabel = curLocale === 'zh' ? 'EN' : '中';
|
||||||
---
|
---
|
||||||
@@ -114,6 +115,9 @@ const switchLabel = curLocale === 'zh' ? 'EN' : '中';
|
|||||||
.nav-link:hover { color: var(--ink-1); }
|
.nav-link:hover { color: var(--ink-1); }
|
||||||
.nav-link[aria-current='page'] { color: var(--accent); }
|
.nav-link[aria-current='page'] { color: var(--accent); }
|
||||||
.nav-lang { font-family: var(--font-mono); font-size: 13px; }
|
.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) {
|
@media (max-width: 560px) {
|
||||||
.nav-link { font-size: 14px; padding-inline: var(--space-1); }
|
.nav-link { font-size: 14px; padding-inline: var(--space-1); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ const first = cards[0];
|
|||||||
<li
|
<li
|
||||||
class="shot"
|
class="shot"
|
||||||
data-group={card.group}
|
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
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -279,6 +279,13 @@ const first = cards[0];
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
/* 高度唯一来源=行跨度;图片封面式填满格子——消除 aspect-ratio 与
|
||||||
|
span 的双约束竞争(视觉复核发现的列洞/丢图根因面) */
|
||||||
|
.shot img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
@media (min-width: 820px) {
|
@media (min-width: 820px) {
|
||||||
.shot { grid-row-end: span var(--s3, 12); }
|
.shot { grid-row-end: span var(--s3, 12); }
|
||||||
}
|
}
|
||||||
@@ -365,6 +372,7 @@ const first = cards[0];
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
}
|
}
|
||||||
|
.lb-meta { text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6); }
|
||||||
.lb-meta strong {
|
.lb-meta strong {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|||||||
+10
-1
@@ -41,7 +41,7 @@ function toDateString(tsSec: number): string {
|
|||||||
* 聚合原始贡献点为 53 周年历:起点为「今天所在周的周一」前推 52 周,
|
* 聚合原始贡献点为 53 周年历:起点为「今天所在周的周一」前推 52 周,
|
||||||
* 网格尾部未来的日子填 0(格渲染为空档),首列可能含早于窗口的 0 天。
|
* 网格尾部未来的日子填 0(格渲染为空档),首列可能含早于窗口的 0 天。
|
||||||
*/
|
*/
|
||||||
export async function loadHeatmap(): Promise<HeatmapYear> {
|
async function loadHeatmapInternal(): Promise<HeatmapYear> {
|
||||||
let raw: RawHeat[] = [];
|
let raw: RawHeat[] = [];
|
||||||
try {
|
try {
|
||||||
const res = await fetch(HEATMAP_API, {
|
const res = await fetch(HEATMAP_API, {
|
||||||
@@ -81,3 +81,12 @@ export async function loadHeatmap(): Promise<HeatmapYear> {
|
|||||||
}
|
}
|
||||||
return { weeks, total };
|
return { weeks, total };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 构建期模块级缓存:zh/en 两个首页各渲染一次,若各自直连远端会抓两遍;
|
||||||
|
// 缓存后第二个页面复用同一份结果(视觉复核发现 en 页数据偶发为空)
|
||||||
|
let _cache: Promise<HeatmapYear> | null = null;
|
||||||
|
export function loadHeatmap(): Promise<HeatmapYear> {
|
||||||
|
_cache ??= loadHeatmapInternal();
|
||||||
|
return _cache;
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
// /en/ 首页:英文 UI + 双语内容(postsEn 优先,缺则中文回退)
|
// /en/ 首页:英文 UI + 双语内容(postsEn 优先,缺则中文回退)
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||||
import AiTranslatedBadge from '../../components/AiTranslatedBadge.astro';
|
|
||||||
import { t } from '../../i18n/ui';
|
import { t } from '../../i18n/ui';
|
||||||
import Heatmap from '../../components/geek/Heatmap.astro';
|
import Heatmap from '../../components/geek/Heatmap.astro';
|
||||||
import { POST_TRACKS, trackOf } from '../../content.config';
|
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">
|
<BaseLayout title="wait4x" description="wait4x's blog: reading · code · photography" track="tech">
|
||||||
<AiTranslatedBadge />
|
|
||||||
<h1 class="visually-hidden">wait4x</h1>
|
<h1 class="visually-hidden">wait4x</h1>
|
||||||
{years.map((year) => (
|
{years.map((year) => (
|
||||||
<section class="year">
|
<section class="year">
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ await page.keyboard.press('t');
|
|||||||
const byKey = await page.getAttribute('html', 'data-theme');
|
const byKey = await page.getAttribute('html', 'data-theme');
|
||||||
ok('明暗切换·t 键', byKey !== persisted, `t 后=${byKey}`);
|
ok('明暗切换·t 键', byKey !== persisted, `t 后=${byKey}`);
|
||||||
await page.screenshot({ path: `${SHOTS}/01-home-dark.png`, fullPage: false });
|
await page.screenshot({ path: `${SHOTS}/01-home-dark.png`, fullPage: false });
|
||||||
|
await page.screenshot({ path: `${SHOTS}/01b-home-dark-confirm.png` });
|
||||||
await page.keyboard.press('t'); // 回亮色
|
await page.keyboard.press('t'); // 回亮色
|
||||||
|
|
||||||
// 2) 软导航后切换不失效(本次修复的回归项)
|
// 2) 软导航后切换不失效(本次修复的回归项)
|
||||||
@@ -93,6 +94,12 @@ ok('g-chords 导航到图库', page.url().includes('/gallery'));
|
|||||||
await page.goto(BASE + '/gallery/', { waitUntil: 'networkidle' });
|
await page.goto(BASE + '/gallery/', { waitUntil: 'networkidle' });
|
||||||
ok('图库·灯箱默认关闭', await page.locator('#lb[open]').count() === 0);
|
ok('图库·灯箱默认关闭', await page.locator('#lb[open]').count() === 0);
|
||||||
ok('图库·网格照片可见', (await page.locator('.wall .shot img:visible').count()) >= 15, `${await page.locator('.wall .shot img:visible').count()} 张`);
|
ok('图库·网格照片可见', (await page.locator('.wall .shot img:visible').count()) >= 15, `${await page.locator('.wall .shot img:visible').count()} 张`);
|
||||||
|
// fullPage 截图不必然触发视口外懒加载:先整页滚动一圈再截(视觉复核 19/21 教训)
|
||||||
|
await page.evaluate(async () => {
|
||||||
|
for (let y = 0; y <= document.body.scrollHeight; y += 400) { window.scrollTo(0, y); await new Promise(r => setTimeout(r, 60)); }
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
});
|
||||||
|
await page.waitForTimeout(600);
|
||||||
await page.screenshot({ path: `${SHOTS}/05-gallery-light.png`, fullPage: true });
|
await page.screenshot({ path: `${SHOTS}/05-gallery-light.png`, fullPage: true });
|
||||||
await page.click('.shot-btn >> nth=0');
|
await page.click('.shot-btn >> nth=0');
|
||||||
await page.waitForTimeout(300);
|
await page.waitForTimeout(300);
|
||||||
|
|||||||
Reference in new issue
Block a user