Add disabled theme entry to default config and default/blog templates.
Migrate obsidian and ttrpg templates from git-based quartz-themes source
to npm @quartz-themes/core package.
Remove unconditional import of CustomOgImagesEmitterName from
.quartz/plugins in Head.tsx. This caused builds to fail when the
og-image plugin was not listed in quartz.config.yaml, violating the
plugin system's opt-in contract.
The fix inlines the emitter name string constant at the usage site.
Also convert the ContentDetails import in fileTrie.ts to
`import type` since it is only used in a type position.
The npm specifier path requires additional work in the esbuild
transpilation pipeline to mark npm imports as external. Reverting
to github: specifiers to restore the docs site immediately.
The npm loader code (parsePluginSource, config-loader, CLI) remains
in place for future use. Only the default config/templates are reverted.
- Added all 44 default plugins as dependencies so npm ci installs them
- Fixed @quartz-community/fonts → @quartz-community/quartz-fonts (actual npm name)
- Regenerated package-lock.json with plugin dependencies
Plugins can now be referenced as "@quartz-community/<name>" in
quartz.config.yaml and via 'quartz plugin add'. The npm path skips
git installation and resolves from node_modules.
Changes:
- gitLoader.ts: detect @scope/name as npm package in parsePluginSource()
- config-loader.ts: skip git install for npm packages, read manifests
from node_modules via createRequire
- install-plugins.ts: filter npm packages from prebuild, fallback to
YAML config parsing to avoid loading full quartz.ts
- plugin-data.js: npm detection in CLI parseGitSource()
- plugin-git-handlers.js: npm install path in handlePluginAdd()
- package.json: add missing hast-util-from-html dependency
The serve-mode watcher globs never matched quartz.config.yaml or
quartz.config.default.yaml, so config edits (theme colors, plugin
flags, footer links) silently required a server restart. This was a
regression from v4, where quartz.config.ts matched the **/*.ts glob.
layout.footer (and other optional layout slots) can be undefined
when disabled. Adding undefined to the seen Set caused a crash in
componentResources.ts when destructuring component properties.
- Fix popover crash on missing Content-Type header (null check)
- Fix SPA loading bar corrupting page via micromorph interference
(remove bar before morph, use ephemeral DOM elements instead of
persistent reference)
- Add stopLoading() cleanup in navigation finally block
addVirtualPageSlugAliases injected extension-stripped aliases for
every PageType-registered extension into ctx.allSlugs (e.g. for
`Canvas.canvas` it added an alias `canvas`). Intended to help
`![[file.canvas]]` transclusions resolve to virtual pages, but:
1. CrawlLinks' shortest strategy treats allSlugs entries as real
files. When an author writes `[[Canvas]]` in a note, shortest
lookup matches BOTH the alias `canvas` and real basenames
like `features/canvas`. With matchingFileNames.length === 2,
the uniqueness check fails and transformLink falls back to
absolute resolution, producing a dead href `./canvas` that
points to no emitted file.
2. The aliases were never actually needed for transclusion.
renderPage.tsx already has its own extension-stripping
fallback (lines 107-119) that consults allFiles directly.
Virtual pages (canvas-page, bases-page) emit at slugs that
KEEP their extension (e.g. `canvas.canvas`), so
`![[Canvas.canvas]]` resolves naturally without any alias.
3. The aliases mispresent Obsidian semantics. In Obsidian,
`[[Canvas]]` resolves to `Canvas.md`; non-md files require
the explicit extension (`[[Canvas.canvas]]`). Injecting
extension-stripped aliases into allSlugs made Quartz claim
bare names can refer to non-md virtual pages, which is
wrong.
Reproduction: docs/features/index.md contains `[[Canvas]]` which
should resolve to docs/features/Canvas.md (slug features/canvas).
Under the old behavior it produced href="../canvas" with
data-slug="canvas" pointing nowhere. After this fix it produces
href="../features/canvas" with data-slug="features/canvas"
correctly.
Verified with fresh `npx quartz build -d docs`:
- [[Canvas]] → ./features/canvas ✓
- ![[Canvas.canvas]] transclusion still works ✓
- ![[Base.base]] virtual page still emits ✓
- 0 internal broken links across all output ✓
- all 91 existing tests pass
The normalizeHastElement helper and its internal _rebaseHastElement
have been promoted to @quartz-community/utils so that plugins can
consume the same cross-slug HAST rebasing logic Quartz core uses
for transclude expansion. Previously they lived only in Quartz's
internal util/path module, which out-of-tree plugins (e.g.
canvas-page, whose buildEmbeddedContent embeds vfile.data.htmlAst
from arbitrary pages) could not import from.
normalizeRelativeURLs and its DOM-element sibling _rebaseHtmlElement
stay local - those operate on DOM Elements at runtime, not HAST AST
nodes, and belong with Quartz's DOM-specific code.