Quartz 中的 Obsidian Bases 支持:用.base文件构建交互式数据库视图
【免费下载链接】quartz🌱 a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites项目地址: https://gitcode.com/GitHub_Trending/qua/quartz
Quartz(一个将 Markdown 内容转换为完整网站的静态站点生成器)在 v5 中引入了对 Obsidian Bases 的原生支持:它能够读取 vault 中的.base文件,将其定义的查询解析为匹配的笔记集合,并以表格、列表、卡片、画廊、看板等可配置视图渲染成交互式"数据库"页面。读完本文,你将掌握在 Quartz 中启用 BasesPage 插件、理解.base文件语法(过滤器、公式、属性、视图)、自定义视图渲染器,以及处理与unlisted页面协作的全部实战技能。
Bases 是什么
Bases 是 Obsidian 桌面端 1.8.0(2025-04-15 发布)引入的功能:.base文件描述了针对 vault 中笔记的查询(filters),并把这些查询结果以可配置的视图形式呈现,例如表格(table)、列表(list)、卡片(cards)、画廊(gallery)和看板(board)。Quartz 将这种能力移植到了静态站点生成流程中,使文档站点本身也能拥有"可交互的数据库式视图"。
在 Quartz 中,Bases 支持由BasesPage插件提供,它属于"Page Type + Component"双重类别:既会针对每个.base文件生成页面,也会渲染页面中的视图 UI。从源码结构看,.base文件的渲染与.canvas文件处于同一套"虚拟页面"机制中——pageTypes/dispatcher.ts 在处理![[file.base]]这类嵌入(transclusion)时,会与.canvas一起解析跨虚拟页面的嵌入;emit.ts 也将 bases 页面与 tag 页面、folder 页面并列为由 page type 插件生成的虚拟页面。
快速启用
Bases 支持默认已随 Quartz 模板启用。在 quartz/cli/templates/default.yaml 中可以看到它被声明为默认插件:
- source: "@quartz-community/bases-page" enabled: true options: {} order: 50如果你使用的是自定义配置,按标准流程安装即可:
npx quartz plugin add github:quartz-community/bases-page该插件同样出现在blog.yaml、obsidian.yaml、ttrpg.yaml等模板中(quartz/cli/templates),并在各模板的layout.byPageType.bases中留出了页面布局配置入口(默认空配置)。
[!note] 有关插件的增删与配置方式,详见 Configuration 文档的 Plugins 章节。
内置视图与核心功能
BasesPage 插件渲染的视图具备以下能力(详见 BasesPage 插件文档):
- Table 视图:列可排序,支持字符串、数字、布尔值、数组、链接等类型的自动渲染。
- List 视图:紧凑列表,每条目附带元数据徽章(chips)。
- Cards 视图:卡片布局,可选的图片属性支持。
- Map 视图:为未来基于地图的可视化预留的占位视图。
- 多视图:单个
.base文件可以定义多个视图,以可切换的标签页展示。 - 过滤器(Filters):支持
and/or/not操作符的递归过滤器树。 - 公式(Formulas):通过表达式计算派生属性。
- 汇总(Summaries):列级聚合,如 Sum、Average、Min、Max、Median 等。
- 属性配置:为属性自定义显示名称。
- 链接渲染:单元格内的 wikilinks 与 Markdown 链接渲染为可点击链接。
一个真实的.base文件:仓库演示
Quartz 文档站自身的 docs/Base.base 就是一个完整的示例,它同时演示了过滤器、公式、属性显示名与多种视图的写法:
filters: and: - file.ext == "md" formulas: doc_type: | if(file.hasTag("plugin/transformer"), "transformer", if(file.hasTag("plugin/emitter"), "emitter", if(file.hasTag("plugin/filter"), "filter", if(file.hasTag("component"), "component", if(file.inFolder("features"), "feature", if(file.inFolder("advanced"), "advanced", if(file.inFolder("plugins"), "plugin", if(file.inFolder("getting-started"), "getting-started", if(file.inFolder("cli"), "cli", "guide"))))))))) last_modified: file.mtime.relative() section: | if(file.inFolder("plugins"), "plugins", if(file.inFolder("features"), "features", if(file.inFolder("advanced"), "advanced", if(file.inFolder("getting-started"), "getting-started", if(file.inFolder("cli"), "cli", if(file.inFolder("tags"), "tags", "core")))))) properties: title: displayName: Title formula.doc_type: displayName: Type formula.last_modified: displayName: Updated formula.section: displayName: Section views: - type: table name: All Documentation groupBy: property: formula.section direction: ASC order: - file.name - title - formula.doc_type - formula.section - formula.last_modified sort: - property: formula.doc_type direction: ASC - property: file.name direction: ASC columnSize: file.name: 185 note.title: 268 formula.doc_type: 146 formula.section: 276 - type: table name: Plugins filters: or: - file.hasTag("plugin/transformer") - file.hasTag("plugin/emitter") - file.hasTag("plugin/filter") groupBy: property: formula.doc_type direction: ASC order: - file.name - title - formula.doc_type - formula.last_modified - type: list name: Recently Updated order: - file.name - formula.last_modified limit: 15 - type: board name: By Type (Board) groupBy: property: formula.doc_type direction: ASC order: - file.name - title - formula.last_modified - type: gallery name: Gallery order: - title - formula.doc_type - formula.section limit: 30 - type: cards name: Cards order: - file.name - title - formula.doc_type - formula.section - formula.last_modified limit: 24 - type: cards name: Image Cards filters: and: - file.folder == "plugins" - "!image.isEmpty()" order: - file.name image: note.image cardSize: 220 imageAspectRatio: 1这个示例覆盖了.base语法的核心要素,值得逐段拆解:
filters:查询哪些笔记
顶层filters用and/or/not组合表达式。示例中file.ext == "md"只纳入 Markdown 文件;"Plugins" 视图则用or组合三个 tag 判断;"Image Cards" 视图通过"!image.isEmpty()"(字符串形式的取反表达式)只显示有图片的插件页。
formulas:计算派生属性
公式表达式以内联字符串或多行字符串(|块)形式出现。示例演示了三类典型用法:
- 基于 tag 与目录的多重嵌套
if,把页面归类为 transformer / emitter / filter / component / feature / plugin / guide 等类型; file.mtime.relative()计算相对修改时间;- 目录判断函数
file.inFolder(...)用于划分区块。
properties:显示名定制
properties节点为属性指定displayName。注意formula.doc_type这种键名——公式计算结果被当作属性参与展示与排序,这正是公式系统的核心用法。
views:一文件多视图
单个.base文件可声明多个views,每个视图有自己的type、name、filters、groupBy、order(列顺序)、sort(排序规则)、limit、columnSize、image、cardSize等配置。示例文件同时声明了 table、list、board、gallery、cards 五种类型共 8 个视图,最终在页面上以可切换标签页呈现。
配置选项
BasesPage 接受以下配置项(完整列表见 BasesPage 插件文档):
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
defaultViewType | string | "table" | .base文件未指定视图类型时的默认视图。 |
linkResolution | string | "shortest" | 视图渲染器中内部链接的解析方式,取值"absolute"/"relative"/"shortest",应与 CrawlLinks 插件 的markdownLinkResolution保持一致。 |
customViews | object | {} | 自定义视图渲染器映射,键为视图类型名,可覆盖内置渲染器或注册新类型,需要 TS override。 |
默认配置(零参数启用):
- source: github:quartz-community/bases-page enabled: true自定义视图渲染器(TS override)
自定义视图需要在quartz.ts中通过 TS override 实现。插件注册(包括 Bases 视图注册这类副作用)必须在loadQuartzConfig()之前完成——这与 config-loader.ts 中"部分插件依赖副作用进行注册"的加载机制相印证:
import * as ExternalPlugin from "./.quartz/plugins" // Must be placed before loadQuartzConfig() ExternalPlugin.BasesPage({ defaultViewType: "table", customViews: { myView: ({ entries, view, basesData, total, locale }) => { // return JSX }, }, })自定义视图渲染器收到entries(查询结果条目)、view(视图配置)、basesData(基础数据)、total(条目总数)、locale(国际化信息)等参数,返回 JSX 即可。
与unlisted页面的协作
BasesPage 遵循由 UnlistedPages 插件 与 EncryptedPages 插件 写入的file.data.unlisted约定:
- 被标记为
unlisted: true的页面(以及stealth: true的加密页面)会从所有base 视图(table、list、board、cards、gallery 及任何自定义视图)中排除,无论 base 的过滤表达式是否匹配它们; - unlisted 页面也无法通过可见页面公式中的
.asFile()被解引用。
构建时渲染的固有限制
Base 视图是在构建期服务端渲染(server-side rendered)的 HTML,不会在访问者解密加密页面后在客户端更新。与之对比,Graph、explorer、search 会从打了补丁的内存内容索引重新水合(re-hydrate),从而在整个浏览器会话中显示新解锁的页面;而 base 视图不会,因为它们是在构建时物化(materialized)的,unlisted 页面早已被排除。访问者成功解密一个可揭示(revealable)的加密页面后,该页面会出现在 graph、explorer 和 search 中,但在站点重新构建并将该页面列入之前,不会出现在任何 base 视图中。这与 backlinks、recent notes、folder listings、tag listings 面临的是同一种结构性限制。
渲染管线中的位置
从源码角度可以看到 Bases 参与渲染管线的几个关键节点:
- renderPage.tsx:
renderPage在渲染 transclusion 后执行"插件提供的树变换(tree transforms)",注释明确提到其用途之一是"解析内联的 bases codeblocks"; - pageTypes/dispatcher.ts:
.base文件与.canvas文件一样,作为虚拟页面参与![[file.base]]式嵌入的解析; - config-loader.ts:插件加载器在合并配置时会执行具有副作用的插件注册(Bases 视图注册即为此类);
- emit.ts:bases 页面与 tag 页面、folder 页面一样,属于 page type 插件生成的虚拟页面,走统一发射流程。
这套机制保证了.base文件既能作为独立页面被生成,也能被嵌入到其他笔记(如本文所在的 Features 文档中通过![[Base.base]]内嵌演示),并遵守与其他页面类型一致的构建与布局约定。
小结
Quartz 的 Bases 支持将 Obsidian 的数据库式视图能力带入了静态站点:filters定义查询、formulas计算派生字段、properties定制显示名、views声明多类型多标签的展示层,而 BasesPage 插件在构建期把这些声明渲染为可排序、可分组、带汇总的服务端 HTML。配合defaultViewType、linkResolution与customViews三个配置项,你可以完全控制视图的默认形态、内部链接解析方式与自定义渲染逻辑;同时,unlisted约定与构建时渲染特性决定了它在隐私页面场景下的行为边界。上述演示文件 docs/Base.base 可直接作为编写自己.base文件的语法参考。
【免费下载链接】quartz🌱 a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites项目地址: https://gitcode.com/GitHub_Trending/qua/quartz
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考