首页
/ Level-two heading

Level-two heading

2026-09-04 13:02:23作者:丁柯新Fawn

Level-two heading


正文从 `##` 开始(不写 `#`),因为页面级 `<h1>` 已由 Hero 组件根据 `title` 字段生成,正文标题从 h2 起步可以避免语义上的一级标题重复。

### 3.2 引用块(Blockquote)

```markdown
> Tell me and I forget. Teach me and I remember. Involve me and I learn.

详情页的 scoped 样式 中,blockquote 被定制为品牌化呈现:更大的字号(--text-lg)、品牌字体 --font-brand、600 字重、左侧 0.25rem 的强调色竖线 border-inline-start,在 ≥50em 的宽屏下进一步放大到 --text-2xl。这是 Astro 组件内 <style> 标签 + :global() 选择器作用于 Markdown 生成 HTML 的典型例子。

3.3 正文段落与内联 HTML 链接

正文段落中直接混入了一个内联 HTML 锚点:

Lorem ipsum dolor sit amet, <a href="…">Astro</a> makes people happy. …

这演示了 Markdown 允许内嵌原始 HTML 的能力。Astro 的 Markdown 管线会把该锚点原样保留进输出 HTML,因此它会自动继承详情页中 .content :global(a) 的样式——半透明下划线 text-decoration: 1px solid underline transparent,hover/focus 时 text-decoration-color 过渡为 currentColor

3.4 三级与四级标题

### Level-three heading
(两个三级标题,分别引导两段不同长度的 Lorem ipsum 正文)

#### Level-four heading

详情页样式对 h1h5 统一设置了 margin: 1.5rem 0,并对内容区做了 max-width: 65ch 的正文宽度约束(.content { max-width: 65ch; margin-inline: auto; }),保证长段落的可读性。

3.5 无序列表

文件以两个列表项收尾:

- We noted this
- And also this other point

这对应本案例“介绍 Markdown 格式”的定位——像侦探游戏一样引导读者识别各个语法元素。

此外还有一个值得注意的整体排版细节:详情页样式里 .content > :global(* + *) { margin-top: 1rem; } 为正文中相邻兄弟元素统一了 1rem 的垂直间距,因此正文中各元素无需手动空行调距,层级结构完全交给 CSS。

4. 集合加载:glob 加载器如何“捡到”这个文件

content.config.ts 定义了 work 集合的加载方式:

import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';

export const collections = {
	work: defineCollection({
		// Load Markdown files in the src/content/work directory.
		loader: glob({ base: './src/content/work', pattern: '**/*.md' }),
		schema: z.object({
			title: z.string(),
			description: z.string(),
			publishDate: z.coerce.date(),
			tags: z.array(z.string()),
			img: z.string(),
			img_alt: z.string().optional(),
		}),
	}),
};

三个关键点,都能从 markdown-mystery-tour.md 的实际情况得到印证:

  1. base: './src/content/work':以该目录为基准扫描,markdown-mystery-tour.md 的直接文件名即其 idmarkdown-mystery-tour);
  2. pattern: '**/*.md':递归匹配所有子目录。这解释了为什么 nested/duvet-genius.md 也能被加载——从 glob 模式推断,子目录中的文件会以带目录的 id(如 nested/duvet-genius)进入集合;
  3. Zod Schema 校验:第 2 节表格中的六个字段在构建时逐一校验,publishDatez.coerce.date() 转为真正的 Date,供后续排序使用。

5. 路由与渲染:从 Markdown 文件到详情页

work/[...slug].astro 是该文件的最终消费者,核心逻辑只有三步:

export async function getStaticPaths() {
	const work = await getCollection('work');
	return work.map((entry) => ({
		params: { slug: entry.id },
		props: { entry },
	}));
}

const { entry } = Astro.props;
const { Content } = await render(entry);
  • getStaticPaths:遍历 work 集合,每个条目的 id 直接作为 [...slug] 参数。由于是 rest 路由([...slug]),嵌套 id(如 nested/duvet-genius)可以推断地映射为 /work/nested/duvet-genius 这样的多级路径;
  • render(entry):把该 Markdown 条目编译为可渲染的 Content 组件,正文 HTML 在模板中以 <Content /> 注入 .content 容器内,外层套 .stack gap-10 布局;
  • Frontmatter 字段的消费点entry.data.title 传给 HeroBaseLayouttitle/descriptionentry.data.tags 渲染为 Pill 标签组;entry.data.description 渲染为说明段落;entry.data.imgimg_alt 渲染为头图 <img>,并带圆角、阴影与渐变背景(.content :global(img) 样式)。

也就是说,markdown-mystery-tour.md 一个文件同时提供了“页面元数据(Frontmatter)+ 页面主体(正文 Markdown)”,而页面外壳(导航、布局、CTA)全部由 Astro 组件承担——这正是内容驱动站点的标准分工。

6. 列表页如何消费同一份数据

work.astro 展示同一集合的另一面用法:

const projects = (await getCollection('work')).sort(
	(a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf(),
);
登录后查看全文
热门项目推荐
相关项目推荐