Compare commits

..

2 Commits
v5.0.0 ... v4

Author SHA1 Message Date
wasita
59b5807601
🐛 fix(cli): use 'gray' instead of 'grey' in styleText calls (#2321)
Some checks failed
Build and Test / build-and-test (ubuntu-latest) (push) Has been skipped
Build and Test / publish-tag (push) Has been skipped
Docker build & push image / build (push) Has been skipped
Build and Test / build-and-test (macos-latest) (push) Has been cancelled
Build and Test / build-and-test (windows-latest) (push) Has been cancelled
Node.js util.styleText does not accept 'grey' as a format name.
While util.inspect.colors defines 'grey' as a non-enumerable alias
for 'gray', styleText validates against Object.keys(inspect.colors)
which only includes enumerable properties — so 'grey' has never
been a valid styleText format and throws ERR_INVALID_ARG_VALUE.
2026-03-04 16:42:49 +01:00
Andrew G. Dunn
9576701d85
fix: await micromorph() to prevent race condition with nav event handlers (#2323)
Some checks failed
Build and Test / build-and-test (ubuntu-latest) (push) Has been skipped
Build and Test / publish-tag (push) Has been skipped
Docker build & push image / build (push) Has been skipped
Build and Test / build-and-test (macos-latest) (push) Has been cancelled
Build and Test / build-and-test (windows-latest) (push) Has been cancelled
micromorph() returns Promise<void> because its internal patch() function
is async and uses Promise.all for recursive child patching. Without
await, the DOM morph may still be in progress when the nav event fires
and downstream handlers attempt to rebuild dynamic content.

Fixes #2322
2026-03-02 08:31:53 -08:00
256 changed files with 11165 additions and 14744 deletions

View File

@ -28,19 +28,8 @@ jobs:
restore-keys: | restore-keys: |
${{ runner.os }}-node- ${{ runner.os }}-node-
- name: Cache Quartz plugins
uses: actions/cache@v5
with:
path: .quartz/plugins
key: ${{ runner.os }}-plugins-${{ hashFiles('quartz.lock.json') }}
restore-keys: |
${{ runner.os }}-plugins-
- run: npm ci - run: npm ci
- name: Install Quartz plugins
run: npx quartz plugin install
- name: Check types and style - name: Check types and style
run: npm run check run: npm run check

View File

@ -3,10 +3,10 @@ name: Build and Test
on: on:
pull_request: pull_request:
branches: branches:
- v5 - v4
push: push:
branches: branches:
- v5 - v4
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@ -26,7 +26,7 @@ jobs:
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: 24 node-version: 22
- name: Cache dependencies - name: Cache dependencies
uses: actions/cache@v5 uses: actions/cache@v5
@ -36,19 +36,8 @@ jobs:
restore-keys: | restore-keys: |
${{ runner.os }}-node- ${{ runner.os }}-node-
- name: Cache Quartz plugins
uses: actions/cache@v5
with:
path: .quartz/plugins
key: ${{ runner.os }}-plugins-${{ hashFiles('quartz.lock.json') }}
restore-keys: |
${{ runner.os }}-plugins-
- run: npm ci - run: npm ci
- name: Install Quartz plugins
run: npx quartz plugin install
- name: Check types and style - name: Check types and style
run: npm run check run: npm run check
@ -59,7 +48,7 @@ jobs:
run: npx quartz build --bundleInfo -d docs run: npx quartz build --bundleInfo -d docs
publish-tag: publish-tag:
if: ${{ github.repository == 'jackyzha0/quartz' && github.ref == 'refs/heads/v5' }} if: ${{ github.repository == 'jackyzha0/quartz' && github.ref == 'refs/heads/v4' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write
@ -70,7 +59,7 @@ jobs:
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: 24 node-version: 22
- name: Get package version - name: Get package version
run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV
- name: Create release tag - name: Create release tag

View File

@ -1,53 +0,0 @@
name: Deploy v5 Preview
on:
push:
branches:
- v5
workflow_dispatch:
permissions:
contents: read
deployments: write
jobs:
deploy-v5:
if: ${{ github.repository == 'jackyzha0/quartz' }}
runs-on: ubuntu-latest
name: Deploy v5 to Cloudflare Pages
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 22
- name: Cache dependencies
uses: actions/cache@v5
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- name: Check types and style
run: npm run check
- name: Build Quartz
run: npx quartz build -d docs -v
- name: Deploy to Cloudflare Pages
uses: AdrianGonz97/refined-cf-pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
githubToken: ${{ secrets.GITHUB_TOKEN }}
projectName: quartz
deploymentName: v5 Branch Preview
branch: v5
directory: public

View File

@ -2,10 +2,10 @@ name: Docker build & push image
on: on:
push: push:
branches: [v5] branches: [v4]
tags: ["v*"] tags: ["v*"]
pull_request: pull_request:
branches: [v5] branches: [v4]
paths: paths:
- .github/workflows/docker-build-push.yaml - .github/workflows/docker-build-push.yaml
- quartz/** - quartz/**

2
.gitignore vendored
View File

@ -9,5 +9,3 @@ tsconfig.tsbuildinfo
private/ private/
.replit .replit
replit.nix replit.nix
.quartz/
quartz/cli/tui/dist/

View File

@ -3,19 +3,5 @@
"quoteProps": "as-needed", "quoteProps": "as-needed",
"trailingComma": "all", "trailingComma": "all",
"tabWidth": 2, "tabWidth": 2,
"semi": false, "semi": false
"overrides": [
{
"files": "*.canvas",
"options": {
"parser": "json"
}
},
{
"files": "*.base",
"options": {
"parser": "yaml"
}
}
]
} }

View File

@ -2,9 +2,7 @@ FROM node:22-slim AS builder
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY package.json . COPY package.json .
COPY package-lock.json* . COPY package-lock.json* .
COPY quartz/ ./quartz/ RUN npm ci
COPY quartz.lock.json .
RUN npm ci; npx quartz plugin install
FROM node:22-slim FROM node:22-slim
WORKDIR /usr/src/app WORKDIR /usr/src/app

View File

@ -1,4 +1,4 @@
# Quartz v5 # Quartz v4
> “[One] who works with the door open gets all kinds of interruptions, but [they] also occasionally gets clues as to what the world is and what might be important.” — Richard Hamming > “[One] who works with the door open gets all kinds of interruptions, but [they] also occasionally gets clues as to what the world is and what might be important.” — Richard Hamming

View File

@ -1,124 +0,0 @@
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: table
name: Components & Features
filters:
or:
- file.hasTag("component")
- file.inFolder("features")
order:
- file.name
- title
- formula.doc_type
- formula.last_modified
- type: list
name: Recently Updated
order:
- file.name
- formula.last_modified
limit: 15
- type: table
name: Core Guides
filters:
not:
- file.inFolder("plugins")
- file.inFolder("features")
- file.inFolder("advanced")
- file.inFolder("getting-started")
- file.inFolder("cli")
- file.inFolder("tags")
order:
- file.name
- title
- formula.last_modified
- 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

View File

@ -1,321 +0,0 @@
{
"nodes": [
{
"id": "group-node-types",
"type": "group",
"x": -30,
"y": 260,
"width": 1220,
"height": 460,
"color": "6",
"label": "Node Types"
},
{
"id": "group-config",
"type": "group",
"x": -30,
"y": 1180,
"width": 1220,
"height": 360,
"color": "2",
"label": "Configuration"
},
{
"id": "group-colors",
"type": "group",
"x": -30,
"y": 790,
"width": 1220,
"height": 320,
"color": "4",
"label": "Preset Colors"
},
{
"id": "group-edges",
"type": "group",
"x": -30,
"y": 1610,
"width": 1220,
"height": 320,
"color": "3",
"label": "Edges & Connections"
},
{
"id": "title",
"type": "text",
"text": "# CanvasPage Plugin\n\nThis plugin renders [JSON Canvas](https://jsoncanvas.org) (`.canvas`) files as interactive, pannable and zoomable canvas pages. It supports the full [JSON Canvas 1.0 spec](https://jsoncanvas.org/spec/1.0/).\n\nInstall: `npx quartz plugin add github:quartz-community/canvas-page`",
"x": 0,
"y": 0,
"width": 560,
"height": 200,
"color": "5"
},
{
"id": "text-node-demo",
"type": "text",
"text": "## Text Nodes\n\nText nodes render **Markdown** content with GFM support:\n\n- **Bold** and *italic* text\n- ~~Strikethrough~~ text\n- [External links](https://jsoncanvas.org)\n- `Inline code` blocks\n- Lists (like this one)\n\n### Headings Work Too\n\nAll standard Markdown syntax is rendered at build time.",
"x": 0,
"y": 300,
"width": 360,
"height": 280,
"color": "1"
},
{
"id": "file-node-info",
"type": "text",
"text": "## File Nodes\n\nFile nodes reference other pages in your vault. They appear as clickable links and support **popover previews** on hover.\n\nThe node below links to the CanvasPage documentation:",
"x": 400,
"y": 300,
"width": 360,
"height": 160,
"color": "2"
},
{
"id": "file-node-demo",
"type": "file",
"file": "plugins/CanvasPage.md",
"x": 400,
"y": 500,
"width": 360,
"height": 80,
"color": "4"
},
{
"id": "link-node-info",
"type": "text",
"text": "## Link Nodes\n\nLink nodes reference external URLs. The node below links to the JSON Canvas specification:",
"x": 800,
"y": 300,
"width": 360,
"height": 120,
"color": "3"
},
{
"id": "link-node-demo",
"type": "link",
"url": "https://jsoncanvas.org/spec/1.0/",
"x": 800,
"y": 460,
"width": 360,
"height": 80,
"color": "5"
},
{
"id": "color-1",
"type": "text",
"text": "**Color 1** — Red",
"x": 0,
"y": 830,
"width": 180,
"height": 80,
"color": "1"
},
{
"id": "color-2",
"type": "text",
"text": "**Color 2** — Orange",
"x": 200,
"y": 830,
"width": 180,
"height": 80,
"color": "2"
},
{
"id": "color-3",
"type": "text",
"text": "**Color 3** — Yellow",
"x": 400,
"y": 830,
"width": 180,
"height": 80,
"color": "3"
},
{
"id": "color-4",
"type": "text",
"text": "**Color 4** — Green",
"x": 600,
"y": 830,
"width": 180,
"height": 80,
"color": "4"
},
{
"id": "color-5",
"type": "text",
"text": "**Color 5** — Cyan",
"x": 800,
"y": 830,
"width": 180,
"height": 80,
"color": "5"
},
{
"id": "color-6",
"type": "text",
"text": "**Color 6** — Purple",
"x": 1000,
"y": 830,
"width": 180,
"height": 80,
"color": "6"
},
{
"id": "color-custom",
"type": "text",
"text": "**Custom hex color** — `#ff6600`",
"x": 400,
"y": 950,
"width": 380,
"height": 80,
"color": "#ff6600"
},
{
"id": "config-options",
"type": "text",
"text": "## Configuration Options\n\n- `enableInteraction` — Enable pan and zoom. Default: `true`\n- `initialZoom` — Initial zoom level. Default: `1`\n- `minZoom` — Minimum zoom level. Default: `0.1`\n- `maxZoom` — Maximum zoom level. Default: `5`\n- `defaultFullscreen` — Start in fullscreen mode. Default: `false`\n\nConfigure in `quartz.config.yaml`:\n\n```\nCanvasPage({ defaultFullscreen: false, initialZoom: 1 })\n```",
"x": 0,
"y": 1220,
"width": 560,
"height": 280
},
{
"id": "config-fullscreen",
"type": "text",
"text": "## Fullscreen Mode\n\nClick the **expand button** (top-right corner) to toggle fullscreen mode. The canvas fills the entire viewport.\n\n- Press **Escape** to exit fullscreen\n- Set `defaultFullscreen: true` to start in fullscreen\n- The toggle button switches between expand and collapse icons\n\n## Quartz Integration\n\n- **Popover previews**: Hover over file nodes to see a preview\n- **Internal links**: File nodes link to pages in your vault\n- **Dark mode**: Canvas adapts to your theme settings",
"x": 600,
"y": 1220,
"width": 560,
"height": 280
},
{
"id": "edge-source",
"type": "text",
"text": "## Edges\n\nEdges connect nodes with SVG paths. They support **labels**, **arrows**, and **colors**.",
"x": 0,
"y": 1650,
"width": 300,
"height": 120,
"color": "1"
},
{
"id": "edge-labeled",
"type": "text",
"text": "This edge has a **label** and an arrow marker.",
"x": 450,
"y": 1650,
"width": 260,
"height": 80,
"color": "4"
},
{
"id": "edge-colored",
"type": "text",
"text": "This edge has a **custom color** (`#ff6600`).",
"x": 450,
"y": 1780,
"width": 260,
"height": 80,
"color": "2"
},
{
"id": "edge-preset",
"type": "text",
"text": "Edges can use the same **preset colors** (16) as nodes, or custom **hex colors** like `#ff6600`.",
"x": 850,
"y": 1650,
"width": 300,
"height": 120,
"color": "6"
},
{
"id": "api-info",
"type": "text",
"text": "## API\n\n- **Category**: Page Type\n- **Function name**: `ExternalPlugin.CanvasPage()`\n- **Source**: [quartz-community/canvas-page](https://github.com/quartz-community/canvas-page)\n- **Install**: `npx quartz plugin add github:quartz-community/canvas-page`",
"x": 0,
"y": 2000,
"width": 560,
"height": 180
},
{
"id": "spec-info",
"type": "text",
"text": "## JSON Canvas Spec\n\nThis plugin implements the [JSON Canvas 1.0](https://jsoncanvas.org/spec/1.0/) specification — an open file format for infinite canvas data.\n\nCanvas files use the `.canvas` extension and are standard JSON. They are natively supported by [Obsidian](https://obsidian.md).",
"x": 600,
"y": 2000,
"width": 560,
"height": 180
}
],
"edges": [
{
"id": "edge-title-to-types",
"fromNode": "title",
"fromSide": "bottom",
"toNode": "group-node-types",
"toSide": "top",
"label": "supports"
},
{
"id": "edge-info-to-file",
"fromNode": "file-node-info",
"fromSide": "bottom",
"toNode": "file-node-demo",
"toSide": "top",
"color": "4"
},
{
"id": "edge-info-to-link",
"fromNode": "link-node-info",
"fromSide": "bottom",
"toNode": "link-node-demo",
"toSide": "top",
"color": "5"
},
{
"id": "edge-types-to-colors",
"fromNode": "group-node-types",
"fromSide": "bottom",
"toNode": "group-colors",
"toSide": "top"
},
{
"id": "edge-colors-to-config",
"fromNode": "group-colors",
"fromSide": "bottom",
"toNode": "group-config",
"toSide": "top"
},
{
"id": "edge-config-to-edges",
"fromNode": "group-config",
"fromSide": "bottom",
"toNode": "group-edges",
"toSide": "top"
},
{
"id": "edge-labeled-demo",
"fromNode": "edge-source",
"fromSide": "right",
"toNode": "edge-labeled",
"toSide": "left",
"label": "labeled edge"
},
{
"id": "edge-colored-demo",
"fromNode": "edge-source",
"fromSide": "right",
"toNode": "edge-colored",
"toSide": "left",
"color": "#ff6600"
},
{
"id": "edge-preset-demo",
"fromNode": "edge-labeled",
"fromSide": "right",
"toNode": "edge-preset",
"toSide": "left",
"color": "6"
}
]
}

View File

@ -11,7 +11,7 @@ This question is best answered by tracing what happens when a user (you!) runs `
1. After running `npx quartz build`, npm will look at `package.json` to find the `bin` entry for `quartz` which points at `./quartz/bootstrap-cli.mjs`. 1. After running `npx quartz build`, npm will look at `package.json` to find the `bin` entry for `quartz` which points at `./quartz/bootstrap-cli.mjs`.
2. This file has a [shebang](<https://en.wikipedia.org/wiki/Shebang_(Unix)>) line at the top which tells npm to execute it using Node. 2. This file has a [shebang](<https://en.wikipedia.org/wiki/Shebang_(Unix)>) line at the top which tells npm to execute it using Node.
3. `bootstrap-cli.mjs` is responsible for a few things: 3. `bootstrap-cli.mjs` is responsible for a few things:
1. Parsing the command-line arguments using [yargs](http://yargs.js.org/). The `plugin` subcommand is also handled here for managing external plugins. 1. Parsing the command-line arguments using [yargs](http://yargs.js.org/).
2. Transpiling and bundling the rest of Quartz (which is in Typescript) to regular JavaScript using [esbuild](https://esbuild.github.io/). The `esbuild` configuration here is slightly special as it also handles `.scss` file imports using [esbuild-sass-plugin v2](https://www.npmjs.com/package/esbuild-sass-plugin). Additionally, we bundle 'inline' client-side scripts (any `.inline.ts` file) that components declare using a custom `esbuild` plugin that runs another instance of `esbuild` which bundles for the browser instead of `node`. Modules of both types are imported as plain text. 2. Transpiling and bundling the rest of Quartz (which is in Typescript) to regular JavaScript using [esbuild](https://esbuild.github.io/). The `esbuild` configuration here is slightly special as it also handles `.scss` file imports using [esbuild-sass-plugin v2](https://www.npmjs.com/package/esbuild-sass-plugin). Additionally, we bundle 'inline' client-side scripts (any `.inline.ts` file) that components declare using a custom `esbuild` plugin that runs another instance of `esbuild` which bundles for the browser instead of `node`. Modules of both types are imported as plain text.
3. Running the local preview server if `--serve` is set. This starts two servers: 3. Running the local preview server if `--serve` is set. This starts two servers:
1. A WebSocket server on port 3001 to handle hot-reload signals. This tracks all inbound connections and sends a 'rebuild' message a server-side change is detected (either content or configuration). 1. A WebSocket server on port 3001 to handle hot-reload signals. This tracks all inbound connections and sends a 'rebuild' message a server-side change is detected (either content or configuration).
@ -35,7 +35,7 @@ This question is best answered by tracing what happens when a user (you!) runs `
4. Filter out unwanted content using plugins. 4. Filter out unwanted content using plugins.
5. Emit files using plugins. 5. Emit files using plugins.
1. Gather all the static resources (e.g. external CSS, JS modules, etc.) each emitter plugin declares. 1. Gather all the static resources (e.g. external CSS, JS modules, etc.) each emitter plugin declares.
2. Emitters that emit HTML files do a bit of extra work here as they need to transform the [hast](https://github.com/syntax-tree/hast) produced in the parse step to JSX. This is done using [hast-util-to-jsx-runtime](https://github.com/syntax-tree/hast-util-to-jsx-runtime) with the [Preact](https://preactjs.com/) runtime. Finally, the JSX is rendered to HTML using [preact-render-to-string](https://github.com/preactjs/preact-render-to-string) which statically renders the JSX to HTML (i.e. doesn't care about `useState`, `useEffect`, or any other React/Preact interactive bits). Here, we also do a bunch of fun stuff like assemble the page [[layout]] from `quartz.config.yaml`, assemble all the inline scripts that actually get shipped to the client, and all the transpiled styles. The bulk of this logic can be found in `quartz/components/renderPage.tsx`. Other fun things of note: 2. Emitters that emit HTML files do a bit of extra work here as they need to transform the [hast](https://github.com/syntax-tree/hast) produced in the parse step to JSX. This is done using [hast-util-to-jsx-runtime](https://github.com/syntax-tree/hast-util-to-jsx-runtime) with the [Preact](https://preactjs.com/) runtime. Finally, the JSX is rendered to HTML using [preact-render-to-string](https://github.com/preactjs/preact-render-to-string) which statically renders the JSX to HTML (i.e. doesn't care about `useState`, `useEffect`, or any other React/Preact interactive bits). Here, we also do a bunch of fun stuff like assemble the page [[layout]] from `quartz.layout.ts`, assemble all the inline scripts that actually get shipped to the client, and all the transpiled styles. The bulk of this logic can be found in `quartz/components/renderPage.tsx`. Other fun things of note:
1. CSS is minified and transformed using [Lightning CSS](https://github.com/parcel-bundler/lightningcss) to add vendor prefixes and do syntax lowering. 1. CSS is minified and transformed using [Lightning CSS](https://github.com/parcel-bundler/lightningcss) to add vendor prefixes and do syntax lowering.
2. Scripts are split into `beforeDOMLoaded` and `afterDOMLoaded` and are inserted in the `<head>` and `<body>` respectively. 2. Scripts are split into `beforeDOMLoaded` and `afterDOMLoaded` and are inserted in the `<head>` and `<body>` respectively.
3. Finally, each emitter plugin is responsible for emitting and writing it's own emitted files to disk. 3. Finally, each emitter plugin is responsible for emitting and writing it's own emitted files to disk.
@ -48,79 +48,5 @@ This question is best answered by tracing what happens when a user (you!) runs `
3. Once the page is done loading, the page will then dispatch a custom synthetic browser event `"nav"`. This is used so client-side scripts declared by components can 'setup' anything that requires access to the page DOM. 3. Once the page is done loading, the page will then dispatch a custom synthetic browser event `"nav"`. This is used so client-side scripts declared by components can 'setup' anything that requires access to the page DOM.
1. If the [[SPA Routing|enableSPA option]] is enabled in the [[configuration]], this `"nav"` event is also fired on any client-navigation to allow for components to unregister and reregister any event handlers and state. 1. If the [[SPA Routing|enableSPA option]] is enabled in the [[configuration]], this `"nav"` event is also fired on any client-navigation to allow for components to unregister and reregister any event handlers and state.
2. If it's not, we wire up the `"nav"` event to just be fired a single time after page load to allow for consistency across how state is setup across both SPA and non-SPA contexts. 2. If it's not, we wire up the `"nav"` event to just be fired a single time after page load to allow for consistency across how state is setup across both SPA and non-SPA contexts.
3. A separate `"render"` event can be dispatched when the DOM is updated in-place without a full navigation (e.g. after content decryption). Components that attach listeners to content elements should listen for both `"nav"` and `"render"`.
## Plugin System The architecture and design of the plugin system was intentionally left pretty vague here as this is described in much more depth in the guide on [[making plugins|making your own plugin]].
Page types define how a category of pages is rendered. They are configured in the `pageTypes` array in `quartz.config.yaml`.
Quartz v5 introduces a community plugin system. Plugins are standalone Git repositories that are cloned into `.quartz/plugins/` and re-exported through an auto-generated index file at `.quartz/plugins/index.ts`.
### Plugin Types
There are now four plugin categories:
- **Transformers**: Map over content (parse frontmatter, generate descriptions, syntax highlighting)
- **Filters**: Filter content (remove drafts, explicit publish)
- **Emitters**: Reduce over content (generate RSS, sitemaps, alias redirects, OG images)
- **Page Types**: Define how pages are rendered. Each page type handles a specific kind of page (content notes, folder listings, tag listings, 404). The `PageTypeDispatcher` emitter routes pages to the appropriate page type plugin based on the content.
### Plugin Resolution
When `npx quartz plugin add github:quartz-community/explorer` is run:
1. The repository is cloned into `.quartz/plugins/explorer/`
2. The plugin is built using `tsup` (defined in each plugin's `tsup.config.ts`)
3. An auto-generated `.quartz/plugins/index.ts` re-exports all installed plugins
4. The plugin's commit hash is recorded in `quartz.lock.json`
### Plugin CLI Commands
- `npx quartz plugin add github:quartz-community/<name>` — Install a community plugin
- `npx quartz plugin update` — Update all plugins to latest commits
- `npx quartz plugin restore` — Restore plugins from locked commits in `quartz.lock.json` (used in CI/CD)
- `npx quartz plugin remove <name>` — Remove an installed plugin
### Plugin Structure
Each community plugin repository contains:
- `src/index.ts` — Plugin entry point exporting the plugin function
- `tsup.config.ts` — Build configuration using tsup
- `package.json` — Declares dependencies on `@quartz-community/types` and `@quartz-community/utils`
The architecture and design of the plugin system was intentionally left pretty vague here as this is described in much more depth in the guide on [[making plugins|creating plugins]].
## Page Frames
Page frames control the inner HTML structure of each page. While the outer shell (`<html>`, `<head>`, `<body>`, `#quartz-root`) is always the same (required for [[SPA Routing]]), the frame determines how layout slots are arranged inside the page.
The frame system lives in `quartz/components/frames/` and consists of:
- `types.ts` — Defines the `PageFrame` and `PageFrameProps` interfaces
- `DefaultFrame.tsx` — Three-column layout (left sidebar, center, right sidebar, footer)
- `FullWidthFrame.tsx` — No sidebars, single center column
- `MinimalFrame.tsx` — No sidebars, no header/beforeBody, just content and footer
- `registry.ts``FrameRegistry` singleton for plugin-registered frames
- `index.ts``resolveFrame()` function and built-in frame registry
### Frame Registry
The `FrameRegistry` (`quartz/components/frames/registry.ts`) is a singleton that stores frames registered by community plugins. It mirrors the design of the `ComponentRegistry`. Plugins declare frames in their `package.json` manifest under the `"quartz"."frames"` field, and these are loaded by `quartz/plugins/loader/frameLoader.ts` during plugin initialization.
### Frame Resolution
The rendering pipeline in `quartz/components/renderPage.tsx` delegates to the resolved frame's `render()` function. Frame resolution happens in the `PageTypeDispatcher` emitter (`quartz/plugins/pageTypes/dispatcher.ts`) using this priority:
1. YAML config: `layout.byPageType.<name>.template`
2. Plugin-registered frame: looked up by name in the `FrameRegistry`
3. Built-in frame: looked up by name in the `builtinFrames` map
4. Fallback: `"default"`
The active frame name is set as a `data-frame` attribute on the `.page` element, enabling frame-specific CSS overrides in `quartz/styles/base.scss`.
### Plugin-Provided Frames
Community plugins can ship their own frames by exporting them from a `./frames` subpath and declaring them in the plugin manifest. For example, the `canvas-page` plugin provides a `"canvas"` frame with a fullscreen layout and togglable sidebar. See [[making plugins#Providing Custom Frames]] for implementation details.
See [[layout#Page Frames]] for user-facing documentation and [[making plugins#Page Types]] for how to set frames in page type plugins.

View File

@ -1,5 +1,5 @@
--- ---
title: Creating Component Plugins title: Creating your own Quartz components
--- ---
> [!warning] > [!warning]
@ -20,31 +20,17 @@ However, HTML doesn't let you create reusable templates. If you wanted to create
In effect, components allow you to write a JavaScript function that takes some data and produces HTML as an output. **While Quartz doesn't use React, it uses the same component concept to allow you to easily express layout templates in your Quartz site.** In effect, components allow you to write a JavaScript function that takes some data and produces HTML as an output. **While Quartz doesn't use React, it uses the same component concept to allow you to easily express layout templates in your Quartz site.**
## Community Component Plugins ## An Example Component
In v5, most components are community plugins — standalone repositories that export a `QuartzComponent`. These plugins are decoupled from the core Quartz repository, allowing for easier maintenance and sharing. ### Constructor
### Getting Started Component files are written in `.tsx` files that live in the `quartz/components` folder. These are re-exported in `quartz/components/index.ts` so you can use them in layouts and other components more easily.
To create a new component plugin, you can use the official plugin template: Each component file should have a default export that satisfies the `QuartzComponentConstructor` function signature. It's a function that takes in a single optional parameter `opts` and returns a Quartz Component. The type of the parameters `opts` is defined by the interface `Options` which you as the component creator also decide.
```shell In your component, you can use the values from the configuration option to change the rendering behaviour inside of your component. For example, the component in the code snippet below will not render if the `favouriteNumber` option is below 0.
git clone https://github.com/quartz-community/plugin-template.git my-component
cd my-component
npm install
```
### Plugin Structure
A component plugin's `src/index.ts` typically exports a function (a constructor) that returns a `QuartzComponent`. This allows users to pass configuration options to your component.
```tsx title="src/index.ts"
import {
QuartzComponent,
QuartzComponentConstructor,
QuartzComponentProps,
} from "@quartz-community/types"
```tsx {11-17}
interface Options { interface Options {
favouriteNumber: number favouriteNumber: number
} }
@ -53,25 +39,28 @@ const defaultOptions: Options = {
favouriteNumber: 42, favouriteNumber: 42,
} }
const MyComponent: QuartzComponentConstructor<Options> = (userOpts?: Options) => { export default ((userOpts?: Options) => {
const opts = { ...defaultOptions, ...userOpts } const opts = { ...userOpts, ...defaultOpts }
function YourComponent(props: QuartzComponentProps) {
if (opts.favouriteNumber < 0) {
return null
}
const Component: QuartzComponent = (props: QuartzComponentProps) => {
if (opts.favouriteNumber < 0) return null
return <p>My favourite number is {opts.favouriteNumber}</p> return <p>My favourite number is {opts.favouriteNumber}</p>
} }
return Component return YourComponent
} }) satisfies QuartzComponentConstructor
export default MyComponent
``` ```
### Props ### Props
The Quartz component itself (lines 11-17 highlighted above) looks like a React component. It takes in properties (sometimes called [props](https://react.dev/learn/passing-props-to-a-component)) and returns JSX.
All Quartz components accept the same set of props: All Quartz components accept the same set of props:
```tsx ```tsx title="quartz/components/types.ts"
// simplified for sake of demonstration
export type QuartzComponentProps = { export type QuartzComponentProps = {
fileData: QuartzPluginData fileData: QuartzPluginData
cfg: GlobalConfiguration cfg: GlobalConfiguration
@ -81,29 +70,50 @@ export type QuartzComponentProps = {
} }
``` ```
- `fileData`: Any metadata plugins may have added to the current page. - `fileData`: Any metadata [[making plugins|plugins]] may have added to the current page.
- `fileData.slug`: slug of the current page. - `fileData.slug`: slug of the current page.
- `fileData.frontmatter`: any frontmatter parsed. - `fileData.frontmatter`: any frontmatter parsed.
- `cfg`: The `configuration` field in `quartz.config.yaml`. - `cfg`: The `configuration` field in `quartz.config.ts`.
- `tree`: the resulting [HTML AST](https://github.com/syntax-tree/hast) after processing and transforming the file. - `tree`: the resulting [HTML AST](https://github.com/syntax-tree/hast) after processing and transforming the file. This is useful if you'd like to render the content using [hast-util-to-jsx-runtime](https://github.com/syntax-tree/hast-util-to-jsx-runtime) (you can find an example of this in `quartz/components/pages/Content.tsx`).
- `allFiles`: Metadata for all files that have been parsed. Useful for doing page listings or figuring out the overall site structure. - `allFiles`: Metadata for all files that have been parsed. Useful for doing page listings or figuring out the overall site structure.
- `displayClass`: a utility class that indicates a preference from the user about how to render it in a mobile or desktop setting. - `displayClass`: a utility class that indicates a preference from the user about how to render it in a mobile or desktop setting. Helpful if you want to conditionally hide a component on mobile or desktop.
### Styling ### Styling
In community plugins, styles are bundled with the plugin. You can define styles using the `.css` property on the component: Quartz components can also define a `.css` property on the actual function component which will get picked up by Quartz. This is expected to be a CSS string which can either be inlined or imported from a `.scss` file.
```tsx Note that inlined styles **must** be plain vanilla CSS:
Component.css = `
.my-component { color: red; } ```tsx {6-10} title="quartz/components/YourComponent.tsx"
export default (() => {
function YourComponent() {
return <p class="red-text">Example Component</p>
}
YourComponent.css = `
p.red-text {
color: red;
}
` `
return YourComponent
}) satisfies QuartzComponentConstructor
``` ```
For SCSS, you can import it and assign it to the `.css` property. The build system will handle the transformation: Imported styles, however, can be from SCSS files:
```tsx ```tsx {1-2,9} title="quartz/components/YourComponent.tsx"
import styles from "./styles.scss" // assuming your stylesheet is in quartz/components/styles/YourComponent.scss
Component.css = styles import styles from "./styles/YourComponent.scss"
export default (() => {
function YourComponent() {
return <p>Example Component</p>
}
YourComponent.css = styles
return YourComponent
}) satisfies QuartzComponentConstructor
``` ```
> [!warning] > [!warning]
@ -111,108 +121,128 @@ Component.css = styles
### Scripts and Interactivity ### Scripts and Interactivity
For interactivity, you can declare `.beforeDOMLoaded` and `.afterDOMLoaded` properties on the component. These should be strings containing the JavaScript to be executed in the browser. What about interactivity? Suppose you want to add an-click handler for example. Like the `.css` property on the component, you can also declare `.beforeDOMLoaded` and `.afterDOMLoaded` properties that are strings that contain the script.
- `.beforeDOMLoaded`: Executed _before_ the page is done loading. Used for prefetching or early initialization. ```tsx title="quartz/components/YourComponent.tsx"
- `.afterDOMLoaded`: Executed once the page has been completely loaded. export default (() => {
function YourComponent() {
return <button id="btn">Click me</button>
}
If you need to create an `afterDOMLoaded` script that depends on page-specific elements that may change when navigating, listen for the `"nav"` event: YourComponent.beforeDOMLoaded = `
console.log("hello from before the page loads!")
`
YourComponent.afterDOMLoaded = `
document.getElementById('btn').onclick = () => {
alert('button clicked!')
}
`
return YourComponent
}) satisfies QuartzComponentConstructor
```
> [!hint]
> For those coming from React, Quartz components are different from React components in that it only uses JSX for templating and layout. Hooks like `useEffect`, `useState`, etc. are not rendered and other properties that accept functions like `onClick` handlers will not work. Instead, do it using a regular JS script that modifies the DOM element directly.
As the names suggest, the `.beforeDOMLoaded` scripts are executed _before_ the page is done loading so it doesn't have access to any elements on the page. This is mostly used to prefetch any critical data.
The `.afterDOMLoaded` script executes once the page has been completely loaded. This is a good place to setup anything that should last for the duration of a site visit (e.g. getting something saved from local storage).
If you need to create an `afterDOMLoaded` script that depends on _page specific_ elements that may change when navigating to a new page, you can listen for the `"nav"` event that gets fired whenever a page loads (which may happen on navigation if [[SPA Routing]] is enabled).
```ts ```ts
document.addEventListener("nav", () => { document.addEventListener("nav", () => {
// do page specific logic here // do page specific logic here
// e.g. attach event listeners
const toggleSwitch = document.querySelector("#switch") as HTMLInputElement const toggleSwitch = document.querySelector("#switch") as HTMLInputElement
if (toggleSwitch) {
toggleSwitch.addEventListener("change", switchTheme) toggleSwitch.addEventListener("change", switchTheme)
window.addCleanup(() => toggleSwitch.removeEventListener("change", switchTheme)) window.addCleanup(() => toggleSwitch.removeEventListener("change", switchTheme))
}
}) })
``` ```
You can also use the `"prenav"` event, which fires before the page is replaced during SPA navigation. You can also add the equivalent of a `beforeunload` event for [[SPA Routing]] via the `prenav` event.
The `"render"` event fires when the DOM has been updated in-place without a full navigation — for example, after content decryption or dynamic DOM modifications by other plugins. If your component attaches event listeners to content elements, listen for `"render"` in addition to `"nav"` to ensure re-initialization:
```ts ```ts
function setupMyComponent() { document.addEventListener("prenav", () => {
const elements = document.querySelectorAll(".my-interactive") // executed after an SPA navigation is triggered but
for (const el of elements) { // before the page is replaced
el.addEventListener("click", handleClick) // one usage pattern is to store things in sessionStorage
window.addCleanup(() => el.removeEventListener("click", handleClick)) // in the prenav and then conditionally load then in the consequent
} // nav
} })
document.addEventListener("nav", setupMyComponent)
document.addEventListener("render", setupMyComponent)
``` ```
It is best practice to track any event handlers via `window.addCleanup` to prevent memory leaks during SPA navigation. It is best practice to track any event handlers via `window.addCleanup` to prevent memory leaks.
This will get called on page navigation.
#### Importing Code #### Importing Code
In community plugins, TypeScript scripts should be transpiled at build time. The plugin template includes an `inlineScriptPlugin` in `tsup.config.ts` that automatically transpiles `.inline.ts` files imported as text: Of course, it isn't always practical (nor desired!) to write your code as a string literal in the component.
```tsx title="src/index.ts" Quartz supports importing component code through `.inline.ts` files.
import script from "./script.inline.ts"
const Component: QuartzComponent = (props) => { ```tsx title="quartz/components/YourComponent.tsx"
// @ts-ignore: typescript doesn't know about our inline bundling system
// so we need to silence the error
import script from "./scripts/graph.inline"
export default (() => {
function YourComponent() {
return <button id="btn">Click me</button> return <button id="btn">Click me</button>
} }
Component.afterDOMLoaded = script
YourComponent.afterDOMLoaded = script
return YourComponent
}) satisfies QuartzComponentConstructor
``` ```
The `inlineScriptPlugin` handles transpiling TypeScript to browser-compatible JavaScript during the build step, allowing you to write type-safe client-side code. ```ts title="quartz/components/scripts/graph.inline.ts"
// any imports here are bundled for the browser
import * as d3 from "d3"
### Installing Your Component document.getElementById("btn").onclick = () => {
alert("button clicked!")
Once your component is published (e.g., to GitHub or npm), users can install it using the Quartz CLI: }
```shell
npx quartz plugin add github:your-username/my-component
``` ```
Then, they can add it to their `quartz.config.yaml`: Additionally, like what is shown in the example above, you can import packages in `.inline.ts` files. This will be bundled by Quartz and included in the actual script.
```yaml title="quartz.config.yaml" ### Using a Component
plugins:
- source: github:your-username/my-component After creating your custom component, re-export it in `quartz/components/index.ts`:
enabled: true
options: ```ts title="quartz/components/index.ts" {4,10}
favouriteNumber: 42 import ArticleTitle from "./ArticleTitle"
layout: import Content from "./pages/Content"
position: left import Darkmode from "./Darkmode"
priority: 60 import YourComponent from "./YourComponent"
export { ArticleTitle, Content, Darkmode, YourComponent }
``` ```
For advanced usage via the TS override in `quartz.ts`: Then, you can use it like any other component in `quartz.layout.ts` via `Component.YourComponent()`. See the [[configuration#Layout|layout]] section for more details.
```ts title="quartz.ts (override)" As Quartz components are just functions that return React components, you can compositionally use them in other Quartz components.
import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
import Plugin from "./.quartz/plugins"
const config = await loadQuartzConfig() ```tsx title="quartz/components/AnotherComponent.tsx"
export default config import YourComponentConstructor from "./YourComponent"
export const layout = await loadQuartzLayout({
byPageType: { export default (() => {
content: { const YourComponent = YourComponentConstructor()
left: [Plugin.MyComponent({ favouriteNumber: 42 })],
}, function AnotherComponent(props: QuartzComponentProps) {
}, return (
}) <div>
<p>It's nested!</p>
<YourComponent {...props} />
</div>
)
}
return AnotherComponent
}) satisfies QuartzComponentConstructor
``` ```
## Internal Components
Quartz also has internal components that provide layout utilities. These live in `quartz/components/` and are primarily used for structural purposes:
- `Component.Head()` — renders the `<head>` tag
- `Component.Spacer()` — adds flexible space
- `Component.Flex()` — flexible layout container
- `Component.MobileOnly()` — shows component only on mobile
- `Component.DesktopOnly()` — shows component only on desktop
- `Component.ConditionalRender()` — conditionally renders based on page data
See [[layout-components]] for more details on these utilities.
> [!hint] > [!hint]
> Look at existing community plugins like [Explorer](https://github.com/quartz-community/explorer) or [Darkmode](https://github.com/quartz-community/darkmode) for real-world examples. > Look in `quartz/components` for more examples of components in Quartz as reference for your own components!

View File

@ -1,10 +1,3 @@
--- ---
title: "Advanced" title: "Advanced"
--- ---
This section covers advanced topics for users who want to extend or deeply customize Quartz.
- **[[architecture]]** — How Quartz works under the hood: the parse, filter, and emit pipeline
- **[[making plugins]]** — Build your own transformer, filter, emitter, or component plugin
- **[[creating components]]** — Create custom layout components with JSX
- **[[paths]]** — How Quartz resolves and transforms file paths

View File

@ -18,52 +18,20 @@ type QuartzPluginInstance =
| QuartzTransformerPluginInstance | QuartzTransformerPluginInstance
| QuartzFilterPluginInstance | QuartzFilterPluginInstance
| QuartzEmitterPluginInstance | QuartzEmitterPluginInstance
| QuartzPageTypePluginInstance
``` ```
The following sections will go into detail for what methods can be implemented for each plugin type. Before we do that, let's clarify a few more ambiguous types: The following sections will go into detail for what methods can be implemented for each plugin type. Before we do that, let's clarify a few more ambiguous types:
- `BuildCtx` is defined in `@quartz-community/types`. It consists of - `BuildCtx` is defined in `quartz/ctx.ts`. It consists of
- `argv`: The command line arguments passed to the Quartz [[build]] command - `argv`: The command line arguments passed to the Quartz [[build]] command
- `cfg`: The full Quartz [[configuration]] - `cfg`: The full Quartz [[configuration]]
- `allSlugs`: a list of all the valid content slugs (see [[paths]] for more information on what a slug is) - `allSlugs`: a list of all the valid content slugs (see [[paths]] for more information on what a slug is)
- `StaticResources` is defined in `@quartz-community/types`. It consists of - `StaticResources` is defined in `quartz/resources.tsx`. It consists of
- `css`: a list of CSS style definitions that should be loaded. A CSS style is described with the `CSSResource` type. It accepts either a source URL or the inline content of the stylesheet. - `css`: a list of CSS style definitions that should be loaded. A CSS style is described with the `CSSResource` type which is also defined in `quartz/resources.tsx`. It accepts either a source URL or the inline content of the stylesheet.
- `js`: a list of scripts that should be loaded. A script is described with the `JSResource` type. It allows you to define a load time (either before or after the DOM has been loaded), whether it should be a module, and either the source URL or the inline content of the script. - `js`: a list of scripts that should be loaded. A script is described with the `JSResource` type which is also defined in `quartz/resources.tsx`. It allows you to define a load time (either before or after the DOM has been loaded), whether it should be a module, and either the source URL or the inline content of the script.
- `additionalHead`: a list of JSX elements or functions that return JSX elements to be added to the `<head>` tag of the page. Functions receive the page's data as an argument and can conditionally render elements. - `additionalHead`: a list of JSX elements or functions that return JSX elements to be added to the `<head>` tag of the page. Functions receive the page's data as an argument and can conditionally render elements.
## Getting Started ## Transformers
In v5, plugins are standalone repositories. The easiest way to create one is using the plugin template:
```shell
# Use the plugin template to create a new repository on GitHub
# Then clone it locally
git clone https://github.com/your-username/my-plugin.git
cd my-plugin
npm install
```
The template provides the build configuration (`tsup.config.ts`), TypeScript setup, and correct package structure.
## Plugin Structure
The basic file structure of a plugin is as follows:
```
my-plugin/
├── src/
│ └── index.ts # Plugin entry point
├── tsup.config.ts # Build configuration
├── package.json # Dependencies and exports
└── tsconfig.json # TypeScript configuration
```
The plugin's `package.json` should declare dependencies on `@quartz-community/types` (for type definitions) and optionally `@quartz-community/utils` (for shared utilities).
## Plugin Types
### Transformers
Transformers **map** over content, taking a Markdown file and outputting modified content or adding metadata to the file itself. Transformers **map** over content, taking a Markdown file and outputting modified content or adding metadata to the file itself.
@ -84,15 +52,15 @@ All transformer plugins must define at least a `name` field to register the plug
- `htmlPlugins` defines a list of [rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md). Similar to how `remark` works, `rehype` is a tool that transforms HTML to HTML in a structured way. - `htmlPlugins` defines a list of [rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md). Similar to how `remark` works, `rehype` is a tool that transforms HTML to HTML in a structured way.
- `externalResources` defines any external resources the plugin may need to load on the client-side for it to work properly. - `externalResources` defines any external resources the plugin may need to load on the client-side for it to work properly.
Normally for both `remark` and `rehype`, you can find existing plugins that you can use. If you'd like to create your own `remark` or `rehype` plugin, checkout the [guide to creating a plugin](https://unifiedjs.com/learn/guide/create-a-plugin/) using `unified` (the underlying AST parser and transformer library). Normally for both `remark` and `rehype`, you can find existing plugins that you can use to . If you'd like to create your own `remark` or `rehype` plugin, checkout the [guide to creating a plugin](https://unifiedjs.com/learn/guide/create-a-plugin/) using `unified` (the underlying AST parser and transformer library).
A good example of a transformer plugin that borrows from the `remark` and `rehype` ecosystems is the [[plugins/Latex|Latex]] plugin: A good example of a transformer plugin that borrows from the `remark` and `rehype` ecosystems is the [[plugins/Latex|Latex]] plugin:
```ts ```ts title="quartz/plugins/transformers/latex.ts"
import remarkMath from "remark-math" import remarkMath from "remark-math"
import rehypeKatex from "rehype-katex" import rehypeKatex from "rehype-katex"
import rehypeMathjax from "rehype-mathjax/svg" import rehypeMathjax from "rehype-mathjax/svg"
import { QuartzTransformerPlugin } from "@quartz-community/types" import { QuartzTransformerPlugin } from "../types"
interface Options { interface Options {
renderEngine: "katex" | "mathjax" renderEngine: "katex" | "mathjax"
@ -141,8 +109,6 @@ export const Latex: QuartzTransformerPlugin<Options> = (opts?: Options) => {
Another common thing that transformer plugins will do is parse a file and add extra data for that file: Another common thing that transformer plugins will do is parse a file and add extra data for that file:
```ts ```ts
import { QuartzTransformerPlugin } from "@quartz-community/types"
export const AddWordCount: QuartzTransformerPlugin = () => { export const AddWordCount: QuartzTransformerPlugin = () => {
return { return {
name: "AddWordCount", name: "AddWordCount",
@ -174,17 +140,11 @@ declare module "vfile" {
Finally, you can also perform transformations over Markdown or HTML ASTs using the `visit` function from the `unist-util-visit` package or the `findAndReplace` function from the `mdast-util-find-and-replace` package. Finally, you can also perform transformations over Markdown or HTML ASTs using the `visit` function from the `unist-util-visit` package or the `findAndReplace` function from the `mdast-util-find-and-replace` package.
```ts ```ts
import { visit } from "unist-util-visit"
import { findAndReplace } from "mdast-util-find-and-replace"
import { QuartzTransformerPlugin } from "@quartz-community/types"
import { Link } from "mdast"
export const TextTransforms: QuartzTransformerPlugin = () => { export const TextTransforms: QuartzTransformerPlugin = () => {
return { return {
name: "TextTransforms", name: "TextTransforms",
markdownPlugins() { markdownPlugins() {
return [ return [() => {
() => {
return (tree, file) => { return (tree, file) => {
// replace _text_ with the italics version // replace _text_ with the italics version
findAndReplace(tree, /_(.+)_/, (_value: string, ...capture: string[]) => { findAndReplace(tree, /_(.+)_/, (_value: string, ...capture: string[]) => {
@ -194,7 +154,7 @@ export const TextTransforms: QuartzTransformerPlugin = () => {
// https://github.com/syntax-tree/mdast // https://github.com/syntax-tree/mdast
return { return {
type: "emphasis", type: "emphasis",
children: [{ type: "text", value: inner }], children: [{ type: 'text', value: inner }]
} }
}) })
@ -203,21 +163,22 @@ export const TextTransforms: QuartzTransformerPlugin = () => {
// https://github.com/syntax-tree/mdast#link in this example // https://github.com/syntax-tree/mdast#link in this example
visit(tree, "link", (link: Link) => { visit(tree, "link", (link: Link) => {
return { return {
type: "paragraph", type: "paragraph"
children: [{ type: "text", value: link.title }], children: [{ type: 'text', value: link.title }]
} }
}) })
} }
}, }]
] }
},
} }
} }
``` ```
All transformer plugins can be found under `quartz/plugins/transformers`. If you decide to write your own transformer plugin, don't forget to re-export it under `quartz/plugins/transformers/index.ts`
A parting word: transformer plugins are quite complex so don't worry if you don't get them right away. Take a look at the built in transformers and see how they operate over content to get a better sense for how to accomplish what you are trying to do. A parting word: transformer plugins are quite complex so don't worry if you don't get them right away. Take a look at the built in transformers and see how they operate over content to get a better sense for how to accomplish what you are trying to do.
### Filters ## Filters
Filters **filter** content, taking the output of all the transformers and determining what files to actually keep and what to discard. Filters **filter** content, taking the output of all the transformers and determining what files to actually keep and what to discard.
@ -236,8 +197,8 @@ A filter plugin must define a `name` field and a `shouldPublish` function that t
For example, here is the built-in plugin for removing drafts: For example, here is the built-in plugin for removing drafts:
```ts ```ts title="quartz/plugins/filters/draft.ts"
import { QuartzFilterPlugin } from "@quartz-community/types" import { QuartzFilterPlugin } from "../types"
export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({ export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({
name: "RemoveDrafts", name: "RemoveDrafts",
@ -249,7 +210,7 @@ export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({
}) })
``` ```
### Emitters ## Emitters
Emitters **reduce** over content, taking in a list of all the transformed and filtered content and creating output files. Emitters **reduce** over content, taking in a list of all the transformed and filtered content and creating output files.
@ -281,7 +242,7 @@ An emitter plugin must define a `name` field, an `emit` function, and a `getQuar
- `partialEmit` is an optional function that enables incremental builds. It receives information about which files have changed (`changeEvents`) and can selectively rebuild only the necessary files. This is useful for optimizing build times in development mode. If `partialEmit` is undefined, it will default to the `emit` function. - `partialEmit` is an optional function that enables incremental builds. It receives information about which files have changed (`changeEvents`) and can selectively rebuild only the necessary files. This is useful for optimizing build times in development mode. If `partialEmit` is undefined, it will default to the `emit` function.
- `getQuartzComponents` declares which Quartz components the emitter uses to construct its pages. - `getQuartzComponents` declares which Quartz components the emitter uses to construct its pages.
Creating new files can be done via regular Node [fs module](https://nodejs.org/api/fs.html) (i.e. `fs.cp` or `fs.writeFile`) or via the `write` function in `@quartz-community/utils` if you are creating files that contain text. `write` has the following signature: Creating new files can be done via regular Node [fs module](https://nodejs.org/api/fs.html) (i.e. `fs.cp` or `fs.writeFile`) or via the `write` function in `quartz/plugins/emitters/helpers.ts` if you are creating files that contain text. `write` has the following signature:
```ts ```ts
export type WriteOptions = (data: { export type WriteOptions = (data: {
@ -301,23 +262,26 @@ This is a thin wrapper around writing to the appropriate output folder and ensur
If you are creating an emitter plugin that needs to render components, there are three more things to be aware of: If you are creating an emitter plugin that needs to render components, there are three more things to be aware of:
- Your component should use `getQuartzComponents` to declare a list of `QuartzComponents` that it uses to construct the page. See the page on [[creating components]] for more information. - Your component should use `getQuartzComponents` to declare a list of `QuartzComponents` that it uses to construct the page. See the page on [[creating components]] for more information.
- You can use the `renderPage` function defined in `@quartz-community/utils` to render Quartz components into HTML. - You can use the `renderPage` function defined in `quartz/components/renderPage.tsx` to render Quartz components into HTML.
- If you need to render an HTML AST to JSX, you can use the `htmlToJsx` function from `@quartz-community/utils`. - If you need to render an HTML AST to JSX, you can use the `htmlToJsx` function from `quartz/util/jsx.ts`. An example of this can be found in `quartz/components/pages/Content.tsx`.
For example, the following is a simplified version of the content page plugin that renders every single page. For example, the following is a simplified version of the content page plugin that renders every single page.
```tsx ```tsx title="quartz/plugins/emitters/contentPage.tsx"
import { QuartzEmitterPlugin, FullPageLayout, QuartzComponentProps } from "@quartz-community/types"
import { renderPage, canonicalizeServer, pageResources, write } from "@quartz-community/utils"
export const ContentPage: QuartzEmitterPlugin = () => { export const ContentPage: QuartzEmitterPlugin = () => {
// construct the layout
const layout: FullPageLayout = {
...sharedPageComponents,
...defaultContentPageLayout,
pageBody: Content(),
}
const { head, header, beforeBody, pageBody, afterBody, left, right, footer } = layout
return { return {
name: "ContentPage", name: "ContentPage",
getQuartzComponents(ctx) { getQuartzComponents() {
const { head, header, beforeBody, pageBody, afterBody, left, right, footer } = ctx.cfg.layout
return [head, ...header, ...beforeBody, pageBody, ...afterBody, ...left, ...right, footer] return [head, ...header, ...beforeBody, pageBody, ...afterBody, ...left, ...right, footer]
}, },
async emit(ctx, content, resources): Promise<FilePath[]> { async emit(ctx, content, resources, emit): Promise<FilePath[]> {
const cfg = ctx.cfg.configuration const cfg = ctx.cfg.configuration
const fps: FilePath[] = [] const fps: FilePath[] = []
const allFiles = content.map((c) => c[1].data) const allFiles = content.map((c) => c[1].data)
@ -333,9 +297,8 @@ export const ContentPage: QuartzEmitterPlugin = () => {
allFiles, allFiles,
} }
const content = renderPage(cfg, slug, componentData, {}, externalResources) const content = renderPage(cfg, slug, componentData, opts, externalResources)
const fp = await write({ const fp = await emit({
ctx,
content, content,
slug: file.data.slug!, slug: file.data.slug!,
ext: ".html", ext: ".html",
@ -349,190 +312,7 @@ export const ContentPage: QuartzEmitterPlugin = () => {
} }
``` ```
Page types define how a category of pages is rendered. They are the primary way to add support for new file types or virtual pages in Quartz. Note that it takes in a `FullPageLayout` as the options. It's made by combining a `SharedLayout` and a `PageLayout` both of which are provided through the `quartz.layout.ts` file.
```ts > [!hint]
export interface QuartzPageTypePluginInstance { > Look in `quartz/plugins` for more examples of plugins in Quartz as reference for your own plugins!
name: string
priority?: number
fileExtensions?: string[]
match: PageMatcher
generate?: PageGenerator
layout: string
frame?: string
body: QuartzComponentConstructor
}
```
- `name`: A unique identifier for this page type.
- `priority`: Controls matching order when multiple page types could match a slug. Higher priority page types are checked first. Default: `0`.
- `fileExtensions`: Array of file extensions this page type handles (e.g. `[".canvas"]`, `[".base"]`). Content files (`.md`) are handled by the default content page type.
- `match`: A function that determines whether a given slug/file should be rendered by this page type.
- `generate`: An optional function that produces virtual pages (pages not backed by files on disk, such as folder listings or tag indices).
- `layout`: The layout configuration key (e.g. `"content"`, `"folder"`, `"tag"`). This determines which `byPageType` entry in `quartz.config.yaml` provides the layout overrides for this page type.
- `frame`: The [[layout#Page Frames|page frame]] to use for this page type. Controls the overall HTML structure (e.g. `"default"`, `"full-width"`, `"minimal"`, or a custom frame provided by your plugin). If not set, defaults to `"default"`. Can be overridden per-page-type via `layout.byPageType.<name>.template` in `quartz.config.yaml`.
- `body`: The Quartz component constructor that renders the page body content.
### Providing Custom Frames
Plugins can ship their own [[layout#Page Frames|page frames]] — custom page layouts that control how the HTML structure (sidebars, header, content area, footer) is arranged. This is useful for page types that need fundamentally different layouts (e.g. a fullscreen canvas, a presentation mode, a dashboard).
To provide a custom frame:
**1. Create the frame file:**
```tsx title="src/frames/MyFrame.tsx"
import type { PageFrame, PageFrameProps } from "@quartz-community/types"
import type { ComponentChildren } from "preact"
export const MyFrame: PageFrame = {
name: "my-frame",
css: `
.page[data-frame="my-frame"] > #quartz-body {
grid-template-columns: 1fr;
grid-template-areas: "center";
}
`,
render({ componentData, pageBody: Content, footer: Footer }: PageFrameProps): unknown {
const renderSlot = (C: (props: typeof componentData) => unknown): ComponentChildren =>
C(componentData) as ComponentChildren
return (
<div class="center">
{(Content as any)(componentData)}
{(Footer as any)(componentData)}
</div>
)
},
}
```
Key requirements:
- `name`: A unique string identifier. This is what page types and YAML config reference.
- `render()`: Receives all layout slots (header, sidebars, content, footer) and returns JSX for the inner page structure.
- `css` (optional): Frame-specific CSS. Scope it with `.page[data-frame="my-frame"]` selectors to avoid conflicts.
**2. Re-export the frame:**
```ts title="src/frames/index.ts"
export { MyFrame } from "./MyFrame"
```
**3. Declare the frame in `package.json`:**
```json title="package.json"
{
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./frames": {
"import": "./dist/frames/index.js",
"types": "./dist/frames/index.d.ts"
}
},
"quartz": {
"frames": {
"MyFrame": { "exportName": "MyFrame" }
}
}
}
```
The `"frames"` field in the `"quartz"` manifest maps export names to frame metadata. The key (e.g. `"MyFrame"`) must match the export name in `src/frames/index.ts`.
**4. Add the frame entry point to your build config:**
```ts title="tsup.config.ts"
export default defineConfig({
entry: ["src/index.ts", "src/frames/index.ts"],
// ...
})
```
**5. Reference the frame in your page type:**
```ts
export const MyPageType: QuartzPageTypePlugin = () => ({
name: "MyPageType",
frame: "my-frame", // References the frame by its name property
// ...
})
```
When a user installs your plugin, Quartz automatically loads the frame from the `./frames` export and registers it in the Frame Registry. The frame is then available by name in any page type or YAML config override.
> [!tip]
> See the [`canvas-page`](https://github.com/quartz-community/canvas-page) plugin for a complete real-world example of a plugin-provided frame.
## Building and Testing
```shell
# Build the plugin
npm run build
# or
npx tsup
```
## Installing Your Plugin
```shell
# In your Quartz project
npx quartz plugin add github:your-username/my-plugin
```
This clones the plugin, builds it, and adds it to both `quartz.config.yaml` and `quartz.lock.json`. You can then configure it in your config:
```yaml title="quartz.config.yaml"
plugins:
- source: github:your-username/my-plugin
enabled: true
```
Or via TS override in `quartz.ts`:
```ts title="quartz.ts (override)"
import * as ExternalPlugin from "./.quartz/plugins"
// ...
transformers: [ExternalPlugin.MyPlugin()]
```
### Development Workflow
During plugin development, you'll frequently install and uninstall your plugin to test changes. The following commands help manage this cycle:
```shell
# Remove your plugin and clean up
npx quartz plugin remove my-plugin
# Re-add after making changes
npx quartz plugin add github:your-username/my-plugin
```
If you've updated your `quartz.config.yaml` to reference a plugin that isn't installed yet, you can install it without manually running `add`:
```shell
# Install all config-referenced plugins missing from the lockfile
npx quartz plugin resolve
# Preview first without making changes
npx quartz plugin resolve --dry-run
```
To clean up plugins that are installed but no longer referenced in your config:
```shell
# Remove orphaned plugins
npx quartz plugin prune
# Preview first without making changes
npx quartz plugin prune --dry-run
```
> [!tip]
> Both `resolve` and `prune` fall back to `quartz.config.default.yaml` if no `quartz.config.yaml` is present. This is useful for CI environments where the default config is the source of truth. See [[cli/plugin#prune|prune]] and [[cli/plugin#resolve|resolve]] for full details.
## Component Plugins
For plugins that provide visual components (like Explorer, Graph, Search), see the [[creating components|creating component plugins]] guide.

View File

@ -1,10 +1,8 @@
--- ---
title: Authoring Content title: Authoring Content
aliases:
- "authoring content"
--- ---
All of the content in your Quartz should go in the `/content` folder. The content for the home page of your Quartz lives in `content/index.md`. If you've [[index#🪴 Get Started|setup Quartz]] already, this folder should already be initialized. Any Markdown in this folder will get processed by Quartz. All of the content in your Quartz should go in the `/content` folder. The content for the home page of your Quartz lives in `content/index.md`. If you've [[index#🪴 Get Started|setup Quartz]] already, this folder should already be initialized. Any Markdown in this folder will get processed by Quartz.
It is recommended that you use [Obsidian](https://obsidian.md/) as a way to edit and maintain your Quartz. It comes with a nice editor and graphical interface to preview, edit, and link your local files and attachments. It is recommended that you use [Obsidian](https://obsidian.md/) as a way to edit and maintain your Quartz. It comes with a nice editor and graphical interface to preview, edit, and link your local files and attachments.
@ -42,7 +40,7 @@ See [[Frontmatter]] for a complete list of frontmatter.
## Syncing your Content ## Syncing your Content
When your Quartz is at a point you're happy with, you can save your changes to GitHub. When your Quartz is at a point you're happy with, you can save your changes to GitHub.
First, make sure you've [[getting-started/installation|already setup your GitHub repository]] and then do `npx quartz sync`. First, make sure you've [[setting up your GitHub repository|already setup your GitHub repository]] and then do `npx quartz sync`.
## Customization ## Customization

27
docs/build.md Normal file
View File

@ -0,0 +1,27 @@
---
title: "Building your Quartz"
---
Once you've [[index#🪴 Get Started|initialized]] Quartz, let's see what it looks like locally:
```bash
npx quartz build --serve
```
This will start a local web server to run your Quartz on your computer. Open a web browser and visit `http://localhost:8080/` to view it.
> [!hint] Flags and options
> For full help options, you can run `npx quartz build --help`.
>
> Most of these have sensible defaults but you can override them if you have a custom setup:
>
> - `-d` or `--directory`: the content folder. This is normally just `content`
> - `-v` or `--verbose`: print out extra logging information
> - `-o` or `--output`: the output folder. This is normally just `public`
> - `--serve`: run a local hot-reloading server to preview your Quartz
> - `--port`: what port to run the local preview server on
> - `--concurrency`: how many threads to use to parse notes
> [!warning] Not to be used for production
> Serve mode is intended for local previews only.
> For production workloads, see the page on [[hosting]].

View File

@ -1,65 +0,0 @@
---
title: quartz build
aliases:
- build
---
The `build` command transforms your Markdown content into a static HTML website. It processes your files through the configured plugins and outputs the final site to a directory of your choice.
## Flags
| Flag | Shorthand | Description | Default |
| ----------------- | --------- | --------------------------------------------------------- | ----------------- |
| `--directory` | `-d` | The directory containing your Quartz project | Current directory |
| `--verbose` | `-v` | Enable detailed logging for debugging | `false` |
| `--output` | `-o` | The directory where the built site will be saved | `public` |
| `--serve` | | Start a local development server | `false` |
| `--watch` | | Rebuild the site when files change | `false` |
| `--port` | | The port for the development server | `8080` |
| `--wsPort` | | The port for the WebSocket hot-reload server | `3001` |
| `--baseDir` | | Set a base directory for the site (e.g. for GitHub Pages) | `/` |
| `--remoteDevHost` | | The hostname to use for the development server | `localhost` |
| `--bundleInfo` | | Output a JSON file with bundle size information | `false` |
| `--concurrency` | | Number of worker threads to use for building | CPU core count |
## Examples
### Basic Build
Generate your site into the `public` folder.
```shell
npx quartz build
```
### Development Mode
Start a local server and watch for changes. This is the most common way to preview your site while writing.
```shell
npx quartz build --serve
```
### Custom Output and Port
Build to a specific folder and run the server on a different port.
```shell
npx quartz build --serve --output dist --port 3000
```
### Performance Tuning
If you have a very large vault, you can limit the number of concurrent workers to save memory.
```shell
npx quartz build --concurrency 2
```
## Development Server
The `--serve` flag starts a local web server. This server is intended for development and previewing only. It is not designed for production use. For information on how to deploy your site, see [[hosting]].
### Hot Reloading
When running with `--serve`, Quartz automatically enables `--watch`. It uses a WebSocket connection (on the port specified by `--wsPort`) to notify your browser when a file has changed. The browser will then automatically refresh to show the latest version of your content.

View File

@ -1,84 +0,0 @@
---
title: quartz create
---
The `create` command initializes a new Quartz project. It helps you set up your content folder, choose a configuration template, set your site's base URL, and configure how Quartz should handle your Markdown files.
## Flags
| Flag | Shorthand | Description |
| ------------- | --------- | --------------------------------------------------------------------- |
| `--template` | `-t` | Configuration template (`default`, `obsidian`, `ttrpg`, or `blog`) |
| `--directory` | `-d` | The directory where Quartz will be initialized |
| `--source` | `-s` | The source directory of your Markdown files |
| `--strategy` | `-X` | How to handle the source files (`new`, `copy`, or `symlink`) |
| `--links` | `-l` | How to resolve internal links (`absolute`, `shortest`, or `relative`) |
| `--baseUrl` | `-b` | Base URL for your site (e.g. `mysite.github.io/quartz`) |
| `--verbose` | `-v` | Enable detailed logging |
## Templates
When you run `quartz create`, you can choose a configuration template that pre-configures Quartz for your use case:
- **Default**: A clean Quartz setup with sensible defaults. Best for starting from scratch.
- **Obsidian**: Optimized for Obsidian vaults with full Obsidian Flavored Markdown support (wikilinks, callouts, mermaid diagrams, etc.). Automatically sets link resolution to `shortest` and skips the link resolution prompt.
- **TTRPG**: Builds on the Obsidian template with the addition of the [Leaflet map plugin](https://github.com/quartz-community/external-quartz-leaflet-map-plugin) and [ITS Theme](https://github.com/saberzero1/quartz-themes) (`its-theme.ttrpg-dnd`). Great for D&D and TTRPG wikis. Also skips the link resolution prompt.
- **Blog**: A blog-focused setup with [recent notes](https://github.com/quartz-community/recent-notes) enabled (showing the 5 most recent posts with tags) and [comments](https://github.com/quartz-community/comments) enabled via giscus. You'll need to fill in the `TODO:` placeholder values in `quartz.config.yaml` with your own giscus repository details.
## Base URL
During setup, Quartz will ask for the base URL of your site. This is the URL where your site will be deployed (e.g. `mysite.github.io/quartz`).
- Do **not** include the protocol (`https://`) — if you do, it will be automatically stripped.
- Trailing slashes are also removed automatically.
- See [[configuration]] for more details on how `baseUrl` is used.
## Strategies
When you run `quartz create`, you must choose a strategy for your content:
- **new**: Creates a fresh, empty content folder. Use this if you are starting a new project from scratch.
- **copy**: Copies all files from your source directory into the Quartz content folder. This is the safest option for existing vaults as it doesn't touch your original files.
- **symlink**: Creates a symbolic link from the Quartz content folder to your source directory. Any changes you make in your source directory (e.g. in Obsidian) will be immediately reflected in Quartz.
- **move**: Moves your files from the source directory into the Quartz content folder.
## Link Resolution
Quartz needs to know how to interpret the internal links in your Markdown files:
- **shortest**: Resolves links to the closest matching file name. This is the default for Obsidian.
- **absolute**: Resolves links relative to the root of your content folder.
- **relative**: Resolves links relative to the current file's location.
> [!note]
> When using the **Obsidian** or **TTRPG** templates, link resolution is automatically set to `shortest` and the prompt is skipped.
## Interactive Walkthrough
If you run `npx quartz create` without any arguments, it will guide you through an interactive setup:
1. **Choose a template**: Select a configuration template (`Default`, `Obsidian`, `TTRPG`, or `Blog`).
2. **Select a strategy**: Choose between `new`, `copy`, or `symlink`.
3. **Enter base URL**: Provide the URL where your site will be hosted.
4. **Select link resolution**: Choose how your links are formatted (skipped for Obsidian and TTRPG templates).
5. **Finish**: Quartz will set up the directory structure and create your configuration.
## Example: Importing an Obsidian Vault
To create a Quartz project that links directly to an existing Obsidian vault:
```shell
npx quartz create --template obsidian --strategy symlink --source ~/Documents/MyVault
```
This command tells Quartz to use the Obsidian template (with full OFM support and shortest link resolution), look at your vault in `~/Documents/MyVault`, and use symbolic links so changes are synced.
## Example: Setting Up a Blog
To quickly set up a blog with recent notes and comments:
```shell
npx quartz create --template blog --strategy new --baseUrl myblog.github.io
```
After setup, edit `quartz.config.yaml` to fill in your giscus repository details in the comments plugin section.

View File

@ -1,46 +0,0 @@
---
title: CLI Reference
---
The Quartz CLI is the primary way to interact with your Quartz project. It provides commands for creating new projects, building static sites, syncing with GitHub, and managing plugins.
You can run the CLI using `npx quartz`.
## Quick Reference
| Command | Description | Example |
| --------- | ------------------------------------------------------- | ------------------------ |
| `create` | Initialize a new Quartz project with template selection | `npx quartz create` |
| `build` | Generate static HTML files | `npx quartz build` |
| `sync` | Sync content with GitHub | `npx quartz sync` |
| `upgrade` | Upgrade Quartz to the latest version | `npx quartz upgrade` |
| `update` | Update installed plugins | `npx quartz update` |
| `plugin` | Manage Quartz plugins | `npx quartz plugin list` |
| `tui` | Launch the interactive plugin manager | `npx quartz tui` |
## Commands
- [[cli/create|create]]: Initialize a new Quartz project with a choice of templates (default, obsidian, ttrpg, blog) and base URL configuration.
- [[cli/build|build]]: Build your Quartz site into static HTML. Includes a development server.
- [[cli/sync|sync]]: Push and pull changes between your local machine and GitHub.
- [[cli/upgrade|upgrade]]: Upgrade the Quartz framework to the latest version.
- [[cli/update|update]]: Update installed plugins to their latest versions.
- [[cli/restore|restore]]: Recover your content folder from the local cache.
- [[cli/migrate|migrate]]: Convert older configuration files to the new YAML format.
- [[cli/plugin|plugin]]: Install, add, remove, prune, resolve, and configure plugins from the command line.
- [[cli/tui|tui]]: Use a terminal interface to manage plugins and layout.
## Help and Versioning
To see a full list of available flags for any command, use the `--help` flag.
```shell
npx quartz --help
npx quartz build --help
```
To check which version of Quartz you are currently running, use the `--version` flag.
```shell
npx quartz --version
```

View File

@ -1,32 +0,0 @@
---
title: quartz migrate
---
The `migrate` command helps you transition your project from Quartz 4 to Quartz v5 by converting your configuration files.
## When to Use
Use this command if you have an existing Quartz 4 project and want to upgrade to the new YAML-based configuration system introduced in v5.
## What it Does
When you run `npx quartz migrate`, the CLI performs several automated steps:
1. **Read Configuration**: It parses your existing `quartz.config.ts` and `quartz.layout.ts` files.
2. **Map Plugins**: It identifies the plugins you are using and maps them to their v5 equivalents.
3. **Generate YAML**: It creates a new `quartz.config.yaml` file that contains all your settings, theme colors, and plugin configurations.
4. **Backup**: It keeps your old `.ts` files so you can refer back to them if needed.
```shell
npx quartz migrate
```
## Verification
After running the migration, you should check the following:
- **Theme Colors**: Ensure your custom colors were correctly transferred to the `theme` section of `quartz.config.yaml`.
- **Plugin Options**: Verify that any custom options you passed to plugins (like `linkClickBehavior`) are present in the new config.
- **Layout**: Check that your component order in the `layout` section matches your previous setup.
For a comprehensive guide on the entire migration process, including manual steps, see [[getting-started/migrating]].

View File

@ -1,219 +0,0 @@
---
title: quartz plugin
---
The `plugin` command is the heart of the Quartz v5 plugin management system. it allows you to install, configure, and update plugins directly from the command line.
All plugins are stored in the `.quartz/plugins/` directory, and their versions are tracked in `quartz.lock.json`.
## Subcommands
### list
List all currently installed plugins and their versions.
```shell
npx quartz plugin list
```
### add
Add a new plugin from a Git repository.
```shell
npx quartz plugin add github:username/repo
```
To install from a specific branch or ref, append `#ref` to the source:
```shell
npx quartz plugin add github:username/repo#my-branch
npx quartz plugin add git+https://github.com/username/repo.git#my-branch
npx quartz plugin add https://github.com/username/repo.git#my-branch
```
You can also add a plugin from a local directory. This is useful for local development or airgapped environments:
```shell
npx quartz plugin add ./path/to/my-plugin
npx quartz plugin add ../sibling-plugin
npx quartz plugin add /absolute/path/to/plugin
```
Local plugins are symlinked into `.quartz/plugins/`, so any changes you make to the source directory are reflected immediately without re-installing.
When a branch is specified, it is stored in the lockfile. All subsequent commands (`install`, `update`, `restore`, `check`, `resolve`) will respect that branch automatically.
### remove
Remove an installed plugin.
```shell
npx quartz plugin remove plugin-name
```
### install
Install all plugins listed in your `quartz.lock.json` file. This is useful when setting up the project on a new machine.
```shell
npx quartz plugin install
```
### update
Update specific plugins or all plugins to their latest versions.
```shell
npx quartz plugin update plugin-name
npx quartz plugin update # updates all
```
### restore
Restore plugins to the exact versions specified in the lockfile. Unlike `install`, this will downgrade plugins if the lockfile specifies an older version. This is recommended for CI/CD environments.
```shell
npx quartz plugin restore
```
### enable / disable
Toggle a plugin's status in your `quartz.config.yaml` without removing its files.
```shell
npx quartz plugin enable plugin-name
npx quartz plugin disable plugin-name
```
### config
View or modify the configuration for a specific plugin.
```shell
# View config
npx quartz plugin config plugin-name
# Set a value
npx quartz plugin config plugin-name --set key=value
```
### check
Check if any of your installed plugins have updates available.
```shell
npx quartz plugin check
```
### prune
Remove installed plugins that are no longer referenced in your `quartz.config.yaml`. This is useful for cleaning up after removing plugin entries from your configuration.
```shell
npx quartz plugin prune
```
Use `--dry-run` to preview which plugins would be removed without making changes:
```shell
npx quartz plugin prune --dry-run
```
### resolve
Install plugins that are listed in your `quartz.config.yaml` but missing from the lockfile. This is the inverse of `prune` — it ensures your installed plugins match your configuration.
```shell
npx quartz plugin resolve
```
Use `--dry-run` to preview which plugins would be installed without making changes:
```shell
npx quartz plugin resolve --dry-run
```
## Common Workflows
### Adding and Enabling a Plugin
To add a new plugin and start using it:
1. Add the plugin: `npx quartz plugin add github:quartz-community/example`
2. Enable it: `npx quartz plugin enable example`
### Updating Everything
To keep your plugins fresh:
```shell
npx quartz plugin update
```
### Managing Configuration
If you want to change a plugin setting without opening the YAML file:
```shell
npx quartz plugin config explorer --set useSavedState=true
```
### Cleaning Up Unused Plugins
If you've removed plugins from your config and want to clean up leftover files:
```shell
npx quartz plugin prune --dry-run # preview first
npx quartz plugin prune # remove orphaned plugins
```
### Setting Up from Config
When setting up on a new machine or in CI, resolve any plugins referenced in your config that aren't yet installed:
```shell
npx quartz plugin resolve
```
### Testing with Branches
If a plugin author has a fix or feature on a separate branch, you can install it directly without waiting for a release to the default branch:
```shell
# Install from a feature branch
npx quartz plugin add github:username/repo#fix/some-bug
# Later, switch back to the default branch by re-adding without a ref
npx quartz plugin remove repo
npx quartz plugin add github:username/repo
```
The branch ref is tracked in `quartz.lock.json`, so `update` and `check` will continue to follow the specified branch until the plugin is re-added without one.
Both `prune` and `resolve` will fall back to `quartz.config.default.yaml` if no `quartz.config.yaml` is present.
### Local Plugin Development
For local plugin development or airgapped environments, you can add a plugin from a local directory:
```shell
npx quartz plugin add ./my-local-plugin
```
Local plugins are symlinked into `.quartz/plugins/`, so changes reflect immediately. When you run `update`, local plugins are rebuilt (npm install + npm run build) without any git operations. The `check` command will show local plugins with a "local" status instead of checking for remote updates.
To switch a local plugin back to a git source:
```shell
npx quartz plugin remove my-local-plugin
npx quartz plugin add github:username/my-local-plugin
```
## Interactive Mode
Running the plugin command without any subcommand will launch the [[cli/tui|TUI]], which provides a visual interface for all these operations.
```shell
npx quartz plugin
```

View File

@ -1,29 +0,0 @@
---
title: quartz restore
---
The `restore` command is a safety mechanism that allows you to recover your content folder from a local cache.
## When to Use
You should use `restore` if:
- A `quartz upgrade` failed and corrupted your content.
- You accidentally deleted files in your content folder.
- You encountered complex merge conflicts that you want to undo.
## How it Works
Quartz maintains a hidden cache of your content folder. Every time you run certain commands, Quartz ensures that a backup of your Markdown files exists. The `restore` command simply copies these files back into your main content directory.
```shell
npx quartz restore
```
## Example Workflow
If an update fails and leaves your project in a broken state:
1. **Restore**: Run `npx quartz restore` to bring back your content.
2. **Clean**: Use Git to reset any other broken code files.
3. **Retry**: Attempt the update again or manually apply the changes you need.

View File

@ -1,74 +0,0 @@
---
title: quartz sync
---
The `sync` command automates the process of pushing your local changes to GitHub and pulling updates from your remote repository. It simplifies the Git workflow for users who want to keep their site updated without running manual Git commands.
## Flags
| Flag | Shorthand | Description | Default |
| ------------- | --------- | ------------------------------------ | ----------------- |
| `--directory` | `-d` | The directory of your Quartz project | Current directory |
| `--verbose` | `-v` | Enable detailed logging | `false` |
| `--commit` | | Whether to commit changes | `true` |
| `--no-commit` | | Skip committing changes | `false` |
| `--message` | `-m` | Custom commit message | `update content` |
| `--push` | | Whether to push changes to remote | `true` |
| `--no-push` | | Skip pushing changes | `false` |
| `--pull` | | Whether to pull changes from remote | `true` |
| `--no-pull` | | Skip pulling changes | `false` |
## Workflow
When you run `npx quartz sync`, Quartz performs the following steps:
1. **Pull**: It fetches and merges changes from your remote GitHub repository.
2. **Add**: It stages all new and modified files in your project.
3. **Commit**: It creates a new commit with your changes.
4. **Push**: It sends your new commit to GitHub.
## Common Workflows
### Regular Sync
The most common usage is to simply run the command with no flags. This pulls, commits, and pushes everything.
```shell
npx quartz sync
```
### First Sync
If you have just set up a new repository and haven't pushed anything yet, you might want to skip the pull step.
```shell
npx quartz sync --no-pull
```
### Custom Commit Message
You can provide a more descriptive message for your changes.
```shell
npx quartz sync --message "add new notes about gardening"
```
### Sync from Another Device
If you are working on a different computer and just want to get the latest changes without pushing anything back yet.
```shell
npx quartz sync --no-push --no-commit
```
## Troubleshooting
### Git Buffer
If you have a very large number of changes, Git might occasionally fail due to buffer limits. If this happens, try syncing smaller batches of files or increasing your Git post buffer size.
### Autostash
Quartz uses `git pull --rebase --autostash` internally. This means if you have unstaged changes when you run `sync`, Quartz will temporarily hide them, pull the remote changes, and then bring your changes back. If a conflict occurs during this process, you will need to resolve it manually using standard Git tools.
For more information on initial setup, see [[getting-started/installation]].

View File

@ -1,64 +0,0 @@
---
title: quartz tui
---
The `tui` command launches an interactive terminal user interface for managing your Quartz project. It provides a visual way to manage plugins, arrange your site layout, and edit general settings.
## Prerequisites
To use the TUI, you must have the following:
1. **Bun**: The TUI requires the Bun runtime. You can find installation instructions at [bun.sh](https://bun.sh/docs/installation).
2. **TUI Plugin**: You must install the TUI plugin in your Quartz project.
### Installation
Run the following command to add the TUI plugin:
```shell
npx quartz plugin add github:quartz-community/tui
```
## Interface Panels
The TUI is divided into three main panels that you can navigate between.
### Plugins Panel
This panel allows you to browse all available and installed plugins. You can:
- Enable or disable plugins with a single keystroke.
- Configure plugin-specific settings.
- Install new plugins from the community or remove existing ones.
### Layout Panel
The Layout panel is where you define where components appear on your site. You can:
- Move components between different sections (e.g. `left`, `right`, `beforeBody`).
- Reorder components within a section to change their vertical stack.
- Set priorities for components to control their placement.
### Settings Panel
This panel provides a central place to edit your `quartz.config.yaml` settings. You can update:
- `pageTitle`
- Theme colors and fonts
- Analytics configuration
- Deployment settings
## Navigation
The TUI uses standard terminal navigation keys:
- **Arrow Keys**: Move between items and panels.
- **Enter**: Select an item or confirm a change.
- **Esc**: Go back or cancel an action.
- **Tab**: Cycle through different interface elements.
## Important Note
All changes made within the TUI are written directly to your `quartz.config.yaml` file. It is a good practice to have a clean Git state before using the TUI so you can easily review and undo any changes it makes.
For command-line based plugin management, see [[cli/plugin|quartz plugin]].

View File

@ -1,38 +0,0 @@
---
title: quartz update
---
The `update` command updates your installed plugins to their latest versions. It is a convenient shortcut for `npx quartz plugin update`.
## Usage
Update all installed plugins:
```shell
npx quartz update
```
Update specific plugins by name:
```shell
npx quartz update my-plugin another-plugin
```
## How it Works
For each plugin, `update` fetches the latest commit from the plugin's remote repository and rebuilds it. If a plugin was installed from a specific branch (e.g., `github:user/repo#my-branch`), updates will track that branch instead of the default branch. Local plugins (added from a file path) are rebuilt without any git operations. The lockfile (`quartz.lock.json`) is updated with the new commit hashes.
This is functionally identical to running:
```shell
npx quartz plugin update
```
## Flags
The `update` command supports the standard [[cli/index|common flags]] (`--directory`, `--verbose`).
## See Also
- [[cli/upgrade|quartz upgrade]] — upgrade the Quartz framework itself
- [[cli/plugin|quartz plugin]] — full plugin management (install, remove, enable, disable, etc.)

View File

@ -1,46 +0,0 @@
---
title: quartz upgrade
---
The `upgrade` command upgrades the Quartz framework itself to the latest version by pulling changes from the official Quartz repository.
## Usage
```shell
npx quartz upgrade
```
## How it Works
When you run `npx quartz upgrade`, Quartz performs the following steps:
1. **Backs up your content** — your content folder is cached locally to prevent data loss.
2. **Pulls the latest Quartz code** — fetches and merges from the official upstream repository (`upstream/v5`) using Git.
3. **Shows version changes** — displays the version transition (e.g., `v5.0.0 → v5.1.0`) or confirms you're already up to date.
4. **Updates dependencies** — runs `npm install` to ensure all packages match the new version.
5. **Restores plugins** — reinstalls plugins from `quartz.lock.json` to ensure compatibility.
6. **Checks plugin compatibility** — verifies that installed plugins are compatible with the new Quartz version.
## Handling Conflicts
Because Quartz allows you to customize almost every part of the code, upgrades can sometimes result in merge conflicts. This happens if you have modified a file that the Quartz team has also updated.
If a conflict occurs:
1. Git will mark the conflicting sections in the affected files.
2. You will need to open these files and manually choose which changes to keep.
3. After resolving the conflicts, you can commit the changes.
## Recovery
If an upgrade goes wrong or leaves your project in an unusable state, you can use the [[cli/restore|restore]] command to recover your content from the local cache.
## Flags
The `upgrade` command supports the standard [[cli/index|common flags]] (`--directory`, `--verbose`).
## See Also
- [[cli/update|quartz update]] — update installed plugins
- [[getting-started/upgrading|Upgrading Quartz]] — detailed upgrading guide
- [[cli/restore|quartz restore]] — recover content from cache

View File

@ -1,60 +0,0 @@
---
title: Community
---
Quartz has a vibrant community of users and contributors. This page highlights community-created plugins, tools, and resources that extend Quartz.
> [!tip] Contributing
> Know of a great community resource? Submit a pull request to add it to this page!
## Community Plugins
Third-party plugins that extend Quartz functionality. Install them with the [[cli/plugin|plugin CLI]]:
```bash
npx quartz plugin install <github-url>
```
<!-- Add community plugins here as they become available -->
<!-- Format: - **[Plugin Name](link)** — Brief description -->
_No community plugins listed yet. Be the first to share yours!_
## Tools & Integrations
Tools, scripts, and integrations built by the community to work with Quartz.
<!-- Add tools here -->
<!-- Format: - **[Tool Name](link)** — Brief description -->
_No community tools listed yet._
## Templates & Themes
Custom themes, CSS snippets, and starter templates for Quartz sites.
<!-- Add templates/themes here -->
<!-- Format: - **[Name](link)** — Brief description -->
_No community templates listed yet._
## Guides & Tutorials
Community-written guides, blog posts, and tutorials about using Quartz.
<!-- Add guides here -->
<!-- Format: - **[Title](link)** by Author — Brief description -->
_No community guides listed yet._
## Related Projects
Projects and tools in the digital garden / PKM ecosystem that pair well with Quartz.
- **[Obsidian](https://obsidian.md/)** — Knowledge base and note-taking app (recommended editor for Quartz content)
---
Looking to see sites built with Quartz? Check out the [[showcase|Quartz Showcase]].
Want to chat with other Quartz users? [Join the Discord community](https://discord.gg/cRFFHYye7t).

View File

@ -2,21 +2,18 @@
title: Configuration title: Configuration
--- ---
Quartz is meant to be extremely configurable, even if you don't know any coding. Most of the configuration you should need can be done by just editing `quartz.config.yaml`. Quartz is meant to be extremely configurable, even if you don't know any coding. Most of the configuration you should need can be done by just editing `quartz.config.ts` or changing [[layout|the layout]] in `quartz.layout.ts`.
> [!tip] > [!tip]
> If you edit `quartz.config.yaml` using a text-editor with YAML language support like VSCode, it will warn you when you've made an error in your configuration, helping you avoid configuration mistakes! > If you edit Quartz configuration using a text-editor that has TypeScript language support like VSCode, it will warn you when you you've made an error in your configuration, helping you avoid configuration mistakes!
The configuration of Quartz can be broken down into two main parts: The configuration of Quartz can be broken down into two main parts:
```yaml title="quartz.config.yaml" ```ts title="quartz.config.ts"
configuration: const config: QuartzConfig = {
pageTitle: "My Site" configuration: { ... },
# ... general configuration plugins: { ... },
plugins: }
- source: github:quartz-community/some-plugin
enabled: true
# ... plugin entries
``` ```
## General Configuration ## General Configuration
@ -42,9 +39,8 @@ This part of the configuration concerns anything that can affect the whole site.
- `{ provider: 'rybbit', siteId: 'my-rybbit-id' }` (managed) or `{ provider: 'rybbit', siteId: 'my-rybbit-id', host: 'my-rybbit-domain.com' }` (self-hosted) use [Rybbit](https://rybbit.com); - `{ provider: 'rybbit', siteId: 'my-rybbit-id' }` (managed) or `{ provider: 'rybbit', siteId: 'my-rybbit-id', host: 'my-rybbit-domain.com' }` (self-hosted) use [Rybbit](https://rybbit.com);
- `locale`: used for [[i18n]] and date formatting - `locale`: used for [[i18n]] and date formatting
- `baseUrl`: this is used for sitemaps and RSS feeds that require an absolute URL to know where the canonical 'home' of your site lives. This is normally the deployed URL of your site (e.g. `quartz.jzhao.xyz` for this site). Do not include the protocol (i.e. `https://`) or any leading or trailing slashes. - `baseUrl`: this is used for sitemaps and RSS feeds that require an absolute URL to know where the canonical 'home' of your site lives. This is normally the deployed URL of your site (e.g. `quartz.jzhao.xyz` for this site). Do not include the protocol (i.e. `https://`) or any leading or trailing slashes.
- You will be prompted to set this during [[cli/create|`npx quartz create`]]. The CLI automatically strips any `https://` or `http://` protocol prefixes and trailing slashes for you.
- This should also include the subpath if you are [[hosting]] on GitHub pages without a custom domain. For example, if my repository is `jackyzha0/quartz`, GitHub pages would deploy to `https://jackyzha0.github.io/quartz` and the `baseUrl` would be `jackyzha0.github.io/quartz`. - This should also include the subpath if you are [[hosting]] on GitHub pages without a custom domain. For example, if my repository is `jackyzha0/quartz`, GitHub pages would deploy to `https://jackyzha0.github.io/quartz` and the `baseUrl` would be `jackyzha0.github.io/quartz`.
- Note that Quartz 5 will avoid using this as much as possible and use relative URLs whenever it can to make sure your site works no matter _where_ you end up actually deploying it. - Note that Quartz 4 will avoid using this as much as possible and use relative URLs whenever it can to make sure your site works no matter _where_ you end up actually deploying it.
- `ignorePatterns`: a list of [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) patterns that Quartz should ignore and not search through when looking for files inside the `content` folder. See [[private pages]] for more details. - `ignorePatterns`: a list of [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) patterns that Quartz should ignore and not search through when looking for files inside the `content` folder. See [[private pages]] for more details.
- `defaultDateType`: whether to use created, modified, or published as the default date to display on pages and page listings. - `defaultDateType`: whether to use created, modified, or published as the default date to display on pages and page listings.
- `theme`: configure how the site looks. - `theme`: configure how the site looks.
@ -71,124 +67,47 @@ You can think of Quartz plugins as a series of transformations over content.
![[quartz transform pipeline.png]] ![[quartz transform pipeline.png]]
```yaml title="quartz.config.yaml" ```ts title="quartz.config.ts"
plugins: plugins: {
- source: github:quartz-community/created-modified-date transformers: [...],
enabled: true filters: [...],
order: 10 # controls execution order emitters: [...],
- source: github:quartz-community/syntax-highlighting }
enabled: true
order: 20
# ... more plugins
``` ```
Plugins are categorized by their type (transformer, filter, emitter, pageType) based on their manifest. The `order` field controls execution order within each category.
> [!note]
> For advanced TS override of plugin configuration, you can modify `quartz.ts`:
>
> ```ts title="quartz.ts"
> import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
>
> const config = await loadQuartzConfig({
> // override any configuration field here
> })
> export default config
> export const layout = await loadQuartzLayout()
> ```
- [[tags/plugin/transformer|Transformers]] **map** over content (e.g. parsing frontmatter, generating a description) - [[tags/plugin/transformer|Transformers]] **map** over content (e.g. parsing frontmatter, generating a description)
- [[tags/plugin/filter|Filters]] **filter** content (e.g. filtering out drafts) - [[tags/plugin/filter|Filters]] **filter** content (e.g. filtering out drafts)
- [[tags/plugin/emitter|Emitters]] **reduce** over content (e.g. creating an RSS feed or pages that list all files with a specific tag) - [[tags/plugin/emitter|Emitters]] **reduce** over content (e.g. creating an RSS feed or pages that list all files with a specific tag)
- **Page Types** define how different types of pages are rendered (content pages, folder listings, tag listings). Each page type can use a different [[layout#Page Frames|page frame]] to control its overall HTML structure.
The `layout.byPageType` section in `quartz.config.yaml` can also set a `template` field to override the page frame for a specific page type: You can customize the behaviour of Quartz by adding, removing and reordering plugins in the `transformers`, `filters` and `emitters` fields.
```yaml title="quartz.config.yaml"
layout:
byPageType:
canvas:
template: minimal # Override the page frame for canvas pages
```
See [[layout#Page Frames]] for details on available frames and how frame resolution works.
### Internal vs External Plugins
Quartz distinguishes between internal plugins that are bundled with Quartz and community plugins that are installed separately.
In `quartz.config.yaml`, community plugins are referenced by their GitHub source:
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/explorer
enabled: true
- source: github:quartz-community/syntax-highlighting
enabled: true
options:
theme:
light: github-light
dark: github-dark
```
Internal plugins (like `FrontMatter`) are bundled with Quartz. Community plugins are installed separately and referenced by their `github:org/repo` source.
### Community Plugins
To install a community plugin, you can use the following command:
```shell
npx quartz plugin add github:quartz-community/explorer
```
This adds the plugin to `quartz.config.yaml` and installs it to `.quartz/plugins/`.
To install all plugins referenced in your config that aren't yet installed (useful when cloning a project or setting up CI):
```shell
npx quartz plugin resolve
```
To remove installed plugins that are no longer in your config:
```shell
npx quartz plugin prune
```
Both commands support `--dry-run` to preview changes. See [[cli/plugin|the plugin CLI reference]] for full details.
### Usage
You can customize the behaviour of Quartz by adding, removing and reordering plugins in `quartz.config.yaml`. Each plugin entry specifies its source, whether it's enabled, execution order, and any options:
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/note-properties
enabled: true
options:
includeAll: false
includedProperties:
- description
- tags
- aliases
order: 5
- source: github:quartz-community/created-modified-date
enabled: true
options:
priority:
- frontmatter
- git
- filesystem
order: 10
- source: github:quartz-community/latex
enabled: true
options:
renderEngine: katex
order: 80
```
> [!note] > [!note]
> For advanced options that require JavaScript (e.g. callback functions), use the TS override in `quartz.ts`. See the plugin-specific documentation for details. > Each node is modified by every transformer _in order_. Some transformers are position sensitive, so you may need to pay particular attention to whether they need to come before or after certain other plugins.
You should take care to add the plugin to the right entry corresponding to its plugin type. For example, to add the [[ExplicitPublish]] plugin (a [[tags/plugin/filter|Filter]]), you would add the following line:
```ts title="quartz.config.ts"
filters: [
...
Plugin.ExplicitPublish(),
...
],
```
To remove a plugin, you should remove all occurrences of it in the `quartz.config.ts`.
To customize plugins further, some plugins may also have their own configuration settings that you can pass in. If you do not pass in a configuration, the plugin will use its default settings.
For example, the [[plugins/Latex|Latex]] plugin allows you to pass in a field specifying the `renderEngine` to choose between Katex and MathJax.
```ts title="quartz.config.ts"
transformers: [
Plugin.FrontMatter(), // use default options
Plugin.Latex({ renderEngine: "katex" }), // set some custom options
]
```
Some plugins are included by default in the [`quartz.config.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz.config.ts), but there are more available.
You can see a list of all plugins and their configuration options [[tags/plugin|here]]. You can see a list of all plugins and their configuration options [[tags/plugin|here]].
@ -196,35 +115,22 @@ If you'd like to make your own plugins, see the [[making plugins|making custom p
## Fonts ## Fonts
Fonts can be specified as a simple string or with advanced options in `quartz.config.yaml`: Fonts can be specified as a `string` or a `FontSpecification`:
```yaml title="quartz.config.yaml" ```ts
configuration: // string
theme: typography: {
typography: header: "Schibsted Grotesk",
header: Schibsted Grotesk ...
body: Source Sans Pro }
code: IBM Plex Mono
```
For more control over font weights and italics, use the TS override in `quartz.ts`: // FontSpecification
```ts title="quartz.ts"
import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
const config = await loadQuartzConfig({
theme: {
typography: { typography: {
header: { header: {
name: "Schibsted Grotesk", name: "Schibsted Grotesk",
weights: [400, 700], weights: [400, 700],
includeItalic: true, includeItalic: true,
}, },
body: "Source Sans Pro", ...
code: "IBM Plex Mono", }
},
},
})
export default config
export const layout = await loadQuartzLayout()
``` ```

View File

@ -1,21 +0,0 @@
---
title: Bases Support
tags:
- component
---
Quartz supports rendering [Obsidian Bases](https://obsidian.md/changelog/2025-04-15-desktop-v1.8.0/) (`.base` files) as interactive database-like views. Bases files define queries over your vault's notes and display the results in configurable views such as tables, lists, cards, galleries, and boards.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
Bases support is provided by the [[BasesPage]] plugin. See the plugin page for configuration options, built-in views, the expression engine, and how to extend with custom views.
## Demo
![[Base.base]]
## Customization
- Install: `npx quartz plugin add github:quartz-community/bases-page`
- Source: [`quartz-community/bases-page`](https://github.com/quartz-community/bases-page)

View File

@ -1,21 +0,0 @@
---
title: Canvas Support
tags:
- component
---
Quartz supports rendering [JSON Canvas](https://jsoncanvas.org) (`.canvas`) files as interactive, pannable and zoomable canvas pages. This brings your Obsidian canvas files to the web, preserving text nodes, file references, link nodes, group nodes, and edges with full visual fidelity.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
Canvas support is provided by the [[CanvasPage]] plugin. See the plugin page for configuration options and a full list of supported features.
## Demo
![[Canvas.canvas]]
## Customization
- Install: `npx quartz plugin add github:quartz-community/canvas-page`
- Source: [`quartz-community/canvas-page`](https://github.com/quartz-community/canvas-page)

View File

@ -1,9 +1,3 @@
---
title: "Docker Support"
tags:
- feature
---
Quartz comes shipped with a Docker image that will allow you to preview your Quartz locally without installing Node. Quartz comes shipped with a Docker image that will allow you to preview your Quartz locally without installing Node.
You can run the below one-liner to run Quartz in Docker. You can run the below one-liner to run Quartz in Docker.

View File

@ -70,9 +70,10 @@ For example:
### Using mhchem ### Using mhchem
If you are using the community Latex plugin, you can add `mhchem` support by forking the plugin repository and adding the following import to the top of `src/index.ts` (before all the other imports): Add the following import to the top of `quartz/plugins/transformers/latex.ts` (before all the other
imports):
```ts title="src/index.ts" ```ts title="quartz/plugins/transformers/latex.ts"
import "katex/contrib/mhchem" import "katex/contrib/mhchem"
``` ```

View File

@ -12,188 +12,6 @@ It also ships with support for [frontmatter parsing](https://help.obsidian.md/Ed
Finally, Quartz also provides [[CrawlLinks]] plugin, which allows you to customize Quartz's link resolution behaviour to match Obsidian. Finally, Quartz also provides [[CrawlLinks]] plugin, which allows you to customize Quartz's link resolution behaviour to match Obsidian.
## Supported Features
### Wikilinks
Internal links using the `[[page]]` syntax are converted to regular links. See [[wikilinks]] for more details. All variations are supported:
```markdown
[[Page]] Link to a page
[[Page|Custom text]] Link with alias
[[Page#Heading]] Link to a heading
[[Page#Heading|Custom text]] Link to a heading with alias
[[Page#^block-id]] Link to a block reference
![[Page]] Embed (transclude) a page
![[image.png]] Embed an image
![[image.png|alt 100x200]] Embed with alt text and dimensions
```
Inside tables, pipes in wikilinks can be escaped with a backslash:
```markdown
| Column |
| --------------- |
| [[page\|alias]] |
```
### Highlights
Wrap text in `==` to highlight it:
```markdown
This is ==highlighted text== in a sentence.
```
This renders as: This is ==highlighted text== in a sentence.
### Comments
Obsidian-style comments are stripped from the output:
```markdown
This is visible. %%This is a comment and won't appear.%%
```
This renders as: This is visible. %%This is a comment and won't appear.%%
Multi-line comments are also supported:
```markdown
%%
This entire block
is a comment.
%%
```
### Tags
Tags starting with `#` are parsed and linked to tag pages:
```markdown
#tag #nested/tag #tag-with-dashes
```
For example: #feature/transformer
> [!note]
> Pure numeric tags like `#123` are ignored, matching Obsidian behaviour.
### Callouts
[[callouts|Obsidian callouts]] are fully supported, including collapsible variants:
```markdown
> [!note]
> This is a note callout.
> [!warning]- Collapsed by default
> This content is hidden initially.
> [!tip]+ Expanded by default
> This content is visible initially.
```
> [!example] Live example
> This is a live callout rendered from Obsidian-flavored Markdown.
All built-in callout types are supported: `note`, `abstract`, `info`, `todo`, `tip`, `success`, `question`, `warning`, `failure`, `danger`, `bug`, `example`, and `quote`, along with their aliases.
### Task Lists and Custom Task Characters
Standard checkboxes work out of the box. With `enableCheckbox: true`, you also get support for custom task characters that are popular in the Obsidian community:
```markdown
- [ ] Unchecked
- [x] Checked
- [?] Question
- [!] Important
- [>] Forwarded
- [/] In progress
- [-] Cancelled
- [s] Special
```
Each custom character is preserved as a `data-task` attribute on the rendered element, allowing CSS-based styling per character.
- [ ] Unchecked
- [x] Checked
- [?] Question
- [!] Important
### Mermaid Diagrams
[[Mermaid diagrams|Mermaid]] code blocks are rendered as diagrams:
````markdown
```mermaid
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[OK]
B -->|No| D[Cancel]
```
````
```mermaid
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[OK]
B -->|No| D[Cancel]
```
### YouTube Embeds
YouTube videos can be embedded using standard image syntax with a YouTube URL:
```markdown
![](https://youtu.be/v5LGaczJaf0)
![](https://www.youtube.com/watch?v=v5LGaczJaf0)
```
For example, the following embed is rendered from `![](https://youtu.be/v5LGaczJaf0)`:
![](https://youtu.be/v5LGaczJaf0)
### Tweet Embeds
Tweets from Twitter/X are embedded as static blockquotes with a link to the original:
```markdown
![](https://x.com/kepano/status/1882142872826442145)
![](https://twitter.com/kepano/status/1882142872826442145)
```
For example, the following embed is rendered from `![](https://x.com/kepano/status/1882142872826442145)`:
![](https://x.com/kepano/status/1882142872826442145)
### Block References
Block references allow linking to specific blocks within a page:
```markdown
Content paragraph. ^my-block
[[Page#^my-block]]
```
### Obsidian URI Links
Links using the `obsidian://` protocol are marked with a CSS class (`obsidian-uri`) and a `data-obsidian-uri` attribute, so you can style them differently from regular links.
### Video Embeds
Video files can be embedded using standard image syntax:
```markdown
![](video.mp4)
![](video.webm)
```
### Embed in HTML
By default, Obsidian does not render its Markdown syntax inside HTML blocks. Quartz extends this with the `enableInHtmlEmbed` option, which parses wikilinks, highlights, and tags inside raw HTML nodes.
## Configuration ## Configuration
This functionality is provided by the [[ObsidianFlavoredMarkdown]], [[Frontmatter]] and [[CrawlLinks]] plugins. See the plugin pages for customization options. This functionality is provided by the [[ObsidianFlavoredMarkdown]], [[Frontmatter]] and [[CrawlLinks]] plugins. See the plugin pages for customization options.

View File

@ -8,42 +8,18 @@ tags:
Because the Markdown generated by ox-hugo is not pure Markdown but Hugo specific, we need to transform it to fit into Quartz. This is done by the [[OxHugoFlavoredMarkdown]] plugin. Even though this plugin was written with `ox-hugo` in mind, it should work for any Hugo specific Markdown. Because the Markdown generated by ox-hugo is not pure Markdown but Hugo specific, we need to transform it to fit into Quartz. This is done by the [[OxHugoFlavoredMarkdown]] plugin. Even though this plugin was written with `ox-hugo` in mind, it should work for any Hugo specific Markdown.
```yaml title="quartz.config.yaml" ```typescript title="quartz.config.ts"
plugins:
- source: github:quartz-community/obsidian-flavored-markdown
enabled: true
order: 30
- source: github:quartz-community/ox-hugo
enabled: true
order: 25 # must come before obsidian-flavored-markdown
- source: github:quartz-community/github-flavored-markdown
enabled: true
order: 40
- source: github:quartz-community/note-properties
enabled: true
options:
delimiters: "+++"
language: toml # if using toml frontmatter
order: 5
```
For the TS override approach:
```ts title="quartz.ts (override)"
plugins: { plugins: {
transformers: [ transformers: [
ExternalPlugin.FrontMatter({ delims: "+++", language: "toml" }), Plugin.FrontMatter({ delims: "+++", language: "toml" }), // if toml frontmatter
// ... // ...
ExternalPlugin.OxHugoFlavouredMarkdown(), Plugin.OxHugoFlavouredMarkdown(),
ExternalPlugin.GitHubFlavoredMarkdown(), Plugin.GitHubFlavoredMarkdown(),
// ... // ...
], ],
} },
``` ```
> [!note]
> In YAML, plugin execution order is controlled by the `order` field. Lower numbers execute first. Ensure `ox-hugo` has a lower `order` than `obsidian-flavored-markdown`.
## Usage ## Usage
Quartz by default doesn't understand `org-roam` files as they aren't Markdown. You're responsible for using an external tool like `ox-hugo` to export the `org-roam` files as Markdown content to Quartz and managing the static assets so that they're available in the final output. Quartz by default doesn't understand `org-roam` files as they aren't Markdown. You're responsible for using an external tool like `ox-hugo` to export the `org-roam` files as Markdown content to Quartz and managing the static assets so that they're available in the final output.

View File

@ -9,31 +9,19 @@ tags:
Quartz supports transforming the special Markdown syntax from Roam Research (like `{{[[components]]}}` and other formatting) into Quartz supports transforming the special Markdown syntax from Roam Research (like `{{[[components]]}}` and other formatting) into
regular Markdown via the [[RoamFlavoredMarkdown]] plugin. regular Markdown via the [[RoamFlavoredMarkdown]] plugin.
```yaml title="quartz.config.yaml" ```typescript title="quartz.config.ts"
plugins:
- source: github:quartz-community/roam
enabled: true
order: 25 # must come before obsidian-flavored-markdown
- source: github:quartz-community/obsidian-flavored-markdown
enabled: true
order: 30
```
For the TS override approach:
```ts title="quartz.ts (override)"
plugins: { plugins: {
transformers: [ transformers: [
// ... // ...
ExternalPlugin.RoamFlavoredMarkdown(), Plugin.RoamFlavoredMarkdown(),
ExternalPlugin.ObsidianFlavoredMarkdown(), Plugin.ObsidianFlavoredMarkdown(),
// ... // ...
], ],
} },
``` ```
> [!warning] > [!warning]
> In YAML, plugin execution order is controlled by the `order` field. Ensure `roam` has a lower `order` value than `obsidian-flavored-markdown` so it runs first. > As seen above placement of `Plugin.RoamFlavoredMarkdown()` within `quartz.config.ts` is very important. It must come before `Plugin.ObsidianFlavoredMarkdown()`.
## Customization ## Customization

View File

@ -1,13 +1,7 @@
---
title: "SPA Routing"
tags:
- feature
---
Single-page-app style rendering. This prevents flashes of unstyled content and improves the smoothness of Quartz. Single-page-app style rendering. This prevents flashes of unstyled content and improves the smoothness of Quartz.
Under the hood, this is done by hijacking page navigations and instead fetching the HTML via a `GET` request and then diffing and selectively replacing parts of the page using [micromorph](https://github.com/natemoo-re/micromorph). This allows us to change the content of the page without fully refreshing the page, reducing the amount of content that the browser needs to load. Under the hood, this is done by hijacking page navigations and instead fetching the HTML via a `GET` request and then diffing and selectively replacing parts of the page using [micromorph](https://github.com/natemoo-re/micromorph). This allows us to change the content of the page without fully refreshing the page, reducing the amount of content that the browser needs to load.
## Configuration ## Configuration
- Disable SPA Routing: set the `enableSPA` field of the [[configuration]] in `quartz.config.yaml` to be `false`. - Disable SPA Routing: set the `enableSPA` field of the [[configuration]] in `quartz.config.ts` to be `false`.

View File

@ -6,12 +6,10 @@ tags:
A backlink for a note is a link from another note to that note. Links in the backlink pane also feature rich [[popover previews]] if you have that feature enabled. A backlink for a note is a link from another note to that note. Links in the backlink pane also feature rich [[popover previews]] if you have that feature enabled.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Customization ## Customization
- Removing backlinks: remove the `backlinks` entry from `quartz.config.yaml` or set `enabled: false`. - Removing backlinks: delete all usages of `Component.Backlinks()` from `quartz.layout.ts`.
- Hide when empty: hide `Backlinks` if given page doesn't contain any backlinks (default to `true`). To disable this, set `hideWhenEmpty: false` in the plugin options in `quartz.config.yaml`. - Hide when empty: hide `Backlinks` if given page doesn't contain any backlinks (default to `true`). To disable this, use `Component.Backlinks({ hideWhenEmpty: false })`.
- Install: `npx quartz plugin add github:quartz-community/backlinks` - Component: `quartz/components/Backlinks.tsx`
- Source: [`quartz-community/backlinks`](https://github.com/quartz-community/backlinks) - Style: `quartz/components/styles/backlinks.scss`
- Script: `quartz/components/scripts/search.inline.ts`

View File

@ -8,46 +8,28 @@ Breadcrumbs provide a way to navigate a hierarchy of pages within your site usin
By default, the element at the very top of your page is the breadcrumb navigation bar (can also be seen at the top on this page!). By default, the element at the very top of your page is the breadcrumb navigation bar (can also be seen at the top on this page!).
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Customization ## Customization
Most configuration can be done via the `options` section of the breadcrumbs plugin entry in `quartz.config.yaml`. Most configuration can be done by passing in options to `Component.Breadcrumbs()`.
For example, here's what the default configuration looks like: For example, here's what the default configuration looks like:
```yaml title="quartz.config.yaml" ```typescript title="quartz.layout.ts"
plugins: Component.Breadcrumbs({
- source: github:quartz-community/breadcrumbs spacerSymbol: "", // symbol between crumbs
enabled: true rootName: "Home", // name of first/root element
options: resolveFrontmatterTitle: true, // whether to resolve folder names through frontmatter titles
spacerSymbol: "" showCurrentPage: true, // whether to display the current page in the breadcrumbs
rootName: Home
resolveFrontmatterTitle: true
showCurrentPage: true
layout:
position: beforeBody
priority: 5
```
For the TS override approach:
```ts title="quartz.ts (override)"
ExternalPlugin.Breadcrumbs({
spacerSymbol: "",
rootName: "Home",
resolveFrontmatterTitle: true,
showCurrentPage: true,
}) })
``` ```
When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field. When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field.
You can also adjust where the breadcrumbs will be displayed by changing the `layout.position` field in the plugin entry in `quartz.config.yaml` (see [[layout]]). You can also adjust where the breadcrumbs will be displayed by adjusting the [[layout]] (moving `Component.Breadcrumbs()` up or down)
Want to customize it even more? Want to customize it even more?
- Removing breadcrumbs: remove the `breadcrumbs` entry from `quartz.config.yaml` or set `enabled: false`. - Removing breadcrumbs: delete all usages of `Component.Breadcrumbs()` from `quartz.layout.ts`.
- Install: `npx quartz plugin add github:quartz-community/breadcrumbs` - Component: `quartz/components/Breadcrumbs.tsx`
- Source: [`quartz-community/breadcrumbs`](https://github.com/quartz-community/breadcrumbs) - Style: `quartz/components/styles/breadcrumbs.scss`
- Script: inline at `quartz/components/Breadcrumbs.tsx`

View File

@ -6,9 +6,6 @@ tags:
Quartz also has the ability to hook into various providers to enable readers to leave comments on your site. Quartz also has the ability to hook into various providers to enable readers to leave comments on your site.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
![[giscus-example.png]] ![[giscus-example.png]]
As of today, only [Giscus](https://giscus.app/) is supported out of the box but PRs to support other providers are welcome! As of today, only [Giscus](https://giscus.app/) is supported out of the box but PRs to support other providers are welcome!
@ -33,54 +30,28 @@ After entering both your repository and selecting the discussion category, Giscu
![[giscus-results.png]] ![[giscus-results.png]]
Finally, in `quartz.config.yaml`, add the comments plugin with the following options (using the values you got from above): Finally, in `quartz.layout.ts`, edit the `afterBody` field of `sharedPageComponents` to include the following options but with the values you got from above:
```yaml title="quartz.config.yaml" ```ts title="quartz.layout.ts"
plugins:
- source: github:quartz-community/comments
enabled: true
options:
provider: giscus
options:
repo: jackyzha0/quartz
repoId: MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg
category: Announcements
categoryId: DIC_kwDOFxRnmM4B-Xg6
lang: en
layout:
position: afterBody
priority: 10
```
For the TS override approach:
```ts title="quartz.ts (override)"
// If using quartz.ts overrides instead of YAML:
import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
const config = await loadQuartzConfig()
export default config
export const layout = await loadQuartzLayout({
defaults: {
afterBody: [ afterBody: [
ExternalPlugin.Comments({ Component.Comments({
provider: "giscus", provider: 'giscus',
options: { options: {
repo: "jackyzha0/quartz", // from data-repo
repoId: "MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg", repo: 'jackyzha0/quartz',
category: "Announcements", // from data-repo-id
categoryId: "DIC_kwDOFxRnmM4B-Xg6", repoId: 'MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg',
lang: "en", // from data-category
}, category: 'Announcements',
// from data-category-id
categoryId: 'DIC_kwDOFxRnmM4B-Xg6',
// from data-lang
lang: 'en'
}
}), }),
], ],
},
})
``` ```
> [!note]
> Install the comments plugin first: `npx quartz plugin add github:quartz-community/comments`
### Customization ### Customization
Quartz also exposes a few of the other Giscus options as well and you can provide them the same way `repo`, `repoId`, `category`, and `categoryId` are provided. Quartz also exposes a few of the other Giscus options as well and you can provide them the same way `repo`, `repoId`, `category`, and `categoryId` are provided.
@ -135,39 +106,19 @@ Quartz supports custom theme for Giscus. To use a custom CSS theme, place the `.
For example, if you have a light theme `light-theme.css`, a dark theme `dark-theme.css`, and your Quartz site is hosted at `https://example.com/`: For example, if you have a light theme `light-theme.css`, a dark theme `dark-theme.css`, and your Quartz site is hosted at `https://example.com/`:
```yaml title="quartz.config.yaml" ```ts
plugins:
- source: github:quartz-community/comments
enabled: true
options:
provider: giscus
options:
# Other options...
themeUrl: "https://example.com/static/giscus" # corresponds to quartz/static/giscus/
lightTheme: light-theme # corresponds to light-theme.css in quartz/static/giscus/
darkTheme: dark-theme # corresponds to dark-theme.css in quartz/static/giscus/
```
```ts title="quartz.ts (override)"
import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
const config = await loadQuartzConfig()
export default config
export const layout = await loadQuartzLayout({
defaults: {
afterBody: [ afterBody: [
ExternalPlugin.Comments({ Component.Comments({
provider: "giscus", provider: 'giscus',
options: { options: {
// Other options... // Other options
themeUrl: "https://example.com/static/giscus",
lightTheme: "light-theme", themeUrl: "https://example.com/static/giscus", // corresponds to quartz/static/giscus/
darkTheme: "dark-theme", lightTheme: "light-theme", // corresponds to light-theme.css in quartz/static/giscus/
}, darkTheme: "dark-theme", // corresponds to dark-theme.css quartz/static/giscus/
}
}), }),
], ],
},
})
``` ```
#### Conditionally display comments #### Conditionally display comments

View File

@ -6,14 +6,12 @@ tags:
Quartz supports darkmode out of the box that respects the user's theme preference. Any future manual toggles of the darkmode switch will be saved in the browser's local storage so it can be persisted across future page loads. Quartz supports darkmode out of the box that respects the user's theme preference. Any future manual toggles of the darkmode switch will be saved in the browser's local storage so it can be persisted across future page loads.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Customization ## Customization
- Removing darkmode: remove the `darkmode` entry from `quartz.config.yaml` or set `enabled: false`. - Removing darkmode: delete all usages of `Component.Darkmode()` from `quartz.layout.ts`.
- Install: `npx quartz plugin add github:quartz-community/darkmode` - Component: `quartz/components/Darkmode.tsx`
- Source: [`quartz-community/darkmode`](https://github.com/quartz-community/darkmode) - Style: `quartz/components/styles/darkmode.scss`
- Script: `quartz/components/scripts/darkmode.inline.ts`
You can also listen to the `themechange` event to perform any custom logic when the theme changes. You can also listen to the `themechange` event to perform any custom logic when the theme changes.

View File

@ -6,30 +6,6 @@ tags:
Quartz features an explorer that allows you to navigate all files and folders on your site. It supports nested folders and is highly customizable. Quartz features an explorer that allows you to navigate all files and folders on your site. It supports nested folders and is highly customizable.
> [!info]
> The Explorer is now a community plugin. This demonstrates how external plugins can extend Quartz functionality while serving as a reference implementation for plugin developers.
## Installation
The Explorer is available as a community plugin from GitHub:
```bash
npm install github:quartz-community/explorer --legacy-peer-deps
```
Then add it to your `quartz.config.yaml`:
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/explorer
enabled: true
layout:
position: left
priority: 50
```
## Features
By default, it shows all folders and files on your page. To display the explorer in a different spot, you can edit the [[layout]]. By default, it shows all folders and files on your page. To display the explorer in a different spot, you can edit the [[layout]].
Display names for folders get determined by the `title` frontmatter field in `folder/index.md` (more detail in [[authoring content | Authoring Content]]). If this file does not exist or does not contain frontmatter, the local folder name will be used instead. Display names for folders get determined by the `title` frontmatter field in `folder/index.md` (more detail in [[authoring content | Authoring Content]]). If this file does not exist or does not contain frontmatter, the local folder name will be used instead.
@ -41,63 +17,42 @@ Display names for folders get determined by the `title` frontmatter field in `fo
## Customization ## Customization
Most configuration can be done by passing in options to `Explorer()`. Most configuration can be done by passing in options to `Component.Explorer()`.
For example, here's what the default configuration looks like: For example, here's what the default configuration looks like:
```yaml title="quartz.config.yaml" ```typescript title="quartz.layout.ts"
plugins: Component.Explorer({
- source: github:quartz-community/explorer title: "Explorer", // title of the explorer component
enabled: true folderClickBehavior: "collapse", // what happens when you click a folder ("link" to navigate to folder page on click or "collapse" to collapse folder on click)
options: folderDefaultState: "collapsed", // default state of folders ("collapsed" or "open")
title: Explorer useSavedState: true, // whether to use local storage to save "state" (which folders are opened) of explorer
folderClickBehavior: collapse # "link" to navigate or "collapse" to toggle // omitted but shown later
folderDefaultState: collapsed # "collapsed" or "open" sortFn: ...,
useSavedState: true filterFn: ...,
layout: mapFn: ...,
position: left // what order to apply functions in
priority: 50
```
For advanced options like custom sort, filter, and map functions, use the TS override in `quartz.ts`:
```ts title="quartz.ts"
import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
import { Explorer } from "@quartz-community/explorer"
// Advanced: pass callback functions that can't be expressed in YAML
Explorer({
sortFn: (a, b) => {
/* ... */
},
filterFn: (node) => {
/* ... */
},
mapFn: (node) => {
/* ... */
},
order: ["filter", "map", "sort"], order: ["filter", "map", "sort"],
}) })
const config = await loadQuartzConfig()
export default config
export const layout = await loadQuartzLayout()
``` ```
When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field. When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field.
Want to customize it even more? Want to customize it even more?
- Removing explorer: remove the `explorer` entry from `quartz.config.yaml` or set `enabled: false` - Removing explorer: remove `Component.Explorer()` from `quartz.layout.ts`
- (optional): After removing the explorer component, you can move the [[table of contents | Table of Contents]] component back to the `left` part of the layout - (optional): After removing the explorer component, you can move the [[table of contents | Table of Contents]] component back to the `left` part of the layout
- Changing `sort`, `filter` and `map` behavior: explained in [[#Advanced customization]] - Changing `sort`, `filter` and `map` behavior: explained in [[#Advanced customization]]
- Component: `quartz/components/Explorer.tsx`
- Style: `quartz/components/styles/explorer.scss`
- Script: `quartz/components/scripts/explorer.inline.ts`
## Advanced customization ## Advanced customization
This component allows you to fully customize all of its behavior. You can pass a custom `sort`, `filter` and `map` function. This component allows you to fully customize all of its behavior. You can pass a custom `sort`, `filter` and `map` function.
All functions you can pass work with the `FileTrieNode` class, which has the following properties: All functions you can pass work with the `FileTrieNode` class, which has the following properties:
```ts title="@quartz-community/explorer" ```ts title="quartz/components/Explorer.tsx"
class FileTrieNode { class FileTrieNode {
isFolder: boolean isFolder: boolean
children: Array<FileTrieNode> children: Array<FileTrieNode>
@ -105,7 +60,7 @@ class FileTrieNode {
} }
``` ```
```ts ```ts title="quartz/plugins/emitters/contentIndex.tsx"
export type ContentDetails = { export type ContentDetails = {
slug: FullSlug slug: FullSlug
title: string title: string
@ -119,7 +74,7 @@ Every function you can pass is optional. By default, only a `sort` function will
```ts title="Default sort function" ```ts title="Default sort function"
// Sort order: folders first, then files. Sort folders and files alphabetically // Sort order: folders first, then files. Sort folders and files alphabetically
Explorer({ Component.Explorer({
sortFn: (a, b) => { sortFn: (a, b) => {
if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) { if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) {
return a.displayName.localeCompare(b.displayName, undefined, { return a.displayName.localeCompare(b.displayName, undefined, {
@ -159,20 +114,8 @@ These examples show the basic usage of `sort`, `map` and `filter`.
Using this example, the explorer will alphabetically sort everything. Using this example, the explorer will alphabetically sort everything.
```yaml title="quartz.config.yaml" ```ts title="quartz.layout.ts"
plugins: Component.Explorer({
- source: github:quartz-community/explorer
enabled: true
options:
# Simple options go in YAML
title: Explorer
folderDefaultState: collapsed
```
Custom sort functions require the TS override:
```ts title="quartz.ts (override)"
Explorer({
sortFn: (a, b) => { sortFn: (a, b) => {
return a.displayName.localeCompare(b.displayName) return a.displayName.localeCompare(b.displayName)
}, },
@ -183,8 +126,8 @@ Explorer({
Using this example, the display names of all `FileNodes` (folders + files) will be converted to full upper case. Using this example, the display names of all `FileNodes` (folders + files) will be converted to full upper case.
```ts title="quartz.ts (override)" ```ts title="quartz.layout.ts"
Explorer({ Component.Explorer({
mapFn: (node) => { mapFn: (node) => {
node.displayName = node.displayName.toUpperCase() node.displayName = node.displayName.toUpperCase()
return node return node
@ -192,16 +135,13 @@ Explorer({
}) })
``` ```
> [!note]
> The `mapFn`, `filterFn`, and `sortFn` options require JavaScript callback functions and cannot be expressed in YAML. Use the TS override for these.
### Remove list of elements (`filter`) ### Remove list of elements (`filter`)
Using this example, you can remove elements from your explorer by providing an array of folders/files to exclude. Using this example, you can remove elements from your explorer by providing an array of folders/files to exclude.
Note that this example filters on the title but you can also do it via slug or any other field available on `FileTrieNode`. Note that this example filters on the title but you can also do it via slug or any other field available on `FileTrieNode`.
```ts title="quartz.ts (override)" ```ts title="quartz.layout.ts"
Explorer({ Component.Explorer({
filterFn: (node) => { filterFn: (node) => {
// set containing names of everything you want to filter out // set containing names of everything you want to filter out
const omit = new Set(["authoring content", "tags", "advanced"]) const omit = new Set(["authoring content", "tags", "advanced"])
@ -218,8 +158,8 @@ Explorer({
You can access the tags of a file by `node.data.tags`. You can access the tags of a file by `node.data.tags`.
```ts title="quartz.ts (override)" ```ts title="quartz.layout.ts"
Explorer({ Component.Explorer({
filterFn: (node) => { filterFn: (node) => {
// exclude files with the tag "explorerexclude" // exclude files with the tag "explorerexclude"
return node.data?.tags?.includes("explorerexclude") !== true return node.data?.tags?.includes("explorerexclude") !== true
@ -232,8 +172,8 @@ Explorer({
By default, the explorer will filter out the `tags` folder. By default, the explorer will filter out the `tags` folder.
To override the default filter function, you can set the filter function to `undefined`. To override the default filter function, you can set the filter function to `undefined`.
```ts title="quartz.ts (override)" ```ts title="quartz.layout.ts"
Explorer({ Component.Explorer({
filterFn: undefined, // apply no filter function, every file and folder will visible filterFn: undefined, // apply no filter function, every file and folder will visible
}) })
``` ```
@ -241,24 +181,24 @@ Explorer({
## Advanced examples ## Advanced examples
> [!tip] > [!tip]
> When writing more complicated functions, the `quartz.ts` file can start to look very cramped. > When writing more complicated functions, the `layout` file can start to look very cramped.
> You can fix this by defining your sort functions outside of the component > You can fix this by defining your sort functions outside of the component
> and passing it in. > and passing it in.
> >
> ```ts title="quartz.ts" > ```ts title="quartz.layout.ts"
> import { ExplorerOptions } from "@quartz-community/explorer/components" > import { Options } from "./quartz/components/Explorer"
> >
> export const mapFn: ExplorerOptions["mapFn"] = (node) => { > export const mapFn: Options["mapFn"] = (node) => {
> // implement your function here > // implement your function here
> } > }
> export const filterFn: ExplorerOptions["filterFn"] = (node) => { > export const filterFn: Options["filterFn"] = (node) => {
> // implement your function here > // implement your function here
> } > }
> export const sortFn: ExplorerOptions["sortFn"] = (a, b) => { > export const sortFn: Options["sortFn"] = (a, b) => {
> // implement your function here > // implement your function here
> } > }
> >
> Explorer({ > Component.Explorer({
> // ... your other options > // ... your other options
> mapFn, > mapFn,
> filterFn, > filterFn,
@ -268,10 +208,10 @@ Explorer({
### Add emoji prefix ### Add emoji prefix
To add emoji prefixes (📁 for folders, 📄 for files), you could use a map function in `quartz.ts`: To add emoji prefixes (📁 for folders, 📄 for files), you could use a map function like this:
```ts title="quartz.ts (override)" ```ts title="quartz.layout.ts"
Explorer({ Component.Explorer({
mapFn: (node) => { mapFn: (node) => {
if (node.isFolder) { if (node.isFolder) {
node.displayName = "📁 " + node.displayName node.displayName = "📁 " + node.displayName

View File

@ -6,9 +6,6 @@ tags:
Full-text search in Quartz is powered by [Flexsearch](https://github.com/nextapps-de/flexsearch). It's fast enough to return search results in under 10ms for Quartzs as large as half a million words. Full-text search in Quartz is powered by [Flexsearch](https://github.com/nextapps-de/flexsearch). It's fast enough to return search results in under 10ms for Quartzs as large as half a million words.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
It can be opened by either clicking on the search bar or pressing `⌘`/`ctrl` + `K`. The top 5 search results are shown on each query. Matching subterms are highlighted and the most relevant 30 words are excerpted. Clicking on a search result will navigate to that page. It can be opened by either clicking on the search bar or pressing `⌘`/`ctrl` + `K`. The top 5 search results are shown on each query. Matching subterms are highlighted and the most relevant 30 words are excerpted. Clicking on a search result will navigate to that page.
To search content by tags, you can either press `⌘`/`ctrl` + `shift` + `K` or start your query with `#` (e.g. `#components`). To search content by tags, you can either press `⌘`/`ctrl` + `shift` + `K` or start your query with `#` (e.g. `#components`).
@ -26,6 +23,8 @@ It properly tokenizes Chinese, Korean, and Japenese characters and constructs se
## Customization ## Customization
- Removing search: remove the `search` entry from `quartz.config.yaml` or set `enabled: false`. - Removing search: delete all usages of `Component.Search()` from `quartz.layout.ts`.
- Install: `npx quartz plugin add github:quartz-community/search` - Component: `quartz/components/Search.tsx`
- Source: [`quartz-community/search`](https://github.com/quartz-community/search) - Style: `quartz/components/styles/search.scss`
- Script: `quartz/components/scripts/search.inline.ts`
- You can edit `contextWindowWords`, `numSearchResults` or `numTagResults` to suit your needs

View File

@ -9,30 +9,6 @@ Quartz features a graph-view that can show both a local graph view and a global
- The local graph view shows files that either link to the current file or are linked from the current file. In other words, it shows all notes that are _at most_ one hop away. - The local graph view shows files that either link to the current file or are linked from the current file. In other words, it shows all notes that are _at most_ one hop away.
- The global graph view can be toggled by clicking the graph icon on the top-right of the local graph view. It shows _all_ the notes in your graph and how they connect to each other. - The global graph view can be toggled by clicking the graph icon on the top-right of the local graph view. It shows _all_ the notes in your graph and how they connect to each other.
> [!info]
> The Graph View is now a community plugin. This demonstrates how external plugins can extend Quartz functionality while serving as a reference implementation for plugin developers.
## Installation
The Graph View is available as a community plugin from GitHub:
```bash
npm install github:quartz-community/graph --legacy-peer-deps
```
Then add it to your `quartz.config.yaml`:
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/graph
enabled: true
layout:
position: right
priority: 10
```
## Features
By default, the node radius is proportional to the total number of incoming and outgoing internal links from that file. By default, the node radius is proportional to the total number of incoming and outgoing internal links from that file.
Additionally, similar to how browsers highlight visited links a different colour, the graph view will also show nodes that you have visited in a different colour. Additionally, similar to how browsers highlight visited links a different colour, the graph view will also show nodes that you have visited in a different colour.
@ -42,50 +18,48 @@ Additionally, similar to how browsers highlight visited links a different colour
## Customization ## Customization
Most configuration can be done by passing in options to `Graph()`. Most configuration can be done by passing in options to `Component.Graph()`.
For example, here's what the default configuration looks like: For example, here's what the default configuration looks like:
```yaml title="quartz.config.yaml" ```typescript title="quartz.layout.ts"
plugins: Component.Graph({
- source: github:quartz-community/graph localGraph: {
enabled: true drag: true, // whether to allow panning the view around
options: zoom: true, // whether to allow zooming in and out
localGraph: depth: 1, // how many hops of notes to display
drag: true scale: 1.1, // default view scale
zoom: true repelForce: 0.5, // how much nodes should repel each other
depth: 1 centerForce: 0.3, // how much force to use when trying to center the nodes
scale: 1.1 linkDistance: 30, // how long should the links be by default?
repelForce: 0.5 fontSize: 0.6, // what size should the node labels be?
centerForce: 0.3 opacityScale: 1, // how quickly do we fade out the labels when zooming out?
linkDistance: 30 removeTags: [], // what tags to remove from the graph
fontSize: 0.6 showTags: true, // whether to show tags in the graph
opacityScale: 1 enableRadial: false, // whether to constrain the graph, similar to Obsidian
removeTags: [] },
showTags: true globalGraph: {
enableRadial: false drag: true,
globalGraph: zoom: true,
drag: true depth: -1,
zoom: true scale: 0.9,
depth: -1 repelForce: 0.5,
scale: 0.9 centerForce: 0.3,
repelForce: 0.5 linkDistance: 30,
centerForce: 0.3 fontSize: 0.6,
linkDistance: 30 opacityScale: 1,
fontSize: 0.6 removeTags: [], // what tags to remove from the graph
opacityScale: 1 showTags: true, // whether to show tags in the graph
removeTags: [] enableRadial: true, // whether to constrain the graph, similar to Obsidian
showTags: true },
focusOnHover: true })
enableRadial: true
layout:
position: right
priority: 10
``` ```
When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field. When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field.
Want to customize it even more? Want to customize it even more?
- Removing graph view: remove the `graph` entry from `quartz.config.yaml` or set `enabled: false` - Removing graph view: delete all usages of `Component.Graph()` from `quartz.layout.ts`.
- Component source: https://github.com/quartz-community/graph - Component: `quartz/components/Graph.tsx`
- Style: `quartz/components/styles/graph.scss`
- Script: `quartz/components/scripts/graph.inline.ts`

View File

@ -2,7 +2,7 @@
title: Internationalization title: Internationalization
--- ---
Internationalization allows users to translate text in the Quartz interface into various supported languages without needing to make extensive code changes. This can be changed via the `locale` [[configuration]] field in `quartz.config.yaml`. Internationalization allows users to translate text in the Quartz interface into various supported languages without needing to make extensive code changes. This can be changed via the `locale` [[configuration]] field in `quartz.config.ts`.
The locale field generally follows a certain format: `{language}-{REGION}` The locale field generally follows a certain format: `{language}-{REGION}`
@ -10,7 +10,7 @@ The locale field generally follows a certain format: `{language}-{REGION}`
- `{REGION}` is usually a [2-letter uppercase region code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) - `{REGION}` is usually a [2-letter uppercase region code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
> [!tip] Interested in contributing? > [!tip] Interested in contributing?
> We [gladly welcome translation PRs](https://github.com/jackyzha0/quartz/tree/v5/quartz/i18n/locales)! To contribute a translation, do the following things: > We [gladly welcome translation PRs](https://github.com/jackyzha0/quartz/tree/v4/quartz/i18n/locales)! To contribute a translation, do the following things:
> >
> 1. In the `quartz/i18n/locales` folder, copy the `en-US.ts` file. > 1. In the `quartz/i18n/locales` folder, copy the `en-US.ts` file.
> 2. Rename it to `{language}-{REGION}.ts` so it matches a locale of the format shown above. > 2. Rename it to `{language}-{REGION}.ts` so it matches a locale of the format shown above.

View File

@ -1,48 +1,3 @@
--- ---
title: Feature List title: Feature List
--- ---
Quartz comes with a wide variety of features out of the box. Most features are powered by [[configuration#Plugins|plugins]] that can be configured, enabled, or disabled via `quartz.config.yaml`.
## Content Features
- [[Obsidian compatibility]] — Full support for Obsidian-flavored Markdown
- [[wikilinks]] — Link between notes using `[[wikilinks]]` syntax
- [[callouts]] — Obsidian-style callout blocks
- [[Latex]] — LaTeX math rendering
- [[Mermaid diagrams]] — Diagram support via Mermaid
- [[syntax highlighting]] — Code block highlighting with themes
- [[OxHugo compatibility]] — Support for ox-hugo Markdown
- [[Roam Research compatibility]] — Support for Roam Research syntax
- [[Citations]] — Academic citation support
- [[Canvas]] — Render Obsidian Canvas files as interactive pages
- [[Bases]] — Database-like views for your notes (tables, cards, galleries, and more)
## Navigation & Discovery
- [[full-text search]] — Search across all your notes
- [[graph view]] — Interactive graph visualization of note connections
- [[backlinks]] — See which notes link to the current page
- [[explorer]] — File tree sidebar for browsing notes
- [[breadcrumbs]] — Breadcrumb navigation trail
- [[table of contents]] — Per-page table of contents
- [[folder and tag listings]] — Browse notes by folder or tag
- [[recent notes]] — Display recently modified notes
- [[popover previews]] — Hover previews for internal links
- [[StackedPages|stacked pages]] — Andy Matuschak-style stacked sliding panes for tracing note connections
- [[EncryptedPages|encrypted pages]] — Password-protect individual pages with client-side encryption
## Appearance & Reading
- [[darkmode]] — Light and dark mode toggle
- [[reader mode]] — Distraction-free reading experience
- [[comments]] — Add comments via Giscus, Utterances, or other providers
- [[social images]] — Auto-generated Open Graph images for social sharing
## Publishing & Deployment
- [[RSS Feed]] — RSS feed generation for content syndication
- [[private pages]] — Control which pages are published
- [[SPA Routing]] — Single-page app navigation
- [[Docker Support]] — Build and deploy with Docker
- [[i18n]] — Internationalization with 30+ supported locales

View File

@ -12,6 +12,6 @@ Similar to Obsidian, [[quartz-layout-desktop.png|images referenced using wikilin
## Configuration ## Configuration
- Remove popovers: set the `enablePopovers` field in `quartz.config.yaml` to be `false`. - Remove popovers: set the `enablePopovers` field in `quartz.config.ts` to be `false`.
- Style: `quartz/components/styles/popover.scss` - Style: `quartz/components/styles/popover.scss`
- Script: `quartz/components/scripts/popover.inline.ts` - Script: `quartz/components/scripts/popover.inline.ts`

View File

@ -17,7 +17,7 @@ If you'd like to only publish a select number of notes, you can instead use [[Ex
## `ignorePatterns` ## `ignorePatterns`
This is a field in `quartz.config.yaml` under the main [[configuration]] which allows you to specify a list of patterns to effectively exclude from parsing all together. Any valid [fast-glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) pattern works here. This is a field in `quartz.config.ts` under the main [[configuration]] which allows you to specify a list of patterns to effectively exclude from parsing all together. Any valid [fast-glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) pattern works here.
> [!note] > [!note]
> Bash's glob syntax is slightly different from fast-glob's and using bash's syntax may lead to unexpected results. > Bash's glob syntax is slightly different from fast-glob's and using bash's syntax may lead to unexpected results.

View File

@ -6,28 +6,15 @@ tags:
Reader Mode is a feature that allows users to focus on the content by hiding the sidebars and other UI elements. When enabled, it provides a clean, distraction-free reading experience. Reader Mode is a feature that allows users to focus on the content by hiding the sidebars and other UI elements. When enabled, it provides a clean, distraction-free reading experience.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Configuration ## Configuration
Reader Mode is enabled by default. To disable it, set `enabled: false` in your `quartz.config.yaml`: Reader Mode is enabled by default. To disable it, you can remove the component from your layout configuration in `quartz.layout.ts`:
```yaml title="quartz.config.yaml" ```ts
plugins: // Remove or comment out this line
- source: github:quartz-community/reader-mode Component.ReaderMode(),
enabled: false
``` ```
Or remove the plugin entirely:
```bash
npx quartz plugin remove github:quartz-community/reader-mode
```
- Install: `npx quartz plugin add github:quartz-community/reader-mode`
- Source: [`quartz-community/reader-mode`](https://github.com/quartz-community/reader-mode)
## Usage ## Usage
The Reader Mode toggle appears as a button with a book icon. When clicked: The Reader Mode toggle appears as a button with a book icon. When clicked:

View File

@ -3,20 +3,15 @@ title: Recent Notes
tags: component tags: component
--- ---
Quartz can generate a list of recent notes based on some filtering and sorting criteria. Though this component isn't included in any [[layout]] by default, you can add it by installing the plugin and configuring it in `quartz.config.yaml`. Quartz can generate a list of recent notes based on some filtering and sorting criteria. Though this component isn't included in any [[layout]] by default, you can add it by using `Component.RecentNotes` in `quartz.layout.ts`.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Customization ## Customization
Most options are configured in the `options` section of the plugin entry in `quartz.config.yaml`: - Changing the title from "Recent notes": pass in an additional parameter to `Component.RecentNotes({ title: "Recent writing" })`
- Changing the number of recent notes: pass in an additional parameter to `Component.RecentNotes({ limit: 5 })`
- Changing the title from "Recent notes": set `title: "Recent writing"` in options - Display the note's tags (defaults to true): `Component.RecentNotes({ showTags: false })`
- Changing the number of recent notes: set `limit: 5` in options - Show a 'see more' link: pass in an additional parameter to `Component.RecentNotes({ linkToMore: "tags/components" })`. This field should be a full slug to a page that exists.
- Display the note's tags (defaults to true): set `showTags: false` in options - Customize filtering: pass in an additional parameter to `Component.RecentNotes({ filter: someFilterFunction })`. The filter function should be a function that has the signature `(f: QuartzPluginData) => boolean`.
- Show a 'see more' link: set `linkToMore: "tags/components"` in options. This field should be a full slug to a page that exists. - Customize sorting: pass in an additional parameter to `Component.RecentNotes({ sort: someSortFunction })`. By default, Quartz will sort by date and then tie break lexographically. The sort function should be a function that has the signature `(f1: QuartzPluginData, f2: QuartzPluginData) => number`. See `byDateAndAlphabetical` in `quartz/components/PageList.tsx` for an example.
- Customize filtering: requires a TS override — pass `filter: someFilterFunction` to the plugin constructor in `quartz.ts`. The filter function should have the signature `(f: QuartzPluginData) => boolean`. - Component: `quartz/components/RecentNotes.tsx`
- Customize sorting: requires a TS override — pass `sort: someSortFunction` to the plugin constructor in `quartz.ts`. By default, Quartz will sort by date and then tie break lexographically. The sort function should have the signature `(f1: QuartzPluginData, f2: QuartzPluginData) => number`. - Style: `quartz/components/styles/recentNotes.scss`
- Install: `npx quartz plugin add github:quartz-community/recent-notes`
- Source: [`quartz-community/recent-notes`](https://github.com/quartz-community/recent-notes)

View File

@ -0,0 +1,12 @@
---
draft: true
---
## misc backlog
- static dead link detection
- cursor chat extension
- sidenotes? https://github.com/capnfabs/paperesque
- direct match in search using double quotes
- https://help.obsidian.md/Advanced+topics/Using+Obsidian+URI
- Canvas

View File

@ -1,17 +0,0 @@
---
title: Getting Started
---
Welcome to Quartz! This section will walk you through setting up your digital garden from scratch.
## Setup
1. **[[getting-started/installation|Installation]]** — Clone Quartz, create your repository, and push your first sync
2. **[[getting-started/authoring-content|Authoring Content]]** — Write and organize your notes in the `content` folder
3. **[[build|Building]]** — Preview your site locally with `npx quartz build --serve`
4. **[[hosting|Hosting]]** — Deploy your Quartz site to the web
## Upgrading & Migrating
- **[[getting-started/upgrading|Upgrading Quartz]]** — Keep your Quartz installation up to date
- **[[getting-started/migrating|Migrating to Quartz 5]]** — Migrate from Quartz 4 or Quartz 3

View File

@ -1,359 +0,0 @@
---
title: "Migrating to Quartz 5"
aliases:
- "migrating from Quartz 3"
- "migrating from Quartz 4"
---
This guide covers migrating to Quartz 5 from previous versions. If you're already on Quartz 5 and want to update to the latest version, see [[getting-started/upgrading|Upgrading Quartz]] instead.
## Migrating from Quartz 4
### Overview
Quartz 5 introduces a community plugin system that fundamentally changes how plugins and components are managed. Most plugins that were built into Quartz 4 are now standalone community plugins maintained under the [quartz-community](https://github.com/quartz-community) organization. This guide walks through the changes needed to migrate your configuration.
### What Changed
- **Plugin system**: Plugins are now standalone Git repositories, installed via `npx quartz plugin add`
- **Import pattern**: Community plugins use `ExternalPlugin.X()` (from `.quartz/plugins`) instead of `Plugin.X()` (from `./quartz/plugins`)
- **Layout structure**: `quartz.layout.ts` is gone — layout position is now a per-plugin property in `quartz.config.yaml`, with `layout.groups` for flex containers (e.g. toolbar) and `layout.byPageType` for per-page-type overrides
- **Page Types**: A new plugin category for page rendering (content, folder, tag pages)
- **Component references**: In layout files, community components use `Plugin.X()` (from `.quartz/plugins`) instead of `Component.X()` (from `./quartz/components`)
### Step-by-Step Migration
#### 1. Set Up Quartz 5 with a Template
The easiest way to migrate is to use `npx quartz create`, which generates a complete `quartz.config.yaml` from a template with all default plugins pre-configured:
```shell
npx quartz create --template default --strategy copy --source /path/to/your/content
```
Available templates: `default`, `obsidian`, `ttrpg`, `blog`. Pick the one closest to your setup — `obsidian` is recommended if you use an Obsidian vault.
> [!tip] Choosing a template
> Each template comes with all 30+ default plugins pre-configured. The main differences are content strategy (OFM support, link resolution) and optional plugins (comments, maps). You can customize everything in `quartz.config.yaml` afterward.
After running `create`, install all the plugins referenced in the generated config:
```shell
npx quartz plugin resolve
```
This reads your `quartz.config.yaml` and installs every plugin listed in it. No need to run 30 individual `npx quartz plugin add` commands.
> [!note] Custom or optional plugins
> If you used optional plugins in v4 (comments, reader-mode, breadcrumbs, recent-notes, citations, etc.), add them after the initial setup:
>
> ```shell
> npx quartz plugin add github:quartz-community/comments
> npx quartz plugin add github:quartz-community/reader-mode
> npx quartz plugin add github:quartz-community/breadcrumbs
> npx quartz plugin add github:quartz-community/recent-notes
> ```
>
> See [[plugins/index|Plugins]] for the full list of available community plugins.
> [!info] Alternative: Use `npx quartz migrate`
> If you have an existing `quartz.config.ts` and `quartz.layout.ts` from v4, you can run `npx quartz migrate` instead. This reads your old config files and generates `quartz.config.yaml` with your existing settings. You'll still need to run `npx quartz plugin resolve` afterward to install the plugins. See [[cli/migrate|quartz migrate]] for details.
#### 2. Update quartz.config.yaml
**Before (v4):**
```ts title="quartz.config.ts"
import * as Plugin from "./quartz/plugins"
plugins: {
transformers: [
Plugin.FrontMatter(),
Plugin.CreatedModifiedDate({ priority: ["frontmatter", "git", "filesystem"] }),
Plugin.Latex({ renderEngine: "katex" }),
],
filters: [Plugin.RemoveDrafts()],
emitters: [
Plugin.AliasRedirects(),
Plugin.ComponentResources(),
Plugin.ContentPage(),
Plugin.FolderPage(),
Plugin.TagPage(),
Plugin.ContentIndex({ enableSiteMap: true, enableRSS: true }),
Plugin.Assets(),
Plugin.Static(),
Plugin.NotFoundPage(),
],
}
```
**After (v5):**
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/note-properties
enabled: true
options:
delimiters: "---"
language: yaml
order: 5
- source: github:quartz-community/created-modified-date
enabled: true
options:
priority:
- frontmatter
- git
- filesystem
order: 10
- source: github:quartz-community/latex
enabled: true
options:
renderEngine: katex
order: 80
- source: github:quartz-community/remove-draft
enabled: true
- source: github:quartz-community/alias-redirects
enabled: true
- source: github:quartz-community/content-index
enabled: true
options:
enableSiteMap: true
enableRSS: true
- source: github:quartz-community/favicon
enabled: true
- source: github:quartz-community/og-image
enabled: true
- source: github:quartz-community/cname
enabled: true
- source: github:quartz-community/content-page
enabled: true
- source: github:quartz-community/folder-page
enabled: true
- source: github:quartz-community/tag-page
enabled: true
# ... more plugins
```
Key changes:
- Plugins are now referenced by their GitHub source (`github:org/repo`)
- Plugin type (transformer, filter, emitter, pageType) is determined by the plugin's manifest, not by which array you place it in
- Execution order is controlled by the `order` field (lower numbers run first)
- Each plugin entry has `enabled`, `options`, `order`, and optionally `layout` fields
- Install community plugins with `npx quartz plugin add github:quartz-community/<name>`
#### 3. Update layout configuration
**Before (v4):**
```ts title="quartz.layout.ts"
import * as Component from "./quartz/components"
export const sharedPageComponents: SharedLayout = {
head: Component.Head(),
header: [],
afterBody: [],
footer: Component.Footer({ links: { ... } }),
}
export const defaultContentPageLayout: PageLayout = {
beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta(), Component.TagList()],
left: [Component.PageTitle(), Component.Search(), Component.Darkmode(), Component.Explorer()],
right: [Component.Graph(), Component.TableOfContents(), Component.Backlinks()],
}
```
**After (v5):**
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/breadcrumbs
enabled: true
layout:
position: beforeBody
priority: 5
- source: github:quartz-community/article-title
enabled: true
layout:
position: beforeBody
priority: 10
- source: github:quartz-community/content-meta
enabled: true
layout:
position: beforeBody
priority: 20
- source: github:quartz-community/tag-list
enabled: true
layout:
position: beforeBody
priority: 30
- source: github:quartz-community/page-title
enabled: true
layout:
position: left
priority: 10
- source: github:quartz-community/search
enabled: true
layout:
position: left
priority: 20
- source: github:quartz-community/darkmode
enabled: true
layout:
position: left
priority: 30
- source: github:quartz-community/explorer
enabled: true
layout:
position: left
priority: 50
- source: github:quartz-community/graph
enabled: true
layout:
position: right
priority: 10
- source: github:quartz-community/backlinks
enabled: true
layout:
position: right
priority: 30
- source: github:quartz-community/footer
enabled: true
options:
links:
GitHub: https://github.com/jackyzha0/quartz
Discord Community: https://discord.gg/cRFFHYye7t
layout:
byPageType:
content: {}
folder:
exclude:
- reader-mode
positions:
right: []
tag:
exclude:
- reader-mode
positions:
right: []
"404":
positions:
beforeBody: []
left: []
right: []
```
Key changes:
- Layout position is now a property on each plugin entry (`layout.position`, `layout.priority`)
- `sharedPageComponents` is gone — all layout is plugin-driven
- Per-page-type overrides live in the `layout.byPageType` section
- Empty arrays (`[]`) clear a position for that page type
- The `exclude` field removes specific plugins from a page type
#### 4. Update CI/CD
Add `npx quartz plugin restore` to your build pipeline, before `npx quartz build`. This installs plugins from the lockfile at their pinned versions.
If your CI uses `quartz.config.default.yaml` (or contributors may add plugins to config without updating the lockfile), also run `npx quartz plugin resolve` to install any config-referenced plugins that are missing from the lockfile:
```shell
npx quartz plugin restore # install pinned plugins from lockfile
npx quartz plugin resolve # install any config-referenced plugins not yet in lockfile
npx quartz build
```
See [[hosting]] for detailed CI/CD examples and [[ci-cd]] for advanced configuration.
#### 5. Commit and Deploy
```shell
git add quartz.config.yaml quartz.lock.json
git commit -m "chore: migrate to Quartz 5 plugin system"
```
> [!tip] Cleaning up leftover plugins
> After migrating, you may have plugins installed from v4 that are no longer in your v5 config. Run `npx quartz plugin prune` to remove them. Use `--dry-run` first to preview what would be removed.
### Plugin Reference Table
Mapping v4 plugin names to v5 equivalents:
| v4 | v5 | Type |
| ----------------------------------- | ------------------------------------------- | --------------------- |
| `Plugin.FrontMatter()` | `Plugin.FrontMatter()` (unchanged) | Internal |
| `Plugin.CreatedModifiedDate()` | `ExternalPlugin.CreatedModifiedDate()` | Community |
| `Plugin.SyntaxHighlighting()` | `ExternalPlugin.SyntaxHighlighting()` | Community |
| `Plugin.ObsidianFlavoredMarkdown()` | `ExternalPlugin.ObsidianFlavoredMarkdown()` | Community |
| `Plugin.GitHubFlavoredMarkdown()` | `ExternalPlugin.GitHubFlavoredMarkdown()` | Community |
| `Plugin.CrawlLinks()` | `ExternalPlugin.CrawlLinks()` | Community |
| `Plugin.Description()` | `ExternalPlugin.Description()` | Community |
| `Plugin.Latex()` | `ExternalPlugin.Latex()` | Community |
| `Plugin.RemoveDrafts()` | `ExternalPlugin.RemoveDrafts()` | Community |
| `Plugin.ContentPage()` | `ExternalPlugin.ContentPage()` | Community (pageTypes) |
| `Plugin.FolderPage()` | `ExternalPlugin.FolderPage()` | Community (pageTypes) |
| `Plugin.TagPage()` | `ExternalPlugin.TagPage()` | Community (pageTypes) |
| `Plugin.NotFoundPage()` | `Plugin.PageTypes.NotFoundPageType()` | Internal (pageTypes) |
| `Plugin.ComponentResources()` | `Plugin.ComponentResources()` (unchanged) | Internal |
| `Plugin.Assets()` | `Plugin.Assets()` (unchanged) | Internal |
| `Plugin.Static()` | `Plugin.Static()` (unchanged) | Internal |
| `Plugin.AliasRedirects()` | `ExternalPlugin.AliasRedirects()` | Community |
| `Plugin.ContentIndex()` | `ExternalPlugin.ContentIndex()` | Community |
Component layout mapping:
| v4 Layout | v5 Layout |
| ----------------------------- | ------------------------------------------ |
| `Component.Explorer()` | `Plugin.Explorer()` |
| `Component.Graph()` | `Plugin.Graph()` |
| `Component.Search()` | `Plugin.Search()` |
| `Component.Backlinks()` | `Plugin.Backlinks()` |
| `Component.Darkmode()` | `Plugin.Darkmode()` |
| `Component.Footer()` | `Plugin.Footer()` |
| `Component.TableOfContents()` | `Plugin.TableOfContents()` |
| `Component.Head()` | `Component.Head()` (unchanged, internal) |
| `Component.Spacer()` | `Component.Spacer()` (unchanged, internal) |
---
## Migrating from Quartz 3
As you already have Quartz locally, you don't need to fork or clone it again. Simply just checkout the v4 branch, install the dependencies, restore plugins, and import your old vault. Then follow the [Quartz 4 migration steps above](#migrating-from-quartz-4) to get to v5.
```bash
git fetch
git checkout v4
git pull upstream v4
npm i
npx quartz plugin restore
npx quartz create
```
If you get an error like `fatal: 'upstream' does not appear to be a git repository`, make sure you add `upstream` as a remote origin:
```shell
git remote add upstream https://github.com/jackyzha0/quartz.git
```
When running `npx quartz create`, you will be prompted as to how to initialize your content folder. Here, you can choose to import or link your previous content folder and Quartz should work just as you expect it to.
> [!note]
> If the existing content folder you'd like to use is at the _same_ path on a different branch, clone the repo again somewhere at a _different_ path in order to use it.
### Key changes from Quartz 3
1. **Removing Hugo and `hugo-obsidian`**: Hugo worked well for earlier versions of Quartz but it also made it hard for people outside of the Golang and Hugo communities to fully understand what Quartz was doing under the hood and be able to properly customize it to their needs. Quartz now uses a Node-based static-site generation process which should lead to much more helpful error messages and an overall smoother user experience.
2. **Full-hot reload**: The many rough edges of how `hugo-obsidian` integrated with Hugo meant that watch mode didn't re-trigger `hugo-obsidian` to update the content index. This lead to a lot of weird cases where the watch mode output wasn't accurate. Quartz now uses a cohesive parse, filter, and emit pipeline which gets run on every change so hot-reloads are always accurate.
3. **Replacing Go template syntax with JSX**: Quartz 3 used [Go templates](https://pkg.go.dev/text/template) to create layouts for pages. However, the syntax isn't great for doing any sort of complex rendering (like [text processing](https://github.com/jackyzha0/quartz/blob/hugo/layouts/partials/textprocessing.html)) and it got very difficult to make any meaningful layout changes to Quartz 3. Quartz now uses an extension of JavaScript syntax called JSX which allows you to write layout code that looks like HTML in JavaScript which is significantly easier to understand and maintain.
4. **A new extensible [[configuration]] and [[configuration#Plugins|plugin]] system**: Quartz 3 was hard to configure without technical knowledge of how Hugo's partials worked. Extensions were even hard to make. Quartz 5's configuration and plugin system is designed to be extended by users while making updating to new versions of Quartz easy.
### Things to update
- You will need to update your deploy scripts. See the [[hosting]] guide for more details.
- Ensure that your default branch on GitHub is updated from `hugo` to `v5`.
- [[folder and tag listings|Folder and tag listings]] have also changed.
- Folder descriptions should go under `content/<folder-name>/index.md` where `<folder-name>` is the name of the folder.
- Tag descriptions should go under `content/tags/<tag-name>.md` where `<tag-name>` is the name of the tag.
- Some HTML layout may not be the same between Quartz 3 and Quartz 5. If you depended on a particular HTML hierarchy or class names, you may need to update your custom CSS to reflect these changes.
- If you customized the layout of Quartz 3, you may need to translate these changes from Go templates back to JSX as Quartz 5 no longer uses Hugo. For components, check out the guide on [[creating components]] for more details on this.

View File

@ -1,40 +0,0 @@
---
title: "Upgrading Quartz"
aliases:
- upgrading
---
> [!note]
> This is specifically a guide for upgrading your Quartz to a more recent update. If you are coming from Quartz 4 or Quartz 3, check out the [[getting-started/migrating|migration guide]] for more info.
To fetch the latest Quartz updates, simply run
```bash
npx quartz upgrade
```
As Quartz uses [git](https://git-scm.com/) under the hood for versioning, upgrading effectively 'pulls' in the updates from the official Quartz GitHub repository. If you have local changes that might conflict with the updates, you may need to resolve these manually yourself (or, pull manually using `git pull origin upstream`).
> [!hint]
> Quartz will try to cache your content before upgrading to try and prevent merge conflicts. If you get a conflict mid-merge, you can stop the merge and then run `npx quartz restore` to restore your content from the cache.
If you have the [GitHub desktop app](https://desktop.github.com/), this will automatically open to help you resolve the conflicts. Otherwise, you will need to resolve this in a text editor like VSCode. For more help on resolving conflicts manually, check out the [GitHub guide on resolving merge conflicts](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line#competing-line-change-merge-conflicts).
To update your installed plugins separately, use:
```bash
npx quartz update
```
See the [[cli/update|CLI reference for update]] and [[cli/upgrade|CLI reference for upgrade]] for more details on available flags.
### Cleaning Up Unused Plugins
If you've removed plugins from your configuration during an upgrade, you can clean up the leftover files:
```bash
npx quartz plugin prune --dry-run # preview what would be removed
npx quartz plugin prune # remove orphaned plugins
```
See the [[cli/plugin#prune|plugin prune reference]] for more details.

View File

@ -12,9 +12,6 @@ However, if you'd like to publish your site to the world, you need a way to host
> [!hint] > [!hint]
> Some Quartz features (like [[RSS Feed]] and sitemap generation) require `baseUrl` to be configured properly in your [[configuration]] to work properly. Make sure you set this before deploying! > Some Quartz features (like [[RSS Feed]] and sitemap generation) require `baseUrl` to be configured properly in your [[configuration]] to work properly. Make sure you set this before deploying!
> [!tip] Keeping plugins in sync
> All hosting examples below use `npx quartz plugin restore` to install plugins from the lockfile. If contributors may add plugins to `quartz.config.yaml` without updating the lockfile, add `npx quartz plugin resolve` after `restore` in your build command to install any missing plugins. See [[cli/plugin#resolve|plugin resolve]] for details.
## Cloudflare Pages ## Cloudflare Pages
1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/) and select your account. 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/) and select your account.
@ -22,10 +19,10 @@ However, if you'd like to publish your site to the world, you need a way to host
3. Select the new GitHub repository that you created and, in the **Set up builds and deployments** section, provide the following information: 3. Select the new GitHub repository that you created and, in the **Set up builds and deployments** section, provide the following information:
| Configuration option | Value | | Configuration option | Value |
| ---------------------- | ----------------------------------------------- | | ---------------------- | ------------------ |
| Production branch | `v5` | | Production branch | `v4` |
| Framework preset | `None` | | Framework preset | `None` |
| Build command | `npx quartz plugin restore && npx quartz build` | | Build command | `npx quartz build` |
| Build output directory | `public` | | Build output directory | `public` |
Press "Save and deploy" and Cloudflare should have a deployed version of your site in about a minute. Then, every time you sync your Quartz changes to GitHub, your site should be updated. Press "Save and deploy" and Cloudflare should have a deployed version of your site in about a minute. Then, every time you sync your Quartz changes to GitHub, your site should be updated.
@ -33,10 +30,7 @@ Press "Save and deploy" and Cloudflare should have a deployed version of your si
To add a custom domain, check out [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/custom-domains/). To add a custom domain, check out [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/custom-domains/).
> [!warning] > [!warning]
> Cloudflare Pages performs a shallow clone by default, so if you rely on `git` for timestamps, it is recommended that you add `git fetch --unshallow &&` to the beginning of the build command (e.g., `git fetch --unshallow && npx quartz plugin restore && npx quartz build`). > Cloudflare Pages performs a shallow clone by default, so if you rely on `git` for timestamps, it is recommended that you add `git fetch --unshallow &&` to the beginning of the build command (e.g., `git fetch --unshallow && npx quartz build`).
> [!note]
> For more detailed CI/CD configuration including caching and plugin management, see [[ci-cd]].
## GitHub Pages ## GitHub Pages
@ -48,7 +42,7 @@ name: Deploy Quartz site to GitHub Pages
on: on:
push: push:
branches: branches:
- v5 - v4
permissions: permissions:
contents: read contents: read
@ -71,8 +65,6 @@ jobs:
node-version: 22 node-version: 22
- name: Install Dependencies - name: Install Dependencies
run: npm ci run: npm ci
- name: Restore Quartz plugins
run: npx quartz plugin restore
- name: Build Quartz - name: Build Quartz
run: npx quartz build run: npx quartz build
- name: Upload artifact - name: Upload artifact
@ -149,10 +141,10 @@ Before deploying to Vercel, a `vercel.json` file is required at the root of the
4. Check that these configuration options are set: 4. Check that these configuration options are set:
| Configuration option | Value | | Configuration option | Value |
| ----------------------------------------- | ----------------------------------------------- | | ----------------------------------------- | ------------------ |
| Framework Preset | `Other` | | Framework Preset | `Other` |
| Root Directory | `./` | | Root Directory | `./` |
| Build and Output Settings > Build Command | `npx quartz plugin restore && npx quartz build` | | Build and Output Settings > Build Command | `npx quartz build` |
5. Press Deploy. Once it's live, you'll have 2 `*.vercel.app` URLs to view the page. 5. Press Deploy. Once it's live, you'll have 2 `*.vercel.app` URLs to view the page.
@ -161,7 +153,7 @@ Before deploying to Vercel, a `vercel.json` file is required at the root of the
> [!note] > [!note]
> If there is something already hosted on the domain, these steps will not work without replacing the previous content. As a workaround, you could use Next.js rewrites or use the next section to create a subdomain. > If there is something already hosted on the domain, these steps will not work without replacing the previous content. As a workaround, you could use Next.js rewrites or use the next section to create a subdomain.
1. Update the `baseUrl` in `quartz.config.yaml` if necessary. 1. Update the `baseUrl` in `quartz.config.js` if necessary.
2. Go to the [Domains - Dashboard](https://vercel.com/dashboard/domains) page in Vercel. 2. Go to the [Domains - Dashboard](https://vercel.com/dashboard/domains) page in Vercel.
3. Connect the domain to Vercel 3. Connect the domain to Vercel
4. Press "Add" to connect a custom domain to Vercel. 4. Press "Add" to connect a custom domain to Vercel.
@ -173,7 +165,7 @@ Before deploying to Vercel, a `vercel.json` file is required at the root of the
Using `docs.example.com` is an example of a subdomain. They're a simple way of connecting multiple deployments to one domain. Using `docs.example.com` is an example of a subdomain. They're a simple way of connecting multiple deployments to one domain.
1. Update the `baseUrl` in `quartz.config.yaml` if necessary. 1. Update the `baseUrl` in `quartz.config.js` if necessary.
2. Ensure your domain has been added to the [Domains - Dashboard](https://vercel.com/dashboard/domains) page in Vercel. 2. Ensure your domain has been added to the [Domains - Dashboard](https://vercel.com/dashboard/domains) page in Vercel.
3. Go to the [Vercel Dashboard](https://vercel.com/dashboard) and select your Quartz project. 3. Go to the [Vercel Dashboard](https://vercel.com/dashboard) and select your Quartz project.
4. Go to the Settings tab and then click Domains in the sidebar 4. Go to the Settings tab and then click Domains in the sidebar
@ -183,7 +175,7 @@ Using `docs.example.com` is an example of a subdomain. They're a simple way of c
1. Log in to the [Netlify dashboard](https://app.netlify.com/) and click "Add new site". 1. Log in to the [Netlify dashboard](https://app.netlify.com/) and click "Add new site".
2. Select your Git provider and repository containing your Quartz project. 2. Select your Git provider and repository containing your Quartz project.
3. Under "Build command", enter `npx quartz plugin restore && npx quartz build`. 3. Under "Build command", enter `npx quartz build`.
4. Under "Publish directory", enter `public`. 4. Under "Publish directory", enter `public`.
5. Press Deploy. Once it's live, you'll have a `*.netlify.app` URL to view the page. 5. Press Deploy. Once it's live, you'll have a `*.netlify.app` URL to view the page.
6. To add a custom domain, check "Domain management" in the left sidebar, just like with Vercel. 6. To add a custom domain, check "Domain management" in the left sidebar, just like with Vercel.
@ -206,12 +198,11 @@ cache: # Cache modules in between jobs
build: build:
stage: build stage: build
rules: rules:
- if: '$CI_COMMIT_REF_NAME == "v5"' - if: '$CI_COMMIT_REF_NAME == "v4"'
before_script: before_script:
- hash -r - hash -r
- npm ci --cache .npm --prefer-offline - npm ci --cache .npm --prefer-offline
script: script:
- npx quartz plugin restore
- npx quartz build - npx quartz build
artifacts: artifacts:
paths: paths:
@ -222,7 +213,7 @@ build:
pages: pages:
stage: deploy stage: deploy
rules: rules:
- if: '$CI_COMMIT_REF_NAME == "v5"' - if: '$CI_COMMIT_REF_NAME == "v4"'
script: script:
- echo "Deploying to GitLab Pages..." - echo "Deploying to GitLab Pages..."
artifacts: artifacts:

View File

@ -1,5 +1,5 @@
--- ---
title: Welcome to Quartz 5 title: Welcome to Quartz 4
--- ---
Quartz is a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites. Thousands of students, developers, and teachers are [[showcase|already using Quartz]] to publish personal notes, websites, and [digital gardens](https://jzhao.xyz/posts/networked-thought) to the web. Quartz is a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites. Thousands of students, developers, and teachers are [[showcase|already using Quartz]] to publish personal notes, websites, and [digital gardens](https://jzhao.xyz/posts/networked-thought) to the web.
@ -11,14 +11,13 @@ Quartz requires **at least [Node](https://nodejs.org/) v22** and `npm` v10.9.2 t
Then, in your terminal of choice, enter the following commands line by line: Then, in your terminal of choice, enter the following commands line by line:
```shell ```shell
git clone -b v5 https://github.com/jackyzha0/quartz.git git clone https://github.com/jackyzha0/quartz.git
cd quartz cd quartz
npm i npm i
npx quartz plugin restore
npx quartz create npx quartz create
``` ```
This will guide you through initializing your Quartz with content, including choosing a [[cli/create#templates|project template]] and configuring your site's base URL. Once you've done so, see how to: This will guide you through initializing your Quartz with content. Once you've done so, see how to:
1. [[authoring content|Writing content]] in Quartz 1. [[authoring content|Writing content]] in Quartz
2. [[configuration|Configure]] Quartz's behaviour 2. [[configuration|Configure]] Quartz's behaviour
@ -27,6 +26,9 @@ This will guide you through initializing your Quartz with content, including cho
5. Sync your changes with [[setting up your GitHub repository|GitHub]] 5. Sync your changes with [[setting up your GitHub repository|GitHub]]
6. [[hosting|Host]] Quartz online 6. [[hosting|Host]] Quartz online
If you prefer instructions in a video format you can try following Nicole van der Hoeven's
[video guide on how to set up Quartz!](https://www.youtube.com/watch?v=6s6DT1yN4dw&t=227s)
## 🔧 Features ## 🔧 Features
- [[Obsidian compatibility]], [[full-text search]], [[graph view]], [[wikilinks|wikilinks, transclusions]], [[backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]], [[comments]] and [many more](./features/) right out of the box - [[Obsidian compatibility]], [[full-text search]], [[graph view]], [[wikilinks|wikilinks, transclusions]], [[backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]], [[comments]] and [many more](./features/) right out of the box
@ -39,6 +41,6 @@ For a comprehensive list of features, visit the [features page](./features/). Yo
### 🚧 Troubleshooting + Updating ### 🚧 Troubleshooting + Updating
Having trouble with Quartz? Try searching for your issue using the search feature or check the [[troubleshooting]] page. If you haven't already, [[upgrading|upgrade]] to the newest version of Quartz to see if this fixes your issue. Having trouble with Quartz? Try searching for your issue using the search feature. If you haven't already, [[upgrading|upgrade]] to the newest version of Quartz to see if this fixes your issue.
If you're still having trouble, feel free to [submit an issue](https://github.com/jackyzha0/quartz/issues) if you feel you found a bug or ask for help in our [Discord Community](https://discord.gg/cRFFHYye7t). You can also browse the [[community]] page for third-party plugins and resources. If you're still having trouble, feel free to [submit an issue](https://github.com/jackyzha0/quartz/issues) if you feel you found a bug or ask for help in our [Discord Community](https://discord.gg/cRFFHYye7t).

View File

@ -4,93 +4,20 @@ title: Higher-Order Layout Components
Quartz provides several higher-order components that help with layout composition and responsive design. These components wrap other components to add additional functionality or modify their behavior. Quartz provides several higher-order components that help with layout composition and responsive design. These components wrap other components to add additional functionality or modify their behavior.
Most common use cases can be configured directly in `quartz.config.yaml` using layout properties. For advanced scenarios requiring custom logic, you can use the TS override approach in `quartz.ts`.
## `Flex` Component ## `Flex` Component
The `Flex` component creates a [flexible box layout](https://developer.mozilla.org/en-US/docs/Web/CSS/flex) that can arrange child components in various ways. It's particularly useful for creating responsive layouts and organizing components in rows or columns. The `Flex` component creates a [flexible box layout](https://developer.mozilla.org/en-US/docs/Web/CSS/flex) that can arrange child components in various ways. It's particularly useful for creating responsive layouts and organizing components in rows or columns.
### YAML Configuration
In YAML, flex layouts are created using **groups**. Define a group in the top-level `layout.groups` section, then assign plugins to that group via their `layout.group` property:
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/search
enabled: true
layout:
position: left
priority: 20
group: toolbar
groupOptions:
grow: true # Search will grow to fill available space
- source: github:quartz-community/darkmode
enabled: true
layout:
position: left
priority: 30
group: toolbar # Darkmode keeps its natural size
- source: github:quartz-community/reader-mode
enabled: true
layout:
position: left
priority: 35
group: toolbar
layout:
groups:
toolbar:
direction: row
gap: 0.5rem
```
The `groupOptions` field on each plugin entry supports the following flex item properties:
| Option | Type | Description |
| --------- | --------------------------------------------------------------- | --------------------------------------------------------- |
| `grow` | `boolean` | Whether the component should grow to fill available space |
| `shrink` | `boolean` | Whether the component should shrink if needed |
| `basis` | `string` | Initial main size of the component (e.g., `"200px"`) |
| `order` | `number` | Order in the flex container |
| `align` | `"start"` \| `"end"` \| `"center"` \| `"stretch"` | Cross-axis alignment |
| `justify` | `"start"` \| `"end"` \| `"center"` \| `"between"` \| `"around"` | Main-axis alignment |
The top-level `layout.groups` section configures the flex container itself:
| Option | Type | Description |
| ----------- | -------------------------------------------------------------- | ----------------------------------------- |
| `direction` | `"row"` \| `"row-reverse"` \| `"column"` \| `"column-reverse"` | Flex direction |
| `wrap` | `"nowrap"` \| `"wrap"` \| `"wrap-reverse"` | Flex wrap behavior |
| `gap` | `string` | Gap between flex items (e.g., `"0.5rem"`) |
### TS Override
For full programmatic control, use the `Component.Flex()` wrapper in `quartz.ts`:
```ts title="quartz.ts (override)"
Component.Flex({
components: [
{
Component: Plugin.Search(),
grow: true, // Search will grow to fill available space
},
{ Component: Plugin.Darkmode() }, // Darkmode keeps its natural size
],
direction: "row",
gap: "1rem",
})
```
```typescript ```typescript
type FlexConfig = { type FlexConfig = {
components: { components: {
Component: QuartzComponent Component: QuartzComponent
grow?: boolean grow?: boolean // whether component should grow to fill space
shrink?: boolean shrink?: boolean // whether component should shrink if needed
basis?: string basis?: string // initial main size of the component
order?: number order?: number // order in flex container
align?: "start" | "end" | "center" | "stretch" align?: "start" | "end" | "center" | "stretch" // cross-axis alignment
justify?: "start" | "end" | "center" | "between" | "around" justify?: "start" | "end" | "center" | "between" | "around" // main-axis alignment
}[] }[]
direction?: "row" | "row-reverse" | "column" | "column-reverse" direction?: "row" | "row-reverse" | "column" | "column-reverse"
wrap?: "nowrap" | "wrap" | "wrap-reverse" wrap?: "nowrap" | "wrap" | "wrap-reverse"
@ -98,8 +25,24 @@ type FlexConfig = {
} }
``` ```
### Example Usage
```typescript
Component.Flex({
components: [
{
Component: Component.Search(),
grow: true, // Search will grow to fill available space
},
{ Component: Component.Darkmode() }, // Darkmode keeps its natural size
],
direction: "row",
gap: "1rem",
})
```
> [!note] Overriding behavior > [!note] Overriding behavior
> Components inside `Flex` get an additional CSS class `flex-component` that adds the `display: flex` property. If you want to override this behavior, you can add a `display` property to the component's CSS class in your custom CSS file. > Components inside `Flex` get an additional CSS class `flex-component` that add the `display: flex` property. If you want to override this behavior, you can add a `display` property to the component's CSS class in your custom CSS file.
> >
> ```scss > ```scss
> .flex-component { > .flex-component {
@ -107,81 +50,29 @@ type FlexConfig = {
> } > }
> ``` > ```
## `MobileOnly` / `DesktopOnly` Components ## `MobileOnly` Component
These components control whether a plugin is visible on mobile or desktop devices. This is useful for creating responsive layouts where certain components should only appear on specific screen sizes. The `MobileOnly` component is a wrapper that makes its child component only visible on mobile devices. This is useful for creating responsive layouts where certain components should only appear on smaller screens.
### YAML Configuration ### Example Usage
In YAML, use the `display` property on a plugin's layout entry: ```typescript
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/table-of-contents
enabled: true
layout:
position: right
priority: 20
display: desktop-only # Only visible on desktop
```
Available `display` values:
| Value | Description |
| -------------- | ------------------------------------- |
| `all` | Visible on all screen sizes (default) |
| `mobile-only` | Only visible on mobile devices |
| `desktop-only` | Only visible on desktop devices |
### TS Override
For the TS override approach, use `Component.MobileOnly()` or `Component.DesktopOnly()` wrappers:
```ts title="quartz.ts (override)"
Component.MobileOnly(Component.Spacer()) Component.MobileOnly(Component.Spacer())
``` ```
```ts title="quartz.ts (override)" ## `DesktopOnly` Component
Component.DesktopOnly(Plugin.TableOfContents())
The `DesktopOnly` component is the counterpart to `MobileOnly`. It makes its child component only visible on desktop devices. This helps create responsive layouts where certain components should only appear on larger screens.
### Example Usage
```typescript
Component.DesktopOnly(Component.TableOfContents())
``` ```
## `ConditionalRender` Component ## `ConditionalRender` Component
The `ConditionalRender` component conditionally renders a plugin based on page properties. This is useful for creating dynamic layouts where components should only appear under certain conditions. The `ConditionalRender` component is a wrapper that conditionally renders its child component based on a provided condition function. This is useful for creating dynamic layouts where components should only appear under certain conditions.
### YAML Configuration
In YAML, use the `condition` property on a plugin's layout entry. Quartz provides several built-in condition presets:
```yaml title="quartz.config.yaml"
plugins:
- source: github:quartz-community/breadcrumbs
enabled: true
layout:
position: beforeBody
priority: 5
condition: not-index # Hide breadcrumbs on the root index page
```
Available built-in conditions:
| Condition | Description |
| --------------- | ----------------------------------------------------- |
| `not-index` | Only render when the page is not the root `index.md` |
| `has-tags` | Only render when the page has tags in its frontmatter |
| `has-backlinks` | Only render when the page has backlinks |
| `has-toc` | Only render when the page has a table of contents |
### TS Override
For custom conditions that aren't covered by the built-in presets, use `Component.ConditionalRender()` in `quartz.ts`:
```ts title="quartz.ts (override)"
Component.ConditionalRender({
component: Plugin.Search(),
condition: (props) => props.displayClass !== "fullpage",
})
```
```typescript ```typescript
type ConditionalRenderConfig = { type ConditionalRenderConfig = {
@ -190,5 +81,22 @@ type ConditionalRenderConfig = {
} }
``` ```
> [!tip] ### Example Usage
> You can also register custom conditions for use in YAML by calling `registerCondition()` in a plugin's initialization code. See [[making plugins]] for more details.
```typescript
Component.ConditionalRender({
component: Component.Search(),
condition: (props) => props.displayClass !== "fullpage",
})
```
The example above would only render the Search component when the page is not in fullpage mode.
```typescript
Component.ConditionalRender({
component: Component.Breadcrumbs(),
condition: (page) => page.fileData.slug !== "index",
})
```
The example above would hide breadcrumbs on the root `index.md` page.

View File

@ -2,12 +2,7 @@
title: Layout title: Layout
--- ---
Certain emitters may also output [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML) files. To enable easy customization, these emitters allow you to fully rearrange the layout of the page. Certain emitters may also output [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML) files. To enable easy customization, these emitters allow you to fully rearrange the layout of the page. The default page layouts can be found in `quartz.layout.ts`.
In v5, the layout is defined in `quartz.config.yaml`. Each plugin controls its own layout position via `layout.position` and `layout.priority` fields. The top-level `layout` section provides two additional mechanisms:
- `layout.groups` defines flex containers (like `toolbar`) that group multiple components into a single row or column. See [[layout-components]] for details.
- `layout.byPageType` contains per-page-type overrides (content, folder, tag, 404) for beforeBody, left, right sections, and optionally a `template` to control the page's [[#Page Frames|page frame]].
Each page is composed of multiple different sections which contain `QuartzComponents`. The following code snippet lists all of the valid sections that you can add components to: Each page is composed of multiple different sections which contain `QuartzComponents`. The following code snippet lists all of the valid sections that you can add components to:
@ -36,160 +31,14 @@ These correspond to following parts of the page:
> There are two additional layout fields that are _not_ shown in the above diagram. > There are two additional layout fields that are _not_ shown in the above diagram.
> >
> 1. `head` is a single component that renders the `<head>` [tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head) in the HTML. This doesn't appear visually on the page and is only is responsible for metadata about the document like the tab title, scripts, and styles. > 1. `head` is a single component that renders the `<head>` [tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head) in the HTML. This doesn't appear visually on the page and is only is responsible for metadata about the document like the tab title, scripts, and styles.
> 2. `header` is a set of components that are laid out horizontally and appears _before_ the `beforeBody` section. This enables you to replicate the old Quartz 3 header bar where the title, search bar, and dark mode toggle. By default, Quartz doesn't place any components in the `header`. > 2. `header` is a set of components that are laid out horizontally and appears _before_ the `beforeBody` section. This enables you to replicate the old Quartz 3 header bar where the title, search bar, and dark mode toggle. By default, Quartz 4 doesn't place any components in the `header`.
Layout components are configured in the `layout` section of `quartz.config.yaml`. Plugins declare their position and priority, and the layout system arranges them automatically: Quartz **components**, like plugins, can take in additional properties as configuration options. If you're familiar with React terminology, you can think of them as Higher-order Components.
```yaml title="quartz.config.yaml" See [a list of all the components](component.md) for all available components along with their configuration options. Additionally, Quartz provides several built-in higher-order components for layout composition - see [[layout-components]] for more details.
plugins:
- source: github:quartz-community/explorer
enabled: true
layout:
position: left
priority: 50
- source: github:quartz-community/graph
enabled: true
layout:
position: right
priority: 10
- source: github:quartz-community/search
enabled: true
layout:
position: left
priority: 20
- source: github:quartz-community/backlinks
enabled: true
layout:
position: right
priority: 30
- source: github:quartz-community/article-title
enabled: true
layout:
position: beforeBody
priority: 10
- source: github:quartz-community/content-meta
enabled: true
layout:
position: beforeBody
priority: 20
- source: github:quartz-community/tag-list
enabled: true
layout:
position: beforeBody
priority: 30
- source: github:quartz-community/footer
enabled: true
options:
links:
GitHub: https://github.com/jackyzha0/quartz
Discord Community: https://discord.gg/cRFFHYye7t
layout:
groups:
toolbar:
direction: row
gap: 0.5rem
byPageType:
content: {}
folder:
exclude:
- reader-mode
positions:
right: []
tag:
exclude:
- reader-mode
positions:
right: []
"404":
positions:
beforeBody: []
left: []
right: []
```
For advanced layout overrides using TypeScript (e.g. custom component wrappers or conditional logic), you can use the TS override in `quartz.ts`:
```ts title="quartz.ts"
import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
const config = await loadQuartzConfig()
export default config
export const layout = await loadQuartzLayout({
defaults: {
// override default layout for all page types
},
byPageType: {
content: {
// override layout for content pages only
},
folder: {
// override layout for folder pages only
},
},
})
```
Fields defined in `defaults` can be overridden by specific entries in `byPageType`.
Community component plugins are installed via `npx quartz plugin add github:quartz-community/<name>`. See [[layout-components]] for built-in layout utilities (Flex, MobileOnly, DesktopOnly, etc.).
You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz. You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz.
### Page Frames
Page frames control the overall HTML structure of a page — specifically, how the layout slots (sidebars, header, content, footer) are arranged inside the page shell. Different page types can use different frames to produce fundamentally different layouts.
Quartz ships with three built-in frames:
| Frame | Description | Used by |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `default` | Three-column layout with left sidebar, center content (header, beforeBody, content, afterBody), right sidebar, and footer. This is the standard Quartz layout. | ContentPage, FolderPage, TagPage, BasesPage |
| `full-width` | No sidebars. Single center column spanning the full width with header, content, afterBody, and footer. | — |
| `minimal` | No sidebars, no header or beforeBody chrome. Only content and footer. | NotFoundPage (404) |
Plugins can also provide their own frames. For example, the `canvas-page` plugin ships a `"canvas"` frame that provides a fullscreen canvas with a togglable sidebar.
#### How frames are resolved
Each page type can declare a default frame in its plugin source code via the `frame` property. The resolution order is:
1. **YAML config override**: `layout.byPageType.<name>.template` in `quartz.config.yaml`
2. **Plugin-registered frame**: Frames registered by plugins via the Frame Registry (loaded from the plugin's `frames` export)
3. **Plugin declaration**: The `frame` property set in the page type plugin's source code
4. **Fallback**: `"default"`
For example, to override canvas pages to use the minimal frame:
```yaml title="quartz.config.yaml"
layout:
byPageType:
canvas:
template: minimal
```
#### Custom frames
There are two ways to provide custom frames:
**1. Plugin-provided frames (recommended for reusable frames):**
Plugins can ship their own frames by declaring them in `package.json` and exporting them from a `./frames` subpath. See [[making plugins#Providing Custom Frames|the plugin guide]] for details. When a plugin with frames is installed, its frames are automatically registered in the Frame Registry and available by name.
**2. Core frames (for project-specific frames):**
You can also create frames directly in `quartz/components/frames/` by implementing the `PageFrame` interface and registering the frame in `quartz/components/frames/index.ts`. See the [[advanced/architecture|architecture overview]] for the full `PageFrame` interface.
Frames are applied as a `data-frame` attribute on the `.page` element, which you can target in CSS:
```scss
.page[data-frame="my-frame"] > #quartz-body {
/* custom grid layout */
}
```
Frame CSS should be scoped with `[data-frame="name"]` selectors to avoid conflicts with other frames.
### Layout breakpoints ### Layout breakpoints
Quartz has different layouts depending on the width the screen viewing the website. Quartz has different layouts depending on the width the screen viewing the website.
@ -209,9 +58,9 @@ $breakpoints: (
### Style ### Style
Most meaningful style changes like colour scheme and font can be done simply through the [[configuration#General Configuration|general configuration]] options. However, if you'd like to make more involved style changes, you can do this by writing your own styles. Quartz uses [Sass](https://sass-lang.com/guide/) for styling. Most meaningful style changes like colour scheme and font can be done simply through the [[configuration#General Configuration|general configuration]] options. However, if you'd like to make more involved style changes, you can do this by writing your own styles. Quartz 4, like Quartz 3, uses [Sass](https://sass-lang.com/guide/) for styling.
You can see the base style sheet in `quartz/styles/base.scss` and write your own in `quartz/styles/custom.scss`. You can see the base style sheet in `quartz/styles/base.scss` and write your own in `quartz/styles/custom.scss`.
> [!note] > [!note]
> Some components may provide their own styling as well! Community plugins bundle their own styles. If you'd like to customize styling for a specific component, double check the component definition to see how its styles are defined. > Some components may provide their own styling as well! For example, `quartz/components/Darkmode.tsx` imports styles from `quartz/components/styles/darkmode.scss`. If you'd like to customize styling for a specific component, double check the component definition to see how its styles are defined.

View File

@ -0,0 +1,41 @@
---
title: "Migrating from Quartz 3"
---
As you already have Quartz locally, you don't need to fork or clone it again. Simply just checkout the alpha branch, install the dependencies, and import your old vault.
```bash
git fetch
git checkout v4
git pull upstream v4
npm i
npx quartz create
```
If you get an error like `fatal: 'upstream' does not appear to be a git repository`, make sure you add `upstream` as a remote origin:
```shell
git remote add upstream https://github.com/jackyzha0/quartz.git
```
When running `npx quartz create`, you will be prompted as to how to initialize your content folder. Here, you can choose to import or link your previous content folder and Quartz should work just as you expect it to.
> [!note]
> If the existing content folder you'd like to use is at the _same_ path on a different branch, clone the repo again somewhere at a _different_ path in order to use it.
## Key changes
1. **Removing Hugo and `hugo-obsidian`**: Hugo worked well for earlier versions of Quartz but it also made it hard for people outside of the Golang and Hugo communities to fully understand what Quartz was doing under the hood and be able to properly customize it to their needs. Quartz 4 now uses a Node-based static-site generation process which should lead to a much more helpful error messages and an overall smoother user experience.
2. **Full-hot reload**: The many rough edges of how `hugo-obsidian` integrated with Hugo meant that watch mode didn't re-trigger `hugo-obsidian` to update the content index. This lead to a lot of weird cases where the watch mode output wasn't accurate. Quartz 4 now uses a cohesive parse, filter, and emit pipeline which gets run on every change so hot-reloads are always accurate.
3. **Replacing Go template syntax with JSX**: Quartz 3 used [Go templates](https://pkg.go.dev/text/template) to create layouts for pages. However, the syntax isn't great for doing any sort of complex rendering (like [text processing](https://github.com/jackyzha0/quartz/blob/hugo/layouts/partials/textprocessing.html)) and it got very difficult to make any meaningful layout changes to Quartz 3. Quartz 4 uses an extension of JavaScript syntax called JSX which allows you to write layout code that looks like HTML in JavaScript which is significantly easier to understand and maintain.
4. **A new extensible [[configuration]] and [[configuration#Plugins|plugin]] system**: Quartz 3 was hard to configure without technical knowledge of how Hugo's partials worked. Extensions were even hard to make. Quartz 4's configuration and plugin system is designed to be extended by users while making updating to new versions of Quartz easy.
## Things to update
- You will need to update your deploy scripts. See the [[hosting]] guide for more details.
- Ensure that your default branch on GitHub is updated from `hugo` to `v4`.
- [[folder and tag listings|Folder and tag listings]] have also changed.
- Folder descriptions should go under `content/<folder-name>/index.md` where `<folder-name>` is the name of the folder.
- Tag descriptions should go under `content/tags/<tag-name>.md` where `<tag-name>` is the name of the tag.
- Some HTML layout may not be the same between Quartz 3 and Quartz 4. If you depended on a particular HTML hierarchy or class names, you may need to update your custom CSS to reflect these changes.
- If you customized the layout of Quartz 3, you may need to translate these changes from Go templates back to JSX as Quartz 4 no longer uses Hugo. For components, check out the guide on [[creating components]] for more details on this.

View File

@ -36,7 +36,7 @@ Quartz is designed first and foremost as a tool for publishing [digital gardens]
At its core, Quartz is designed to be easy to use enough for non-technical people to get going but also powerful enough that senior developers can tweak it to work how they'd like it to work. At its core, Quartz is designed to be easy to use enough for non-technical people to get going but also powerful enough that senior developers can tweak it to work how they'd like it to work.
1. If you like the default configuration of Quartz and just want to change the content, the only thing that you need to change is the contents of the `content` folder. 1. If you like the default configuration of Quartz and just want to change the content, the only thing that you need to change is the contents of the `content` folder.
2. If you'd like to make basic configuration tweaks but don't want to edit source code, one can tweak the plugins and components in `quartz.config.yaml` in a guided manner to their liking. 2. If you'd like to make basic configuration tweaks but don't want to edit source code, one can tweak the plugins and components in `quartz.config.ts` and `quartz.layout.ts` in a guided manner to their liking.
3. If you'd like to tweak the actual source code of the underlying plugins, components, or even build process, Quartz purposefully ships its full source code to the end user to allow customization at this level too. 3. If you'd like to tweak the actual source code of the underlying plugins, components, or even build process, Quartz purposefully ships its full source code to the end user to allow customization at this level too.
Most software either confines you to either Most software either confines you to either

View File

@ -33,6 +33,5 @@ This plugin has no configuration options.
## API ## API
- Category: Emitter - Category: Emitter
- Function name: `ExternalPlugin.AliasRedirects()`. - Function name: `Plugin.AliasRedirects()`.
- Source: [`quartz-community/alias-redirects`](https://github.com/quartz-community/alias-redirects) - Source: [`quartz/plugins/emitters/aliases.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/aliases.ts).
- Install: `npx quartz plugin add github:quartz-community/alias-redirects`

View File

@ -1,19 +0,0 @@
---
title: ArticleTitle
tags:
- plugin/component
---
This plugin renders the article title from the page's frontmatter as an `<h1>` heading at the top of the page content. It reads the `title` field from frontmatter (falling back to the filename if no title is set).
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
This plugin has no configuration options.
## API
- Category: Component
- Function name: `ExternalPlugin.ArticleTitle()`.
- Source: [`quartz-community/article-title`](https://github.com/quartz-community/article-title)
- Install: `npx quartz plugin add github:quartz-community/article-title`

View File

@ -16,5 +16,5 @@ This plugin has no configuration options.
## API ## API
- Category: Emitter - Category: Emitter
- Function name: `Plugin.Assets()` (internal plugin). - Function name: `Plugin.Assets()`.
- Source: [`quartz/plugins/emitters/assets.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/emitters/assets.ts). - Source: [`quartz/plugins/emitters/assets.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/assets.ts).

View File

@ -1,34 +0,0 @@
---
title: Backlinks
tags:
- plugin/component
---
Shows pages that link to the current page.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[backlinks]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `hideWhenEmpty`: Hide the backlinks section if the current page has no backlinks. Defaults to `true`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/backlinks
enabled: true
options:
hideWhenEmpty: true
```
## API
- Category: Component
- Function name: `ExternalPlugin.Backlinks()`.
- Source: [`quartz-community/backlinks`](https://github.com/quartz-community/backlinks)
- Install: `npx quartz plugin add github:quartz-community/backlinks`

View File

@ -1,60 +0,0 @@
---
title: BasesPage
tags:
- plugin/pageType
- plugin/component
---
This plugin provides support for [Obsidian Bases](https://obsidian.md/changelog/2025-04-15-desktop-v1.8.0/) (`.base` files) in Quartz. It reads `.base` files from your vault, resolves matching notes based on the query definition, and renders them as interactive database-like views with support for tables, lists, cards, and maps. It uses the `default` [[layout#Page Frames|page frame]] (three-column layout with sidebars).
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Features
- **Table view**: Sortable columns with automatic type rendering (strings, numbers, booleans, arrays, links).
- **List view**: Compact list with metadata chips for each entry.
- **Cards view**: Card layout with optional image property support.
- **Map view**: Placeholder for future map-based visualization.
- **Multiple views**: A single `.base` file can define multiple views, displayed as switchable tabs.
- **Filters**: Recursive filter trees with `and`/`or`/`not` operators.
- **Formulas**: Computed properties via formula expressions.
- **Summaries**: Column-level aggregations (Sum, Average, Min, Max, Median, etc.).
- **Property configuration**: Custom display names for properties.
- **Link rendering**: Wikilinks and Markdown links within cell values are rendered as clickable links.
## Configuration
This plugin accepts the following configuration options:
- `defaultViewType`: The default view type when none is specified in the `.base` file. Defaults to `"table"`.
- `customViews`: A map of custom view renderers. Keys are view type names. These override built-in renderers for the same type, or add new view types. Requires a TS override.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/bases-page
enabled: true
```
For custom view renderers, use a TS override in `quartz.ts`:
```ts title="quartz.ts (override)"
import * as ExternalPlugin from "./.quartz/plugins"
ExternalPlugin.BasesPage({
defaultViewType: "table",
customViews: {
myView: ({ entries, view, basesData, total, locale }) => {
// return JSX
},
},
})
```
## API
- Category: Page Type, Component
- Function name: `ExternalPlugin.BasesPage()`.
- Source: [`quartz-community/bases-page`](https://github.com/quartz-community/bases-page)
- Install: `npx quartz plugin add github:quartz-community/bases-page`

View File

@ -1,40 +0,0 @@
---
title: Breadcrumbs
tags:
- plugin/component
---
Navigation breadcrumb trail.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[breadcrumbs]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `spacerSymbol`: The symbol to use between breadcrumb items. Defaults to `""`.
- `rootName`: The name of the root page. Defaults to `Home`.
- `resolveFrontmatterTitle`: Whether to use the `title` frontmatter field for breadcrumb items. Defaults to `true`.
- `showCurrentPage`: Whether to show the current page in the breadcrumb trail. Defaults to `true`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/breadcrumbs
enabled: true
options:
spacerSymbol: ""
rootName: Home
resolveFrontmatterTitle: true
showCurrentPage: true
```
## API
- Category: Component
- Function name: `ExternalPlugin.Breadcrumbs()`.
- Source: [`quartz-community/breadcrumbs`](https://github.com/quartz-community/breadcrumbs)
- Install: `npx quartz plugin add github:quartz-community/breadcrumbs`

View File

@ -18,6 +18,5 @@ This plugin has no configuration options.
## API ## API
- Category: Emitter - Category: Emitter
- Function name: `ExternalPlugin.CNAME()`. - Function name: `Plugin.CNAME()`.
- Source: [`quartz-community/cname`](https://github.com/quartz-community/cname) - Source: [`quartz/plugins/emitters/cname.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/cname.ts).
- Install: `npx quartz plugin add github:quartz-community/cname`

View File

@ -1,53 +0,0 @@
---
title: CanvasPage
tags:
- plugin/pageType
---
This plugin is a page type plugin that renders [JSON Canvas](https://jsoncanvas.org) (`.canvas`) files as interactive, pannable and zoomable canvas pages. It uses a custom `"canvas"` [[layout#Page Frames|page frame]] that provides a fullscreen, always-on canvas experience with a togglable left sidebar for navigation. It supports the full [JSON Canvas 1.0 spec](https://jsoncanvas.org/spec/1.0/), including text nodes with Markdown rendering, file nodes that link to other pages in your vault, link nodes for external URLs, and group nodes for visual organization. Edges between nodes are rendered as SVG paths with optional labels, arrow markers, and colors.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options:
- `enableInteraction`: Whether to enable pan and zoom interaction on the canvas. Default: `true{:ts}`.
- `initialZoom`: The initial zoom level when the canvas is first displayed. Default: `1{:ts}`.
- `minZoom`: The minimum zoom level allowed when zooming out. Default: `0.1{:ts}`.
- `maxZoom`: The maximum zoom level allowed when zooming in. Default: `5{:ts}`.
### Canvas Frame
The canvas-page plugin provides its own `"canvas"` page frame via the [[layout#Page Frames|Frame Registry]]. This frame:
- Renders the canvas in **fullscreen mode** by default (100vw × 100vh), giving the canvas maximum screen space — leaning into the "endless canvas" concept of JSON Canvas.
- Provides a **togglable left sidebar** that slides in from the left edge. This is the only layout slot available — it renders the same components as the `left` sidebar on content pages (e.g., Explorer, Search, Page Title).
- The sidebar toggle button (hamburger/close icon) is positioned in the top-left corner.
- Canvas controls (zoom in, zoom out, reset) are positioned on the right side.
- On mobile, the sidebar overlays the canvas rather than pushing it aside.
Users can override this frame via `quartz.config.yaml` if needed:
```yaml title="quartz.config.yaml"
layout:
byPageType:
canvas:
template: default # Use standard three-column layout instead
```
### Features
- **Text nodes**: Render Markdown content including headings, bold, italic, strikethrough, lists, links, and code blocks via [GFM](https://github.github.com/gfm/) support.
- **File nodes**: Link to other pages in your vault. Supports popover previews on hover.
- **Link nodes**: Reference external URLs.
- **Group nodes**: Visual grouping containers with optional labels and background colors.
- **Edges**: SVG connections between nodes with optional labels, arrow markers, and colors. Supports all four sides (top, right, bottom, left) and both preset colors (16) and custom hex colors.
- **Togglable sidebar**: Hamburger button in the top-left corner toggles the left sidebar for navigation. Press `Escape` or click the close button to dismiss.
- **Preset colors**: Six preset colors (red, orange, yellow, green, cyan, purple) plus custom hex colors (`#RRGGBB`) for nodes and edges.
## API
- Category: Page Type
- Function name: `ExternalPlugin.CanvasPage()`.
- Source: [`quartz-community/canvas-page`](https://github.com/quartz-community/canvas-page)
- Install: `npx quartz plugin add github:quartz-community/canvas-page`

View File

@ -20,6 +20,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.Citations()`. - Function name: `Plugin.Citations()`.
- Source: [`quartz-community/citations`](https://github.com/quartz-community/citations) - Source: [`quartz/plugins/transformers/citations.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/citations.ts).
- Install: `npx quartz plugin add github:quartz-community/citations`

View File

@ -1,53 +0,0 @@
---
title: Comments
tags:
- plugin/component
---
Comment system (giscus, utterances, etc.).
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[comments]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `provider`: The comment provider to use. Currently only `giscus` is supported.
- `options`: Provider-specific options.
- `repo`: The GitHub repository to use for comments.
- `repoId`: The ID of the GitHub repository.
- `category`: The discussion category to use.
- `categoryId`: The ID of the discussion category.
- `lang`: The language for the comment system. Defaults to `en`.
- `themeUrl`: URL to a folder with custom themes.
- `lightTheme`: Filename for the light theme CSS file. Defaults to `light`.
- `darkTheme`: Filename for the dark theme CSS file. Defaults to `dark`.
- `mapping`: How to map pages to discussions. Defaults to `url`.
- `strict`: Use strict title matching. Defaults to `true`.
- `reactionsEnabled`: Whether to enable reactions for the main post. Defaults to `true`.
- `inputPosition`: Where to put the comment input box relative to the comments. Defaults to `bottom`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/comments
enabled: true
options:
provider: giscus
options:
repo: jackyzha0/quartz
repoId: MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg
category: Announcements
categoryId: DIC_kwDOFxRnmM4B-Xg6
lang: en
```
## API
- Category: Component
- Function name: `ExternalPlugin.Comments()`.
- Source: [`quartz-community/comments`](https://github.com/quartz-community/comments)
- Install: `npx quartz plugin add github:quartz-community/comments`

View File

@ -14,5 +14,5 @@ This plugin has no configuration options.
## API ## API
- Category: Emitter - Category: Emitter
- Function name: `Plugin.ComponentResources()` (internal plugin). - Function name: `Plugin.ComponentResources()`.
- Source: [`quartz/plugins/emitters/componentResources.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/emitters/componentResources.ts). - Source: [`quartz/plugins/emitters/componentResources.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/componentResources.ts).

View File

@ -23,6 +23,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Emitter - Category: Emitter
- Function name: `ExternalPlugin.ContentIndex()`. - Function name: `Plugin.ContentIndex()`.
- Source: [`quartz-community/content-index`](https://github.com/quartz-community/content-index) - Source: [`quartz/plugins/emitters/contentIndex.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/contentIndex.ts).
- Install: `npx quartz plugin add github:quartz-community/content-index`

View File

@ -1,34 +0,0 @@
---
title: ContentMeta
tags:
- plugin/component
---
This plugin displays content metadata below the article title, such as the creation date and estimated reading time.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Configuration
This plugin accepts the following configuration options:
- `showReadingTime`: Whether to display the estimated reading time. Defaults to `true`.
- `showComma`: Whether to display a comma between metadata items. Defaults to `true`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/content-meta
enabled: true
options:
showReadingTime: true
showComma: true
```
## API
- Category: Component
- Function name: `ExternalPlugin.ContentMeta()`.
- Source: [`quartz-community/content-meta`](https://github.com/quartz-community/content-meta)
- Install: `npx quartz plugin add github:quartz-community/content-meta`

View File

@ -1,10 +1,10 @@
--- ---
title: ContentPage title: ContentPage
tags: tags:
- plugin/pageType - plugin/emitter
--- ---
This plugin is a page type plugin for the Quartz framework. It generates the HTML pages for each piece of Markdown content. It emits the full-page [[layout]], including headers, footers, and body content, among others. It uses the `default` [[layout#Page Frames|page frame]] (three-column layout with sidebars). It is now configured in the `pageTypes` section of `quartz.config.yaml`. This plugin is a core component of the Quartz framework. It generates the HTML pages for each piece of Markdown content. It emits the full-page [[layout]], including headers, footers, and body content, among others.
> [!note] > [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. > For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
@ -13,7 +13,6 @@ This plugin has no configuration options.
## API ## API
- Category: Page Type - Category: Emitter
- Function name: `ExternalPlugin.ContentPage()`. - Function name: `Plugin.ContentPage()`.
- Source: [`quartz-community/content-page`](https://github.com/quartz-community/content-page) - Source: [`quartz/plugins/emitters/contentPage.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/contentPage.tsx).
- Install: `npx quartz plugin add github:quartz-community/content-page`

View File

@ -26,6 +26,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.CrawlLinks()`. - Function name: `Plugin.CrawlLinks()`.
- Source: [`quartz-community/crawl-links`](https://github.com/quartz-community/crawl-links) - Source: [`quartz/plugins/transformers/links.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/links.ts).
- Install: `npx quartz plugin add github:quartz-community/crawl-links`

View File

@ -16,13 +16,12 @@ This plugin accepts the following configuration options:
When loading the frontmatter, the value of [[Frontmatter#List]] is used. When loading the frontmatter, the value of [[Frontmatter#List]] is used.
> [!warning] > [!warning]
> If you rely on `git` for dates, make sure `defaultDateType` is set to `modified` in `quartz.config.yaml`. > If you rely on `git` for dates, make sure `defaultDateType` is set to `modified` in `quartz.config.ts`.
> >
> Depending on how you [[hosting|host]] your Quartz, the `filesystem` dates of your local files may not match the final dates. In these cases, it may be better to use `git` or `frontmatter` to guarantee correct dates. > Depending on how you [[hosting|host]] your Quartz, the `filesystem` dates of your local files may not match the final dates. In these cases, it may be better to use `git` or `frontmatter` to guarantee correct dates.
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.CreatedModifiedDate()`. - Function name: `Plugin.CreatedModifiedDate()`.
- Source: [`quartz-community/created-modified-date`](https://github.com/quartz-community/created-modified-date) - Source: [`quartz/plugins/transformers/lastmod.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/lastmod.ts).
- Install: `npx quartz plugin add github:quartz-community/created-modified-date`

View File

@ -25,29 +25,22 @@ The Custom OG Images emitter plugin generates social media preview images for yo
This plugin accepts the following configuration options: This plugin accepts the following configuration options:
```yaml title="quartz.config.yaml" ```typescript title="quartz.config.ts"
plugins: import { CustomOgImages } from "./quartz/plugins/emitters/ogImage"
- source: github:quartz-community/og-image
enabled: true
options:
colorScheme: lightMode # "lightMode" or "darkMode"
width: 1200
height: 630
excludeRoot: false
```
For the TS override approach (needed for custom `imageStructure`):
```ts title="quartz.ts (override)"
import { defaultImage } from "./quartz/plugins/emitters/ogImage"
const config: QuartzConfig = {
plugins: {
emitters: [
CustomOgImages({ CustomOgImages({
colorScheme: "lightMode", colorScheme: "lightMode", // what colors to use for generating image, same as theme colors from config, valid values are "darkMode" and "lightMode"
width: 1200, width: 1200, // width to generate with (in pixels)
height: 630, height: 630, // height to generate with (in pixels)
excludeRoot: false, excludeRoot: false, // wether to exclude "/" index path to be excluded from auto generated images (false = use auto, true = use default og image)
imageStructure: defaultImage, // custom JSX component — requires TS imageStructure: defaultImage, // custom image component to use
}) }),
],
},
}
``` ```
### Configuration Options ### Configuration Options
@ -83,7 +76,7 @@ You can fully customize how the images being generated look by passing your own
### Fonts ### Fonts
You will also be passed an array containing a header and a body font (where the first entry is header and the second is body). The fonts matches the ones selected in `theme.typography.header` and `theme.typography.body` from `quartz.config.yaml` and will be passed in the format required by [`satori`](https://github.com/vercel/satori). To use them in CSS, use the `.name` property (e.g. `fontFamily: fonts[1].name` to use the "body" font family). You will also be passed an array containing a header and a body font (where the first entry is header and the second is body). The fonts matches the ones selected in `theme.typography.header` and `theme.typography.body` from `quartz.config.ts` and will be passed in the format required by [`satori`](https://github.com/vercel/satori). To use them in CSS, use the `.name` property (e.g. `fontFamily: fonts[1].name` to use the "body" font family).
An example of a component using the header font could look like this: An example of a component using the header font could look like this:
@ -365,10 +358,3 @@ export const og: SocialImageOptions["Component"] = (
) )
} }
``` ```
## API
- Category: Emitter
- Function name: `ExternalPlugin.CustomOgImages()`.
- Source: [`quartz-community/og-image`](https://github.com/quartz-community/og-image)
- Install: `npx quartz plugin add github:quartz-community/og-image`

View File

@ -1,32 +0,0 @@
---
title: Darkmode
tags:
- plugin/component
---
Dark mode toggle.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[darkmode]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `enabled`: Whether to enable the dark mode toggle. Defaults to `true`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/darkmode
enabled: true
```
## API
- Category: Component
- Function name: `ExternalPlugin.Darkmode()`.
- Source: [`quartz-community/darkmode`](https://github.com/quartz-community/darkmode)
- Install: `npx quartz plugin add github:quartz-community/darkmode`

View File

@ -19,6 +19,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.Description()`. - Function name: `Plugin.Description()`.
- Source: [`quartz-community/description`](https://github.com/quartz-community/description) - Source: [`quartz/plugins/transformers/description.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/description.ts).
- Install: `npx quartz plugin add github:quartz-community/description`

View File

@ -1,25 +0,0 @@
---
title: Encrypted Pages Demo
password: quartz
tags:
- plugin/transformer
---
Congratulations! You've successfully decrypted this page. 🎉
This is a live demo of the [[EncryptedPages]] plugin. The content you're reading was encrypted at build time using AES-256-GCM and decrypted in your browser using the Web Crypto API.
## What just happened?
1. At build time, the plugin read the `password` field from this page's frontmatter and encrypted all content below the title.
2. When you visited this page, you were shown a password prompt instead of the page content.
3. After entering the correct password, the plugin derived an encryption key using PBKDF2 and decrypted the content client-side.
4. A `render` event was dispatched so other components (graph, explorer, etc.) could re-initialize with the decrypted content.
## Password caching
Your password has been cached in session storage. If there were other encrypted pages on this site, the plugin would automatically try this password before showing the prompt — so you'd only need to enter it once per session for pages that share the same password.
## Try it yourself
To add encrypted pages to your own Quartz site, install the plugin and add a `password` field to any page's frontmatter. See [[EncryptedPages]] for full setup instructions.

View File

@ -1,72 +0,0 @@
---
title: EncryptedPages
tags:
- plugin/transformer
- plugin/filter
---
Password-protected encrypted pages. Encrypts page content at build time using AES-256-GCM and decrypts client-side with the Web Crypto API. Passwords are set per-page via frontmatter.
> [!example] Live demo
> Try it yourself: [[EncryptedPages Demo]]. The password is `quartz`.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Usage
Add a `password` field to any page's frontmatter to encrypt it:
```yaml
---
title: My Secret Page
password: mysecretpassword
---
```
The page content will be encrypted at build time. Visitors must enter the correct password to view the content.
Successful passwords are cached in the browser's session storage and automatically tried on other encrypted pages for convenience.
## Configuration
This plugin provides a transformer, a filter, and a component.
### Transformer options
- `visibility`: How encrypted pages appear in graph, explorer, and backlinks. `"visible"` shows the page normally, `"icon"` adds a lock indicator, `"hidden"` hides the page completely. Defaults to `"icon"`.
- `iterations`: PBKDF2 iteration count for key derivation. Higher values are more secure but slower to unlock. Defaults to `600000`.
- `passwordField`: Frontmatter field name that holds the page password. Defaults to `"password"`.
### Filter options
- `visibility`: Controls whether encrypted pages appear in search, RSS, and sitemap. When set to `"hidden"`, encrypted pages are excluded from content indices entirely. Defaults to `"icon"`.
### Component options
- `className`: CSS class for the component wrapper. Defaults to `"encrypted-page-wrapper"`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/encrypted-pages
enabled: true
options:
visibility: icon
iterations: 600000
passwordField: password
```
## Security
- Content is encrypted with AES-256-GCM using PBKDF2 SHA-256 key derivation.
- Plaintext is stripped from search indices and RSS feeds regardless of visibility setting.
- Passwords are set per-page in frontmatter. Avoid committing passwords to public repositories.
- This is client-side encryption of a static site. It protects against casual browsing but not against determined attackers with access to the page source.
## API
- Category: Transformer, Filter
- Function name: `ExternalPlugin.EncryptedPages()`, `ExternalPlugin.EncryptedPageFilter()`.
- Source: [`quartz-community/encrypted-pages`](https://github.com/quartz-community/encrypted-pages)
- Install: `npx quartz plugin add github:quartz-community/encrypted-pages`

View File

@ -14,6 +14,5 @@ This plugin has no configuration options.
## API ## API
- Category: Filter - Category: Filter
- Function name: `ExternalPlugin.ExplicitPublish()`. - Function name: `Plugin.ExplicitPublish()`.
- Source: [`quartz-community/explicit-publish`](https://github.com/quartz-community/explicit-publish) - Source: [`quartz/plugins/filters/explicit.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/filters/explicit.ts).
- Install: `npx quartz plugin add github:quartz-community/explicit-publish`

View File

@ -1,40 +0,0 @@
---
title: Explorer
tags:
- plugin/component
---
File tree explorer sidebar.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[explorer]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `title`: The title of the explorer. Defaults to `Explorer`.
- `folderClickBehavior`: The behavior when a folder is clicked. Can be `"link"` to navigate or `"collapse"` to toggle. Defaults to `collapse`.
- `folderDefaultState`: The default state of folders. Can be `"collapsed"` or `"open"`. Defaults to `collapsed`.
- `useSavedState`: Whether to use local storage to save the state of the explorer. Defaults to `true`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/explorer
enabled: true
options:
title: Explorer
folderClickBehavior: collapse
folderDefaultState: collapsed
useSavedState: true
```
## API
- Category: Component
- Function name: `ExternalPlugin.Explorer()`.
- Source: [`quartz-community/explorer`](https://github.com/quartz-community/explorer)
- Install: `npx quartz plugin add github:quartz-community/explorer`

View File

@ -15,6 +15,5 @@ This plugin has no configuration options.
## API ## API
- Category: Emitter - Category: Emitter
- Function name: `ExternalPlugin.Favicon()`. - Function name: `Plugin.Favicon()`.
- Source: [`quartz-community/favicon`](https://github.com/quartz-community/favicon) - Source: [`quartz/plugins/emitters/favicon.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/favicon.ts).
- Install: `npx quartz plugin add github:quartz-community/favicon`

View File

@ -1,23 +1,24 @@
--- ---
title: FolderPage title: FolderPage
tags: tags:
- plugin/pageType - plugin/emitter
--- ---
This plugin is a page type plugin that generates index pages for folders, creating a listing page for each folder that contains multiple content files. It uses the `default` [[layout#Page Frames|page frame]] (three-column layout with sidebars). See [[folder and tag listings]] for more information. This plugin generates index pages for folders, creating a listing page for each folder that contains multiple content files. See [[folder and tag listings]] for more information.
Example: [[advanced/|Advanced]] Example: [[advanced/|Advanced]]
> [!note] > [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. > For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
The pages are displayed using the `defaultListPageLayout` in `quartz.layouts.ts`. For the content, the `FolderContent` component is used. If you want to modify the layout, you must edit it directly (`quartz/components/pages/FolderContent.tsx`).
This plugin accepts the following configuration options: This plugin accepts the following configuration options:
- `sort`: A function of type `(f1: QuartzPluginData, f2: QuartzPluginData) => number{:ts}` used to sort entries. Defaults to sorting by date and tie-breaking on lexographical order. - `sort`: A function of type `(f1: QuartzPluginData, f2: QuartzPluginData) => number{:ts}` used to sort entries. Defaults to sorting by date and tie-breaking on lexographical order.
## API ## API
- Category: Page Type - Category: Emitter
- Function name: `ExternalPlugin.FolderPage()`. - Function name: `Plugin.FolderPage()`.
- Source: [`quartz-community/folder-page`](https://github.com/quartz-community/folder-page) - Source: [`quartz/plugins/emitters/folderPage.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/folderPage.tsx).
- Install: `npx quartz plugin add github:quartz-community/folder-page`

View File

@ -1,34 +0,0 @@
---
title: Footer
tags:
- plugin/component
---
This plugin renders a footer at the bottom of the page with a "Created with Quartz" message and a set of configurable links.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## Configuration
This plugin accepts the following configuration options:
- `links`: A map of link labels to their URLs to display in the footer. Defaults to `{}`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/footer
enabled: true
options:
links:
GitHub: https://github.com/jackyzha0/quartz
Discord Community: https://discord.gg/cRFFHYye7t
```
## API
- Category: Component
- Function name: `ExternalPlugin.Footer()`.
- Source: [`quartz-community/footer`](https://github.com/quartz-community/footer)
- Install: `npx quartz plugin add github:quartz-community/footer`

View File

@ -1,107 +1,72 @@
--- ---
title: "Frontmatter" title: "Frontmatter"
aliases:
- note-properties
- Note Properties
description: "Parses frontmatter and displays note properties in a collapsible panel."
tags: tags:
- plugin/transformer - plugin/transformer
- plugin/component
publish: true
enableToc: true
--- ---
This plugin parses the frontmatter of the page using the [gray-matter](https://github.com/jonschlinkert/gray-matter) library and optionally displays selected properties in a collapsible panel. See [[authoring content#Syntax]], [[Obsidian compatibility]] and [[OxHugo compatibility]] for more information. This plugin parses the frontmatter of the page using the [gray-matter](https://github.com/jonschlinkert/gray-matter) library. See [[authoring content#Syntax]], [[Obsidian compatibility]] and [[OxHugo compatibility]] for more information.
> [!note] > [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. > For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
> [!warning]
> This plugin must not be removed, otherwise Quartz will break.
## Configuration
This plugin accepts the following configuration options: This plugin accepts the following configuration options:
- `delimiters`: the delimiters to use for the frontmatter. Can have one value (e.g. `"---"`) or separate values for opening and closing delimiters (e.g. `["---", "~~~"]`). Defaults to `"---"`. - `delimiters`: the delimiters to use for the frontmatter. Can have one value (e.g. `"---"`) or separate values for opening and closing delimiters (e.g. `["---", "~~~"]`). Defaults to `"---"`.
- `language`: the language to use for parsing the frontmatter. Can be `yaml` (default) or `toml`. - `language`: the language to use for parsing the frontmatter. Can be `yaml` (default) or `toml`.
- `includeAll`: include all frontmatter properties in the properties panel. When `false`, only `includedProperties` are shown. Defaults to `false`.
- `includedProperties`: properties to include when `includeAll` is `false`. Defaults to `["description", "tags", "aliases"]`.
- `excludedProperties`: properties to always exclude from display, even when `includeAll` is `true`. Defaults to `[]`.
- `hidePropertiesView`: hide the visual properties panel while still processing frontmatter. Useful if you only need frontmatter parsing without the UI. Defaults to `false`.
### Default options > [!warning]
> This plugin must not be removed, otherwise Quartz will break.
```yaml title="quartz.config.yaml" ## List
- source: github:quartz-community/note-properties
enabled: true Quartz supports the following frontmatter:
options:
includeAll: false - title
includedProperties: - `title`
- description - description
- `description`
- permalink
- `permalink`
- comments
- `comments`
- lang
- `lang`
- publish
- `publish`
- draft
- `draft`
- enableToc
- `enableToc`
- tags - tags
- `tags`
- `tag`
- aliases - aliases
excludedProperties: [] - `aliases`
hidePropertiesView: false - `alias`
delimiters: "---" - cssclasses
language: yaml - `cssclasses`
``` - `cssclass`
- socialDescription
## Properties panel - `socialDescription`
- socialImage
When enabled, this plugin renders a collapsible "Properties" panel before the page body. The panel displays selected frontmatter fields in a table with automatic type rendering: - `socialImage`
- `image`
- **Strings** are shown as plain text. [[Wikilinks]] and [markdown links](https://example.com) within strings are rendered as clickable links. - `cover`
- **Arrays** are rendered as comma-separated lists. - created
- **Booleans** are rendered as disabled checkboxes. - `created`
- **Numbers** are rendered in a monospace font. - `date`
- **Objects** are rendered as JSON in a code block. - modified
- **Tags** get special treatment: they are rendered as highlighted links that point to the corresponding tag page. - `modified`
- **Null/undefined** values are shown as an em-dash (—). - `lastmod`
- `updated`
### Per-note overrides - `last-modified`
- published
You can control the properties panel on a per-note basis using frontmatter keys: - `published`
- `publishDate`
- `quartz-properties` (or `quartzProperties`): set to `true` to force-show the panel, or `false` to force-hide it, overriding the global `hidePropertiesView` setting. - `date`
- `quartz-properties-collapse` (or `quartzPropertiesCollapse`): set to `true` to start the panel collapsed, or `false` to start it expanded, overriding the default collapse state.
These keys are automatically excluded from the visible properties table.
```yaml title="Example frontmatter"
---
title: My Note
quartz-properties: true
quartz-properties-collapse: false
---
```
## Supported frontmatter
Quartz supports the following frontmatter fields. Where multiple keys are listed, they are aliases — the first matching key is used.
| Field | Keys | Description |
| ------------------ | ------------------------------------------------- | ------------------------------------------------------------------ |
| Title | `title` | Page title. Falls back to filename if empty. |
| Description | `description` | Page description for metadata and search. |
| Tags | `tags`, `tag` | Categorization tags. Automatically slugified. |
| Aliases | `aliases`, `alias` | Alternative names for the page, used for link resolution. |
| Permalink | `permalink` | Custom URL slug. Also added to aliases. |
| CSS classes | `cssclasses`, `cssclass` | CSS classes applied to the page body. |
| Social image | `socialImage`, `image`, `cover` | Image used for social media previews. |
| Social description | `socialDescription` | Description used specifically for social media previews. |
| Created date | `created`, `date` | When the note was created. |
| Modified date | `modified`, `lastmod`, `updated`, `last-modified` | When the note was last modified. Falls back to `created` if unset. |
| Published date | `published`, `publishDate`, `date` | When the note was published. |
| Publish | `publish` | Whether the note should be published. |
| Draft | `draft` | Whether the note is a draft. |
| Comments | `comments` | Whether comments are enabled for the note. |
| Language | `lang` | Language code for the note. |
| Enable TOC | `enableToc` | Whether to show the table of contents. |
## API ## API
- Category: Transformer, Component - Category: Transformer
- Function name: `ExternalPlugin.NoteProperties()`. - Function name: `Plugin.Frontmatter()`.
- Source: [`quartz-community/note-properties`](https://github.com/quartz-community/note-properties) - Source: [`quartz/plugins/transformers/frontmatter.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/frontmatter.ts).
- Install: `npx quartz plugin add github:quartz-community/note-properties`

View File

@ -19,6 +19,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.GitHubFlavoredMarkdown()`. - Function name: `Plugin.GitHubFlavoredMarkdown()`.
- Source: [`quartz-community/github-flavored-markdown`](https://github.com/quartz-community/github-flavored-markdown) - Source: [`quartz/plugins/transformers/gfm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/gfm.ts).
- Install: `npx quartz plugin add github:quartz-community/github-flavored-markdown`

View File

@ -1,77 +0,0 @@
---
title: Graph
tags:
- plugin/component
---
Interactive graph visualization.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[graph view]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `localGraph`: Options for the local graph view.
- `globalGraph`: Options for the global graph view.
Both `localGraph` and `globalGraph` accept the following options:
- `drag`: Enable dragging nodes. Defaults to `true`.
- `zoom`: Enable zooming. Defaults to `true`.
- `depth`: The depth of the graph. Defaults to `1` for local and `-1` for global.
- `scale`: The initial scale of the graph.
- `repelForce`: The force that pushes nodes apart.
- `centerForce`: The force that pulls nodes to the center.
- `linkDistance`: The distance between linked nodes.
- `fontSize`: The font size of node labels.
- `opacityScale`: The scale of node opacity.
- `removeTags`: Tags to exclude from the graph.
- `showTags`: Whether to show tags in the graph.
- `enableRadial`: Whether to enable radial layout.
- `focusOnHover`: Whether to focus on the hovered node (global only).
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/graph
enabled: true
options:
localGraph:
drag: true
zoom: true
depth: 1
scale: 1.1
repelForce: 0.5
centerForce: 0.3
linkDistance: 30
fontSize: 0.6
opacityScale: 1
removeTags: []
showTags: true
enableRadial: false
globalGraph:
drag: true
zoom: true
depth: -1
scale: 0.9
repelForce: 0.5
centerForce: 0.3
linkDistance: 30
fontSize: 0.6
opacityScale: 1
removeTags: []
showTags: true
focusOnHover: true
enableRadial: true
```
## API
- Category: Component
- Function name: `ExternalPlugin.Graph()`.
- Source: [`quartz-community/graph`](https://github.com/quartz-community/graph)
- Install: `npx quartz plugin add github:quartz-community/graph`

View File

@ -14,6 +14,5 @@ This plugin has no configuration options.
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.HardLineBreaks()`. - Function name: `Plugin.HardLineBreaks()`.
- Source: [`quartz-community/hard-line-breaks`](https://github.com/quartz-community/hard-line-breaks) - Source: [`quartz/plugins/transformers/linebreaks.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/linebreaks.ts).
- Install: `npx quartz plugin add github:quartz-community/hard-line-breaks`

View File

@ -17,6 +17,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.Latex()`. - Function name: `Plugin.Latex()`.
- Source: [`quartz-community/latex`](https://github.com/quartz-community/latex) - Source: [`quartz/plugins/transformers/latex.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/latex.ts).
- Install: `npx quartz plugin add github:quartz-community/latex`

View File

@ -1,10 +1,10 @@
--- ---
title: NotFoundPage title: NotFoundPage
tags: tags:
- plugin/pageType - plugin/emitter
--- ---
This plugin emits a 404 (Not Found) page for broken or non-existent URLs. It uses the `minimal` [[layout#Page Frames|page frame]] (no sidebars, no header or beforeBody chrome — only content and footer) to present a clean error page. This plugin emits a 404 (Not Found) page for broken or non-existent URLs.
> [!note] > [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. > For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
@ -13,6 +13,6 @@ This plugin has no configuration options.
## API ## API
- Category: Page Type - Category: Emitter
- Function name: `Plugin.NotFoundPage()` (internal plugin). - Function name: `Plugin.NotFoundPage()`.
- Source: [`quartz/plugins/pageTypes/404.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/pageTypes/404.ts) - Source: [`quartz/plugins/emitters/404.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/404.tsx).

View File

@ -1,17 +0,0 @@
---
title: NoteProperties
tags:
- plugin/component
---
The NoteProperties plugin is documented under [[Frontmatter]].
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
## API
- Category: Component
- Function name: `ExternalPlugin.NoteProperties()`.
- Source: [`quartz-community/note-properties`](https://github.com/quartz-community/note-properties)
- Install: `npx quartz plugin add github:quartz-community/note-properties`

View File

@ -17,13 +17,12 @@ This plugin accepts the following configuration options:
- `callouts`: If `true` (default), adds support for [[callouts|callout]] blocks for emphasizing content. - `callouts`: If `true` (default), adds support for [[callouts|callout]] blocks for emphasizing content.
- `mermaid`: If `true` (default), enables [[Mermaid diagrams|Mermaid diagram]] rendering within Markdown files. - `mermaid`: If `true` (default), enables [[Mermaid diagrams|Mermaid diagram]] rendering within Markdown files.
- `parseTags`: If `true` (default), parses and links tags within the content. - `parseTags`: If `true` (default), parses and links tags within the content.
- `parseArrows`: If `true` (default), transforms arrow symbols into their HTML character equivalents.
- `parseBlockReferences`: If `true` (default), handles block references, linking to specific content blocks. - `parseBlockReferences`: If `true` (default), handles block references, linking to specific content blocks.
- `enableInHtmlEmbed`: If `true`, allows embedding of content directly within HTML. Defaults to `false`. - `enableInHtmlEmbed`: If `true`, allows embedding of content directly within HTML. Defaults to `false`.
- `enableYouTubeEmbed`: If `true` (default), enables the embedding of YouTube videos and playlists using external image Markdown syntax. - `enableYouTubeEmbed`: If `true` (default), enables the embedding of YouTube videos and playlists using external image Markdown syntax.
- `enableTweetEmbed`: If `true` (default), enables the embedding of tweets as static blockquotes from Twitter/X URLs.
- `enableVideoEmbed`: If `true` (default), enables the embedding of video files. - `enableVideoEmbed`: If `true` (default), enables the embedding of video files.
- `enableCheckbox`: If `true`, adds support for interactive checkboxes in content, including custom task characters (e.g. `- [?]`, `- [!]`, `- [/]`). Defaults to `false`. - `enableCheckbox`: If `true`, adds support for interactive checkboxes in content. Defaults to `false`.
- `enableObsidianUri`: If `true` (default), marks `obsidian://` protocol links with a CSS class and data attribute for custom styling.
- `disableBrokenWikilinks`: If `true`, replaces links to non-existent notes with a dimmed, disabled link. Defaults to `false`. - `disableBrokenWikilinks`: If `true`, replaces links to non-existent notes with a dimmed, disabled link. Defaults to `false`.
> [!warning] > [!warning]
@ -32,6 +31,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.ObsidianFlavoredMarkdown()`. - Function name: `Plugin.ObsidianFlavoredMarkdown()`.
- Source: [`quartz-community/obsidian-flavored-markdown`](https://github.com/quartz-community/obsidian-flavored-markdown) - Source: [`quartz/plugins/transformers/ofm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/ofm.ts)
- Install: `npx quartz plugin add github:quartz-community/obsidian-flavored-markdown`

View File

@ -25,6 +25,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.OxHugoFlavoredMarkdown()`. - Function name: `Plugin.OxHugoFlavoredMarkdown()`.
- Source: [`quartz-community/ox-hugo`](https://github.com/quartz-community/ox-hugo) - Source: [`quartz/plugins/transformers/oxhugofm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/oxhugofm.ts).
- Install: `npx quartz plugin add github:quartz-community/ox-hugo`

View File

@ -1,19 +0,0 @@
---
title: PageTitle
tags:
- plugin/component
---
This plugin renders the site-wide page title (configured via the `pageTitle` field in [[configuration]]) as a clickable link to the home page. It typically appears in the left sidebar.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
This plugin has no configuration options. The displayed title is controlled by the `pageTitle` field in `quartz.config.yaml`.
## API
- Category: Component
- Function name: `ExternalPlugin.PageTitle()`.
- Source: [`quartz-community/page-title`](https://github.com/quartz-community/page-title)
- Install: `npx quartz plugin add github:quartz-community/page-title`

View File

@ -1,32 +0,0 @@
---
title: ReaderMode
tags:
- plugin/component
---
Distraction-free reading mode.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[reader mode]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `enabled`: Whether to enable reader mode. Defaults to `true`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/reader-mode
enabled: true
```
## API
- Category: Component
- Function name: `ExternalPlugin.ReaderMode()`.
- Source: [`quartz-community/reader-mode`](https://github.com/quartz-community/reader-mode)
- Install: `npx quartz plugin add github:quartz-community/reader-mode`

View File

@ -1,40 +0,0 @@
---
title: RecentNotes
tags:
- plugin/component
---
Shows recently modified notes.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[recent notes]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `title`: The title of the recent notes section. Defaults to `Recent notes`.
- `limit`: The maximum number of recent notes to display. Defaults to `5`.
- `showTags`: Whether to display the tags for each note. Defaults to `true`.
- `linkToMore`: A slug to a page that shows more notes. Defaults to `""`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/recent-notes
enabled: true
options:
title: Recent notes
limit: 5
showTags: true
linkToMore: ""
```
## API
- Category: Component
- Function name: `ExternalPlugin.RecentNotes()`.
- Source: [`quartz-community/recent-notes`](https://github.com/quartz-community/recent-notes)
- Install: `npx quartz plugin add github:quartz-community/recent-notes`

View File

@ -14,6 +14,5 @@ This plugin has no configuration options.
## API ## API
- Category: Filter - Category: Filter
- Function name: `ExternalPlugin.RemoveDrafts()`. - Function name: `Plugin.RemoveDrafts()`.
- Source: [`quartz-community/remove-draft`](https://github.com/quartz-community/remove-draft) - Source: [`quartz/plugins/filters/draft.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/filters/draft.ts).
- Install: `npx quartz plugin add github:quartz-community/remove-draft`

View File

@ -22,6 +22,5 @@ This plugin accepts the following configuration options:
## API ## API
- Category: Transformer - Category: Transformer
- Function name: `ExternalPlugin.RoamFlavoredMarkdown()`. - Function name: `Plugin.RoamFlavoredMarkdown()`.
- Source: [`quartz-community/roam`](https://github.com/quartz-community/roam) - Source: [`quartz/plugins/transformers/roam.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/roam.ts).
- Install: `npx quartz plugin add github:quartz-community/roam`

View File

@ -1,32 +0,0 @@
---
title: Search
tags:
- plugin/component
---
Full-text search functionality.
> [!note]
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
See [[full-text search]] for detailed usage information.
## Configuration
This plugin accepts the following configuration options:
- `enabled`: Whether to enable full-text search. Defaults to `true`.
### Default options
```yaml title="quartz.config.yaml"
- source: github:quartz-community/search
enabled: true
```
## API
- Category: Component
- Function name: `ExternalPlugin.Search()`.
- Source: [`quartz-community/search`](https://github.com/quartz-community/search)
- Install: `npx quartz plugin add github:quartz-community/search`

Some files were not shown because too many files have changed in this diff Show More