- 首页/归档/RSS(zh+en)集合查询统一 draft+hidden 双过滤——样张
永久保留为可访问不列出的活样例(回归测试资产)
- 写作指南视音频段更正:raw HTML 相对路径不走资产管线(实测),
媒体放 public/media/{slug}/ 用绝对 /media/ 引用,与仓外 store
同命名空间
验证: pnpm astro build exit 0(hidden 过滤后样张退出列表与 RSS)
Spec: 2026-10-25_add-media-and-polish
Co-authored-by: GLM-5.3
160 lines
5.1 KiB
Plaintext
160 lines
5.1 KiB
Plaintext
---
|
|
// /en/ 首页:与 zh 版结构逐区对齐(名片区/文章列表/最新影像/热力图/项目墙)
|
|
import { Image } from 'astro:assets';
|
|
import { getCollection } from 'astro:content';
|
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
import IdCard from '../../components/IdCard.astro';
|
|
import PostList from '../../components/PostList.astro';
|
|
import ProjectWall from '../../components/geek/ProjectWall.astro';
|
|
import Heatmap from '../../components/geek/Heatmap.astro';
|
|
import { t } from '../../i18n/ui';
|
|
|
|
const posts = (await getCollection('posts', ({ data }) => !data.draft && !data.tags.includes('hidden'))).sort(
|
|
(a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime(),
|
|
);
|
|
// 列表标题吃 postsEn 译题(缺译回退 zh,与 /en/archives 同策略)
|
|
const enTitle = Object.fromEntries(
|
|
(await getCollection('postsEn')).map((e) => [e.id, e.data.title]),
|
|
);
|
|
const photos = (await getCollection('photos')).slice(0, 4);
|
|
---
|
|
|
|
<BaseLayout title="wait4x" description="wait4x's blog: reading · code · photography">
|
|
<IdCard>
|
|
<div class="socials">
|
|
<a
|
|
class="tap social"
|
|
href="https://github.com/wait4xx"
|
|
rel="noopener noreferrer"
|
|
aria-label="GitHub"
|
|
title="GitHub"
|
|
>
|
|
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true">
|
|
<path
|
|
d="M12 2C6.48 2 2 6.58 2 12.25c0 4.53 2.87 8.37 6.84 9.73.5.1.68-.22.68-.49 0-.24-.01-.88-.01-1.73-2.78.62-3.37-1.37-3.37-1.37-.45-1.18-1.11-1.5-1.11-1.5-.91-.63.07-.62.07-.62 1 .07 1.53 1.06 1.53 1.06.89 1.57 2.34 1.12 2.91.85.09-.66.35-1.11.63-1.37-2.22-.26-4.56-1.14-4.56-5.07 0-1.12.39-2.03 1.03-2.75-.1-.26-.45-1.3.1-2.7 0 0 .84-.28 2.75 1.05a9.3 9.3 0 0 1 5 0c1.91-1.33 2.75-1.05 2.75-1.05.55 1.4.2 2.44.1 2.7.64.72 1.03 1.63 1.03 2.75 0 3.94-2.34 4.8-4.57 5.06.36.32.68.94.68 1.9 0 1.37-.01 2.47-.01 2.81 0 .27.18.6.69.49A10.26 10.26 0 0 0 22 12.25C22 6.58 17.52 2 12 2Z"
|
|
></path>
|
|
</svg>
|
|
</a>
|
|
<a class="tap social" href="/en/rss.xml" aria-label="RSS feed" title="RSS feed">
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
width="16"
|
|
height="16"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="1.8"
|
|
stroke-linecap="round"
|
|
aria-hidden="true"
|
|
>
|
|
<path d="M4 11.5a8.5 8.5 0 0 1 8.5 8.5M4 4.5a15.5 15.5 0 0 1 15.5 15.5"></path>
|
|
<circle cx="5.4" cy="18.6" r="1.5" fill="currentColor" stroke="none"></circle>
|
|
</svg>
|
|
</a>
|
|
<a class="tap social" href="mailto:admin@wait4x.online" aria-label="Email" title="Email">
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
width="16"
|
|
height="16"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="1.8"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
aria-hidden="true"
|
|
>
|
|
<rect x="3" y="5.5" width="18" height="13" rx="2.5"></rect>
|
|
<path d="m4 7.5 8 5.5 8-5.5"></path>
|
|
</svg>
|
|
</a>
|
|
</div>
|
|
</IdCard>
|
|
|
|
<PostList {posts} locale="en" titleOverrides={enTitle} />
|
|
|
|
<section class="latest" aria-label={t('latest_photos', 'en')}>
|
|
<div class="latest-head">
|
|
<span class="lab">{t('latest_photos', 'en')}</span>
|
|
<a class="tap more" href="/en/gallery/">{t('enter_gallery', 'en')}</a>
|
|
</div>
|
|
<div class="thumbs">
|
|
{photos.map((photo) => (
|
|
<a class="thumb" href="/en/gallery/" aria-label={`Gallery: ${photo.data.title}`}>
|
|
<Image
|
|
src={photo.data.image}
|
|
alt={photo.data.alt ?? photo.data.title}
|
|
widths={[180, 360]}
|
|
sizes="(min-width: 820px) 20vw, 42vw"
|
|
/>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</section>
|
|
|
|
<Heatmap
|
|
labels={{
|
|
title: t('heatmap_title', 'en'),
|
|
summary: t('heatmap_summary', 'en'),
|
|
less: t('heatmap_less', 'en'),
|
|
more: t('heatmap_more', 'en'),
|
|
note: t('heatmap_note', 'en'),
|
|
}}
|
|
/>
|
|
<ProjectWall />
|
|
</BaseLayout>
|
|
|
|
<style>
|
|
.socials {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
margin-top: var(--space-2);
|
|
}
|
|
.social {
|
|
color: var(--ink-3);
|
|
border-radius: 8px;
|
|
transition: color var(--dur) var(--ease);
|
|
}
|
|
.social:hover { color: var(--accent); }
|
|
|
|
.latest { margin-top: var(--space-6); }
|
|
.latest-head {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: var(--space-3);
|
|
}
|
|
.lab {
|
|
font-size: 12.5px;
|
|
color: var(--ink-4);
|
|
letter-spacing: 0.08em;
|
|
}
|
|
.more {
|
|
font-size: 13px;
|
|
color: var(--accent);
|
|
padding-inline: var(--space-2);
|
|
transition: color var(--dur) var(--ease);
|
|
}
|
|
.more:hover { color: var(--ink-1); }
|
|
.thumbs {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: var(--space-2);
|
|
margin-top: var(--space-3);
|
|
}
|
|
.thumb {
|
|
aspect-ratio: 1;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
.thumb :global(img) {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
transition: transform var(--dur) var(--ease);
|
|
}
|
|
.thumb:hover :global(img) { transform: scale(1.03); }
|
|
@media (min-width: 820px) {
|
|
.thumbs { grid-template-columns: repeat(4, 1fr); }
|
|
}
|
|
</style>
|