inkpaper 功能详解
inkpaper 功能详解
inkpaper 的功能不多,但每个都想清楚了再做。这篇把各个功能点拆开讲。
侧边栏配置
侧边栏是用得最多的导航元素,所以做了比较细的配置粒度。
Astro 版本通过 getSidebarItems 函数生成侧边栏数据,配置方式与 VitePress 版对齐:
inkpaper({
sidebar: {
home: { show: true, tree: 'directory' },
archive: { show: true, tree: 'date' },
tags: { show: false },
article: { show: true, tree: 'directory' },
},
})
四种页面类型,每种可以独立配置:
| 页面类型 | 默认 show | 默认 tree |
|---|---|---|
| home | true | directory |
| archive | true | date |
| tags | false | — |
| article | true | directory |
两种树类型:
- directory:按内容集合的目录结构组织,目录名作为分组标题,文件按日期倒序排列。适合文章有明确分类的场景。
- date:按年份→月份的时间线组织。适合归档浏览。
不传 sidebar 配置就是默认行为,和上面表格里写的一样。
首页组件
HomeLayout 显示四块内容:
- 标题和副标题:分别读取集成配置的
title和description。改配置就能改首页显示,不用动组件代码。 - 统计栏:文章总数、标签总数、最近更新日期。一行排开,信息密度高。
- 标签云:取出现次数最多的前 10 个标签,点击跳转到标签页并自动筛选。
- 最近文章:最新的 10 篇文章,显示标题、日期、标签。列表项有交错的 fadeInUp 动画。
归档页组件
ArchivePage 把所有文章按年份分组,年份倒序排列。每个年份标题后面带文章数量。
实现上就是拿到 posts 数据,按 date.slice(0, 4) 分组,排序,渲染。没有分页——个人博客很少有上千篇文章的情况,全量渲染反而搜索体验更好。
标签页组件
TagsPage 分两个区域:
顶部是标签云,显示所有标签和对应的文章数。点击标签切换筛选,再点一次取消。当前选中的标签用朱砂色标记。
下面是文章列表,根据选中标签实时过滤。不选标签时显示全部文章。
标签页支持 URL query 参数:访问 /tags?tag=CSS 会自动选中 CSS 标签。首页标签云的链接就是用这个机制跳转的。
交互使用 vanilla JS + data-* 属性实现,无需引入额外的前端框架。
文章侧边栏
每篇文章右侧显示三块信息:
字数统计和阅读时间:在构建时从 Markdown 源文件计算,去掉 frontmatter 和标记语法后统计字符数。阅读时间按 400 字/分钟计算,至少显示 1 min。
当前文章标签:从 frontmatter 读取,每个标签链接到标签页。
相关文章:推荐逻辑分两层。优先查找用户通过配置提供的 related 映射。如果没有,fallback 到标签交集:遍历所有文章,计算与当前文章共有标签数作为分数,取前 5 篇。
related 配置格式:
inkpaper({
related: {
'/posts/some-article': [
{ link: '/posts/another-article', title: '另一篇文章' }
]
}
})
路由自动注入
Astro 版本通过 injectRoute API 自动注入四个默认页面路由:
| 路由 | 页面 |
|---|---|
/ | 首页 |
/archive | 归档页 |
/tags | 标签页 |
/posts/[...slug] | 文章详情页 |
用户不需要手动创建任何页面文件。如果需要自定义某个页面,在 src/pages/ 下创建同名文件即可覆盖默认路由——Astro 的路由优先级机制保证用户定义的路由优先。
虚拟模块 virtual:inkpaper-config 的 TypeScript 类型声明也通过 injectTypes API 自动注入,用户不需要在 env.d.ts 里手写。
内容集合
Astro 版本使用 Content Collections 管理文章。这是目前唯一需要用户手动配置的文件——Astro 暂未提供集成级别注入 content collection 的 API。
// src/content/config.ts
import { defineCollection } from 'astro:content'
import { postSchema } from '@inkpaper/astro/content'
export const collections = {
posts: defineCollection({ type: 'content', schema: postSchema }),
}
getSortedPosts 从内容集合读取文章,提取 title、date、tags、order,按日期倒序排列。
包结构
主题分成四个 npm 包:
@inkpaper/core 是纯 CSS,定义设计变量、字体加载、宣纸纹理、通用组件样式。不依赖任何框架。
@inkpaper/vitepress 依赖 core,提供 Vue 组件、Layout、数据注入、sidebar 配置函数、内容加载器。
@inkpaper/astro 依赖 core,提供 Astro 集成(自动注入路由和类型声明)、Astro 组件、Layout、sidebar 生成、内容集合 schema。
@inkpaper/create-for-vitepress 是 VitePress 版本的脚手架工具。Astro 版本不需要脚手架——集成本身已包含所有默认页面。
两个框架版本共享 @inkpaper/core 的全部 CSS,组件层各自实现。