feat(pages): /stack 装备页 + /colophon 制作页(双语)与页脚入口

- colophon:五节灰阶数据表讲"这站怎么造的"(build/visual/写作流
  /i18n/features,变字体提速等实数入表)
- stack:homelab/自托管/站点依赖/日常四节(版本号实读
  package.json;硬件细节与 daily 清单 TODO(下轮) 待补)
- Footer 顺手修真缺陷:locale prop 机制存在但从未透传,en 全站
  页脚实为 zh 文案——改 Astro.url.pathname 构建期自推断(localeOf
  复用,显式 prop 优先),零 BaseLayout 改动
- 页脚「装备 · 制作」双入口(en 轨自动 /en/ 前缀)

车道:op-artalk(自验 15/15:双页双语桌面+390 溢出断言+Footer
双轨感知);收编验收 6 检全过

验证: pnpm astro build 34 页 exit 0;双页双语 390 视口无溢出;E2E
      31/31 PASS

Spec: none (两静态页+Footer 修复,车道级交付)

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-10-25 20:51:02 +08:00
1 parent a347ce8baf
commit aa050d8035
6 files changed
+479 -2

No files matched your search

+115
View File
@@ -0,0 +1,115 @@
---
// en/colophon: English track of /colophon — same structure, condensed copy
import BaseLayout from '../../layouts/BaseLayout.astro';
const SECTIONS = [
{
tag: 'build',
items: [
['Astro 7.3.8', 'static site generation, zero runtime framework JS; interactions are small native scripts'],
['Pagefind', 'search index built at compile time — search on a static site, no backend'],
['Shiki', 'dual-theme syntax highlighting, done at build'],
['output', '~30 pages in seconds, triggered by every push'],
],
},
{
tag: 'visual',
items: [
['grayscale × tracks', 'a grayscale skeleton for structure; body typography switches per content track'],
['four families', 'Noto Serif SC (books) · Noto Sans SC (UI/tech) · JetBrains Mono (code) · LXGW WenKai (quotes, system fallback)'],
['@fontsource', 'self-hosted, subset fonts; switching to variable fonts cut font CSS 345KB → 106KB'],
['tokens', 'colors, spacing and motion are all CSS variables — light/dark in one codebase'],
],
},
{
tag: 'writing flow',
items: [
['gitea', 'self-hosted git: my local editor and the web UI write to the same repository'],
['webhook', 'push-triggered, HMAC-verified, main branch only'],
['pipeline', 'homelab build → rsync → nginx; no cloud build minutes'],
['transparency', 'the built-from line in the footer links to the exact commit'],
],
},
{
tag: 'i18n',
items: [
['pre-translation', 'machine-translated by Tencent TMT at build; .en.md files live in the repo'],
['dual track', '/en/ pages are prebuilt — switching language is pure navigation'],
['honesty', 'machine-translated posts carry a note; corrections welcome'],
],
},
{
tag: 'features',
items: [
['comments', 'self-hosted Artalk 2.10 (sqlite) at /artalk'],
['gallery', 'EXIF extracted at build (exifr) + aspect-ratio-driven masonry via sharp, no runtime JS'],
['edge', 'ESA CDN, wildcard HTTPS; ICP filing kept in the footer as required'],
],
},
];
---
<BaseLayout title="colophon" description="How this blog is built: pipeline, typography, and the self-hosted stack">
<section class="colo">
<h1 class="colo-title">colophon <span class="dim">/ 制作</span></h1>
<p class="colo-lead">
A static blog that decides for itself wherever it can: its own build, its own hosting, its own translations, its own version history.
</p>
{SECTIONS.map((s) => (
<section class="sec">
<h2 class="sec-tag">{s.tag}</h2>
<dl class="rows">
{s.items.map(([term, desc]) => (
<div class="row">
<dt>{term}</dt>
<dd>{desc}</dd>
</div>
))}
</dl>
</section>
))}
</section>
</BaseLayout>
<style>
.colo { max-width: 720px; }
.colo-title {
font-size: 22px;
color: var(--ink-1);
margin: var(--space-5) 0 var(--space-2);
}
.dim { color: var(--ink-4); font-family: var(--font-mono); font-size: 16px; }
.colo-lead {
font-size: 14px;
color: var(--ink-3);
margin-bottom: var(--space-5);
}
.sec { margin-bottom: var(--space-5); }
.sec-tag {
font-family: var(--font-mono);
font-size: 12px;
color: var(--ink-4);
letter-spacing: 0.08em;
border-bottom: 1px solid var(--line);
padding-bottom: var(--space-1);
margin-bottom: var(--space-2);
}
.rows { margin: 0; }
.row {
display: grid;
grid-template-columns: 130px 1fr;
gap: var(--space-3);
padding-block: var(--space-2);
}
.row + .row { border-top: 1px dashed var(--line); }
dt {
font-family: var(--font-mono);
font-size: 13px;
color: var(--ink-2);
overflow-wrap: anywhere;
}
dd { margin: 0; font-size: 13px; color: var(--ink-3); line-height: 1.7; }
@media (max-width: 560px) {
.row { grid-template-columns: 1fr; gap: 2px; }
}
</style>
+117
View File
@@ -0,0 +1,117 @@
---
// en/stack: English track of /stack — same structure, condensed copy
import BaseLayout from '../../layouts/BaseLayout.astro';
const SECTIONS = [
{
tag: 'homelab',
items: [
['Debian 13', 'trixie, the host system'],
['Docker', 'Engine + Compose; every service runs containerized'],
// TODO(next round): hardware details (machine/CPU/RAM/storage) pending
],
},
{
tag: 'self-hosted',
items: [
['gitea 28.2', 'git hosting — the source of the writing & build flow (git.wait4x.online)'],
['nginx', 'static site serving and reverse proxy'],
['Artalk 2.10', 'comments, sqlite storage'],
['ddns-go', 'IPv6 dynamic DNS'],
['clash', 'outbound traffic routing'],
['new-api', 'LLM API gateway (build-time translation goes through it)'],
['crawl4ai', 'headless-browser fetching service'],
],
},
{
tag: 'site deps',
items: [
['Astro 7.3.8', 'the SSG framework'],
['sharp 0.35', 'image optimization pipeline'],
['exifr 7.1', 'EXIF extraction at build'],
['@fontsource 5.3', 'self-hosted subset fonts: Noto Sans/Serif SC, JetBrains Mono'],
['Pagefind', 'static search index'],
['Playwright 1.64', 'E2E self-checks (chromium screenshots & assertions)'],
],
},
{
tag: 'daily',
items: [
// TODO(next round): daily software list pending
],
},
];
---
<BaseLayout title="stack" description="The hardware, software and services behind this site">
<section class="stack">
<h1 class="stack-title">stack <span class="dim">/ 装备</span></h1>
<p class="stack-lead">One small machine and a handful of open source. Self-host what can be self-hosted; version what can be versioned.</p>
{SECTIONS.map((s) => (
<section class="sec">
<h2 class="sec-tag">{s.tag}</h2>
{s.items.length === 0 ? (
<p class="todo">TODO(next round): list pending</p>
) : (
<dl class="rows">
{s.items.map(([term, desc]) => (
<div class="row">
<dt>{term}</dt>
<dd>{desc}</dd>
</div>
))}
</dl>
)}
</section>
))}
</section>
</BaseLayout>
<style>
.stack { max-width: 720px; }
.stack-title {
font-size: 22px;
color: var(--ink-1);
margin: var(--space-5) 0 var(--space-2);
}
.dim { color: var(--ink-4); font-family: var(--font-mono); font-size: 16px; }
.stack-lead {
font-size: 14px;
color: var(--ink-3);
margin-bottom: var(--space-5);
}
.sec { margin-bottom: var(--space-5); }
.sec-tag {
font-family: var(--font-mono);
font-size: 12px;
color: var(--ink-4);
letter-spacing: 0.08em;
border-bottom: 1px solid var(--line);
padding-bottom: var(--space-1);
margin-bottom: var(--space-2);
}
.rows { margin: 0; }
.row {
display: grid;
grid-template-columns: 130px 1fr;
gap: var(--space-3);
padding-block: var(--space-2);
}
.row + .row { border-top: 1px dashed var(--line); }
dt {
font-family: var(--font-mono);
font-size: 13px;
color: var(--ink-2);
overflow-wrap: anywhere;
}
dd { margin: 0; font-size: 13px; color: var(--ink-3); line-height: 1.7; }
.todo {
font-family: var(--font-mono);
font-size: 12px;
color: var(--ink-4);
margin: 0;
}
@media (max-width: 560px) {
.row { grid-template-columns: 1fr; gap: 2px; }
}
</style>