首页修改记录 03:最近更新、最近摄影和内容数据流
首页第二屏不再堆入口卡片,而是用最近更新和最近摄影承接内容。文章来自 Velite,照片来自 YAML,页面只负责展示。
首页第一屏解决的是“这是谁的网站”。第二屏要解决另一个问题:访客为什么要继续看。
我不想把第二屏做成四个大入口卡片,因为那会太像产品 landing page。最后选了两个更像个人资料馆的模块:最近更新和最近摄影。它们不是功能介绍,而是直接把最新内容露出来。
最近更新:时间线比卡片更合适
博客文章是按时间持续增长的内容,用时间线表达比卡片网格更自然。它让访客一眼看到最近写了什么,也能感觉到这个站点是活的。
数据来自 Velite:
const recentPosts = sortByDateDesc(
blogs.filter((post) => post.lang === locale && !post.draft),
).slice(0, 4);这里做了三件事:
- 只取当前语言的文章。
- 排除草稿。
- 按日期倒序取最新 4 篇。
页面不直接读文件,也不解析 MDX。Velite 在构建前把内容变成结构化数据,页面只消费结果。
时间线的小细节
时间线最容易出错的是线和圆点的对齐。早期版本里,圆点会挡住日期,虚线也不在圆心上。最后把圆点、线和日期拆成明确的 grid 列:
<Link className="grid grid-cols-[1.5rem_1fr] sm:grid-cols-[1.5rem_8rem_1fr]">
<span aria-hidden="true">{/* dot and dashed line */}</span>
<time>{formatDate(post.date, locale)}</time>
<span>{post.title}</span>
</Link>圆点所在列只负责视觉标记,日期有自己的列,标题也有自己的列。布局稳定之后,虚线才不会跟着文本长度乱跑。
最近摄影:不是裁切墙,而是照片墙
摄影模块最初像一张随机图片,后来改成最新几张照片拼在一起。这里有一个重要取舍:缩略图也尽量保留原比例,不为了整齐强行裁切。
现在用 CSS columns 做轻量照片墙:
<div className="columns-2 gap-3 sm:columns-3 lg:columns-4">
{latestPhotos.map((photo) => (
<Image
src={photo.thumbnail ?? photo.image}
width={photo.width ?? 1200}
height={photo.height ?? 1600}
className="h-auto w-full"
/>
))}
</div>h-auto w-full 保留图片比例,columns 负责自动堆叠。它不如完整 masonry 算法可控,但足够轻,也符合“最近看一眼”的用途。
为什么首页不直接处理图片
首页只读取 content/gallery/*.yaml 生成的数据,不知道 R2 上传细节:
title: "Brooklyn Botanic Garden"
image: "https://img.huzejun.com/..."
thumbnail: "https://img.huzejun.com/..."
width: 1200
height: 1600
blurDataURL: "data:image/webp;base64,..."这让页面代码很简单。图片处理、上传、生成 YAML 都在脚本里完成;页面只决定怎么展示。
小结
最近更新和最近摄影解决的是同一个问题:让首页不只是入口,而是内容的窗口。
文章从 MDX 来,照片从 YAML 来,音乐从 Last.fm 来。首页把这些来源排在同一条叙事里,但不把它们混成一团。这个边界感,是后续继续加“最近读书”或其他模块时最需要保留的东西。

