feat(layout): 基础布局/导航/页脚/明暗不闪烁
- BaseLayout:字体三轨统持、viewport-fit=cover、theme-color 双套、skip-link - Header:≤4 项导航纪律 + sticky 毛玻璃 + aria-current;搜索 icon 占位待 T8 - Footer:ICP 备案链接(法定保留)+ built-from 具名槽位待 T7 - ThemeScript:head 内联先于首帧,手选 > 系统偏好,防白闪 验证: pnpm astro build exit 0;dist/index.html 含 ICP 文案与跳到正文链 Spec: 2026-10-24_add-blog-skeleton Co-authored-by: GLM-5.3
This commit is contained in:
1 parent
ee53279822
commit
b50eddf2bb
5 files changed
+185
-13
No files matched your search
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
// 页脚:版权 + ICP 备案(法定保留)+ 构建透明槽位(T7 built-from 填充)
|
||||||
|
---
|
||||||
|
|
||||||
|
<footer class="site-footer safe-area">
|
||||||
|
<div class="container">
|
||||||
|
<p class="fine">
|
||||||
|
© {new Date().getFullYear()} wait4x ·
|
||||||
|
<a href="https://beian.miit.gov.cn/" rel="noopener noreferrer" target="_blank" class="link">
|
||||||
|
陕ICP备2026014860号-1
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<!-- T7 注入:built from {commit} · {time} · Astro(链到 gitea commit) -->
|
||||||
|
<slot name="build-info" />
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.site-footer {
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
margin-top: var(--space-6);
|
||||||
|
padding-block: var(--space-4);
|
||||||
|
}
|
||||||
|
.fine {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--ink-3);
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--space-2);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
:global(.build-info) {
|
||||||
|
margin-top: var(--space-1);
|
||||||
|
text-align: center;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--ink-4);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
// 顶部导航:≤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);
|
||||||
|
---
|
||||||
|
|
||||||
|
<header class="site-header safe-area">
|
||||||
|
<div class="container-wide header-inner">
|
||||||
|
<a href="/" class="brand" aria-label="wait4x 首页">wait4x</a>
|
||||||
|
<nav aria-label="主导航">
|
||||||
|
<ul>
|
||||||
|
{nav.map((item) => (
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href={item.href}
|
||||||
|
class="tap nav-link"
|
||||||
|
aria-current={isCurrent(item.href) ? 'page' : undefined}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
<!-- 搜索入口:T8 Pagefind 面板接管,先留可聚焦占位 -->
|
||||||
|
<li>
|
||||||
|
<button class="tap nav-link" type="button" data-search-trigger aria-label="搜索">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||||
|
<circle cx="11" cy="11" r="7"></circle>
|
||||||
|
<path d="m20 20-3.5-3.5"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.site-header {
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background: color-mix(in oklab, var(--bg) 88%, transparent);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.header-inner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 56px;
|
||||||
|
}
|
||||||
|
.brand {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 18px;
|
||||||
|
color: var(--ink-1);
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
nav ul {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-2);
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.nav-link {
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--ink-3);
|
||||||
|
padding-inline: var(--space-2);
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: color var(--dur) var(--ease);
|
||||||
|
}
|
||||||
|
.nav-link:hover { color: var(--ink-1); }
|
||||||
|
.nav-link[aria-current='page'] { color: var(--accent); }
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.nav-link { font-size: 14px; padding-inline: var(--space-1); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
// 明暗不闪烁脚本:<head> 内联、先于首帧。
|
||||||
|
// 优先级:用户手选(localStorage) > 系统偏好;切换按钮(T7 键盘/组件)写同一 key。
|
||||||
|
---
|
||||||
|
|
||||||
|
<script is:inline>
|
||||||
|
(function () {
|
||||||
|
var saved = localStorage.getItem('theme');
|
||||||
|
var theme = saved === 'light' || saved === 'dark'
|
||||||
|
? saved
|
||||||
|
: (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||||
|
document.documentElement.dataset.theme = theme;
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
// 基础布局:字体/样式统一在此持有(页面不再各自引包)
|
||||||
|
// 明暗不闪烁:ThemeScript 必须在 <head> 内联先于首帧执行
|
||||||
|
import 'lxgw-wenkai-screen-webfont/lxgwwenkaiscreen.css';
|
||||||
|
import '@fontsource/noto-sans-sc/400.css';
|
||||||
|
import '@fontsource/noto-sans-sc/500.css';
|
||||||
|
import '@fontsource/noto-sans-sc/700.css';
|
||||||
|
import '@fontsource/jetbrains-mono/400.css';
|
||||||
|
import '@fontsource/jetbrains-mono/700.css';
|
||||||
|
import '../styles/global.css';
|
||||||
|
import Header from '../components/Header.astro';
|
||||||
|
import Footer from '../components/Footer.astro';
|
||||||
|
import ThemeScript from '../components/ThemeScript.astro';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
/** 正文轨:reading 书评纸墨 / tech 技术(body 级字体氛围) */
|
||||||
|
track?: 'reading' | 'tech';
|
||||||
|
}
|
||||||
|
const { title, description = 'wait4x 的博客:阅读 · 技术 · 摄影', track = 'tech' } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="zh" data-track={track}>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||||
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
<meta name="description" content={description} />
|
||||||
|
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
|
||||||
|
<meta name="theme-color" content="#191d23" media="(prefers-color-scheme: dark)" />
|
||||||
|
<title>{title}</title>
|
||||||
|
<ThemeScript />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a class="skip-link" href="#main">跳到正文</a>
|
||||||
|
<Header />
|
||||||
|
<main id="main" class="container">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+4
-13
@@ -1,15 +1,6 @@
|
|||||||
---
|
---
|
||||||
// T1 占位首页:T5 起替换为 BaseLayout + 真实首页结构
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||||
// 字体三轨在此预挂(T5 移入 BaseLayout):unicode-range 预分片自托管
|
|
||||||
import 'lxgw-wenkai-screen-webfont/lxgwwenkaiscreen.css';
|
|
||||||
import '@fontsource/noto-sans-sc/400.css';
|
|
||||||
import '@fontsource/noto-sans-sc/500.css';
|
|
||||||
import '@fontsource/noto-sans-sc/700.css';
|
|
||||||
import '@fontsource/jetbrains-mono/400.css';
|
|
||||||
import '@fontsource/jetbrains-mono/700.css';
|
|
||||||
import '../styles/global.css';
|
|
||||||
---
|
---
|
||||||
<html lang="zh">
|
<BaseLayout title="wait4x">
|
||||||
<head><meta charset="utf-8" /><title>wait4x</title></head>
|
<p>Phase 1 · T5 布局就绪,首页结构 T6 填充。</p>
|
||||||
<body>Phase 1 skeleton</body>
|
</BaseLayout>
|
||||||
</html>
|
|
||||||
Reference in new issue
Block a user