Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 47d0c3518d | |||
| 7a95030086 | |||
| 36d1925580 | |||
| d25a6eabf9 | |||
| 59b5807601 | |||
| 9576701d85 | |||
| 16ac065be5 | |||
| 7f268bb227 |
@@ -28,18 +28,7 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ 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 install
|
||||
|
||||
- name: Install Quartz plugins
|
||||
run: npx quartz plugin install
|
||||
- run: npm ci
|
||||
|
||||
- name: Check types and style
|
||||
run: npm run check
|
||||
@@ -48,7 +37,7 @@ jobs:
|
||||
run: npx quartz build -d docs -v
|
||||
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: preview-build
|
||||
path: public
|
||||
|
||||
@@ -3,10 +3,10 @@ name: Build and Test
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- v5
|
||||
- v4
|
||||
push:
|
||||
branches:
|
||||
- v5
|
||||
- v4
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v5
|
||||
@@ -36,18 +36,7 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ 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 install
|
||||
|
||||
- name: Install Quartz plugins
|
||||
run: npx quartz plugin install
|
||||
- run: npm ci
|
||||
|
||||
- name: Check types and style
|
||||
run: npm run check
|
||||
@@ -59,7 +48,7 @@ jobs:
|
||||
run: npx quartz build --bundleInfo -d docs
|
||||
|
||||
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
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -70,7 +59,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
- name: Get package version
|
||||
run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV
|
||||
- name: Create release tag
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
name: Deploy Preview to Cloudflare Pages
|
||||
steps:
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v7
|
||||
id: preview-build-artifact
|
||||
with:
|
||||
name: preview-build
|
||||
|
||||
@@ -1,64 +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: 24
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ 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 install
|
||||
|
||||
- name: Install Quartz plugins
|
||||
run: npx quartz plugin install
|
||||
|
||||
- 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
|
||||
@@ -2,10 +2,10 @@ name: Docker build & push image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [v5]
|
||||
branches: [v4]
|
||||
tags: ["v*"]
|
||||
pull_request:
|
||||
branches: [v5]
|
||||
branches: [v4]
|
||||
paths:
|
||||
- .github/workflows/docker-build-push.yaml
|
||||
- quartz/**
|
||||
@@ -25,11 +25,11 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Inject slug/short variables
|
||||
uses: rlespinasse/github-slug-action@v5.6.0
|
||||
uses: rlespinasse/github-slug-action@v5.4.0
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
install: true
|
||||
driver-opts: |
|
||||
@@ -37,9 +37,9 @@ jobs:
|
||||
network=host
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@v4.1.2
|
||||
uses: sigstore/cosign-installer@v4.0.0
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
if: github.event_name != 'pull_request'
|
||||
with:
|
||||
registry: ghcr.io
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
- name: Extract metadata tags and labels on PRs
|
||||
if: github.event_name == 'pull_request'
|
||||
id: meta-pr
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ env.OWNER_LOWERCASE }}/quartz
|
||||
tags: |
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
- name: Extract metadata tags and labels for main, release or tag
|
||||
if: github.event_name != 'pull_request'
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
flavor: |
|
||||
latest=auto
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
build-args: |
|
||||
|
||||
+1
-3
@@ -9,6 +9,4 @@ tsconfig.tsbuildinfo
|
||||
private/
|
||||
.replit
|
||||
replit.nix
|
||||
.quartz/
|
||||
quartz/cli/tui/dist/
|
||||
.turbo/
|
||||
public/
|
||||
|
||||
+1
-15
@@ -3,19 +3,5 @@
|
||||
"quoteProps": "as-needed",
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.canvas",
|
||||
"options": {
|
||||
"parser": "json"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.base",
|
||||
"options": {
|
||||
"parser": "yaml"
|
||||
}
|
||||
}
|
||||
]
|
||||
"semi": false
|
||||
}
|
||||
|
||||
+1
-8
@@ -1,15 +1,8 @@
|
||||
FROM node:22-slim AS builder
|
||||
|
||||
# install git to install plugins
|
||||
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
COPY package.json .
|
||||
COPY package-lock.json* .
|
||||
COPY .npmrc* .
|
||||
COPY quartz/ ./quartz/
|
||||
COPY quartz.lock.json* .
|
||||
RUN npm install; npx quartz plugin install
|
||||
RUN npm ci
|
||||
|
||||
FROM node:22-slim
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
-135
@@ -1,135 +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
|
||||
- type: cards
|
||||
name: Image Cards
|
||||
filters:
|
||||
and:
|
||||
- file.folder == "plugins"
|
||||
- "!image.isEmpty()"
|
||||
order:
|
||||
- file.name
|
||||
image: note.image
|
||||
cardSize: 220
|
||||
imageAspectRatio: 1
|
||||
@@ -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** (1–6) 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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`.
|
||||
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:
|
||||
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.
|
||||
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).
|
||||
@@ -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.
|
||||
5. Emit files using plugins.
|
||||
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.
|
||||
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.
|
||||
@@ -48,102 +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.
|
||||
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.
|
||||
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"`.
|
||||
|
||||
## Community Package Layering
|
||||
|
||||
Quartz v5 separates shared code into three community packages, each with a distinct responsibility:
|
||||
|
||||
- **`@quartz-community/types`** — Type definitions, interfaces, and the canonical `vfile` DataMap augmentation. This is the "contract" between Quartz and plugins. It has no runtime dependencies.
|
||||
- **`@quartz-community/utils`** — Shared utility functions (path manipulation, DOM helpers, sorting, date formatting, JSX conversion, etc.). Depends on `@quartz-community/types`.
|
||||
- **`@quartz-community/runtime`** — Browser-only utilities for client-side scripts (event handling, navigation, storage, script loading). Depends on both `types` and `utils`.
|
||||
|
||||
```
|
||||
types (no deps)
|
||||
↑
|
||||
utils (depends on types)
|
||||
↑
|
||||
runtime (depends on types + utils)
|
||||
↑
|
||||
plugins (depend on any combination)
|
||||
```
|
||||
|
||||
Plugins should import types from `@quartz-community/types`, utility functions from `@quartz-community/utils`, and browser utilities from `@quartz-community/runtime`. This layering ensures plugins don't depend on Quartz core.
|
||||
|
||||
## Plugin System
|
||||
|
||||
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.
|
||||
- **Bases Views**: Custom view renderers for the `bases-page` plugin's database-like view system. Plugins can register new view types (e.g., timeline, kanban) via the `ViewRegistry`. See [[making plugins#Bases Views]] for details.
|
||||
|
||||
Note that plugin types are **not mutually exclusive** — a single plugin can be a transformer AND provide components (e.g., `obsidian-flavored-markdown`), or be a page type AND provide custom frames (e.g., `canvas-page`).
|
||||
|
||||
### 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 install --latest` — Update all plugins to latest commits
|
||||
- `npx quartz plugin install --clean` — 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.
|
||||
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]].
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Creating Component Plugins
|
||||
title: Creating your own Quartz components
|
||||
---
|
||||
|
||||
> [!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.**
|
||||
|
||||
## 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
|
||||
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"
|
||||
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.
|
||||
|
||||
```tsx {11-17}
|
||||
interface Options {
|
||||
favouriteNumber: number
|
||||
}
|
||||
@@ -53,25 +39,28 @@ const defaultOptions: Options = {
|
||||
favouriteNumber: 42,
|
||||
}
|
||||
|
||||
const MyComponent: QuartzComponentConstructor<Options> = (userOpts?: Options) => {
|
||||
const opts = { ...defaultOptions, ...userOpts }
|
||||
export default ((userOpts?: Options) => {
|
||||
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 Component
|
||||
}
|
||||
|
||||
export default MyComponent
|
||||
return YourComponent
|
||||
}) satisfies QuartzComponentConstructor
|
||||
```
|
||||
|
||||
### 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:
|
||||
|
||||
```tsx
|
||||
```tsx title="quartz/components/types.ts"
|
||||
// simplified for sake of demonstration
|
||||
export type QuartzComponentProps = {
|
||||
fileData: QuartzPluginData
|
||||
cfg: GlobalConfiguration
|
||||
@@ -81,186 +70,179 @@ 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.frontmatter`: any frontmatter parsed.
|
||||
- `cfg`: The `configuration` field in `quartz.config.yaml`.
|
||||
- `tree`: the resulting [HTML AST](https://github.com/syntax-tree/hast) after processing and transforming the file.
|
||||
- `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. 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.
|
||||
- `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
|
||||
|
||||
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
|
||||
Component.css = `
|
||||
.my-component { color: red; }
|
||||
`
|
||||
Note that inlined styles **must** be plain vanilla CSS:
|
||||
|
||||
```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
|
||||
import styles from "./styles.scss"
|
||||
Component.css = styles
|
||||
```tsx {1-2,9} title="quartz/components/YourComponent.tsx"
|
||||
// assuming your stylesheet is in quartz/components/styles/YourComponent.scss
|
||||
import styles from "./styles/YourComponent.scss"
|
||||
|
||||
export default (() => {
|
||||
function YourComponent() {
|
||||
return <p>Example Component</p>
|
||||
}
|
||||
|
||||
YourComponent.css = styles
|
||||
return YourComponent
|
||||
}) satisfies QuartzComponentConstructor
|
||||
```
|
||||
|
||||
> [!warning]
|
||||
> Quartz does not use CSS modules so any styles you declare here apply _globally_. If you only want it to apply to your component, make sure you use specific class names and selectors.
|
||||
|
||||
### Internationalization
|
||||
|
||||
Component plugins should use the i18n pattern for any user-facing strings. See [[making plugins#Internationalization (i18n)]] for the full setup guide.
|
||||
|
||||
Quick reference:
|
||||
|
||||
```tsx
|
||||
import { i18n } from "../i18n"
|
||||
|
||||
const MyComponent: QuartzComponent = ({ cfg }) => {
|
||||
const t = i18n(cfg.locale ?? "en-US").components.myComponent
|
||||
return <h2>{t.title}</h2>
|
||||
}
|
||||
```
|
||||
|
||||
Always provide at least an `en-US` locale as the fallback. Additional locales are optional but encouraged for international reach.
|
||||
|
||||
### 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.
|
||||
- `.afterDOMLoaded`: Executed once the page has been completely loaded.
|
||||
```tsx title="quartz/components/YourComponent.tsx"
|
||||
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
|
||||
document.addEventListener("nav", () => {
|
||||
// do page specific logic here
|
||||
// e.g. attach event listeners
|
||||
const toggleSwitch = document.querySelector("#switch") as HTMLInputElement
|
||||
if (toggleSwitch) {
|
||||
toggleSwitch.addEventListener("change", switchTheme)
|
||||
window.addCleanup(() => toggleSwitch.removeEventListener("change", switchTheme))
|
||||
}
|
||||
toggleSwitch.addEventListener("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.
|
||||
|
||||
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:
|
||||
You can also add the equivalent of a `beforeunload` event for [[SPA Routing]] via the `prenav` event.
|
||||
|
||||
```ts
|
||||
function setupMyComponent() {
|
||||
const elements = document.querySelectorAll(".my-interactive")
|
||||
for (const el of elements) {
|
||||
el.addEventListener("click", handleClick)
|
||||
window.addCleanup(() => el.removeEventListener("click", handleClick))
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("nav", setupMyComponent)
|
||||
document.addEventListener("render", setupMyComponent)
|
||||
document.addEventListener("prenav", () => {
|
||||
// executed after an SPA navigation is triggered but
|
||||
// before the page is replaced
|
||||
// one usage pattern is to store things in sessionStorage
|
||||
// in the prenav and then conditionally load then in the consequent
|
||||
// nav
|
||||
})
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
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"
|
||||
import script from "./script.inline.ts"
|
||||
Quartz supports importing component code through `.inline.ts` files.
|
||||
|
||||
const Component: QuartzComponent = (props) => {
|
||||
return <button id="btn">Click me</button>
|
||||
}
|
||||
Component.afterDOMLoaded = script
|
||||
```
|
||||
```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"
|
||||
|
||||
The `inlineScriptPlugin` handles transpiling TypeScript to browser-compatible JavaScript during the build step, allowing you to write type-safe client-side code.
|
||||
|
||||
### Installing Your Component
|
||||
|
||||
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`:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:your-username/my-component
|
||||
enabled: true
|
||||
options:
|
||||
favouriteNumber: 42
|
||||
layout:
|
||||
position: left
|
||||
priority: 60
|
||||
```
|
||||
|
||||
For advanced usage via the TS override in `quartz.ts`:
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
|
||||
import Plugin from "./.quartz/plugins"
|
||||
|
||||
const config = await loadQuartzConfig()
|
||||
export default config
|
||||
export const layout = await loadQuartzLayout({
|
||||
byPageType: {
|
||||
content: {
|
||||
left: [Plugin.MyComponent({ favouriteNumber: 42 })],
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Receiving YAML Options in Component-Only Plugins
|
||||
|
||||
Component plugins that also belong to a processing category (transformer, filter, emitter, page type) receive options through their factory function automatically. However, **component-only plugins** — those whose manifest declares only `"category": ["component"]` — are loaded via side-effect import and don't go through the factory path.
|
||||
|
||||
To receive YAML options in a component-only plugin, export an `init` function from your entry point:
|
||||
|
||||
```ts title="src/index.ts"
|
||||
export function init(options?: Record<string, unknown>): void {
|
||||
// options contains merged defaultOptions + user's YAML options
|
||||
const myFlag = (options?.myFlag as boolean) ?? false
|
||||
// Use options to configure registrations, global state, etc.
|
||||
}
|
||||
```
|
||||
|
||||
Quartz's config-loader calls `init()` after importing the module, passing the merged result of your manifest's `defaultOptions` and the user's `options` from `quartz.config.yaml`. The merge follows the same `{ ...defaultOptions, ...userOptions }` pattern used for processing plugins — user values take precedence.
|
||||
|
||||
Declare your defaults in `package.json`:
|
||||
|
||||
```json title="package.json"
|
||||
{
|
||||
"quartz": {
|
||||
"category": ["component"],
|
||||
"defaultOptions": {
|
||||
"myFlag": false
|
||||
}
|
||||
export default (() => {
|
||||
function YourComponent() {
|
||||
return <button id="btn">Click me</button>
|
||||
}
|
||||
|
||||
YourComponent.afterDOMLoaded = script
|
||||
return YourComponent
|
||||
}) satisfies QuartzComponentConstructor
|
||||
```
|
||||
|
||||
```ts title="quartz/components/scripts/graph.inline.ts"
|
||||
// any imports here are bundled for the browser
|
||||
import * as d3 from "d3"
|
||||
|
||||
document.getElementById("btn").onclick = () => {
|
||||
alert("button clicked!")
|
||||
}
|
||||
```
|
||||
|
||||
If your plugin does not export `init`, it continues to work as a pure side-effect import — this is fully backward compatible.
|
||||
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.
|
||||
|
||||
## Internal Components
|
||||
### Using a Component
|
||||
|
||||
Quartz also has internal components that provide layout utilities. These live in `quartz/components/` and are primarily used for structural purposes:
|
||||
After creating your custom component, re-export it in `quartz/components/index.ts`:
|
||||
|
||||
- `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
|
||||
```ts title="quartz/components/index.ts" {4,10}
|
||||
import ArticleTitle from "./ArticleTitle"
|
||||
import Content from "./pages/Content"
|
||||
import Darkmode from "./Darkmode"
|
||||
import YourComponent from "./YourComponent"
|
||||
|
||||
See [[layout-components]] for more details on these utilities.
|
||||
export { ArticleTitle, Content, Darkmode, YourComponent }
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
As Quartz components are just functions that return React components, you can compositionally use them in other Quartz components.
|
||||
|
||||
```tsx title="quartz/components/AnotherComponent.tsx"
|
||||
import YourComponentConstructor from "./YourComponent"
|
||||
|
||||
export default (() => {
|
||||
const YourComponent = YourComponentConstructor()
|
||||
|
||||
function AnotherComponent(props: QuartzComponentProps) {
|
||||
return (
|
||||
<div>
|
||||
<p>It's nested!</p>
|
||||
<YourComponent {...props} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return AnotherComponent
|
||||
}) satisfies QuartzComponentConstructor
|
||||
```
|
||||
|
||||
> [!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!
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
---
|
||||
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
|
||||
|
||||
+57
-487
@@ -18,71 +18,20 @@ type QuartzPluginInstance =
|
||||
| QuartzTransformerPluginInstance
|
||||
| QuartzFilterPluginInstance
|
||||
| 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:
|
||||
|
||||
- `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
|
||||
- `cfg`: The full Quartz [[configuration]]
|
||||
- `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
|
||||
- `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.
|
||||
- `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.
|
||||
- `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 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 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.
|
||||
|
||||
## Getting Started
|
||||
|
||||
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
|
||||
|
||||
## Choosing a Plugin Type
|
||||
|
||||
Quartz supports six plugin capabilities. A single plugin can combine multiple types.
|
||||
|
||||
| I want to... | Plugin Type |
|
||||
| ------------------------------------------------ | ----------- |
|
||||
| Transform Markdown/HTML content | Transformer |
|
||||
| Decide which pages to publish | Filter |
|
||||
| Generate output files (RSS, sitemaps, manifests) | Emitter |
|
||||
| Define how a category of pages renders | Page Type |
|
||||
| Add a UI component to the layout | Component |
|
||||
| Add a custom view to the Bases database system | Bases View |
|
||||
|
||||
These are **not mutually exclusive**. For example:
|
||||
|
||||
- `obsidian-flavored-markdown` is both a **transformer** (processes OFM syntax) and provides **components** (mermaid rendering)
|
||||
- `canvas-page` is a **page type** that also provides a custom **frame**
|
||||
- A plugin could be a **transformer** that adds metadata AND a **component** that displays it
|
||||
|
||||
### Transformers
|
||||
## Transformers
|
||||
|
||||
Transformers **map** over content, taking a Markdown file and outputting modified content or adding metadata to the file itself.
|
||||
|
||||
@@ -103,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.
|
||||
- `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:
|
||||
|
||||
```ts
|
||||
```ts title="quartz/plugins/transformers/latex.ts"
|
||||
import remarkMath from "remark-math"
|
||||
import rehypeKatex from "rehype-katex"
|
||||
import rehypeMathjax from "rehype-mathjax/svg"
|
||||
import { QuartzTransformerPlugin } from "@quartz-community/types"
|
||||
import { QuartzTransformerPlugin } from "../types"
|
||||
|
||||
interface Options {
|
||||
renderEngine: "katex" | "mathjax"
|
||||
@@ -160,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:
|
||||
|
||||
```ts
|
||||
import { QuartzTransformerPlugin } from "@quartz-community/types"
|
||||
|
||||
export const AddWordCount: QuartzTransformerPlugin = () => {
|
||||
return {
|
||||
name: "AddWordCount",
|
||||
@@ -193,50 +140,45 @@ 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.
|
||||
|
||||
```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 = () => {
|
||||
return {
|
||||
name: "TextTransforms",
|
||||
markdownPlugins() {
|
||||
return [
|
||||
() => {
|
||||
return (tree, file) => {
|
||||
// replace _text_ with the italics version
|
||||
findAndReplace(tree, /_(.+)_/, (_value: string, ...capture: string[]) => {
|
||||
// inner is the text inside of the () of the regex
|
||||
const [inner] = capture
|
||||
// return an mdast node
|
||||
// https://github.com/syntax-tree/mdast
|
||||
return {
|
||||
type: "emphasis",
|
||||
children: [{ type: "text", value: inner }],
|
||||
}
|
||||
})
|
||||
return [() => {
|
||||
return (tree, file) => {
|
||||
// replace _text_ with the italics version
|
||||
findAndReplace(tree, /_(.+)_/, (_value: string, ...capture: string[]) => {
|
||||
// inner is the text inside of the () of the regex
|
||||
const [inner] = capture
|
||||
// return an mdast node
|
||||
// https://github.com/syntax-tree/mdast
|
||||
return {
|
||||
type: "emphasis",
|
||||
children: [{ type: 'text', value: inner }]
|
||||
}
|
||||
})
|
||||
|
||||
// remove all links (replace with just the link content)
|
||||
// match by 'type' field on an mdast node
|
||||
// https://github.com/syntax-tree/mdast#link in this example
|
||||
visit(tree, "link", (link: Link) => {
|
||||
return {
|
||||
type: "paragraph",
|
||||
children: [{ type: "text", value: link.title }],
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
// remove all links (replace with just the link content)
|
||||
// match by 'type' field on an mdast node
|
||||
// https://github.com/syntax-tree/mdast#link in this example
|
||||
visit(tree, "link", (link: Link) => {
|
||||
return {
|
||||
type: "paragraph"
|
||||
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.
|
||||
|
||||
### Filters
|
||||
## Filters
|
||||
|
||||
Filters **filter** content, taking the output of all the transformers and determining what files to actually keep and what to discard.
|
||||
|
||||
@@ -255,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:
|
||||
|
||||
```ts
|
||||
import { QuartzFilterPlugin } from "@quartz-community/types"
|
||||
```ts title="quartz/plugins/filters/draft.ts"
|
||||
import { QuartzFilterPlugin } from "../types"
|
||||
|
||||
export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({
|
||||
name: "RemoveDrafts",
|
||||
@@ -268,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.
|
||||
|
||||
@@ -300,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.
|
||||
- `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
|
||||
export type WriteOptions = (data: {
|
||||
@@ -320,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:
|
||||
|
||||
- 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.
|
||||
- If you need to render an HTML AST to JSX, you can use the `htmlToJsx` function from `@quartz-community/utils`.
|
||||
- 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/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.
|
||||
|
||||
```tsx
|
||||
import { QuartzEmitterPlugin, FullPageLayout, QuartzComponentProps } from "@quartz-community/types"
|
||||
import { renderPage, canonicalizeServer, pageResources, write } from "@quartz-community/utils"
|
||||
|
||||
```tsx title="quartz/plugins/emitters/contentPage.tsx"
|
||||
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 {
|
||||
name: "ContentPage",
|
||||
getQuartzComponents(ctx) {
|
||||
const { head, header, beforeBody, pageBody, afterBody, left, right, footer } = ctx.cfg.layout
|
||||
getQuartzComponents() {
|
||||
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 fps: FilePath[] = []
|
||||
const allFiles = content.map((c) => c[1].data)
|
||||
@@ -352,9 +297,8 @@ export const ContentPage: QuartzEmitterPlugin = () => {
|
||||
allFiles,
|
||||
}
|
||||
|
||||
const content = renderPage(cfg, slug, componentData, {}, externalResources)
|
||||
const fp = await write({
|
||||
ctx,
|
||||
const content = renderPage(cfg, slug, componentData, opts, externalResources)
|
||||
const fp = await emit({
|
||||
content,
|
||||
slug: file.data.slug!,
|
||||
ext: ".html",
|
||||
@@ -368,381 +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
|
||||
export interface QuartzPageTypePluginInstance {
|
||||
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: Footers }: PageFrameProps): unknown {
|
||||
const renderSlot = (C: (props: typeof componentData) => unknown): ComponentChildren =>
|
||||
C(componentData) as ComponentChildren
|
||||
return (
|
||||
<div class="center">
|
||||
{(Content as any)(componentData)}
|
||||
{Footers.map((Footer) => (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. Note that `footer` is a `QuartzComponent[]` (an array) — frames should iterate over it with `.map()` to render all footer components.
|
||||
- `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.
|
||||
|
||||
### Bases Views
|
||||
|
||||
The `bases-page` plugin provides a database-like view system similar to Obsidian Bases. Other plugins can register custom view types via the `ViewRegistry`:
|
||||
|
||||
```ts
|
||||
import { viewRegistry } from "@quartz-community/bases-page";
|
||||
import type { ViewTypeRegistration } from "@quartz-community/bases-page";
|
||||
|
||||
viewRegistry.register({
|
||||
id: "timeline",
|
||||
name: "Timeline",
|
||||
icon: "git-branch",
|
||||
render: ({ entries, view, slug, allSlugs }) => (
|
||||
<div class="bases-timeline">
|
||||
{entries.map(entry => <div>{entry.properties.title}</div>)}
|
||||
</div>
|
||||
),
|
||||
css: `.bases-timeline { display: flex; flex-direction: column; }`,
|
||||
afterDOMLoaded: `document.addEventListener("nav", () => { /* setup */ })`,
|
||||
});
|
||||
```
|
||||
|
||||
Each view registration includes:
|
||||
|
||||
- `id`: Unique identifier (e.g., `"timeline"`, `"kanban"`)
|
||||
- `name`: Display name shown in the view selector
|
||||
- `icon`: Optional Lucide icon name
|
||||
- `render`: Function that receives `ViewRendererProps` and returns Preact JSX
|
||||
- `css`: Optional CSS string (deduplicated by view ID)
|
||||
- `afterDOMLoaded`: Optional client-side script (same lifecycle as component scripts)
|
||||
- `options`: Optional configuration passed to every render invocation
|
||||
|
||||
The `ViewRegistry` is a global singleton (via `Symbol.for`) ensuring all copies of the module share the same registry.
|
||||
|
||||
## Building and Distribution
|
||||
|
||||
Quartz v5 plugins ship pre-built `dist/` in their repositories. When a user installs your plugin, Quartz detects the pre-built output and skips the install/build cycle entirely — making installation near-instant.
|
||||
|
||||
### Build Configuration
|
||||
|
||||
The plugin template's `tsup.config.ts` bundles all dependencies by default. Only **singleton externals** — packages that must be the same instance across all plugins — are left unbundled:
|
||||
|
||||
```ts
|
||||
const SINGLETON_EXTERNALS = [
|
||||
"preact",
|
||||
"preact/hooks",
|
||||
"preact/jsx-runtime",
|
||||
"preact/compat",
|
||||
"@jackyzha0/quartz",
|
||||
"@jackyzha0/quartz/*",
|
||||
"vfile",
|
||||
"vfile/*",
|
||||
"unified",
|
||||
]
|
||||
|
||||
export default defineConfig({
|
||||
// ...
|
||||
noExternal: [/.*/], // Bundle everything
|
||||
external: SINGLETON_EXTERNALS, // Except singletons
|
||||
})
|
||||
```
|
||||
|
||||
This means your plugin's `dist/index.js` is self-contained — no `npm install` needed at install time.
|
||||
|
||||
### Shipping Pre-built Output
|
||||
|
||||
Your plugin's `dist/` directory should be committed to the repository:
|
||||
|
||||
1. **Do NOT add `dist/` to `.gitignore`**
|
||||
2. Run `npm run build` before committing
|
||||
3. The CI workflow verifies `dist/` is up to date on every push
|
||||
|
||||
If `dist/` is missing or gitignored, Quartz falls back to the full install/build cycle (useful during local development with symlinked plugins).
|
||||
|
||||
### Plugins with Native Dependencies
|
||||
|
||||
Plugins that require native packages (e.g. `sharp` for image processing) cannot bundle those. For these plugins:
|
||||
|
||||
1. Set `"requiresInstall": true` in your `package.json` quartz manifest
|
||||
2. Declare the native package as a `peerDependency`
|
||||
3. Quartz will install it into the host project at build time
|
||||
|
||||
```shell
|
||||
# Build the plugin
|
||||
npm run build
|
||||
# or
|
||||
npx tsup
|
||||
```
|
||||
|
||||
## What to Import from Where
|
||||
|
||||
| You need... | Import from |
|
||||
| ---------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
||||
| Type definitions (`QuartzTransformerPlugin`, `QuartzComponent`, etc.) | `@quartz-community/types` |
|
||||
| Path utilities (`simplifySlug`, `resolveRelative`, `pathToRoot`) | `@quartz-community/utils/path` |
|
||||
| DOM utilities (`removeAllChildren`, `registerEscapeHandler`) | `@quartz-community/utils/dom` |
|
||||
| JSX conversion (`htmlToJsx`) | `@quartz-community/utils/jsx` |
|
||||
| Language utilities (`classNames`, `capitalize`) | `@quartz-community/utils/lang` |
|
||||
| Date/sort utilities (`formatDate`, `getDate`, `byDateAndAlphabetical`) | `@quartz-community/utils/date` and `@quartz-community/utils/sort` |
|
||||
| HTML escaping (`escapeHTML`, `unescapeHTML`) | `@quartz-community/utils/escape` |
|
||||
| Emoji utilities (`getIconCode`) | `@quartz-community/utils/emoji` |
|
||||
| Browser runtime (`onNav`, `onRender`, `fetchContentIndex`) | `@quartz-community/runtime` |
|
||||
|
||||
Do **not** import from `@jackyzha0/quartz` or from `vfile` directly. Use the community packages instead.
|
||||
|
||||
## Internationalization (i18n)
|
||||
|
||||
Plugins should provide their own translations for user-facing strings. Do **not** hardcode strings in components.
|
||||
|
||||
### Setting Up i18n
|
||||
|
||||
Create the following structure:
|
||||
|
||||
```
|
||||
src/i18n/
|
||||
├── index.ts
|
||||
└── locales/
|
||||
└── en-US.ts
|
||||
```
|
||||
|
||||
**`src/i18n/locales/en-US.ts`** (required base locale):
|
||||
|
||||
```ts
|
||||
export default {
|
||||
components: {
|
||||
myPlugin: {
|
||||
title: "My Plugin",
|
||||
description: "A description",
|
||||
itemCount: ({ count }: { count: number }) => (count === 1 ? "1 item" : `${count} items`),
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**`src/i18n/index.ts`**:
|
||||
|
||||
```ts
|
||||
import enUS from "./locales/en-US"
|
||||
|
||||
const locales: Record<string, typeof enUS> = {
|
||||
"en-US": enUS,
|
||||
}
|
||||
|
||||
export function i18n(locale: string) {
|
||||
return locales[locale] || enUS
|
||||
}
|
||||
```
|
||||
|
||||
### Using i18n in Components
|
||||
|
||||
```tsx
|
||||
import { i18n } from "../i18n"
|
||||
|
||||
const MyComponent: QuartzComponent = ({ cfg }) => {
|
||||
const locale = cfg.locale ?? "en-US"
|
||||
const t = i18n(locale).components.myPlugin
|
||||
return <h2>{t.title}</h2>
|
||||
}
|
||||
```
|
||||
|
||||
### Adding Translations
|
||||
|
||||
To add a new locale, copy `en-US.ts`, translate the strings, and register it:
|
||||
|
||||
```ts
|
||||
// src/i18n/locales/fr-FR.ts
|
||||
export default {
|
||||
components: {
|
||||
myPlugin: {
|
||||
title: "Mon Plugin",
|
||||
description: "Une description",
|
||||
itemCount: ({ count }: { count: number }) =>
|
||||
count === 1 ? "1 élément" : `${count} éléments`,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/i18n/index.ts
|
||||
import enUS from "./locales/en-US"
|
||||
import frFR from "./locales/fr-FR"
|
||||
|
||||
const locales: Record<string, typeof enUS> = {
|
||||
"en-US": enUS,
|
||||
"fr-FR": frFR,
|
||||
}
|
||||
```
|
||||
|
||||
Use [BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) locale codes (e.g., `en-US`, `de-DE`, `ja-JP`, `zh-CN`). For dynamic content, use function-based translations as shown with `itemCount` above.
|
||||
|
||||
## Installing Your Plugin
|
||||
|
||||
```shell
|
||||
# In your Quartz project
|
||||
npx quartz plugin add github:your-username/my-plugin
|
||||
```
|
||||
|
||||
This clones the plugin and adds it to both `quartz.config.yaml` and `quartz.lock.json`. If the plugin ships pre-built `dist/` (recommended), installation completes in seconds with no build step. You can then configure it in your config:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:your-username/my-plugin
|
||||
enabled: true
|
||||
```
|
||||
|
||||
For options that require JavaScript callback functions (not expressible in YAML), use the TS override in `quartz.ts`:
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
import * as ExternalPlugin from "./.quartz/plugins"
|
||||
|
||||
// Must be placed before loadQuartzConfig()
|
||||
ExternalPlugin.MyPlugin({
|
||||
customFn: (data) => {
|
||||
// ...
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Options set via `quartz.ts` are merged with YAML options at instantiation time, with `quartz.ts` overrides taking precedence. These calls must be placed **before** `loadQuartzConfig()` in your `quartz.ts`.
|
||||
|
||||
### 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 install --from-config
|
||||
|
||||
# Preview first without making changes
|
||||
npx quartz plugin install --from-config --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.
|
||||
|
||||
Component-only plugins (those with `"category": ["component"]` in their manifest) are loaded via side-effect import rather than a factory function. If your component-only plugin needs to receive user options from `quartz.config.yaml`, export an `init(options)` function — see [[creating components#Receiving YAML Options in Component-Only Plugins|receiving YAML options]] for details.
|
||||
> [!hint]
|
||||
> Look in `quartz/plugins` for more examples of plugins in Quartz as reference for your own plugins!
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
---
|
||||
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 followed the [[installation|installation guide]], 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.
|
||||
|
||||
Got everything set up? Preview your site locally with `npx quartz build --serve`, or see the [[build|build reference]] for more options.
|
||||
Got everything setup? Let's [[build]] and preview your Quartz locally!
|
||||
|
||||
## Syntax
|
||||
|
||||
@@ -42,7 +40,7 @@ See [[Frontmatter]] for a complete list of frontmatter.
|
||||
## Syncing your Content
|
||||
|
||||
When your Quartz is at a point you're happy with, you can save your changes to GitHub.
|
||||
First, make sure you've [[installation#Setting Up Your GitHub Repository|set up your GitHub repository]] and then run `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
|
||||
|
||||
@@ -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]].
|
||||
@@ -1,78 +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` | `-c` | 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
|
||||
```
|
||||
|
||||
## Serve vs Watch
|
||||
|
||||
The `--serve` and `--watch` flags control different behaviors:
|
||||
|
||||
- **`--serve`** starts a local development server AND automatically watches for changes (implies `--watch`). This is the recommended mode for local development.
|
||||
- **`--watch`** only watches for file changes and rebuilds automatically, without starting a server. This is useful for CI pipelines or custom server setups where you want automatic rebuilds but handle serving separately.
|
||||
|
||||
In most cases, you want `--serve`:
|
||||
|
||||
```shell
|
||||
npx quartz build --serve
|
||||
```
|
||||
|
||||
## 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.
|
||||
@@ -1,83 +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. The selected template always overwrites `quartz.config.yaml`, even if one already exists. After applying the template, Quartz automatically runs plugin resolution to install any plugins the template requires and remove any that are no longer referenced.
|
||||
|
||||
- **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 bases plugin](https://github.com/Requiae/quartz-leaflet-bases-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.
|
||||
|
||||
## 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, create your configuration, and automatically install any plugins referenced in the template.
|
||||
|
||||
## 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.
|
||||
@@ -1,55 +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 (alias: `update`) | `npx quartz upgrade` |
|
||||
| `plugin` | Manage Quartz plugins (install, add, remove, etc.) | `npx quartz plugin list` |
|
||||
| `tui` | Launch the interactive plugin manager | `npx quartz tui` |
|
||||
|
||||
## Commands
|
||||
|
||||
- [[create|create]]: Initialize a new Quartz project with a choice of templates (default, obsidian, ttrpg, blog) and base URL configuration.
|
||||
- [[build|build]]: Build your Quartz site into static HTML. Includes a development server.
|
||||
- [[sync|sync]]: Push and pull changes between your local machine and GitHub.
|
||||
- [[upgrade|upgrade]]: Upgrade the Quartz framework to the latest version. Also available as `npx quartz update`.
|
||||
- [[restore|restore]]: Recover your content folder from the local cache.
|
||||
- [[cli/plugin|plugin]]: Install, add, remove, prune, and configure plugins. Use `plugin install` with flags for lockfile/config sync, updates, and checks.
|
||||
- [[tui|tui]]: Use a terminal interface to manage plugins and layout.
|
||||
|
||||
## Global Flags
|
||||
|
||||
These flags are accepted by every Quartz command:
|
||||
|
||||
| Flag | Shorthand | Description | Default |
|
||||
| --------------- | --------- | ------------------------------------------------------------------------------------------------------- | -------------- |
|
||||
| `--directory` | `-d` | The directory containing your Quartz project | `content` |
|
||||
| `--verbose` | `-v` | Enable detailed logging for debugging | `false` |
|
||||
| `--concurrency` | `-c` | Max parallel workers for operations that run in parallel (e.g. `build`, `plugin install`, `plugin add`) | CPU core count |
|
||||
|
||||
Commands that don't perform parallel work accept `-c` as a no-op, so it's always safe to pass. See [[build#Performance Tuning|build]] and [[cli/plugin#Installing on low-end hardware|plugin]] for practical examples.
|
||||
|
||||
## 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
|
||||
```
|
||||
@@ -1,281 +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`, `prune`) will respect that branch automatically. Use `install --latest` to fetch the latest commit from that branch.
|
||||
|
||||
> [!tip]
|
||||
> `plugin add` also accepts `--concurrency` / `-c` to limit how many remote repositories are cloned and built at the same time. This is the same flag documented under [[#install]] and is useful when adding several plugins at once on low-end hardware.
|
||||
|
||||
### remove
|
||||
|
||||
Remove an installed plugin.
|
||||
|
||||
```shell
|
||||
npx quartz plugin remove plugin-name
|
||||
```
|
||||
|
||||
### install
|
||||
|
||||
Install plugins for your Quartz project. By default, this installs all plugins listed in your `quartz.lock.json` file.
|
||||
|
||||
```shell
|
||||
npx quartz plugin install
|
||||
```
|
||||
|
||||
#### Flags
|
||||
|
||||
- `--from-config`: Synchronize plugins with `quartz.config.yaml` instead of the lockfile. This will install missing plugins and prune orphaned ones.
|
||||
- `--latest`: Fetch the latest version of plugins from their remote sources instead of using the version in the lockfile.
|
||||
- `--clean`: Skip existing directories and perform a fresh installation.
|
||||
- `--dry-run`: Preview the changes without actually installing or removing any files.
|
||||
- `--concurrency`, `-c`: Maximum number of plugins to clone, fetch, and build in parallel. Defaults to the number of CPU cores. Lower this (e.g. `-c 1` or `-c 2`) on memory- or CPU-constrained machines where the default parallelism causes failures, OOMs, or hangs. See [[#Installing on low-end hardware]] below.
|
||||
|
||||
#### Positional Arguments
|
||||
|
||||
- `[names..]`: Optional list of specific plugin names to install or update.
|
||||
|
||||
```shell
|
||||
# Update specific plugins to latest
|
||||
npx quartz plugin install --latest plugin-a plugin-b
|
||||
|
||||
# Preview what would be installed from config
|
||||
npx quartz plugin install --from-config --dry-run
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
> [!note]
|
||||
> Running `plugin install --from-config` also removes orphaned plugins as part of its synchronization. Use `prune` when you only want to clean up without installing anything new.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## 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 install --latest
|
||||
```
|
||||
|
||||
### Installing on low-end hardware
|
||||
|
||||
By default, `plugin install` and `plugin add` clone, fetch, and build plugins in parallel across all your CPU cores. On memory-constrained machines (low-end laptops, Raspberry Pi, small VPS instances, restrictive CI runners) this can exhaust RAM or overwhelm the system because each worker may kick off its own `npm install` / `npm run build` at the same time.
|
||||
|
||||
> [!note]
|
||||
> Most community plugins now ship with a pre-built `dist/` directory. When Quartz finds this, it skips the installation and build steps entirely, making the process much faster and lighter on resources. This section is primarily relevant for plugins in development or those that don't provide pre-built distribution.
|
||||
|
||||
If `plugin install` fails, hangs, or OOMs on your machine, lower the concurrency with `--concurrency` / `-c`:
|
||||
|
||||
```shell
|
||||
# Install one plugin at a time (safest, slowest)
|
||||
npx quartz plugin install --latest -c 1
|
||||
|
||||
# Two at a time — usually a good balance on 4 GB machines
|
||||
npx quartz plugin install --latest --concurrency 2
|
||||
```
|
||||
|
||||
The same flag works on `plugin add` and the other plugin subcommands that perform parallel work:
|
||||
|
||||
```shell
|
||||
npx quartz plugin add github:quartz-community/some-plugin -c 1
|
||||
```
|
||||
|
||||
### 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, `install --from-config` ensures your installed plugins match your config — installing missing plugins and removing any that are no longer referenced:
|
||||
|
||||
```shell
|
||||
npx quartz plugin install --from-config
|
||||
```
|
||||
|
||||
### 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 `install --latest` will continue to follow the specified branch until the plugin is re-added without one.
|
||||
|
||||
Both `prune` and `install --from-config` 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 `install --latest`, local plugins are rebuilt (npm install + npm run build) without any git operations.
|
||||
|
||||
> [!note]
|
||||
> Local symlinked plugins typically use this build-on-install fallback because the `dist/` directory is usually gitignored during development.
|
||||
|
||||
The `install --latest --dry-run` 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
|
||||
```
|
||||
|
||||
### Subdirectory (Monorepo) Plugins
|
||||
|
||||
Some plugins live in a subdirectory of a larger repository rather than at the root. For these, you can specify the plugin source as an object in `quartz.config.yaml` with a `subdir` field:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source:
|
||||
repo: "https://github.com/username/monorepo.git"
|
||||
subdir: plugin
|
||||
enabled: true
|
||||
```
|
||||
|
||||
This tells Quartz to clone the full repository but install only the contents of the specified subdirectory.
|
||||
|
||||
You can combine `subdir` with `ref` to pin a branch or tag, and `name` to override the plugin directory name:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source:
|
||||
repo: "https://github.com/username/monorepo.git"
|
||||
subdir: packages/my-plugin
|
||||
ref: v2.0
|
||||
name: my-plugin
|
||||
enabled: true
|
||||
```
|
||||
|
||||
See [[configuration#Advanced Source Options|Advanced Source Options]] for the full reference on object source fields.
|
||||
|
||||
> [!note]
|
||||
> The `plugin add` CLI command works with string sources. To use the object source format with `subdir`, edit `quartz.config.yaml` directly, then run `npx quartz plugin install --from-config` to install it.
|
||||
|
||||
## Migration from Deprecated Commands
|
||||
|
||||
| Old command | New equivalent |
|
||||
| ------------------------------------- | --------------------------------------------------- |
|
||||
| `npx quartz plugin restore` | `npx quartz plugin install --clean` |
|
||||
| `npx quartz plugin update` | `npx quartz plugin install --latest` |
|
||||
| `npx quartz plugin update my-plugin` | `npx quartz plugin install --latest my-plugin` |
|
||||
| `npx quartz plugin check` | `npx quartz plugin install --latest --dry-run` |
|
||||
| `npx quartz plugin resolve` | `npx quartz plugin install --from-config` |
|
||||
| `npx quartz plugin resolve --dry-run` | `npx quartz plugin install --from-config --dry-run` |
|
||||
| `npx quartz update` | `npx quartz plugin install --latest` |
|
||||
|
||||
The old commands still work as hidden aliases but will print a deprecation warning.
|
||||
|
||||
## Plugin Status
|
||||
|
||||
Running the plugin command without any subcommand shows a status dashboard of all installed plugins, including whether updates are available:
|
||||
|
||||
```shell
|
||||
npx quartz plugin
|
||||
```
|
||||
|
||||
This displays each plugin with its source, commit, enabled/disabled status, and checks for available updates in parallel. For the full interactive management interface, use [[tui|npx quartz tui]] instead.
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
title: quartz restore
|
||||
---
|
||||
|
||||
The `restore` command is a safety mechanism that allows you to recover your **content folder** from a local cache. This command only affects your Markdown files and does not restore plugins or configuration.
|
||||
|
||||
To restore plugins to a specific state, use [[cli/plugin|npx quartz plugin install]].
|
||||
|
||||
## 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.
|
||||
@@ -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 [[installation]].
|
||||
@@ -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]].
|
||||
@@ -1,48 +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.
|
||||
|
||||
Quartz automatically handles merge conflicts in `quartz.lock.json` by backing up your lockfile before pulling and restoring it afterward. This prevents the most common source of conflicts during upgrades.
|
||||
|
||||
For other files, 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 [[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/plugin|quartz plugin install --latest]] — update installed plugins
|
||||
- [[upgrading|Upgrading Quartz]] — detailed upgrading guide
|
||||
- [[restore|quartz restore]] — recover content from cache
|
||||
@@ -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 add <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).
|
||||
+57
-224
@@ -2,21 +2,18 @@
|
||||
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]
|
||||
> 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:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
configuration:
|
||||
pageTitle: "My Site"
|
||||
# ... general configuration
|
||||
plugins:
|
||||
- source: github:quartz-community/some-plugin
|
||||
enabled: true
|
||||
# ... plugin entries
|
||||
```ts title="quartz.config.ts"
|
||||
const config: QuartzConfig = {
|
||||
configuration: { ... },
|
||||
plugins: { ... },
|
||||
}
|
||||
```
|
||||
|
||||
## General Configuration
|
||||
@@ -42,14 +39,11 @@ 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);
|
||||
- `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.
|
||||
- You will be prompted to set this during [[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`.
|
||||
- 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.
|
||||
- `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.
|
||||
- `fontOrigin`: where to load fonts from.
|
||||
- `"googleFonts"` (default): loads fonts from Google Fonts API. Fastest option, especially with CDN caching enabled.
|
||||
- `"local"`: downloads fonts and serves them from your site. Fully self-contained with no external requests.
|
||||
- `cdnCaching`: if `true` (default), use Google CDN to cache the fonts. This will generally be faster. Disable (`false`) this if you want Quartz to download the fonts to be self-contained.
|
||||
- `typography`: what fonts to use. Any font available on [Google Fonts](https://fonts.google.com/) works here.
|
||||
- `title`: font for the title of the site (optional, same as `header` by default)
|
||||
@@ -73,191 +67,47 @@ You can think of Quartz plugins as a series of transformations over content.
|
||||
|
||||
![[quartz transform pipeline.png]]
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:quartz-community/created-modified-date
|
||||
enabled: true
|
||||
order: 10 # controls execution order
|
||||
- source: github:quartz-community/syntax-highlighting
|
||||
enabled: true
|
||||
order: 20
|
||||
# ... more plugins
|
||||
```ts title="quartz.config.ts"
|
||||
plugins: {
|
||||
transformers: [...],
|
||||
filters: [...],
|
||||
emitters: [...],
|
||||
}
|
||||
```
|
||||
|
||||
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/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)
|
||||
- **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:
|
||||
|
||||
```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 install --from-config
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### Advanced Source Options
|
||||
|
||||
The `source` field for a plugin can be either a simple string or an object with additional options. The string form is the most common:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:quartz-community/explorer
|
||||
enabled: true
|
||||
```
|
||||
|
||||
For plugins that live in a subdirectory of a repository (monorepo-style), or when you need to pin to a specific branch or tag, use the object form:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source:
|
||||
repo: "https://github.com/user/repo.git"
|
||||
subdir: plugin
|
||||
ref: main
|
||||
name: my-plugin
|
||||
enabled: true
|
||||
```
|
||||
|
||||
The object form supports the following fields:
|
||||
|
||||
| Field | Required | Description |
|
||||
| -------- | :------: | --------------------------------------------------------------------------------------------------------- |
|
||||
| `repo` | ✅ | Git repository URL (e.g. `https://github.com/user/repo.git`). |
|
||||
| `subdir` | ❌ | Subdirectory within the repository that contains the plugin. Used for monorepo-style plugin repositories. |
|
||||
| `ref` | ❌ | Git ref (branch or tag) to pin to. Equivalent to the `#ref` suffix on string sources. |
|
||||
| `name` | ❌ | Override the directory name used in `.quartz/plugins/`. Defaults to the repository name. |
|
||||
|
||||
> [!example] Real-world example
|
||||
> The [quartz-themes](https://github.com/saberzero1/quartz-themes) plugin lives in the `plugin/` subdirectory of its repository. To install it:
|
||||
>
|
||||
> ```yaml title="quartz.config.yaml"
|
||||
> plugins:
|
||||
> - source:
|
||||
> name: quartz-themes
|
||||
> repo: "https://github.com/saberzero1/quartz-themes.git"
|
||||
> subdir: plugin
|
||||
> enabled: true
|
||||
> options:
|
||||
> theme: "tokyo-night"
|
||||
> mode: both
|
||||
> ```
|
||||
|
||||
> [!tip]
|
||||
> The string form `github:user/repo#branch` and the object form `{ repo, ref }` are equivalent ways to specify a branch. Use the object form when you also need `subdir` or `name`, or when you prefer a more readable configuration.
|
||||
|
||||
### 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
|
||||
```
|
||||
You can customize the behaviour of Quartz by adding, removing and reordering plugins in the `transformers`, `filters` and `emitters` fields.
|
||||
|
||||
> [!note]
|
||||
> Some plugin options require JavaScript callback functions (e.g. custom sort, filter, or map functions) that can't be expressed in YAML. For these, use the TS override in `quartz.ts`:
|
||||
>
|
||||
> ```ts title="quartz.ts"
|
||||
> import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
|
||||
> import * as ExternalPlugin from "./.quartz/plugins"
|
||||
>
|
||||
> ExternalPlugin.Explorer({
|
||||
> mapFn: (node) => {
|
||||
> node.displayName = node.displayName.toUpperCase()
|
||||
> return node
|
||||
> },
|
||||
> })
|
||||
>
|
||||
> const config = await loadQuartzConfig()
|
||||
> export default config
|
||||
> export const layout = await loadQuartzLayout()
|
||||
> ```
|
||||
>
|
||||
> Options set in `quartz.ts` are merged with YAML options and take precedence. Plugin overrides must be placed **before** `loadQuartzConfig()` so they are applied when components are instantiated during config loading. See the plugin-specific documentation for available callback options.
|
||||
> 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]].
|
||||
|
||||
@@ -265,39 +115,22 @@ If you'd like to make your own plugins, see the [[making plugins|making custom p
|
||||
|
||||
## 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"
|
||||
configuration:
|
||||
theme:
|
||||
typography:
|
||||
title: Schibsted Grotesk # optional, defaults to header font
|
||||
header: Schibsted Grotesk
|
||||
body: Source Sans Pro
|
||||
code: IBM Plex Mono
|
||||
```
|
||||
```ts
|
||||
// string
|
||||
typography: {
|
||||
header: "Schibsted Grotesk",
|
||||
...
|
||||
}
|
||||
|
||||
For more control over font weights and italics, use the TS override in `quartz.ts`:
|
||||
|
||||
```ts title="quartz.ts"
|
||||
import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"
|
||||
|
||||
const config = await loadQuartzConfig({
|
||||
theme: {
|
||||
typography: {
|
||||
header: {
|
||||
name: "Schibsted Grotesk",
|
||||
weights: [400, 700],
|
||||
includeItalic: true,
|
||||
},
|
||||
body: "Source Sans Pro",
|
||||
code: "IBM Plex Mono",
|
||||
},
|
||||
// FontSpecification
|
||||
typography: {
|
||||
header: {
|
||||
name: "Schibsted Grotesk",
|
||||
weights: [400, 700],
|
||||
includeItalic: true,
|
||||
},
|
||||
})
|
||||
export default config
|
||||
export const layout = await loadQuartzLayout()
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
> [!tip]
|
||||
> For per-heading font control, self-hosted fonts, or Obsidian theme font bridging, see the [[plugins/Fonts|Fonts]] plugin. It can download Google Fonts at build time and serve them locally with `fontOrigin: selfHosted`, making your site fully self-contained.
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
|
||||
You can run the below one-liner to run Quartz in Docker.
|
||||
|
||||
@@ -70,9 +70,10 @@ For example:
|
||||
|
||||
### 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"
|
||||
```
|
||||
|
||||
|
||||
@@ -12,212 +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.
|
||||
|
||||
## 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
|
||||

|
||||

|
||||
```
|
||||
|
||||
For example, the following embed is rendered from ``:
|
||||
|
||||

|
||||
|
||||
### Tweet Embeds
|
||||
|
||||
Tweets from Twitter/X are embedded as static blockquotes with a link to the original:
|
||||
|
||||
```markdown
|
||||

|
||||

|
||||
```
|
||||
|
||||
For example, the following embed is rendered from ``:
|
||||
|
||||

|
||||
|
||||
### 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
|
||||

|
||||

|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
### Footnotes
|
||||
|
||||
Footnotes using the `[^1]` syntax are fully supported through the [[GitHubFlavoredMarkdown]] plugin:
|
||||
|
||||
```markdown
|
||||
Here is a sentence with a footnote.[^1]
|
||||
|
||||
[^1]: This is the footnote content.
|
||||
```
|
||||
|
||||
## Obsidian Community Plugin Support
|
||||
|
||||
Quartz focuses on supporting Obsidian's core features. Functionality from Obsidian community plugins is handled by Quartz community plugins:
|
||||
|
||||
| Obsidian Plugin | Quartz Support |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Dataview | Supported via [Quartz Syncer](https://community.obsidian.md/plugins/quartz-syncer) — exports Dataview queries as static content during sync |
|
||||
| Excalidraw | Supported via the `obsidian-plugin-excalidraw` community plugin |
|
||||
| Leaflet Maps | Supported via the `obsidian-plugin-leaflet` community plugin |
|
||||
| Style Settings | Supported via the `quartz-themes` community plugin |
|
||||
|
||||
> [!tip]
|
||||
> As a general rule: Obsidian core features are supported by Quartz directly, while Obsidian community plugin features are supported by corresponding Quartz community plugins. Not all Obsidian community plugins will have Quartz equivalents, but popular ones are likely to be supported by the community.
|
||||
|
||||
## Configuration
|
||||
|
||||
This functionality is provided by the [[ObsidianFlavoredMarkdown]], [[Frontmatter]] and [[CrawlLinks]] plugins. See the plugin pages for customization options.
|
||||
|
||||
@@ -8,37 +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.
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
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
|
||||
```typescript title="quartz.config.ts"
|
||||
plugins: {
|
||||
transformers: [
|
||||
Plugin.FrontMatter({ delims: "+++", language: "toml" }), // if toml frontmatter
|
||||
// ...
|
||||
Plugin.OxHugoFlavouredMarkdown(),
|
||||
Plugin.GitHubFlavoredMarkdown(),
|
||||
// ...
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||
For the TS override approach, place overrides before `loadQuartzConfig()` in `quartz.ts`:
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
import * as ExternalPlugin from "./.quartz/plugins"
|
||||
|
||||
ExternalPlugin.NoteProperties({ delims: "+++", language: "toml" })
|
||||
ExternalPlugin.OxHugoFlavouredMarkdown()
|
||||
```
|
||||
|
||||
> [!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
|
||||
|
||||
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.
|
||||
|
||||
@@ -9,26 +9,19 @@ tags:
|
||||
Quartz supports transforming the special Markdown syntax from Roam Research (like `{{[[components]]}}` and other formatting) into
|
||||
regular Markdown via the [[RoamFlavoredMarkdown]] plugin.
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
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, place overrides before `loadQuartzConfig()` in `quartz.ts`:
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
import * as ExternalPlugin from "./.quartz/plugins"
|
||||
|
||||
ExternalPlugin.RoamFlavoredMarkdown()
|
||||
```typescript title="quartz.config.ts"
|
||||
plugins: {
|
||||
transformers: [
|
||||
// ...
|
||||
Plugin.RoamFlavoredMarkdown(),
|
||||
Plugin.ObsidianFlavoredMarkdown(),
|
||||
// ...
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||
> [!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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
|
||||
- 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`.
|
||||
|
||||
@@ -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.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
## Customization
|
||||
|
||||
- Removing backlinks: remove the `backlinks` entry from `quartz.config.yaml` or set `enabled: false`.
|
||||
- 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`.
|
||||
- Install: `npx quartz plugin add github:quartz-community/backlinks`
|
||||
- Source: [`quartz-community/backlinks`](https://github.com/quartz-community/backlinks)
|
||||
- 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, use `Component.Backlinks({ hideWhenEmpty: false })`.
|
||||
- Component: `quartz/components/Backlinks.tsx`
|
||||
- Style: `quartz/components/styles/backlinks.scss`
|
||||
- Script: `quartz/components/scripts/search.inline.ts`
|
||||
|
||||
@@ -8,47 +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!).
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
## 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:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:quartz-community/breadcrumbs
|
||||
enabled: true
|
||||
options:
|
||||
spacerSymbol: "❯"
|
||||
rootName: Home
|
||||
resolveFrontmatterTitle: true
|
||||
showCurrentPage: true
|
||||
layout:
|
||||
position: beforeBody
|
||||
priority: 5
|
||||
```
|
||||
|
||||
For the TS override approach:
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
// Must be placed before loadQuartzConfig()
|
||||
ExternalPlugin.Breadcrumbs({
|
||||
spacerSymbol: "❯",
|
||||
rootName: "Home",
|
||||
resolveFrontmatterTitle: true,
|
||||
showCurrentPage: true,
|
||||
```typescript title="quartz.layout.ts"
|
||||
Component.Breadcrumbs({
|
||||
spacerSymbol: "❯", // symbol between crumbs
|
||||
rootName: "Home", // name of first/root element
|
||||
resolveFrontmatterTitle: true, // whether to resolve folder names through frontmatter titles
|
||||
showCurrentPage: true, // whether to display the current page in the breadcrumbs
|
||||
})
|
||||
```
|
||||
|
||||
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?
|
||||
|
||||
- Removing breadcrumbs: remove the `breadcrumbs` entry from `quartz.config.yaml` or set `enabled: false`.
|
||||
- Install: `npx quartz plugin add github:quartz-community/breadcrumbs`
|
||||
- Source: [`quartz-community/breadcrumbs`](https://github.com/quartz-community/breadcrumbs)
|
||||
- Removing breadcrumbs: delete all usages of `Component.Breadcrumbs()` from `quartz.layout.ts`.
|
||||
- Component: `quartz/components/Breadcrumbs.tsx`
|
||||
- Style: `quartz/components/styles/breadcrumbs.scss`
|
||||
- Script: inline at `quartz/components/Breadcrumbs.tsx`
|
||||
|
||||
+31
-80
@@ -6,9 +6,6 @@ tags:
|
||||
|
||||
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]]
|
||||
|
||||
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]]
|
||||
|
||||
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"
|
||||
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
|
||||
```ts title="quartz.layout.ts"
|
||||
afterBody: [
|
||||
Component.Comments({
|
||||
provider: 'giscus',
|
||||
options: {
|
||||
// from data-repo
|
||||
repo: 'jackyzha0/quartz',
|
||||
// from data-repo-id
|
||||
repoId: 'MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg',
|
||||
// from data-category
|
||||
category: 'Announcements',
|
||||
// from data-category-id
|
||||
categoryId: 'DIC_kwDOFxRnmM4B-Xg6',
|
||||
// from data-lang
|
||||
lang: 'en'
|
||||
}
|
||||
}),
|
||||
],
|
||||
```
|
||||
|
||||
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: [
|
||||
ExternalPlugin.Comments({
|
||||
provider: "giscus",
|
||||
options: {
|
||||
repo: "jackyzha0/quartz",
|
||||
repoId: "MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg",
|
||||
category: "Announcements",
|
||||
categoryId: "DIC_kwDOFxRnmM4B-Xg6",
|
||||
lang: "en",
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
> [!note]
|
||||
> Install the comments plugin first: `npx quartz plugin add github:quartz-community/comments`
|
||||
|
||||
### 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.
|
||||
@@ -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/`:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
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
|
||||
afterBody: [
|
||||
Component.Comments({
|
||||
provider: 'giscus',
|
||||
options: {
|
||||
// Other options
|
||||
|
||||
```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: [
|
||||
ExternalPlugin.Comments({
|
||||
provider: "giscus",
|
||||
options: {
|
||||
// Other options...
|
||||
themeUrl: "https://example.com/static/giscus",
|
||||
lightTheme: "light-theme",
|
||||
darkTheme: "dark-theme",
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
})
|
||||
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 quartz/static/giscus/
|
||||
}
|
||||
}),
|
||||
],
|
||||
```
|
||||
|
||||
#### Conditionally display comments
|
||||
|
||||
@@ -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.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
## Customization
|
||||
|
||||
- Removing darkmode: remove the `darkmode` entry from `quartz.config.yaml` or set `enabled: false`.
|
||||
- Install: `npx quartz plugin add github:quartz-community/darkmode`
|
||||
- Source: [`quartz-community/darkmode`](https://github.com/quartz-community/darkmode)
|
||||
- Removing darkmode: delete all usages of `Component.Darkmode()` from `quartz.layout.ts`.
|
||||
- Component: `quartz/components/Darkmode.tsx`
|
||||
- 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.
|
||||
|
||||
|
||||
+39
-110
@@ -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.
|
||||
|
||||
> [!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]].
|
||||
|
||||
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,73 +17,42 @@ Display names for folders get determined by the `title` frontmatter field in `fo
|
||||
|
||||
## 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:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:quartz-community/explorer
|
||||
enabled: true
|
||||
options:
|
||||
title: Explorer
|
||||
folderClickBehavior: collapse # "link" to navigate or "collapse" to toggle
|
||||
folderDefaultState: collapsed # "collapsed" or "open"
|
||||
useSavedState: true
|
||||
layout:
|
||||
position: left
|
||||
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 * as ExternalPlugin from "./.quartz/plugins"
|
||||
|
||||
// Advanced: pass callback functions that can't be expressed in YAML
|
||||
ExternalPlugin.Explorer({
|
||||
sortFn: (a, b) => {
|
||||
/* ... */
|
||||
},
|
||||
filterFn: (node) => {
|
||||
/* ... */
|
||||
},
|
||||
mapFn: (node) => {
|
||||
/* ... */
|
||||
},
|
||||
```typescript title="quartz.layout.ts"
|
||||
Component.Explorer({
|
||||
title: "Explorer", // title of the explorer component
|
||||
folderClickBehavior: "collapse", // what happens when you click a folder ("link" to navigate to folder page on click or "collapse" to collapse folder on click)
|
||||
folderDefaultState: "collapsed", // default state of folders ("collapsed" or "open")
|
||||
useSavedState: true, // whether to use local storage to save "state" (which folders are opened) of explorer
|
||||
// omitted but shown later
|
||||
sortFn: ...,
|
||||
filterFn: ...,
|
||||
mapFn: ...,
|
||||
// what order to apply functions in
|
||||
order: ["filter", "map", "sort"],
|
||||
})
|
||||
|
||||
const config = await loadQuartzConfig()
|
||||
export default config
|
||||
export const layout = await loadQuartzLayout()
|
||||
```
|
||||
|
||||
> [!info] How overrides work
|
||||
> When you call `ExternalPlugin.Explorer({...})` in `quartz.ts`, the options are recorded and merged with the YAML configuration when the component is instantiated during the build. Options set in `quartz.ts` take precedence over those in `quartz.config.yaml`, following this order: `plugin defaults < YAML options < quartz.ts overrides`.
|
||||
>
|
||||
> If you have two plugins that export the same name (e.g. two different Explorer plugins installed via `--name`), use the `plugins` map to disambiguate:
|
||||
>
|
||||
> ```ts title="quartz.ts"
|
||||
> import * as ExternalPlugin from "./.quartz/plugins"
|
||||
> ExternalPlugin.plugins["my-explorer"].Explorer({ mapFn: ... })
|
||||
> ```
|
||||
|
||||
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?
|
||||
|
||||
- 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
|
||||
- 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
|
||||
|
||||
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:
|
||||
|
||||
```ts title="@quartz-community/explorer"
|
||||
```ts title="quartz/components/Explorer.tsx"
|
||||
class FileTrieNode {
|
||||
isFolder: boolean
|
||||
children: Array<FileTrieNode>
|
||||
@@ -115,7 +60,7 @@ class FileTrieNode {
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
```ts title="quartz/plugins/emitters/contentIndex.tsx"
|
||||
export type ContentDetails = {
|
||||
slug: FullSlug
|
||||
title: string
|
||||
@@ -129,7 +74,7 @@ Every function you can pass is optional. By default, only a `sort` function will
|
||||
|
||||
```ts title="Default sort function"
|
||||
// Sort order: folders first, then files. Sort folders and files alphabetically
|
||||
ExternalPlugin.Explorer({
|
||||
Component.Explorer({
|
||||
sortFn: (a, b) => {
|
||||
if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) {
|
||||
return a.displayName.localeCompare(b.displayName, undefined, {
|
||||
@@ -169,20 +114,8 @@ These examples show the basic usage of `sort`, `map` and `filter`.
|
||||
|
||||
Using this example, the explorer will alphabetically sort everything.
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- 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)"
|
||||
ExternalPlugin.Explorer({
|
||||
```ts title="quartz.layout.ts"
|
||||
Component.Explorer({
|
||||
sortFn: (a, b) => {
|
||||
return a.displayName.localeCompare(b.displayName)
|
||||
},
|
||||
@@ -193,8 +126,8 @@ ExternalPlugin.Explorer({
|
||||
|
||||
Using this example, the display names of all `FileNodes` (folders + files) will be converted to full upper case.
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
ExternalPlugin.Explorer({
|
||||
```ts title="quartz.layout.ts"
|
||||
Component.Explorer({
|
||||
mapFn: (node) => {
|
||||
node.displayName = node.displayName.toUpperCase()
|
||||
return node
|
||||
@@ -202,16 +135,13 @@ ExternalPlugin.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`)
|
||||
|
||||
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`.
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
ExternalPlugin.Explorer({
|
||||
```ts title="quartz.layout.ts"
|
||||
Component.Explorer({
|
||||
filterFn: (node) => {
|
||||
// set containing names of everything you want to filter out
|
||||
const omit = new Set(["authoring content", "tags", "advanced"])
|
||||
@@ -228,8 +158,8 @@ ExternalPlugin.Explorer({
|
||||
|
||||
You can access the tags of a file by `node.data.tags`.
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
ExternalPlugin.Explorer({
|
||||
```ts title="quartz.layout.ts"
|
||||
Component.Explorer({
|
||||
filterFn: (node) => {
|
||||
// exclude files with the tag "explorerexclude"
|
||||
return node.data?.tags?.includes("explorerexclude") !== true
|
||||
@@ -242,8 +172,8 @@ ExternalPlugin.Explorer({
|
||||
By default, the explorer will filter out the `tags` folder.
|
||||
To override the default filter function, you can set the filter function to `undefined`.
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
ExternalPlugin.Explorer({
|
||||
```ts title="quartz.layout.ts"
|
||||
Component.Explorer({
|
||||
filterFn: undefined, // apply no filter function, every file and folder will visible
|
||||
})
|
||||
```
|
||||
@@ -251,25 +181,24 @@ ExternalPlugin.Explorer({
|
||||
## Advanced examples
|
||||
|
||||
> [!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
|
||||
> and passing it in.
|
||||
>
|
||||
> ```ts title="quartz.ts"
|
||||
> import * as ExternalPlugin from "./.quartz/plugins"
|
||||
> import type { ExplorerOptions } from "./.quartz/plugins"
|
||||
> ```ts title="quartz.layout.ts"
|
||||
> import { Options } from "./quartz/components/Explorer"
|
||||
>
|
||||
> const mapFn: ExplorerOptions["mapFn"] = (node) => {
|
||||
> export const mapFn: Options["mapFn"] = (node) => {
|
||||
> // implement your function here
|
||||
> }
|
||||
> const filterFn: ExplorerOptions["filterFn"] = (node) => {
|
||||
> export const filterFn: Options["filterFn"] = (node) => {
|
||||
> // implement your function here
|
||||
> }
|
||||
> const sortFn: ExplorerOptions["sortFn"] = (a, b) => {
|
||||
> export const sortFn: Options["sortFn"] = (a, b) => {
|
||||
> // implement your function here
|
||||
> }
|
||||
>
|
||||
> ExternalPlugin.Explorer({
|
||||
> Component.Explorer({
|
||||
> // ... your other options
|
||||
> mapFn,
|
||||
> filterFn,
|
||||
@@ -279,10 +208,10 @@ ExternalPlugin.Explorer({
|
||||
|
||||
### 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)"
|
||||
ExternalPlugin.Explorer({
|
||||
```ts title="quartz.layout.ts"
|
||||
Component.Explorer({
|
||||
mapFn: (node) => {
|
||||
if (node.isFolder) {
|
||||
node.displayName = "📁 " + node.displayName
|
||||
|
||||
@@ -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.
|
||||
|
||||
> [!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.
|
||||
|
||||
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
|
||||
|
||||
- Removing search: remove the `search` entry from `quartz.config.yaml` or set `enabled: false`.
|
||||
- Install: `npx quartz plugin add github:quartz-community/search`
|
||||
- Source: [`quartz-community/search`](https://github.com/quartz-community/search)
|
||||
- Removing search: delete all usages of `Component.Search()` from `quartz.layout.ts`.
|
||||
- Component: `quartz/components/Search.tsx`
|
||||
- Style: `quartz/components/styles/search.scss`
|
||||
- Script: `quartz/components/scripts/search.inline.ts`
|
||||
- You can edit `contextWindowWords`, `numSearchResults` or `numTagResults` to suit your needs
|
||||
|
||||
+36
-62
@@ -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 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.
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- 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
|
||||
layout:
|
||||
position: right
|
||||
priority: 10
|
||||
```typescript title="quartz.layout.ts"
|
||||
Component.Graph({
|
||||
localGraph: {
|
||||
drag: true, // whether to allow panning the view around
|
||||
zoom: true, // whether to allow zooming in and out
|
||||
depth: 1, // how many hops of notes to display
|
||||
scale: 1.1, // default view scale
|
||||
repelForce: 0.5, // how much nodes should repel each other
|
||||
centerForce: 0.3, // how much force to use when trying to center the nodes
|
||||
linkDistance: 30, // how long should the links be by default?
|
||||
fontSize: 0.6, // what size should the node labels be?
|
||||
opacityScale: 1, // how quickly do we fade out the labels when zooming out?
|
||||
removeTags: [], // what tags to remove from the graph
|
||||
showTags: true, // whether to show tags in the graph
|
||||
enableRadial: false, // whether to constrain the graph, similar to Obsidian
|
||||
},
|
||||
globalGraph: {
|
||||
drag: true,
|
||||
zoom: true,
|
||||
depth: -1,
|
||||
scale: 0.9,
|
||||
repelForce: 0.5,
|
||||
centerForce: 0.3,
|
||||
linkDistance: 30,
|
||||
fontSize: 0.6,
|
||||
opacityScale: 1,
|
||||
removeTags: [], // what tags to remove from the graph
|
||||
showTags: true, // whether to show tags in the graph
|
||||
enableRadial: true, // whether to constrain the graph, similar to Obsidian
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
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?
|
||||
|
||||
- Removing graph view: remove the `graph` entry from `quartz.config.yaml` or set `enabled: false`
|
||||
- Component source: https://github.com/quartz-community/graph
|
||||
- Removing graph view: delete all usages of `Component.Graph()` from `quartz.layout.ts`.
|
||||
- Component: `quartz/components/Graph.tsx`
|
||||
- Style: `quartz/components/styles/graph.scss`
|
||||
- Script: `quartz/components/scripts/graph.inline.ts`
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
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}`
|
||||
|
||||
@@ -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)
|
||||
|
||||
> [!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.
|
||||
> 2. Rename it to `{language}-{REGION}.ts` so it matches a locale of the format shown above.
|
||||
|
||||
@@ -1,48 +1,3 @@
|
||||
---
|
||||
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
|
||||
- [[features/Latex|Latex]] — LaTeX math rendering
|
||||
- [[Mermaid diagrams]] — Diagram support via Mermaid
|
||||
- [[syntax highlighting|Syntax highlighting]] — Code block highlighting with themes
|
||||
- [[OxHugo compatibility]] — Support for ox-hugo Markdown
|
||||
- [[Roam Research compatibility]] — Support for Roam Research syntax
|
||||
- [[features/Citations|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
|
||||
- [[features/backlinks]] — See which notes link to the current page
|
||||
- [[features/explorer]] — File tree sidebar for browsing notes
|
||||
- [[features/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
|
||||
|
||||
- [[features/darkmode]] — Light and dark mode toggle
|
||||
- [[reader mode]] — Distraction-free reading experience
|
||||
- [[features/comments|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
|
||||
|
||||
@@ -12,6 +12,6 @@ Similar to Obsidian, [[quartz-layout-desktop.png|images referenced using wikilin
|
||||
|
||||
## 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`
|
||||
- Script: `quartz/components/scripts/popover.inline.ts`
|
||||
|
||||
@@ -17,7 +17,7 @@ If you'd like to only publish a select number of notes, you can instead use [[Ex
|
||||
|
||||
## `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]
|
||||
> Bash's glob syntax is slightly different from fast-glob's and using bash's syntax may lead to unexpected results.
|
||||
|
||||
@@ -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.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
## 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"
|
||||
plugins:
|
||||
- source: github:quartz-community/reader-mode
|
||||
enabled: false
|
||||
```ts
|
||||
// Remove or comment out this line
|
||||
Component.ReaderMode(),
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
The Reader Mode toggle appears as a button with a book icon. When clicked:
|
||||
|
||||
@@ -3,22 +3,15 @@ title: Recent Notes
|
||||
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`.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
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`.
|
||||
|
||||
## Customization
|
||||
|
||||
Most options are configured in the `options` section of the plugin entry in `quartz.config.yaml`:
|
||||
|
||||
- Changing the title from "Recent notes": set `title: "Recent writing"` in options
|
||||
- Changing the number of recent notes: set `limit: 5` in options
|
||||
- Display the note's tags (defaults to true): set `showTags: false` in options
|
||||
- Hide generated tag pages from the list (defaults to false): set `hideTagPages: true` in options. This filters out any page whose slug lives under the conventional `tags/` prefix.
|
||||
- Hide generated folder index pages from the list (defaults to false): set `hideFolderPages: true` in options. This filters out any page whose slug matches Quartz's folder-path convention (trailing slash or `index` suffix).
|
||||
- Show a 'see more' link: set `linkToMore: "tags/components"` in options. This field should be a full slug to a page that exists.
|
||||
- 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`.
|
||||
- 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`.
|
||||
- Install: `npx quartz plugin add github:quartz-community/recent-notes`
|
||||
- Source: [`quartz-community/recent-notes`](https://github.com/quartz-community/recent-notes)
|
||||
- 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 })`
|
||||
- Display the note's tags (defaults to true): `Component.RecentNotes({ showTags: false })`
|
||||
- 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.
|
||||
- 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`.
|
||||
- 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.
|
||||
- Component: `quartz/components/RecentNotes.tsx`
|
||||
- Style: `quartz/components/styles/recentNotes.scss`
|
||||
|
||||
@@ -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
|
||||
@@ -8,8 +8,6 @@ Quartz supports Wikilinks by default and these links are resolved by Quartz usin
|
||||
|
||||
This is enabled as a part of [[Obsidian compatibility]] and can be configured and enabled/disabled from that plugin.
|
||||
|
||||
Wikilink matching is case-insensitive to mirror Obsidian: `[[My Note]]`, `[[my note]]`, and `[[MY NOTE]]` all resolve to the same file. The generated URL is lowercased (e.g. `my-note`).
|
||||
|
||||
## Syntax
|
||||
|
||||
- `[[Path to file]]`: produces a link to `Path to file.md` (or `Path-to-file.md`) with the text `Path to file`
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
title: Getting Started
|
||||
---
|
||||
|
||||
This guide walks you through setting up Quartz from scratch. If you already ran the [[index#🪴 Get Started|quickstart]] on the home page, you can skip ahead to whichever step you're on.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You need these tools installed before continuing:
|
||||
|
||||
- **[Node.js](https://nodejs.org/) v22 or later** (run `node -v` to check)
|
||||
- **npm v10.9.2 or later** (bundled with Node — run `npm -v` to check)
|
||||
- **[Git](https://git-scm.com/)** (run `git -v` to check)
|
||||
|
||||
> [!warning] Common issues
|
||||
>
|
||||
> - **Linux**: System packages (`apt install nodejs`) often ship much older versions. Use [nvm](https://github.com/nvm-sh/nvm) or the [NodeSource](https://github.com/nodesource/distributions) repository to get Node.js v22.
|
||||
> - **Windows**: When installing Git, make sure **"Git from the command line and also from 3rd-party software"** is selected so that `git` is available in your terminal. If `node -v` or `git -v` shows "command not found", restart your terminal or check your PATH.
|
||||
> - **macOS**: The Xcode command-line tools include Git (`xcode-select --install`). For Node.js, [nvm](https://github.com/nvm-sh/nvm) or the [official installer](https://nodejs.org/) both work.
|
||||
|
||||
## Setup Steps
|
||||
|
||||
Follow these in order:
|
||||
|
||||
1. **[[installation|Installation]]** — Get Quartz (via GitHub template or clone), install dependencies, run the setup wizard (`npx quartz create`), install plugins, and preview your site locally
|
||||
2. **[[authoring-content|Authoring Content]]** — Write and organize your Markdown notes in the `content/` folder
|
||||
3. **[[installation#Setting Up Your GitHub Repository|Push to GitHub]]** — Create a repository and push your site with `npx quartz sync`
|
||||
4. **[[hosting|Deploy]]** — Host your site for free on GitHub Pages, Cloudflare, Netlify, or Vercel
|
||||
|
||||
## Upgrading & Migrating
|
||||
|
||||
- **[[whats-new|What's New in Quartz 5]]** — Overview of new features and changes
|
||||
- **[[upgrading|Upgrading Quartz]]** — Keep your Quartz installation up to date
|
||||
- **[[migrating|Migrating to Quartz 5]]** — Migrate from Quartz 4 or Quartz 3
|
||||
@@ -1,161 +0,0 @@
|
||||
---
|
||||
title: "Installation"
|
||||
aliases:
|
||||
- "setting up your GitHub repository"
|
||||
---
|
||||
|
||||
This page walks you through the full Quartz setup: from getting the source code to previewing your site locally, then pushing it to GitHub.
|
||||
|
||||
## 1. Get Quartz
|
||||
|
||||
There are two ways to get started. Pick whichever you prefer:
|
||||
|
||||
### Option A: Use the GitHub Template (Recommended)
|
||||
|
||||
> [!tip] Why this option?
|
||||
> Using the template creates your own repository in one click — no need to reconfigure Git remotes later.
|
||||
|
||||
1. Go to the [Quartz repository](https://github.com/jackyzha0/quartz) and click **Use this template** → **Create a new repository**
|
||||
2. Give your repository a name (e.g. `quartz`, `notes`, `garden`), choose public or private, then click **Create repository**
|
||||
3. Clone **your new repository** and enter the folder:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your-username>/<your-repo>.git
|
||||
cd <your-repo>
|
||||
```
|
||||
|
||||
### Option B: Clone Directly
|
||||
|
||||
If you don't use GitHub or prefer a manual setup:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/jackyzha0/quartz.git
|
||||
cd quartz
|
||||
```
|
||||
|
||||
> [!note]
|
||||
> With this option, you'll need to [[#Connect Your Local Clone|point the `origin` remote]] to your own repository later when you're ready to publish.
|
||||
|
||||
## 2. Install Dependencies
|
||||
|
||||
> [!important]
|
||||
> Quartz requires **Node.js 22** or later. Check your version with `node -v` and upgrade at [nodejs.org](https://nodejs.org/) if needed.
|
||||
|
||||
```bash
|
||||
npm i
|
||||
```
|
||||
|
||||
> [!note]
|
||||
> On subsequent clones of your own repository (e.g. on a new machine), use `npm ci` instead for a faster, reproducible install from the lockfile.
|
||||
|
||||
## 3. Initialize Your Site
|
||||
|
||||
Run the interactive setup wizard:
|
||||
|
||||
```bash
|
||||
npx quartz create
|
||||
```
|
||||
|
||||
This will prompt you for:
|
||||
|
||||
- A **template** (`default`, `obsidian`, `ttrpg`, `blog`) — pick the one that matches your use case. See [[create#Templates]] for details on each.
|
||||
- A **content strategy** — choose how to populate the `content/` folder:
|
||||
- **new**: Start with an empty folder
|
||||
- **copy**: Copy files from an existing folder (e.g. your Obsidian vault)
|
||||
- **symlink**: Link to an existing folder so changes sync automatically
|
||||
- A **base URL** — the URL where your site will be deployed (e.g. `mysite.github.io/quartz`). Don't include `https://`.
|
||||
- A **link resolution** strategy — how to resolve internal links (`shortest`, `absolute`, or `relative`). Skipped for Obsidian and TTRPG templates.
|
||||
|
||||
For non-interactive usage and more details, see the [[create|`quartz create` CLI reference]].
|
||||
|
||||
## 4. Install Plugins
|
||||
|
||||
The template you chose references community plugins that need to be installed:
|
||||
|
||||
```bash
|
||||
npx quartz plugin install --from-config
|
||||
```
|
||||
|
||||
This downloads and builds all plugins listed in `quartz.config.yaml` into `.quartz/plugins/`.
|
||||
|
||||
> [!tip]
|
||||
> If some plugins fail to build, try refreshing them to their latest versions:
|
||||
>
|
||||
> ```bash
|
||||
> npx quartz plugin install --latest
|
||||
> ```
|
||||
>
|
||||
> See [[troubleshooting#Plugins fail to build on a fresh clone]] for more details.
|
||||
|
||||
## 5. Preview Your Site
|
||||
|
||||
```bash
|
||||
npx quartz build --serve
|
||||
```
|
||||
|
||||
Your site is now running at `http://localhost:8080`. The dev server watches for file changes and reloads automatically.
|
||||
|
||||
At this point you can [[authoring-content|start writing content]] in the `content/` folder. When you're ready to publish, continue below to push your site to GitHub and [[hosting|deploy it]].
|
||||
|
||||
---
|
||||
|
||||
## Setting Up Your GitHub Repository
|
||||
|
||||
> [!note]
|
||||
> If you used **Option A** (GitHub Template) in step 1, your repository already exists and `origin` is already set. You can skip straight to [[#Push Your Site]].
|
||||
|
||||
To publish your site, you'll need your own GitHub repository. This section is for **Option B** (direct clone) users.
|
||||
|
||||
### Create the Repository
|
||||
|
||||
Create a new repository on [GitHub.com](https://github.com/new). Do **not** initialize it with a README, license, or `.gitignore` — Quartz already includes these files, and duplicating them will cause merge conflicts on your first push.
|
||||
|
||||
![[github-init-repo-options.png]]
|
||||
|
||||
Copy the repository URL from the Quick Setup page:
|
||||
|
||||
![[github-quick-setup.png]]
|
||||
|
||||
### Connect Your Local Clone
|
||||
|
||||
Point your local Quartz at your new repository:
|
||||
|
||||
```bash
|
||||
# Check current remotes
|
||||
git remote -v
|
||||
|
||||
# Point origin to your repository
|
||||
git remote set-url origin REMOTE-URL
|
||||
```
|
||||
|
||||
> [!tip]
|
||||
> You don't need to add an `upstream` remote manually — `npx quartz create` already configured it for you. The upstream remote is used by `npx quartz upgrade` to pull in future Quartz updates.
|
||||
|
||||
### Push Your Site
|
||||
|
||||
```bash
|
||||
npx quartz sync --no-pull
|
||||
```
|
||||
|
||||
This commits your content and pushes everything to your repository. For subsequent updates, just run:
|
||||
|
||||
```bash
|
||||
npx quartz sync
|
||||
```
|
||||
|
||||
> [!hint] Flags and options
|
||||
> For full help options, you can run `npx quartz sync --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
|
||||
> - `--commit` or `--no-commit`: whether to make a `git` commit for your changes
|
||||
> - `--push` or `--no-push`: whether to push updates to your GitHub fork of Quartz
|
||||
> - `--pull` or `--no-pull`: whether to try and pull in any updates from your GitHub fork (i.e. from other devices) before pushing
|
||||
|
||||
## Next Steps
|
||||
|
||||
- **[[authoring-content|Authoring Content]]** — Write and organize your notes
|
||||
- **[[hosting|Hosting]]** — Deploy your site to GitHub Pages, Cloudflare, Netlify, or Vercel
|
||||
- **[[configuration|Configuration]]** — Customize your site's appearance and behavior
|
||||
@@ -1,228 +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 [[upgrading|Upgrading Quartz]] instead.
|
||||
|
||||
If you're new to Quartz entirely, skip this guide and follow the [[installation|installation guide]] instead.
|
||||
|
||||
## Before You Start: Save Your Content
|
||||
|
||||
Before switching branches, make sure your content is safe. Switching to v5 will replace the files in your working directory with the v5 codebase, so your v4 content folder won't be visible until you restore it.
|
||||
|
||||
Copy your content folder somewhere outside the repo before switching:
|
||||
|
||||
```bash
|
||||
# macOS / Linux
|
||||
cp -r content /tmp/quartz-content
|
||||
|
||||
# Windows (PowerShell)
|
||||
Copy-Item -Recurse content $env:TEMP\quartz-content
|
||||
```
|
||||
|
||||
> [!note] Your old branch is preserved
|
||||
> Switching branches does **not** delete your v4 (or v3/hugo) branch. You can always switch back with `git checkout v4` to access your old content and configuration.
|
||||
|
||||
## Getting the v5 Branch
|
||||
|
||||
Whether you're coming from Quartz 4 or Quartz 3, the first step is the same: get the v5 branch onto your machine and push it to your repository.
|
||||
|
||||
```bash
|
||||
# Add the official Quartz repository as a remote called "upstream" (skip if already set)
|
||||
git remote add upstream https://github.com/jackyzha0/quartz.git
|
||||
|
||||
# Fetch the v5 branch from the official repository
|
||||
git fetch upstream v5
|
||||
|
||||
# Create a local v5 branch from the official one
|
||||
git checkout -b v5 upstream/v5
|
||||
|
||||
# Install dependencies
|
||||
npm i
|
||||
|
||||
# Push v5 to your GitHub repository
|
||||
git push -u origin v5
|
||||
```
|
||||
|
||||
## Setting Up Your Site
|
||||
|
||||
Once you're on v5, run the interactive setup to configure your site and import your content:
|
||||
|
||||
```bash
|
||||
npx quartz create
|
||||
```
|
||||
|
||||
This will prompt you for:
|
||||
|
||||
- A **template** (`default`, `obsidian`, `ttrpg`, `blog`) — pick the one closest to your old setup. `obsidian` is recommended if you use an Obsidian vault.
|
||||
- A **content strategy** — choose "Copy" and point it to your backed-up content folder.
|
||||
|
||||
If you skipped the `create` wizard or need to restore your content manually:
|
||||
|
||||
```bash
|
||||
# macOS / Linux
|
||||
cp -r /tmp/quartz-content/* content/
|
||||
|
||||
# Windows (PowerShell)
|
||||
Copy-Item -Recurse $env:TEMP\quartz-content\* content\
|
||||
```
|
||||
|
||||
After running `create`, install all plugins referenced in the generated config:
|
||||
|
||||
```bash
|
||||
npx quartz plugin install --from-config
|
||||
```
|
||||
|
||||
## What Changed in v5
|
||||
|
||||
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.
|
||||
|
||||
Key changes:
|
||||
|
||||
- **Configuration format**: TypeScript (`quartz.config.ts`, `quartz.layout.ts`) → YAML (`quartz.config.yaml`)
|
||||
- **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`
|
||||
- **Page types**: A new plugin category for page rendering (content, folder, tag pages)
|
||||
- **URL casing**: All generated URLs are now lowercased and hyphenated (e.g. `My Notes/Hello World.md` → `/my-notes/hello-world`). In v4, the original casing of file and folder names was preserved in URLs.
|
||||
|
||||
### URL Casing and SEO
|
||||
|
||||
If your v4 site had URLs with uppercase letters, those URLs will return 404 errors after upgrading to v5. This also affects search engine indexing, since Google treats URLs as [case-sensitive](https://developers.google.com/search/docs/crawling-indexing/url-structure).
|
||||
|
||||
The [[AliasRedirects]] plugin (enabled by default) automatically handles this. During build, it detects files whose original path contained uppercase characters and generates redirect pages at the old URLs. These redirect pages include proper SEO signals (`<link rel="canonical">`, `<meta http-equiv="refresh">`, `<meta name="robots" content="noindex">`) so that search engines transfer ranking to the new lowercase URLs.
|
||||
|
||||
No manual configuration is needed — the plugin is enabled by default and the case redirect behavior is on by default. If you want to disable it, set `enableCaseRedirects: false` in the plugin options:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:quartz-community/alias-redirects
|
||||
enabled: true
|
||||
options:
|
||||
enableCaseRedirects: false
|
||||
```
|
||||
|
||||
> [!tip] Hosting on Netlify?
|
||||
> Netlify automatically lowercases all URLs and issues server-side 301 redirects. If you're hosting on Netlify, the case redirect pages aren't strictly necessary, but they don't hurt either.
|
||||
|
||||
> [!note] Most users don't need to worry about these details
|
||||
> If you used the default Quartz 4 configuration (or only changed settings that `npx quartz create` prompts for), the setup wizard handles everything. The details below are for users who had custom plugin configurations.
|
||||
|
||||
### Plugin Reference Table
|
||||
|
||||
Mapping v4 plugin names to v5 equivalents:
|
||||
|
||||
| v4 | v5 | Type |
|
||||
| ----------------------------------- | ------------------------------------------- | --------------------- |
|
||||
| `Plugin.FrontMatter()` | `ExternalPlugin.NoteProperties()` | Community |
|
||||
| `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()` | `Plugin.Spacer()` |
|
||||
|
||||
## Updating Your CI/CD
|
||||
|
||||
Quartz 5 requires plugins to be installed before building. Add a plugin install step and (optionally) caching to your CI pipeline.
|
||||
|
||||
Here's the recommended pattern, based on the project's own GitHub Actions:
|
||||
|
||||
```yaml
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ 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
|
||||
|
||||
- name: Install Quartz plugins
|
||||
run: npx quartz plugin install
|
||||
|
||||
- name: Build Quartz
|
||||
run: npx quartz build
|
||||
```
|
||||
|
||||
The plugin cache uses `quartz.lock.json` as the cache key, so plugins are only re-downloaded when the lockfile changes.
|
||||
|
||||
For non-GitHub CI providers (Cloudflare, Vercel, Netlify), the build command should be:
|
||||
|
||||
```shell
|
||||
npx quartz plugin install && npx quartz build
|
||||
```
|
||||
|
||||
See [[hosting]] for provider-specific setup details.
|
||||
|
||||
## Setting Your Default Branch to v5
|
||||
|
||||
After verifying your site builds and deploys correctly, update your repository's default branch to `v5`:
|
||||
|
||||
1. Go to your repository on GitHub
|
||||
2. Navigate to **Settings** → **General**
|
||||
3. Under **Default branch**, click the switch icon next to your current default branch
|
||||
4. Select `v5` from the dropdown and click **Update**
|
||||
5. Confirm the change
|
||||
|
||||
This ensures that new clones, pull requests, and GitHub Pages deployments all target v5 by default. Your old v4 branch remains available for reference.
|
||||
|
||||
> [!warning] Update your CI triggers
|
||||
> If your CI workflow triggers on a specific branch (e.g. `branches: [v4]`), make sure to update it to `v5`. See the [[hosting]] guide for examples.
|
||||
|
||||
## Notes for Quartz 3 Users
|
||||
|
||||
If you're coming from Quartz 3 (the Hugo-based version), follow the same steps above — get the v5 branch, run `npx quartz create`, and import your content. There is no need to go through Quartz 4 first.
|
||||
|
||||
### Key changes from Quartz 3
|
||||
|
||||
1. **Hugo is gone**: Quartz now uses a Node-based static-site generation process. No more Go templates or `hugo-obsidian`.
|
||||
2. **Full hot-reload**: The development server (`npx quartz build --serve`) re-processes all content on every change.
|
||||
3. **JSX instead of Go templates**: Layout components are written in JSX (JavaScript XML), which is significantly easier to customize.
|
||||
4. **New plugin system**: See [[configuration#Plugins|Plugins]] for details on the extensible plugin architecture.
|
||||
|
||||
### Things to update
|
||||
|
||||
- Update your deploy scripts — see the [[hosting]] guide.
|
||||
- Ensure your default branch on GitHub is updated to `v5`.
|
||||
- [[folder and tag listings|Folder and tag listings]] have changed:
|
||||
- Folder descriptions go under `content/<folder-name>/index.md`
|
||||
- Tag descriptions go under `content/tags/<tag-name>.md`
|
||||
- Custom CSS may need updates if you depended on specific HTML hierarchy or class names from Quartz 3.
|
||||
@@ -1,121 +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 [[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. Merge conflicts in `quartz.lock.json` are handled automatically — Quartz backs up your lockfile before pulling and restores it afterward. For other files with local changes that 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 plugin install --latest
|
||||
```
|
||||
|
||||
See the [[upgrade|CLI reference for upgrade]] for more details on available flags.
|
||||
|
||||
### Layout System Changes
|
||||
|
||||
The `footer` layout slot is now an array of components, consistent with other layout slots like `header`, `left`, and `right`. Additionally, `header` and `footer` are now configurable layout positions — plugins can declare `layout: { position: header }` or `layout: { position: footer }` in their YAML config.
|
||||
|
||||
**If you override layouts in `quartz.ts`**, update any `footer` assignments to use arrays:
|
||||
|
||||
```ts title="quartz.ts"
|
||||
// Before
|
||||
export const layout = await loadQuartzLayout({
|
||||
defaults: { footer: MyFooterComponent },
|
||||
})
|
||||
|
||||
// After
|
||||
export const layout = await loadQuartzLayout({
|
||||
defaults: { footer: [MyFooterComponent] },
|
||||
})
|
||||
```
|
||||
|
||||
**If you have a custom page frame**, update the `render` function to iterate the footer array:
|
||||
|
||||
```tsx
|
||||
// Before
|
||||
render({ footer: Footer, ...rest }: PageFrameProps) {
|
||||
return <Footer {...componentData} />
|
||||
}
|
||||
|
||||
// After
|
||||
render({ footer, ...rest }: PageFrameProps) {
|
||||
return footer.map((F) => <F {...componentData} />)
|
||||
}
|
||||
```
|
||||
|
||||
Both changes are caught by TypeScript at compile time — running `npx quartz build` will show the error.
|
||||
|
||||
No changes are needed for `quartz.config.yaml` — the YAML format is unchanged.
|
||||
|
||||
### 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.
|
||||
|
||||
## Switching to npm Plugin Specifiers
|
||||
|
||||
First-party Quartz plugins are now published to npm under the `@quartz-community` scope. If your `quartz.config.yaml` uses `github:` specifiers, you can optionally switch to npm specifiers for faster installs and better version pinning.
|
||||
|
||||
### Why Switch?
|
||||
|
||||
- **Faster installs**: npm packages are cached locally and don't require git cloning
|
||||
- **Version pinning**: npm uses semver ranges, so you control when to update
|
||||
- **No build step**: npm packages ship pre-built, unlike git sources which may need to build on install
|
||||
|
||||
### How to Migrate
|
||||
|
||||
Update each plugin source in your `quartz.config.yaml` from the `github:` format to the quoted npm format:
|
||||
|
||||
```yaml
|
||||
# Before
|
||||
plugins:
|
||||
- source: github:quartz-community/syntax-highlighting
|
||||
enabled: true
|
||||
|
||||
# After
|
||||
plugins:
|
||||
- source: "@quartz-community/syntax-highlighting"
|
||||
enabled: true
|
||||
```
|
||||
|
||||
> [!important]
|
||||
> The `@` scoped name must be quoted in YAML. Use double quotes around the source value.
|
||||
|
||||
Then install the packages:
|
||||
|
||||
```bash
|
||||
npm install @quartz-community/syntax-highlighting
|
||||
```
|
||||
|
||||
Or install all default plugins at once:
|
||||
|
||||
```bash
|
||||
npm install @quartz-community/created-modified-date @quartz-community/syntax-highlighting @quartz-community/obsidian-flavored-markdown @quartz-community/github-flavored-markdown @quartz-community/table-of-contents @quartz-community/crawl-links @quartz-community/description @quartz-community/latex @quartz-community/quartz-fonts @quartz-community/remove-draft @quartz-community/alias-redirects @quartz-community/content-index @quartz-community/favicon @quartz-community/og-image @quartz-community/cname @quartz-community/canvas-page @quartz-community/content-page @quartz-community/folder-page @quartz-community/tag-page @quartz-community/explorer @quartz-community/graph @quartz-community/search @quartz-community/backlinks @quartz-community/article-title @quartz-community/content-meta @quartz-community/page-title @quartz-community/darkmode @quartz-community/reader-mode @quartz-community/breadcrumbs @quartz-community/footer @quartz-community/spacer @quartz-community/bases-page @quartz-community/note-properties @quartz-community/unlisted-pages @quartz-community/encrypted-pages
|
||||
```
|
||||
|
||||
### Do I Have to Switch?
|
||||
|
||||
No. The `github:` specifiers continue to work and will be supported indefinitely. They are still the recommended approach for third-party and community plugins that are not published to npm. The npm path is an optional improvement for first-party plugins.
|
||||
@@ -1,193 +0,0 @@
|
||||
---
|
||||
title: "What's New in Quartz 5"
|
||||
aliases:
|
||||
- "changelog"
|
||||
- "v5"
|
||||
---
|
||||
|
||||
Quartz 5 is a ground-up rearchitecture of Quartz focused on extensibility, performance, and Obsidian compatibility. If you're coming from v4, see [[migrating|Migrating to Quartz 5]] for the upgrade path.
|
||||
|
||||
## Plugin Ecosystem
|
||||
|
||||
The biggest change in v5 is the move to a **community plugin ecosystem**. Plugins are now standalone packages maintained in the [quartz-community](https://github.com/quartz-community) GitHub organization and installed via git:
|
||||
|
||||
```bash
|
||||
npx quartz plugin add github:quartz-community/explorer
|
||||
```
|
||||
|
||||
This means:
|
||||
|
||||
- **Independent versioning**: Plugins can be updated without upgrading Quartz itself
|
||||
- **Community contributions**: Anyone can publish a Quartz plugin
|
||||
- **Smaller core**: Quartz core is leaner; features live in plugins
|
||||
- **Plugin registry**: Discover plugins via `npx quartz tui` or the [plugin registry](https://github.com/quartz-community/registry)
|
||||
|
||||
Over 40 official plugins ship with Quartz, covering everything from search and graph view to encrypted pages and canvas rendering.
|
||||
|
||||
## YAML Configuration
|
||||
|
||||
Configuration moved from TypeScript (`quartz.config.ts`) to **YAML** (`quartz.config.yaml`):
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
configuration:
|
||||
pageTitle: My Digital Garden
|
||||
enableSPA: true
|
||||
enablePopovers: true
|
||||
locale: en-US
|
||||
baseUrl: mysite.github.io
|
||||
theme:
|
||||
typography:
|
||||
header: Schibsted Grotesk
|
||||
body: Source Sans Pro
|
||||
code: IBM Plex Mono
|
||||
plugins:
|
||||
- source: github:quartz-community/obsidian-flavored-markdown
|
||||
enabled: true
|
||||
order: 30
|
||||
- source: github:quartz-community/explorer
|
||||
enabled: true
|
||||
layout:
|
||||
position: left
|
||||
priority: 50
|
||||
```
|
||||
|
||||
Benefits:
|
||||
|
||||
- **No TypeScript knowledge required** for basic customization
|
||||
- **JSON Schema validation** — editors with YAML support show errors inline
|
||||
- **Layout defined per-plugin** — each plugin declares its own position and priority
|
||||
- **Templates** — `npx quartz create` offers preconfigured templates (default, obsidian, ttrpg, blog)
|
||||
|
||||
For advanced options that need JavaScript (callbacks, custom components), the `quartz.ts` override system provides full programmatic control.
|
||||
|
||||
## Improved Obsidian Compatibility
|
||||
|
||||
Quartz 5 aims for full compatibility with Obsidian's core features:
|
||||
|
||||
- **Wikilinks** — all variations including aliases, headings, block references, and pipe escaping in tables
|
||||
- **Callouts** — all built-in types, collapsible variants, and nested callouts
|
||||
- **Highlights** — `==highlighted text==` syntax
|
||||
- **Comments** — `%%hidden comments%%` (inline and block)
|
||||
- **Tags** — `#tag` and `#nested/tag` with tag pages
|
||||
- **Custom task characters** — `[?]`, `[!]`, `[>]`, etc. preserved as `data-task` attributes
|
||||
- **Mermaid diagrams** — rendered with expand button
|
||||
- **YouTube and Tweet embeds** — via image syntax
|
||||
- **Block references** — `^block-id` with broad character support
|
||||
- **Video/audio embeds** — full format support (mp4, webm, ogv, mov, mkv, avi, flac, aac, etc.)
|
||||
- **Canvas files** — rendered as interactive, pannable pages via the canvas-page plugin
|
||||
- **Obsidian URI links** — marked with CSS class for custom styling
|
||||
- **Footnotes** — via the GitHub Flavored Markdown plugin
|
||||
|
||||
See [[Obsidian compatibility]] for the full list.
|
||||
|
||||
## Page Type System
|
||||
|
||||
Quartz 5 introduces **page types** — plugins that define how different kinds of pages are rendered:
|
||||
|
||||
- **Content pages** — regular markdown notes
|
||||
- **Folder pages** — directory listing pages
|
||||
- **Tag pages** — pages listing notes with a given tag
|
||||
- **Canvas pages** — interactive JSON Canvas renderings
|
||||
- **Bases pages** — database-style views of your content
|
||||
|
||||
Each page type can use a different [[layout#Page Frames|page frame]] for fundamentally different HTML structures (three-column, full-width, minimal, etc.).
|
||||
|
||||
## Layout System
|
||||
|
||||
The layout system is now declarative. Plugins declare their position (`left`, `right`, `beforeBody`, `afterBody`) and priority in the config:
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
- source: github:quartz-community/explorer
|
||||
layout:
|
||||
position: left
|
||||
priority: 50
|
||||
- source: github:quartz-community/graph
|
||||
layout:
|
||||
position: right
|
||||
priority: 10
|
||||
```
|
||||
|
||||
Additional features:
|
||||
|
||||
- **Groups** — combine components into flex rows/columns (e.g., toolbar with search + darkmode toggle)
|
||||
- **Conditional rendering** — show/hide components based on page properties (`condition: not-index`, `condition: has-tags`)
|
||||
- **Display modifiers** — `display: mobile-only` or `display: desktop-only`
|
||||
- **Per-page-type overrides** — different layouts for content, folder, tag, and 404 pages
|
||||
|
||||
## Performance
|
||||
|
||||
- **Parallel processing** — markdown parsing uses a worker pool across all CPU cores
|
||||
- **Incremental rebuilds** — watch mode only re-processes changed files
|
||||
- **Pre-built plugins** — community plugins ship compiled `dist/` directories, skipping build-from-source on install
|
||||
- **SPA routing** — client-side navigation with `micromorph` for instant page transitions
|
||||
- **CDN-cached fonts** — Google Fonts with aggressive caching, or fully self-hosted with `fontOrigin: local`
|
||||
|
||||
## CLI Improvements
|
||||
|
||||
The CLI is simpler and more helpful:
|
||||
|
||||
| Command | Description |
|
||||
| -------------------------------- | --------------------------------------- |
|
||||
| `npx quartz create` | Interactive setup wizard with templates |
|
||||
| `npx quartz build --serve` | Build and serve with hot reload |
|
||||
| `npx quartz sync` | Commit and push to GitHub |
|
||||
| `npx quartz upgrade` | Pull latest Quartz updates |
|
||||
| `npx quartz plugin install` | Install plugins from lockfile |
|
||||
| `npx quartz plugin add <source>` | Add a new plugin |
|
||||
| `npx quartz plugin list` | List installed plugins |
|
||||
| `npx quartz plugin prune` | Remove unused plugins |
|
||||
|
||||
Other improvements:
|
||||
|
||||
- **Node.js version check** — clear error message if running on Node < 22
|
||||
- **Port conflict handling** — helpful message when port is already in use
|
||||
- **Plugin lockfile** — `quartz.lock.json` pins plugin versions for reproducible builds
|
||||
- **Concurrency control** — `--concurrency` flag for memory-constrained environments
|
||||
|
||||
## Internationalization
|
||||
|
||||
Quartz 5 supports multiple locales out of the box. Set `locale: ja-JP` (or any supported locale) in your config to translate all UI strings — search placeholders, "table of contents", date formatting, and more.
|
||||
|
||||
## New Plugins
|
||||
|
||||
Plugins new to v5 (not available in v4):
|
||||
|
||||
```base
|
||||
filters:
|
||||
and:
|
||||
- file.ext == "md"
|
||||
- file.inFolder("plugins")
|
||||
- note["new-in-v5"] == true
|
||||
properties:
|
||||
title:
|
||||
displayName: Plugin
|
||||
repository:
|
||||
displayName: Repository
|
||||
description:
|
||||
displayName: Description
|
||||
views:
|
||||
- type: table
|
||||
name: New in v5
|
||||
order:
|
||||
- title
|
||||
- repository
|
||||
- description
|
||||
sort:
|
||||
- property: title
|
||||
direction: ASC
|
||||
```
|
||||
|
||||
## For Plugin Developers
|
||||
|
||||
If you built plugins for v4, the development model has changed significantly:
|
||||
|
||||
- Plugins are **standalone npm packages** with their own `package.json`, `tsconfig.json`, and build system
|
||||
- The **factory function pattern** (inspired by Astro integrations) replaces class-based plugins
|
||||
- **`@quartz-community/types`** provides full type safety without depending on the Quartz core
|
||||
- **`@quartz-community/utils`** provides shared path, DOM, and language utilities
|
||||
- **`@quartz-community/runtime`** provides browser runtime utilities
|
||||
- Plugins can ship **components**, **frames**, **stylesheets**, and **client scripts**
|
||||
- A **plugin template** is available at [quartz-community/plugin-template](https://github.com/quartz-community/plugin-template)
|
||||
|
||||
See [[making plugins]] for the full guide.
|
||||
+31
-94
@@ -7,36 +7,30 @@ Quartz effectively turns your Markdown files and other resources into a bundle o
|
||||
However, if you'd like to publish your site to the world, you need a way to host it online. This guide will detail how to deploy with common hosting providers but any service that allows you to deploy static HTML should work as well.
|
||||
|
||||
> [!warning]
|
||||
> The rest of this guide assumes that you've already created your own GitHub repository for Quartz. If you haven't already, follow the [[installation#Setting Up Your GitHub Repository|GitHub repository setup]] section of the installation guide.
|
||||
> The rest of this guide assumes that you've already created your own GitHub repository for Quartz. If you haven't already, [[setting up your GitHub repository|make sure you do so]].
|
||||
|
||||
> [!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!
|
||||
|
||||
> [!tip] Keeping plugins in sync
|
||||
> All hosting examples below use `npx quartz plugin install` to install plugins from the lockfile. If contributors may add plugins to `quartz.config.yaml` without updating the lockfile, add `npx quartz plugin install --from-config` after `install` in your build command to install any missing plugins. See [[cli/plugin#install|plugin install]] for details.
|
||||
|
||||
## Cloudflare Pages
|
||||
|
||||
1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/) and select your account.
|
||||
2. In Account Home, select **Compute (Workers)** > **Workers & Pages** > **Create application** > **Pages** > **Connect to Git**.
|
||||
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 |
|
||||
| ---------------------- | ----------------------------------------------- |
|
||||
| Production branch | `v5` |
|
||||
| Framework preset | `None` |
|
||||
| Build command | `npx quartz plugin install && npx quartz build` |
|
||||
| Build output directory | `public` |
|
||||
| Configuration option | Value |
|
||||
| ---------------------- | ------------------ |
|
||||
| Production branch | `v4` |
|
||||
| Framework preset | `None` |
|
||||
| Build command | `npx quartz build` |
|
||||
| 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.
|
||||
|
||||
To add a custom domain, check out [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/custom-domains/).
|
||||
|
||||
> [!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 install && npx quartz build`).
|
||||
|
||||
> [!note]
|
||||
> For more detailed CI/CD configuration including caching and plugin management, see [[migrating#Updating Your CI/CD|the migration guide]].
|
||||
> 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`).
|
||||
|
||||
## GitHub Pages
|
||||
|
||||
@@ -48,7 +42,7 @@ name: Deploy Quartz site to GitHub Pages
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v5
|
||||
- v4
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -61,32 +55,16 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for git info
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ 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-
|
||||
node-version: 22
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
- name: Install Quartz plugins
|
||||
run: npx quartz plugin install
|
||||
- name: Build Quartz
|
||||
run: npx quartz build
|
||||
- name: Upload artifact
|
||||
@@ -134,11 +112,7 @@ Here's how to add a custom domain to your GitHub pages deployment.
|
||||
- `185.199.111.153`
|
||||
- If you are using a subdomain, navigate to your DNS provider and create a `CNAME` record that points your subdomain to the default domain for your site. For example, if you want to use the subdomain `quartz.example.com` for your user site, create a `CNAME` record that points `quartz.example.com` to `<github-username>.github.io`.
|
||||
|
||||
![[dns records.png]]_The above shows a screenshot of Google Domains configured for both `jzhao.xyz`
|
||||
|
||||
(an apex domain) and `quartz.jzhao.xyz`
|
||||
|
||||
(a subdomain)._
|
||||
![[dns records.png]]_The above shows a screenshot of Google Domains configured for both `jzhao.xyz` (an apex domain) and `quartz.jzhao.xyz` (a subdomain)._
|
||||
|
||||
See the [GitHub documentation](https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-a-subdomain) for more detail about how to setup your own custom domain with GitHub Pages.
|
||||
|
||||
@@ -166,11 +140,11 @@ Before deploying to Vercel, a `vercel.json` file is required at the root of the
|
||||
3. Give the project a name (lowercase characters and hyphens only)
|
||||
4. Check that these configuration options are set:
|
||||
|
||||
| Configuration option | Value |
|
||||
| ----------------------------------------- | ----------------------------------------------- |
|
||||
| Framework Preset | `Other` |
|
||||
| Root Directory | `./` |
|
||||
| Build and Output Settings > Build Command | `npx quartz plugin install && npx quartz build` |
|
||||
| Configuration option | Value |
|
||||
| ----------------------------------------- | ------------------ |
|
||||
| Framework Preset | `Other` |
|
||||
| Root Directory | `./` |
|
||||
| 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.
|
||||
|
||||
@@ -179,7 +153,7 @@ Before deploying to Vercel, a `vercel.json` file is required at the root of the
|
||||
> [!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.
|
||||
|
||||
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.
|
||||
3. Connect the domain to Vercel
|
||||
4. Press "Add" to connect a custom domain to Vercel.
|
||||
@@ -191,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.
|
||||
|
||||
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.
|
||||
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
|
||||
@@ -201,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".
|
||||
2. Select your Git provider and repository containing your Quartz project.
|
||||
3. Under "Build command", enter `npx quartz plugin install && npx quartz build`.
|
||||
3. Under "Build command", enter `npx quartz build`.
|
||||
4. Under "Publish directory", enter `public`.
|
||||
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.
|
||||
@@ -215,33 +189,31 @@ stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
image: node:24
|
||||
cache:
|
||||
- key: npm-$CI_COMMIT_REF_SLUG
|
||||
paths:
|
||||
- .npm/
|
||||
- key: plugins-$CI_COMMIT_REF_SLUG
|
||||
paths:
|
||||
- .quartz/plugins/
|
||||
image: node:22
|
||||
cache: # Cache modules in between jobs
|
||||
key: $CI_COMMIT_REF_SLUG
|
||||
paths:
|
||||
- .npm/
|
||||
|
||||
build:
|
||||
stage: build
|
||||
rules:
|
||||
- if: '$CI_COMMIT_REF_NAME == "v5"'
|
||||
- if: '$CI_COMMIT_REF_NAME == "v4"'
|
||||
before_script:
|
||||
- hash -r
|
||||
- npm ci --cache .npm --prefer-offline
|
||||
script:
|
||||
- npx quartz plugin install
|
||||
- npx quartz build
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
tags:
|
||||
- gitlab-org-docker
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
rules:
|
||||
- if: '$CI_COMMIT_REF_NAME == "v5"'
|
||||
- if: '$CI_COMMIT_REF_NAME == "v4"'
|
||||
script:
|
||||
- echo "Deploying to GitLab Pages..."
|
||||
artifacts:
|
||||
@@ -314,38 +286,3 @@ example.com {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Caching
|
||||
|
||||
Quartz emits CSS and JS files with content hashes in their filenames (e.g. `index-a3f2c1b.css`, `component-7d4e2f.css`). Since the filename changes whenever the content changes, these files can be cached indefinitely. HTML files should not be cached long-term since they reference the hashed filenames and need to stay fresh.
|
||||
|
||||
### Cloudflare Pages / Vercel / Netlify
|
||||
|
||||
These platforms handle caching automatically. No configuration is needed — hashed assets will be served with appropriate cache headers out of the box.
|
||||
|
||||
### Nginx
|
||||
|
||||
```nginx title="nginx.conf"
|
||||
# Immutable cache for hashed assets
|
||||
location ~* \.(css|js)$ {
|
||||
if ($uri ~* "-[0-9a-f]{8}\.") {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caddy
|
||||
|
||||
```caddy title="Caddyfile"
|
||||
@hashed path_regexp hashed -[0-9a-f]{8}\.(css|js)$
|
||||
header @hashed Cache-Control "public, max-age=31536000, immutable"
|
||||
```
|
||||
|
||||
### Apache
|
||||
|
||||
```apache title=".htaccess"
|
||||
# Immutable cache for content-hashed assets
|
||||
<FilesMatch "-[0-9a-f]{8}\.(css|js)$">
|
||||
Header set Cache-Control "public, max-age=31536000, immutable"
|
||||
</FilesMatch>
|
||||
```
|
||||
|
||||
+15
-38
@@ -1,60 +1,37 @@
|
||||
---
|
||||
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.
|
||||
|
||||
## 🪴 Get Started
|
||||
|
||||
Quartz requires **at least [Node](https://nodejs.org/) v22** and `npm` v10.9.2 to function correctly. Ensure you have these installed on your machine before continuing. See the [[getting-started/index#Prerequisites|prerequisites]] for help installing them.
|
||||
Quartz requires **at least [Node](https://nodejs.org/) v22** and `npm` v10.9.2 to function correctly. Ensure you have this installed on your machine before continuing.
|
||||
|
||||
> [!tip] GitHub users
|
||||
> You can also use the **[GitHub template](https://github.com/jackyzha0/quartz/generate)** to create your repository in one click, then clone that instead. See [[installation#Option A Use the GitHub Template Recommended|Option A]] in the installation guide.
|
||||
Then, in your terminal of choice, enter the following commands line by line:
|
||||
|
||||
```shell
|
||||
# 1. Clone the Quartz repository
|
||||
git clone https://github.com/jackyzha0/quartz.git
|
||||
cd quartz
|
||||
|
||||
# 2. Install dependencies
|
||||
npm i
|
||||
|
||||
# 3. Initialize your site (choose a template, set your base URL, import content)
|
||||
npx quartz create
|
||||
|
||||
# 4. Install plugins referenced by your chosen template
|
||||
npx quartz plugin install --from-config
|
||||
|
||||
# 5. Preview your site locally
|
||||
npx quartz build --serve
|
||||
```
|
||||
|
||||
Your site is now running at `http://localhost:8080`. From here:
|
||||
This will guide you through initializing your Quartz with content. Once you've done so, see how to:
|
||||
|
||||
- **[[authoring-content|Write content]]** in the `content/` folder
|
||||
- **[[installation|Push to GitHub]]** with `npx quartz sync`
|
||||
- **[[hosting|Deploy]]** to GitHub Pages, Cloudflare, Netlify, or Vercel
|
||||
1. [[authoring content|Writing content]] in Quartz
|
||||
2. [[configuration|Configure]] Quartz's behaviour
|
||||
3. Change Quartz's [[layout]]
|
||||
4. [[build|Build and preview]] Quartz
|
||||
5. Sync your changes with [[setting up your GitHub repository|GitHub]]
|
||||
6. [[hosting|Host]] Quartz online
|
||||
|
||||
For the full walkthrough, see the [[getting-started/index|Getting Started]] guide.
|
||||
|
||||
### Returning User?
|
||||
|
||||
Already have a Quartz repository and cloning it on a new machine?
|
||||
|
||||
```shell
|
||||
git clone https://github.com/<your-username>/<your-repo>.git
|
||||
cd <your-repo>
|
||||
npm ci
|
||||
npx quartz plugin install
|
||||
npx quartz build --serve
|
||||
```
|
||||
|
||||
> [!tip]
|
||||
> If you hit build errors on a fresh clone, try `npx quartz plugin install --latest` to refresh plugins to their latest versions. See [[troubleshooting#Plugins fail to build on a fresh clone]] for details.
|
||||
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
|
||||
|
||||
- [[Obsidian compatibility]], [[full-text search]], [[graph view]], [[wikilinks|wikilinks, transclusions]], [[plugins/Backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]], [[features/comments|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
|
||||
- Hot-reload on configuration edits and incremental rebuilds for content edits
|
||||
- Simple JSX layouts and [[creating components|page components]]
|
||||
- [[SPA Routing|Ridiculously fast page loads]] and tiny bundle sizes
|
||||
@@ -64,6 +41,6 @@ For a comprehensive list of features, visit the [features page](./features/). Yo
|
||||
|
||||
### 🚧 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).
|
||||
|
||||
+55
-147
@@ -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.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
type FlexConfig = {
|
||||
components: {
|
||||
Component: QuartzComponent
|
||||
grow?: boolean
|
||||
shrink?: boolean
|
||||
basis?: string
|
||||
order?: number
|
||||
align?: "start" | "end" | "center" | "stretch"
|
||||
justify?: "start" | "end" | "center" | "between" | "around"
|
||||
grow?: boolean // whether component should grow to fill space
|
||||
shrink?: boolean // whether component should shrink if needed
|
||||
basis?: string // initial main size of the component
|
||||
order?: number // order in flex container
|
||||
align?: "start" | "end" | "center" | "stretch" // cross-axis alignment
|
||||
justify?: "start" | "end" | "center" | "between" | "around" // main-axis alignment
|
||||
}[]
|
||||
direction?: "row" | "row-reverse" | "column" | "column-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
|
||||
> 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
|
||||
> .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:
|
||||
|
||||
```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)"
|
||||
```typescript
|
||||
Component.MobileOnly(Component.Spacer())
|
||||
```
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
Component.DesktopOnly(Plugin.TableOfContents())
|
||||
## `DesktopOnly` Component
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
### 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",
|
||||
})
|
||||
```
|
||||
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.
|
||||
|
||||
```typescript
|
||||
type ConditionalRenderConfig = {
|
||||
@@ -190,5 +81,22 @@ type ConditionalRenderConfig = {
|
||||
}
|
||||
```
|
||||
|
||||
> [!tip]
|
||||
> 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.
|
||||
### Example Usage
|
||||
|
||||
```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.
|
||||
|
||||
+7
-189
@@ -2,12 +2,7 @@
|
||||
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.
|
||||
|
||||
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]].
|
||||
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`.
|
||||
|
||||
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:
|
||||
|
||||
@@ -20,7 +15,7 @@ export interface FullPageLayout {
|
||||
afterBody: QuartzComponent[] // laid out vertically
|
||||
left: QuartzComponent[] // vertical on desktop and tablet, horizontal on mobile
|
||||
right: QuartzComponent[] // vertical on desktop, horizontal on tablet and mobile
|
||||
footer: QuartzComponent[] // laid out vertically
|
||||
footer: QuartzComponent // single component
|
||||
}
|
||||
```
|
||||
|
||||
@@ -36,191 +31,14 @@ These correspond to following parts of the page:
|
||||
> 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.
|
||||
> 2. `header` is a set of components that are laid out horizontally and appears _before_ the `beforeBody` section. You can place components in the header by setting `layout.position: header` in your plugin configuration. This enables layouts similar to Quartz 3's header bar with title, search bar, and dark mode toggle.
|
||||
> 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"
|
||||
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/darkmode
|
||||
enabled: true
|
||||
layout:
|
||||
position: header
|
||||
priority: 10
|
||||
- source: github:quartz-community/footer
|
||||
enabled: true
|
||||
options:
|
||||
links:
|
||||
GitHub: https://github.com/jackyzha0/quartz
|
||||
Discord Community: https://discord.gg/cRFFHYye7t
|
||||
layout:
|
||||
position: footer
|
||||
priority: 50
|
||||
|
||||
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: []
|
||||
```
|
||||
|
||||
### Conditional Rendering
|
||||
|
||||
Plugins can specify a `condition` in their layout block to control when they appear. This uses built-in presets:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:quartz-community/breadcrumbs
|
||||
enabled: true
|
||||
layout:
|
||||
position: beforeBody
|
||||
priority: 5
|
||||
condition: not-index
|
||||
```
|
||||
|
||||
Available conditions:
|
||||
|
||||
| Condition | Effect |
|
||||
| ----------- | ---------------------------------------------------- |
|
||||
| `not-index` | Hidden on the root index page, shown everywhere else |
|
||||
| `has-tags` | Only shown on pages that have tags in frontmatter |
|
||||
|
||||
See [[layout-components]] for more details on conditional rendering and display options.
|
||||
|
||||
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.).
|
||||
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.
|
||||
|
||||
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 [[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
|
||||
|
||||
Quartz has different layouts depending on the width the screen viewing the website.
|
||||
@@ -240,9 +58,9 @@ $breakpoints: (
|
||||
|
||||
### 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`.
|
||||
|
||||
> [!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.
|
||||
|
||||
@@ -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.
|
||||
+1
-1
@@ -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.
|
||||
|
||||
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.
|
||||
|
||||
Most software either confines you to either
|
||||
|
||||
@@ -1,68 +1,37 @@
|
||||
---
|
||||
title: AliasRedirects
|
||||
description: Generates redirect pages from frontmatter aliases and case-preserving URLs.
|
||||
tags:
|
||||
- plugin/emitter
|
||||
image: https://images.unsplash.com/photo-1601735479770-bb5de9dbe844
|
||||
repository: "[quartz-community/alias-redirects](https://github.com/quartz-community/alias-redirects)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin emits HTML redirect pages so that old URLs redirect to the canonical page. It handles two types of redirects:
|
||||
This plugin emits HTML redirect pages for aliases and permalinks defined in the frontmatter of content files.
|
||||
|
||||
1. **Frontmatter aliases**: Redirect pages for aliases defined in your content's frontmatter.
|
||||
2. **Case-preserving redirects**: Automatic redirect pages for URLs that changed due to Quartz v5's lowercase slug normalization.
|
||||
|
||||
### Frontmatter Aliases
|
||||
|
||||
If `foo.md` has the following frontmatter:
|
||||
For example, A `foo.md` has the following frontmatter
|
||||
|
||||
```md title="foo.md"
|
||||
---
|
||||
title: "Foo"
|
||||
aliases:
|
||||
alias:
|
||||
- "bar"
|
||||
---
|
||||
```
|
||||
|
||||
The target `host.me/bar` will be permanently redirected to `host.me/foo`.
|
||||
The target `host.me/bar` will be redirected to `host.me/foo`
|
||||
|
||||
The emitter supports the following frontmatter fields:
|
||||
Note that these are permanent redirect.
|
||||
|
||||
The emitter supports the following aliases:
|
||||
|
||||
- `aliases`
|
||||
- `alias`
|
||||
|
||||
### Case-Preserving Redirects
|
||||
|
||||
Quartz v5 normalizes all URLs to lowercase. If you are migrating from v4 (which preserved the original casing), previously indexed URLs containing uppercase letters (e.g. `/Diary/My-Note`) would return 404 errors.
|
||||
|
||||
When `enableCaseRedirects` is enabled (the default), this plugin automatically detects files whose original path differs from the lowercased slug and generates redirect pages at the original-case URL. For example, if your content directory contains `Diary/2026-01-01.md`, the plugin generates:
|
||||
|
||||
- The canonical page at `/diary/2026-01-01` (produced by the normal build)
|
||||
- A redirect page at `/Diary/2026-01-01` (produced by this plugin)
|
||||
|
||||
The redirect page includes proper SEO signals:
|
||||
|
||||
- `<meta http-equiv="refresh" content="0; url=...">` for an instant redirect
|
||||
- `<link rel="canonical">` pointing to the lowercase URL
|
||||
- `<meta name="robots" content="noindex">` to prevent duplicate indexing
|
||||
|
||||
This preserves search engine rankings and ensures inbound links continue to work.
|
||||
|
||||
> [!note]
|
||||
> Case-preserving redirects have no effect on case-insensitive filesystems (macOS, Windows) where the server already resolves either casing to the same file. The plugin automatically detects the filesystem type and skips redirect generation when unnecessary.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
This plugin accepts the following configuration options:
|
||||
|
||||
- `enableCaseRedirects`: If `true` (default), automatically generates redirect pages for URLs that changed casing due to v5's lowercase normalization. Set to `false` to disable this behavior.
|
||||
This plugin has no configuration options.
|
||||
|
||||
## API
|
||||
|
||||
- Category: Emitter
|
||||
- Function name: `ExternalPlugin.AliasRedirects()`.
|
||||
- Source: [`quartz-community/alias-redirects`](https://github.com/quartz-community/alias-redirects)
|
||||
- Install: `npx quartz plugin add github:quartz-community/alias-redirects`
|
||||
- Function name: `Plugin.AliasRedirects()`.
|
||||
- Source: [`quartz/plugins/emitters/aliases.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/aliases.ts).
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
title: ArticleTitle
|
||||
description: Renders the article title as an h1 heading.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
repository: "[quartz-community/article-title](https://github.com/quartz-community/article-title)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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`
|
||||
@@ -2,7 +2,6 @@
|
||||
title: Assets
|
||||
tags:
|
||||
- plugin/emitter
|
||||
image: https://images.unsplash.com/photo-1526304640581-d334cdbbf45e
|
||||
---
|
||||
|
||||
This plugin emits all non-Markdown static assets in your content folder (like images, videos, HTML, etc). The plugin respects the `ignorePatterns` in the global [[configuration]].
|
||||
@@ -17,5 +16,5 @@ This plugin has no configuration options.
|
||||
## API
|
||||
|
||||
- Category: Emitter
|
||||
- Function name: `Plugin.Assets()` (internal plugin).
|
||||
- Source: [`quartz/plugins/emitters/assets.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/emitters/assets.ts).
|
||||
- Function name: `Plugin.Assets()`.
|
||||
- Source: [`quartz/plugins/emitters/assets.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/assets.ts).
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
title: Backlinks
|
||||
description: Shows pages that link to the current page.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
repository: "[quartz-community/backlinks](https://github.com/quartz-community/backlinks)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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 [[plugins/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`
|
||||
@@ -1,75 +0,0 @@
|
||||
---
|
||||
title: BasesPage
|
||||
description: Renders Obsidian Bases files as database-style views.
|
||||
tags:
|
||||
- plugin/pageType
|
||||
- plugin/component
|
||||
image:
|
||||
new-in-v5: true
|
||||
repository: "[quartz-community/bases-page](https://github.com/quartz-community/bases-page)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
## Interaction with `unlisted` pages
|
||||
|
||||
`BasesPage` respects the `file.data.unlisted` convention written by [[UnlistedPages]] and [[EncryptedPages]]. Pages marked `unlisted: true` (or encrypted pages with `stealth: true`) are excluded from every rendered base view — table, list, board, cards, gallery, and any custom view — regardless of whether the base's filter expression would match them. Unlisted pages also cannot be dereferenced from formulas on visible pages via `.asFile()`.
|
||||
|
||||
> [!note]
|
||||
> Base views are **server-side rendered** HTML baked at build time. They do not update client-side after a visitor decrypts an encrypted page. Graph, explorer, and search all re-hydrate from the patched in-memory content index and show newly-unlocked pages for the rest of the browser session — base views do not, because they were materialized at build time with unlisted pages already excluded. A visitor who successfully decrypts a revealable encrypted page will see it appear in graph, explorer, and search, but **not** in any base view, until the site is rebuilt with that page listed. This is the same structural limitation that applies to backlinks, recent notes, folder listings, and tag listings.
|
||||
|
||||
## Configuration
|
||||
|
||||
This plugin accepts the following configuration options:
|
||||
|
||||
- `defaultViewType`: The default view type when none is specified in the `.base` file. Defaults to `"table"`.
|
||||
- `linkResolution`: How to resolve internal links in view renderers. Should match the `markdownLinkResolution` setting of the [[CrawlLinks]] plugin. Can be `"absolute"`, `"relative"`, or `"shortest"`. Defaults to `"shortest"`.
|
||||
- `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"
|
||||
|
||||
// Must be placed before loadQuartzConfig()
|
||||
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`
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
title: Breadcrumbs
|
||||
description: Breadcrumb navigation trail.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
repository: "[quartz-community/breadcrumbs](https://github.com/quartz-community/breadcrumbs)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
Navigation breadcrumb trail.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
See [[plugins/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`
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: CNAME
|
||||
description: Emits a CNAME file for custom domain deployment.
|
||||
tags:
|
||||
- plugin/emitter
|
||||
image:
|
||||
repository: "[quartz-community/cname](https://github.com/quartz-community/cname)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin emits a `CNAME` record that points your subdomain to the default domain of your site.
|
||||
@@ -23,6 +18,5 @@ This plugin has no configuration options.
|
||||
## API
|
||||
|
||||
- Category: Emitter
|
||||
- Function name: `ExternalPlugin.CNAME()`.
|
||||
- Source: [`quartz-community/cname`](https://github.com/quartz-community/cname)
|
||||
- Install: `npx quartz plugin add github:quartz-community/cname`
|
||||
- Function name: `Plugin.CNAME()`.
|
||||
- Source: [`quartz/plugins/emitters/cname.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/cname.ts).
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
---
|
||||
title: CanvasPage
|
||||
description: Renders JSON Canvas files as interactive, pannable pages.
|
||||
tags:
|
||||
- plugin/pageType
|
||||
image: "#7852ee"
|
||||
new-in-v5: true
|
||||
repository: "[quartz-community/canvas-page](https://github.com/quartz-community/canvas-page)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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 (1–6) 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`
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: Citations
|
||||
description: Academic citation and bibliography support via BibTeX.
|
||||
title: "Citations"
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image: https://images.unsplash.com/photo-1582079133805-43655f026448
|
||||
repository: "[quartz-community/citations](https://github.com/quartz-community/citations)"
|
||||
enabled: false
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin adds Citation support to Quartz.
|
||||
@@ -20,10 +15,10 @@ This plugin accepts the following configuration options:
|
||||
- `suppressBibliography`: whether to suppress the bibliography at the end of the document. Defaults to `false`.
|
||||
- `linkCitations`: whether to link citations to the bibliography. Defaults to `false`.
|
||||
- `csl`: the citation style to use. Defaults to `apa`. Reference [rehype-citation](https://rehype-citation.netlify.app/custom-csl) for more options.
|
||||
- `prettyLink`: whether to use pretty links for citations. Defaults to `true`.
|
||||
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.Citations()`.
|
||||
- Source: [`quartz-community/citations`](https://github.com/quartz-community/citations)
|
||||
- Install: `npx quartz plugin add github:quartz-community/citations`
|
||||
- Function name: `Plugin.Citations()`.
|
||||
- Source: [`quartz/plugins/transformers/citations.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/citations.ts).
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
---
|
||||
title: Comments
|
||||
description: Comment system integration (Giscus, Utterances, etc.).
|
||||
tags:
|
||||
- plugin/component
|
||||
image: "[[giscus-results.png]]"
|
||||
repository: "[quartz-community/comments](https://github.com/quartz-community/comments)"
|
||||
enabled: false
|
||||
required: false
|
||||
---
|
||||
|
||||
Comment system (giscus, utterances, etc.).
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
See [[plugins/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`
|
||||
@@ -2,7 +2,6 @@
|
||||
title: ComponentResources
|
||||
tags:
|
||||
- plugin/emitter
|
||||
image:
|
||||
---
|
||||
|
||||
This plugin manages and emits the static resources required for the Quartz framework. This includes CSS stylesheets and JavaScript scripts that enhance the functionality and aesthetics of the generated site. See also the `cdnCaching` option in the `theme` section of the [[configuration]].
|
||||
@@ -15,5 +14,5 @@ This plugin has no configuration options.
|
||||
## API
|
||||
|
||||
- Category: Emitter
|
||||
- Function name: `Plugin.ComponentResources()` (internal plugin).
|
||||
- Source: [`quartz/plugins/emitters/componentResources.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/emitters/componentResources.ts).
|
||||
- Function name: `Plugin.ComponentResources()`.
|
||||
- Source: [`quartz/plugins/emitters/componentResources.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/componentResources.ts).
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: ContentIndex
|
||||
description: Generates sitemap, RSS feed, and content index.
|
||||
tags:
|
||||
- plugin/emitter
|
||||
image:
|
||||
repository: "[quartz-community/content-index](https://github.com/quartz-community/content-index)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin emits both RSS and an XML sitemap for your site. The [[RSS Feed]] allows users to subscribe to content on your site and the sitemap allows search engines to better index your site. The plugin also emits a `contentIndex.json` file which is used by dynamic frontend components like search and graph.
|
||||
@@ -21,13 +16,12 @@ This plugin accepts the following configuration options:
|
||||
- `enableSiteMap`: If `true` (default), generates a sitemap XML file (`sitemap.xml`) listing all site URLs for search engines in content discovery.
|
||||
- `enableRSS`: If `true` (default), produces an RSS feed (`index.xml`) with recent content updates.
|
||||
- `rssLimit`: Defines the maximum number of entries to include in the RSS feed, helping to focus on the most recent or relevant content. Defaults to `10`.
|
||||
- `rssFullHtml`: If `true`, the RSS feed includes the full rendered HTML content of each page. Defaults to `false`.
|
||||
- `rssFullHtml`: If `true`, the RSS feed includes full HTML content. Otherwise it includes just summaries.
|
||||
- `rssSlug`: Slug to the generated RSS feed XML file. Defaults to `"index"`.
|
||||
- `includeEmptyFiles`: If `true` (default), content files with no body text are included in the generated index and resources.
|
||||
|
||||
## API
|
||||
|
||||
- Category: Emitter
|
||||
- Function name: `ExternalPlugin.ContentIndex()`.
|
||||
- Source: [`quartz-community/content-index`](https://github.com/quartz-community/content-index)
|
||||
- Install: `npx quartz plugin add github:quartz-community/content-index`
|
||||
- Function name: `Plugin.ContentIndex()`.
|
||||
- Source: [`quartz/plugins/emitters/contentIndex.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/contentIndex.ts).
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
title: ContentMeta
|
||||
description: Displays creation date and reading time.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
repository: "[quartz-community/content-meta](https://github.com/quartz-community/content-meta)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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`
|
||||
@@ -1,15 +1,10 @@
|
||||
---
|
||||
title: ContentPage
|
||||
description: Generates HTML pages for Markdown content.
|
||||
tags:
|
||||
- plugin/pageType
|
||||
image:
|
||||
repository: "[quartz-community/content-page](https://github.com/quartz-community/content-page)"
|
||||
enabled: true
|
||||
required: false
|
||||
- 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]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
@@ -18,7 +13,6 @@ This plugin has no configuration options.
|
||||
|
||||
## API
|
||||
|
||||
- Category: Page Type
|
||||
- Function name: `ExternalPlugin.ContentPage()`.
|
||||
- Source: [`quartz-community/content-page`](https://github.com/quartz-community/content-page)
|
||||
- Install: `npx quartz plugin add github:quartz-community/content-page`
|
||||
- Category: Emitter
|
||||
- Function name: `Plugin.ContentPage()`.
|
||||
- Source: [`quartz/plugins/emitters/contentPage.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/contentPage.tsx).
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: CrawlLinks
|
||||
description: Parses and resolves internal links. Removing it is not recommended.
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image:
|
||||
repository: "[quartz-community/crawl-links](https://github.com/quartz-community/crawl-links)"
|
||||
enabled: true
|
||||
required: true
|
||||
---
|
||||
|
||||
This plugin parses links and processes them to point to the right places. It is also needed for embedded links (like images). See [[Obsidian compatibility]] for more information.
|
||||
@@ -24,7 +19,6 @@ This plugin accepts the following configuration options:
|
||||
- `openLinksInNewTab`: If `true`, configures external links to open in a new tab. Defaults to `false`.
|
||||
- `lazyLoad`: If `true`, adds lazy loading to resource elements (`img`, `video`, etc.) to improve page load performance. Defaults to `false`.
|
||||
- `externalLinkIcon`: Adds an icon next to external links when `true` (default) to visually distinguishing them from internal links.
|
||||
- `disableBrokenWikilinks`: If `true`, internal links whose resolved slug is not present in the site (i.e. no matching file under `markdownLinkResolution`) gain an additional `broken` CSS class alongside `internal`, so they can be styled distinctly. Defaults to `false`. Applies to both wikilinks and regular Markdown links, since both are indistinguishable `<a>` elements by the time this plugin runs.
|
||||
|
||||
> [!warning]
|
||||
> Removing this plugin is _not_ recommended and will likely break the page.
|
||||
@@ -32,6 +26,5 @@ This plugin accepts the following configuration options:
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.CrawlLinks()`.
|
||||
- Source: [`quartz-community/crawl-links`](https://github.com/quartz-community/crawl-links)
|
||||
- Install: `npx quartz plugin add github:quartz-community/crawl-links`
|
||||
- Function name: `Plugin.CrawlLinks()`.
|
||||
- Source: [`quartz/plugins/transformers/links.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/links.ts).
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: CreatedModifiedDate
|
||||
description: Determines creation and modification dates from frontmatter, git, or filesystem.
|
||||
title: "CreatedModifiedDate"
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image:
|
||||
repository: "[quartz-community/created-modified-date](https://github.com/quartz-community/created-modified-date)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin determines the created, modified, and published dates for a document using three potential data sources: frontmatter metadata, Git history, and the filesystem. See [[authoring content#Syntax]] for more information.
|
||||
@@ -17,18 +12,16 @@ This plugin determines the created, modified, and published dates for a document
|
||||
This plugin accepts the following configuration options:
|
||||
|
||||
- `priority`: The data sources to consult for date information. Highest priority first. Possible values are `"frontmatter"`, `"git"`, and `"filesystem"`. Defaults to `["frontmatter", "git", "filesystem"]`.
|
||||
- `defaultDateType`: Which date type to use when displaying dates. Can be `"created"`, `"modified"`, or `"published"`. Defaults to `"modified"`.
|
||||
|
||||
When loading the frontmatter, the value of [[Frontmatter#List]] is used.
|
||||
|
||||
> [!warning]
|
||||
> If you rely on `git` for dates, make sure `defaultDateType` is set to `modified` in the plugin's options.
|
||||
> 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.
|
||||
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.CreatedModifiedDate()`.
|
||||
- Source: [`quartz-community/created-modified-date`](https://github.com/quartz-community/created-modified-date)
|
||||
- Install: `npx quartz plugin add github:quartz-community/created-modified-date`
|
||||
- Function name: `Plugin.CreatedModifiedDate()`.
|
||||
- Source: [`quartz/plugins/transformers/lastmod.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/lastmod.ts).
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: Custom OG Images
|
||||
description: Generates Open Graph social preview images.
|
||||
tags:
|
||||
- feature/emitter
|
||||
image: "[[social-image-preview-dark.png]]"
|
||||
repository: "[quartz-community/og-image](https://github.com/quartz-community/og-image)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
The Custom OG Images emitter plugin generates social media preview images for your pages. It uses [satori](https://github.com/vercel/satori) to convert HTML/CSS into images, allowing you to create beautiful and consistent social media preview cards for your content.
|
||||
@@ -30,44 +25,33 @@ The Custom OG Images emitter plugin generates social media preview images for yo
|
||||
|
||||
This plugin accepts the following configuration options:
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
plugins:
|
||||
- source: github:quartz-community/og-image
|
||||
enabled: true
|
||||
options:
|
||||
colorScheme: lightMode # "lightMode" or "darkMode"
|
||||
width: 1200
|
||||
height: 630
|
||||
excludeRoot: false
|
||||
```
|
||||
```typescript title="quartz.config.ts"
|
||||
import { CustomOgImages } from "./quartz/plugins/emitters/ogImage"
|
||||
|
||||
For the TS override approach (needed for custom `imageStructure`):
|
||||
|
||||
```ts title="quartz.ts (override)"
|
||||
import * as ExternalPlugin from "./.quartz/plugins"
|
||||
import { defaultImage } from "./quartz/plugins/emitters/ogImage"
|
||||
|
||||
// Must be placed before loadQuartzConfig()
|
||||
ExternalPlugin.CustomOgImages({
|
||||
colorScheme: "lightMode",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
excludeRoot: false,
|
||||
imageStructure: defaultImage,
|
||||
})
|
||||
const config: QuartzConfig = {
|
||||
plugins: {
|
||||
emitters: [
|
||||
CustomOgImages({
|
||||
colorScheme: "lightMode", // what colors to use for generating image, same as theme colors from config, valid values are "darkMode" and "lightMode"
|
||||
width: 1200, // width to generate with (in pixels)
|
||||
height: 630, // height to generate with (in pixels)
|
||||
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 image component to use
|
||||
}),
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| -------------------- | --------- | ------------------------- | ----------------------------------------------------------------- |
|
||||
| `colorScheme` | string | "lightMode" | Theme to use for generating images ("darkMode" or "lightMode") |
|
||||
| `width` | number | 1200 | Width of the generated image in pixels |
|
||||
| `height` | number | 630 | Height of the generated image in pixels |
|
||||
| `excludeRoot` | boolean | false | Whether to exclude the root index page from auto-generated images |
|
||||
| `defaultTitle` | string | "Untitled" | Fallback title when a page has no title |
|
||||
| `defaultDescription` | string | "No description provided" | Fallback description when a page has no description |
|
||||
| `imageStructure` | component | defaultImage | Custom component to use for image generation |
|
||||
| Option | Type | Default | Description |
|
||||
| ---------------- | --------- | ------------ | ----------------------------------------------------------------- |
|
||||
| `colorScheme` | string | "lightMode" | Theme to use for generating images ("darkMode" or "lightMode") |
|
||||
| `width` | number | 1200 | Width of the generated image in pixels |
|
||||
| `height` | number | 630 | Height of the generated image in pixels |
|
||||
| `excludeRoot` | boolean | false | Whether to exclude the root index page from auto-generated images |
|
||||
| `imageStructure` | component | defaultImage | Custom component to use for image generation |
|
||||
|
||||
## Frontmatter Properties
|
||||
|
||||
@@ -92,7 +76,7 @@ You can fully customize how the images being generated look by passing your own
|
||||
|
||||
### 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:
|
||||
|
||||
@@ -374,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`
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
title: Darkmode
|
||||
description: Toggle between light and dark themes.
|
||||
tags:
|
||||
- plugin/component
|
||||
image: "#0052cc"
|
||||
repository: "[quartz-community/darkmode](https://github.com/quartz-community/darkmode)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
Dark mode toggle.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
See [[plugins/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`
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: Description
|
||||
description: Generates page descriptions for metadata and previews.
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image:
|
||||
repository: "[quartz-community/description](https://github.com/quartz-community/description)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin generates descriptions that are used as metadata for the HTML `head`, the [[RSS Feed]] and in [[folder and tag listings]] if there is no main body content, the description is used as the text between the title and the listing.
|
||||
@@ -18,13 +13,11 @@ If the frontmatter contains a `description` property, it is used (see [[authorin
|
||||
|
||||
This plugin accepts the following configuration options:
|
||||
|
||||
- `descriptionLength`: the target length of the generated description. Default is 150 characters. The cut off happens after the first _sentence_ that ends after the given length.
|
||||
- `maxDescriptionLength`: the hard maximum length of the description. If the generated description exceeds this, it is truncated with an ellipsis. Default is 300 characters.
|
||||
- `descriptionLength`: the maximum length of the generated description. Default is 150 characters. The cut off happens after the first _sentence_ that ends after the given length.
|
||||
- `replaceExternalLinks`: If `true` (default), replace external links with their domain and path in the description (e.g. `https://domain.tld/some_page/another_page?query=hello&target=world` is replaced with `domain.tld/some_page/another_page`).
|
||||
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.Description()`.
|
||||
- Source: [`quartz-community/description`](https://github.com/quartz-community/description)
|
||||
- Install: `npx quartz plugin add github:quartz-community/description`
|
||||
- Function name: `Plugin.Description()`.
|
||||
- Source: [`quartz/plugins/transformers/description.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/description.ts).
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
---
|
||||
title: Encrypted Pages Demo
|
||||
password: quartz
|
||||
unlisted: true
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image:
|
||||
---
|
||||
|
||||
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. This page is also `unlisted: true`, which means it was hidden from every discovery surface on the site until you entered the password.
|
||||
|
||||
## 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. Because this page is `unlisted: true`, the plugin emitted its metadata (slug, title, links, tags) to a separate `static/encryptedContentIndex.json` file, encrypted with this page's own password.
|
||||
3. When you visited this page, you were shown a password prompt instead of the content. The page was absent from the sidebar graph, explorer, search, RSS, sitemap, backlinks, tag listings, and bases views.
|
||||
4. After entering the correct password, the plugin derived an encryption key using PBKDF2 and decrypted the content client-side.
|
||||
5. The plugin then used the cached password to unlock this page's entry in the shadow content index and patched the in-memory content index in place. A `content-index-updated` event was dispatched, so graph, explorer, and search re-initialized with the newly unlocked entry — if you navigate back to any other page now, you will see this page in the sidebar, the graph, and search results. Server-side rendered listings (backlinks, recent notes, tag pages, folder listings, and [[BasesPage|bases views]]) were baked into HTML at build time and will not update within this session; they will only reflect decrypted pages on a fresh build of the site.
|
||||
|
||||
## Password caching
|
||||
|
||||
Your password has been cached in session storage. If there were other encrypted pages on this site with the same password, the plugin would automatically try this password on each one — unlocking its content as well as its entry in the shadow content index — so you'd only need to enter it once per session.
|
||||
|
||||
## 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.
|
||||
@@ -1,129 +0,0 @@
|
||||
---
|
||||
title: EncryptedPages
|
||||
description: Password-protected encrypted pages with shadow content index.
|
||||
tags:
|
||||
- plugin/transformer
|
||||
- plugin/emitter
|
||||
image: "#FF1493"
|
||||
new-in-v5: true
|
||||
repository: "[quartz-community/encrypted-pages](https://github.com/quartz-community/encrypted-pages)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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. A companion emitter writes an encrypted shadow content index so unlisted encrypted pages can be dynamically revealed in graph, explorer, and search after a successful decryption — without ever leaking their metadata to visitors who do not hold the password.
|
||||
|
||||
> [!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.
|
||||
|
||||
### Hiding encrypted pages from discovery surfaces
|
||||
|
||||
By default, encrypted pages still appear in the graph, explorer, search, RSS, sitemap, and backlinks — visitors can see the page exists and its title, but cannot read the content without the password.
|
||||
|
||||
To hide an encrypted page entirely until a visitor successfully decrypts it, set `unlisted: true` in its frontmatter:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: My Secret Page
|
||||
password: mysecretpassword
|
||||
unlisted: true
|
||||
---
|
||||
```
|
||||
|
||||
An unlisted page:
|
||||
|
||||
- Is **absent** from `contentIndex.json`, `sitemap.xml`, the RSS feed, backlinks, recent notes, folder listings, tag listings, bases views, graph, explorer, and search.
|
||||
- Is still emitted as HTML, so it remains accessible by direct URL.
|
||||
- Has its metadata (slug, title, links, tags) written to a separate `static/encryptedContentIndex.json` file, encrypted with the page's own password.
|
||||
- Is dynamically re-added to the in-memory content index when a visitor successfully decrypts it, so graph, explorer, and search reflect it for the rest of the browser session. Server-rendered listings — backlinks, recent notes, tag pages, folder listings, and [[BasesPage|bases views]] — remain statically hidden even after decryption because they are baked as HTML at build time.
|
||||
|
||||
To make this the default for every encrypted page on your site, set `unlistWhenEncrypted: true` in the plugin options. Individual pages can then opt back in with `unlisted: false`.
|
||||
|
||||
> [!note]
|
||||
> The `unlisted: true` frontmatter field above only takes effect for encrypted pages when this plugin is installed. If you also want `unlisted: true` to work on **non-encrypted** pages across your site, install [[UnlistedPages]] alongside this one. The two plugins compose cleanly — when both are enabled, `unlisted: true` hides any page, encrypted or not, from every discovery surface that respects the `file.data.unlisted` convention.
|
||||
|
||||
### Permanently hiding encrypted pages (`stealth`)
|
||||
|
||||
By default, an `unlisted: true` encrypted page is _revealed_ in graph, explorer, and search after a visitor successfully decrypts it. This is usually what you want: the user just proved they know the password, so showing them the page in the sidebar makes sense for the rest of their session.
|
||||
|
||||
If you instead want a page that stays permanently invisible — accessible only by direct URL, even to users who have successfully decrypted other pages on the same site — set `stealth: true` in its frontmatter:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Deep Secret
|
||||
password: mysecretpassword
|
||||
stealth: true
|
||||
---
|
||||
```
|
||||
|
||||
A stealth page:
|
||||
|
||||
- Is **absent** from every discovery surface, same as any `unlisted` page.
|
||||
- Has **no entry** in the shadow content index (`encryptedContentIndex.json`). The plugin deliberately skips stealth pages when building the shadow index.
|
||||
- Stays hidden even after the visitor enters the correct password. Since there is no shadow-index entry to decrypt, there is nothing to patch into the in-memory content index — graph, explorer, and search never learn the page exists. Only the decrypted HTML is visible to the user on the page itself.
|
||||
- The password is still cached in session storage, so re-visiting the same stealth page will auto-unlock it.
|
||||
|
||||
`stealth: true` implies `unlisted: true` — you do not need to set both, and if you write `stealth: true, unlisted: false` the stealth flag wins. On non-encrypted pages `stealth: true` has no effect (there is no shadow index to skip).
|
||||
|
||||
Use stealth pages for "secret door" content that should only reach users who already know the exact URL: private notes linked from an external wiki, personal pages you send to specific people, or anything you never want to show up in a site-internal search even to authenticated readers.
|
||||
|
||||
## Configuration
|
||||
|
||||
This plugin provides a transformer, an emitter, and a component. All options are set on a single config entry and shared between the transformer and the emitter — Quartz instantiates both automatically.
|
||||
|
||||
- `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. Shared by the transformer and the emitter. Defaults to `"password"`.
|
||||
- `unlistWhenEncrypted`: If `true`, every encrypted page is marked `unlisted` unless its frontmatter explicitly overrides it. Defaults to `false`.
|
||||
- `outputPath`: Output path for the shadow content index, relative to Quartz's output directory. Defaults to `"static/encryptedContentIndex.json"`.
|
||||
|
||||
### 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:
|
||||
iterations: 600000
|
||||
passwordField: password
|
||||
unlistWhenEncrypted: false
|
||||
outputPath: static/encryptedContentIndex.json
|
||||
```
|
||||
|
||||
> [!warning]
|
||||
> The `EncryptedPages` transformer replaces the entire HAST tree of an encrypted page with an opaque ciphertext container. Any transformer that needs to read the real HTML — in particular [[CrawlLinks]], which populates the links used by backlinks and the shadow content index — must run **before** `EncryptedPages`. Use the `order` field in `quartz.config.yaml` to control this.
|
||||
|
||||
## Security
|
||||
|
||||
- Content is encrypted with AES-256-GCM using PBKDF2 SHA-256 key derivation.
|
||||
- Plaintext is stripped from search indices, RSS feeds, and the shadow content index regardless of visibility setting.
|
||||
- The shadow content index is a flat array of opaque encrypted blobs. An attacker who downloads it learns only the number of unlisted encrypted pages and the PBKDF2 iteration count — no slugs, titles, or link relationships leak.
|
||||
- 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, Emitter
|
||||
- Function name: `ExternalPlugin.EncryptedPages()`, `ExternalPlugin.EncryptedContentIndex()`.
|
||||
- Source: [`quartz-community/encrypted-pages`](https://github.com/quartz-community/encrypted-pages)
|
||||
- Install: `npx quartz plugin add github:quartz-community/encrypted-pages`
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: ExplicitPublish
|
||||
description: "Only publishes pages explicitly marked with publish: true."
|
||||
tags:
|
||||
- plugin/filter
|
||||
image:
|
||||
repository: "[quartz-community/explicit-publish](https://github.com/quartz-community/explicit-publish)"
|
||||
enabled: false
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin filters content based on an explicit `publish` flag in the frontmatter, allowing only content that is explicitly marked for publication to pass through. It's the opt-in version of [[RemoveDrafts]]. See [[private pages]] for more information.
|
||||
@@ -19,6 +14,5 @@ This plugin has no configuration options.
|
||||
## API
|
||||
|
||||
- Category: Filter
|
||||
- Function name: `ExternalPlugin.ExplicitPublish()`.
|
||||
- Source: [`quartz-community/explicit-publish`](https://github.com/quartz-community/explicit-publish)
|
||||
- Install: `npx quartz plugin add github:quartz-community/explicit-publish`
|
||||
- Function name: `Plugin.ExplicitPublish()`.
|
||||
- Source: [`quartz/plugins/filters/explicit.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/filters/explicit.ts).
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
---
|
||||
title: Explorer
|
||||
description: File tree explorer sidebar.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
repository: "[quartz-community/explorer](https://github.com/quartz-community/explorer)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
File tree explorer sidebar.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
See [[plugins/Explorer]] for detailed usage information.
|
||||
|
||||
## Configuration
|
||||
|
||||
This plugin accepts the following configuration options:
|
||||
|
||||
**YAML options** (in `quartz.config.yaml`):
|
||||
|
||||
- `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 `link`.
|
||||
- `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`.
|
||||
|
||||
**TS override options** (in `quartz.ts`, for callback functions that can't be expressed in YAML):
|
||||
|
||||
- `sortFn`: Custom sort function for ordering files and folders.
|
||||
- `filterFn`: Custom filter function to exclude specific nodes.
|
||||
- `mapFn`: Custom map function to transform node properties (e.g. display names).
|
||||
- `order`: Array controlling the order of operations. Defaults to `["filter", "map", "sort"]`.
|
||||
|
||||
### Default options
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
- source: github:quartz-community/explorer
|
||||
enabled: true
|
||||
options:
|
||||
title: Explorer
|
||||
folderClickBehavior: link
|
||||
folderDefaultState: collapsed
|
||||
useSavedState: true
|
||||
```
|
||||
|
||||
### TS override example
|
||||
|
||||
```ts title="quartz.ts"
|
||||
import * as ExternalPlugin from "./.quartz/plugins"
|
||||
|
||||
// Must be placed before loadQuartzConfig()
|
||||
ExternalPlugin.Explorer({
|
||||
mapFn: (node) => {
|
||||
node.displayName = node.displayName.toUpperCase()
|
||||
return node
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
See [[features/explorer#Advanced customization]] for more examples.
|
||||
|
||||
## 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`
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: Favicon
|
||||
description: Emits the site favicon.
|
||||
tags:
|
||||
- plugin/emitter
|
||||
image:
|
||||
repository: "[quartz-community/favicon](https://github.com/quartz-community/favicon)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin emits a `favicon.ico` into the `public` folder. It creates the favicon from `icon.png` located in the `quartz/static` folder.
|
||||
@@ -20,6 +15,5 @@ This plugin has no configuration options.
|
||||
## API
|
||||
|
||||
- Category: Emitter
|
||||
- Function name: `ExternalPlugin.Favicon()`.
|
||||
- Source: [`quartz-community/favicon`](https://github.com/quartz-community/favicon)
|
||||
- Install: `npx quartz plugin add github:quartz-community/favicon`
|
||||
- Function name: `Plugin.Favicon()`.
|
||||
- Source: [`quartz/plugins/emitters/favicon.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/favicon.ts).
|
||||
|
||||
@@ -1,31 +1,24 @@
|
||||
---
|
||||
title: FolderPage
|
||||
description: Generates listing pages for folders.
|
||||
tags:
|
||||
- plugin/pageType
|
||||
image:
|
||||
repository: "[quartz-community/folder-page](https://github.com/quartz-community/folder-page)"
|
||||
enabled: true
|
||||
required: false
|
||||
- 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]]
|
||||
|
||||
> [!note]
|
||||
> 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:
|
||||
|
||||
- `showFolderCount`: Whether to display the number of pages in the folder. Defaults to `true`.
|
||||
- `showSubfolders`: Whether to include pages from subfolders in the listing. Defaults to `true`.
|
||||
- `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. Requires a TS override.
|
||||
- `prefixFolders`: If `true`, generated folder page titles are prefixed with "Folder: " (e.g. "Folder: notes"). Defaults to `false`.
|
||||
- `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
|
||||
|
||||
- Category: Page Type
|
||||
- Function name: `ExternalPlugin.FolderPage()`.
|
||||
- Source: [`quartz-community/folder-page`](https://github.com/quartz-community/folder-page)
|
||||
- Install: `npx quartz plugin add github:quartz-community/folder-page`
|
||||
- Category: Emitter
|
||||
- Function name: `Plugin.FolderPage()`.
|
||||
- Source: [`quartz/plugins/emitters/folderPage.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/folderPage.tsx).
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
---
|
||||
title: Fonts
|
||||
description: Fine-grained font control with per-heading support, Google Fonts integration, and theme font discovery.
|
||||
tags:
|
||||
- plugin/transformer
|
||||
- plugin/emitter
|
||||
image:
|
||||
repository: "[quartz-community/fonts](https://github.com/quartz-community/fonts)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin provides fine-grained control over fonts in your Quartz site. It supports per-heading font families, automatic theme font discovery when used with [Quartz Themes](https://github.com/saberzero1/quartz-themes), Google Fonts integration with automatic weight and italic loading, and falls back to Obsidian's default system font stacks.
|
||||
|
||||
> [!note]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
|
||||
## Why use Fonts?
|
||||
|
||||
Quartz uses three CSS variables for fonts: `--headerFont`, `--bodyFont`, and `--codeFont`. Obsidian themes use a different system with per-heading variables (`--h1-font` through `--h6-font`), `--font-text`, and `--font-monospace`. These two systems don't bridge correctly, causing heading fonts to not render as themes intend.
|
||||
|
||||
Fonts solves this by:
|
||||
|
||||
1. Bridging the Obsidian and Quartz font systems
|
||||
2. Emitting **unlayered** CSS that correctly overrides Quartz's base heading styles
|
||||
3. Providing per-heading font control that neither system offers alone
|
||||
4. Optionally loading fonts from Google Fonts with fine-grained weight and italic control
|
||||
|
||||
## Configuration
|
||||
|
||||
Font options accept either a CSS font-family string or an object with Google Fonts loading control:
|
||||
|
||||
```yaml
|
||||
# String form
|
||||
body: '"Inter", sans-serif'
|
||||
|
||||
# Object form (for Google Fonts weight/italic control)
|
||||
body:
|
||||
name: Inter
|
||||
weights: [400, 600, 700]
|
||||
includeItalic: true
|
||||
```
|
||||
|
||||
This plugin accepts the following configuration options:
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| --------------- | ------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| `title` | `FontSpecification` | `header` value | Font family for the site title. |
|
||||
| `body` | `FontSpecification` | Obsidian default | Font family for body text. |
|
||||
| `header` | `FontSpecification` | Obsidian default | Default font family for all headings (h1-h6). |
|
||||
| `code` | `FontSpecification` | Obsidian default | Font family for code and monospace elements. |
|
||||
| `interface` | `FontSpecification` | Obsidian default | Font family for UI elements. |
|
||||
| `h1` – `h6` | `FontSpecification` | `header` value | Per-heading font family overrides. |
|
||||
| `useThemeFonts` | `boolean` | `true` | Use fonts from [Quartz Themes](https://github.com/saberzero1/quartz-themes) as defaults when it is installed. |
|
||||
| `fontOrigin` | `string` | `"googleFonts"` | `"googleFonts"` to load from Google Fonts CDN, `"selfHosted"` to download and serve locally, `"local"` for no loading. |
|
||||
|
||||
### Default options
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
useThemeFonts: true
|
||||
fontOrigin: googleFonts
|
||||
```
|
||||
|
||||
### Font resolution
|
||||
|
||||
Fonts are resolved using a priority chain:
|
||||
|
||||
```
|
||||
User config (plugin options)
|
||||
→ Theme fonts (from Quartz Themes, if installed)
|
||||
→ Obsidian defaults (system font stacks)
|
||||
```
|
||||
|
||||
For individual headings:
|
||||
|
||||
```
|
||||
h1 option → header option → theme --h1-font → theme font → Obsidian default
|
||||
```
|
||||
|
||||
For the site title:
|
||||
|
||||
```
|
||||
title option → header option → theme font → Obsidian default
|
||||
```
|
||||
|
||||
## Usage with Quartz Themes
|
||||
|
||||
When [Quartz Themes](https://github.com/saberzero1/quartz-themes) is installed and enabled, Fonts automatically discovers the theme's font metadata and uses it as defaults. Any options you explicitly set in Fonts will override the theme fonts.
|
||||
|
||||
Fonts must run **after** Quartz Themes. This is handled automatically by plugin ordering (Quartz Themes = 10, Fonts = 60).
|
||||
|
||||
> [!warning]
|
||||
> If Quartz Themes is enabled but hasn't run yet when Fonts executes, you'll see a warning in the console. Make sure Quartz Themes has a lower `defaultOrder` than Fonts.
|
||||
|
||||
## Usage without Quartz Themes
|
||||
|
||||
Fonts works standalone. Without a theme, it falls back to Obsidian's default system font stacks. You can set fonts explicitly via the plugin options.
|
||||
|
||||
## Examples
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
# Use theme fonts automatically (default behavior)
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
|
||||
# Override just the heading font
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
header: '"Playfair Display", serif'
|
||||
|
||||
# Full control with per-heading fonts
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
body: '"Inter", sans-serif'
|
||||
header: '"Playfair Display", serif'
|
||||
code: '"JetBrains Mono", monospace'
|
||||
h1: '"Playfair Display", serif'
|
||||
h2: '"Lora", serif'
|
||||
|
||||
# Load from Google Fonts automatically
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
fontOrigin: googleFonts
|
||||
body: Inter
|
||||
header: Playfair Display
|
||||
code: JetBrains Mono
|
||||
|
||||
# Google Fonts with weight/italic control
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
fontOrigin: googleFonts
|
||||
body:
|
||||
name: Inter
|
||||
weights: [400, 600, 700]
|
||||
includeItalic: true
|
||||
header:
|
||||
name: Playfair Display
|
||||
weights: [400, 700]
|
||||
code:
|
||||
name: JetBrains Mono
|
||||
weights: [400]
|
||||
|
||||
# Custom title font (separate from header)
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
fontOrigin: googleFonts
|
||||
title: Abril Fatface
|
||||
header: Playfair Display
|
||||
body: Inter
|
||||
code: JetBrains Mono
|
||||
|
||||
# Self-hosted fonts (downloaded at build time, no external requests)
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
fontOrigin: selfHosted
|
||||
body: Inter
|
||||
header: Playfair Display
|
||||
code: JetBrains Mono
|
||||
|
||||
# Ignore theme fonts entirely
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
useThemeFonts: false
|
||||
body: '"Inter", sans-serif'
|
||||
```
|
||||
|
||||
## Self-Hosted Fonts
|
||||
|
||||
When `fontOrigin: selfHosted` is set, Fonts downloads fonts from Google Fonts during the build and serves them from your site's `static/fonts/` directory. This makes your site fully self-contained with no external requests to Google at runtime.
|
||||
|
||||
At build time, the plugin:
|
||||
|
||||
1. Fetches the Google Fonts CSS for your configured fonts
|
||||
2. Downloads each font file (`.woff2`, `.woff`, etc.)
|
||||
3. Writes the font files to `static/fonts/` in your build output
|
||||
4. Generates a `quartz-fonts.css` file with `@font-face` rules pointing to the local files
|
||||
|
||||
> [!note]
|
||||
> Self-hosted fonts require `baseUrl` to be set in your Quartz configuration, since font URLs in the CSS need an absolute path.
|
||||
|
||||
```yaml title="quartz.config.yaml"
|
||||
configuration:
|
||||
baseUrl: "example.com"
|
||||
|
||||
plugins:
|
||||
- source: github:quartz-community/fonts
|
||||
enabled: true
|
||||
options:
|
||||
fontOrigin: selfHosted
|
||||
body: Inter
|
||||
header: Playfair Display
|
||||
code: JetBrains Mono
|
||||
```
|
||||
|
||||
## Google Fonts Validation
|
||||
|
||||
When `fontOrigin: googleFonts` is set and the optional [`google-font-metadata`](https://www.npmjs.com/package/google-font-metadata) package is installed, Fonts validates your font configuration at build time:
|
||||
|
||||
- Checks that font family names exist in Google Fonts.
|
||||
- Warns if requested weights are not available for a font.
|
||||
- Warns if italic is requested but the font doesn't support it.
|
||||
|
||||
Install it to enable validation:
|
||||
|
||||
```bash
|
||||
npm install google-font-metadata
|
||||
```
|
||||
|
||||
Validation warnings are logged to the console but do not block the build.
|
||||
|
||||
## API
|
||||
|
||||
- Category: Transformer, Emitter
|
||||
- Function name: `ExternalPlugin.Fonts()` (transformer), `ExternalPlugin.FontsEmitter()` (emitter).
|
||||
- Source: [`quartz-community/fonts`](https://github.com/quartz-community/fonts)
|
||||
- Install: `npx quartz plugin add github:quartz-community/fonts`
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
title: Footer
|
||||
description: Page footer with configurable links.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
repository: "[quartz-community/footer](https://github.com/quartz-community/footer)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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`
|
||||
+52
-91
@@ -1,111 +1,72 @@
|
||||
---
|
||||
title: Frontmatter
|
||||
aliases:
|
||||
- note-properties
|
||||
- Note Properties
|
||||
description: Parses frontmatter and displays note properties in a collapsible panel.
|
||||
title: "Frontmatter"
|
||||
tags:
|
||||
- plugin/transformer
|
||||
- plugin/component
|
||||
publish: true
|
||||
enableToc: true
|
||||
image:
|
||||
repository: "[quartz-community/note-properties](https://github.com/quartz-community/note-properties)"
|
||||
enabled: true
|
||||
required: 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]
|
||||
> 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:
|
||||
|
||||
- `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`.
|
||||
- `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"
|
||||
- source: github:quartz-community/note-properties
|
||||
enabled: true
|
||||
options:
|
||||
includeAll: false
|
||||
includedProperties:
|
||||
- description
|
||||
- tags
|
||||
- aliases
|
||||
excludedProperties: []
|
||||
hidePropertiesView: false
|
||||
delimiters: "---"
|
||||
language: yaml
|
||||
```
|
||||
## List
|
||||
|
||||
## Properties panel
|
||||
Quartz supports the following frontmatter:
|
||||
|
||||
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:
|
||||
|
||||
- **Strings** are shown as plain text. [[wikilinks]] and [markdown links](https://example.com) within strings are rendered as clickable links. Wikilink targets are slugified the same way as body-content links (e.g. `[[My Note]]` resolves to `my-note`) and matching is case-insensitive to mirror Obsidian's behavior, so `[[MyNote]]`, `[[mynote]]`, and `[[MYNOTE]]` all point to the same page.
|
||||
- **Arrays** are rendered as comma-separated lists.
|
||||
- **Booleans** are rendered as disabled checkboxes.
|
||||
- **Numbers** are rendered in a monospace font.
|
||||
- **Objects** are rendered as JSON in a code block.
|
||||
- **Tags** get special treatment: they are rendered as highlighted links that point to the corresponding tag page.
|
||||
- **Null/undefined** values are shown as an em-dash (—).
|
||||
|
||||
### Per-note overrides
|
||||
|
||||
You can control the properties panel on a per-note basis using frontmatter keys:
|
||||
|
||||
- `quartz-properties` (or `quartzProperties`): set to `true` to force-show the panel, or `false` to force-hide it, overriding the global `hidePropertiesView` setting.
|
||||
- `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. Slugified the same way as file paths: spaces become `-`, `&` becomes `-and-`, `%` becomes `-percent`, and tags are lowercased so that `#MyTag` and `#mytag` resolve to the same tag page (matching Obsidian). |
|
||||
| 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. |
|
||||
- title
|
||||
- `title`
|
||||
- description
|
||||
- `description`
|
||||
- permalink
|
||||
- `permalink`
|
||||
- comments
|
||||
- `comments`
|
||||
- lang
|
||||
- `lang`
|
||||
- publish
|
||||
- `publish`
|
||||
- draft
|
||||
- `draft`
|
||||
- enableToc
|
||||
- `enableToc`
|
||||
- tags
|
||||
- `tags`
|
||||
- `tag`
|
||||
- aliases
|
||||
- `aliases`
|
||||
- `alias`
|
||||
- cssclasses
|
||||
- `cssclasses`
|
||||
- `cssclass`
|
||||
- socialDescription
|
||||
- `socialDescription`
|
||||
- socialImage
|
||||
- `socialImage`
|
||||
- `image`
|
||||
- `cover`
|
||||
- created
|
||||
- `created`
|
||||
- `date`
|
||||
- modified
|
||||
- `modified`
|
||||
- `lastmod`
|
||||
- `updated`
|
||||
- `last-modified`
|
||||
- published
|
||||
- `published`
|
||||
- `publishDate`
|
||||
- `date`
|
||||
|
||||
## API
|
||||
|
||||
- Category: Transformer, 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`
|
||||
- Category: Transformer
|
||||
- Function name: `Plugin.Frontmatter()`.
|
||||
- Source: [`quartz/plugins/transformers/frontmatter.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/frontmatter.ts).
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: GitHubFlavoredMarkdown
|
||||
description: GitHub Flavored Markdown support (tables, task lists, footnotes, strikethrough).
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image:
|
||||
repository: "[quartz-community/github-flavored-markdown](https://github.com/quartz-community/github-flavored-markdown)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin enhances Markdown processing to support GitHub Flavored Markdown (GFM) which adds features like autolink literals, footnotes, strikethrough, tables and tasklists.
|
||||
@@ -24,6 +19,5 @@ This plugin accepts the following configuration options:
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.GitHubFlavoredMarkdown()`.
|
||||
- Source: [`quartz-community/github-flavored-markdown`](https://github.com/quartz-community/github-flavored-markdown)
|
||||
- Install: `npx quartz plugin add github:quartz-community/github-flavored-markdown`
|
||||
- Function name: `Plugin.GitHubFlavoredMarkdown()`.
|
||||
- Source: [`quartz/plugins/transformers/gfm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/gfm.ts).
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
title: Graph
|
||||
description: Interactive link graph visualization.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
repository: "[quartz-community/graph](https://github.com/quartz-community/graph)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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. Defaults to `1.1` for local and `0.9` for global.
|
||||
- `repelForce`: The force that pushes nodes apart. Defaults to `0.5`.
|
||||
- `centerForce`: The force that pulls nodes to the center. Defaults to `0.3` for local and `0.2` for global.
|
||||
- `linkDistance`: The distance between linked nodes. Defaults to `30`.
|
||||
- `fontSize`: The font size of node labels. Defaults to `0.6`.
|
||||
- `opacityScale`: The scale of node opacity. Defaults to `1`.
|
||||
- `removeTags`: Tags to exclude from the graph. Defaults to `[]`.
|
||||
- `showTags`: Whether to show tags in the graph. Defaults to `true`.
|
||||
- `enableRadial`: Whether to enable radial layout. Defaults to `false` for local and `true` for global.
|
||||
- `focusOnHover`: Whether to focus on the hovered node. Defaults to `false` for local and `true` for global.
|
||||
|
||||
### 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
|
||||
focusOnHover: false
|
||||
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`
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: HardLineBreaks
|
||||
description: Treats single newlines as hard line breaks.
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image: "#ff8000"
|
||||
repository: "[quartz-community/hard-line-breaks](https://github.com/quartz-community/hard-line-breaks)"
|
||||
enabled: false
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin automatically converts single line breaks in Markdown text into hard line breaks in the HTML output. This plugin is not enabled by default as this doesn't follow the semantics of actual Markdown but you may enable it if you'd like parity with [[Obsidian compatibility|Obsidian]].
|
||||
@@ -19,6 +14,5 @@ This plugin has no configuration options.
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.HardLineBreaks()`.
|
||||
- Source: [`quartz-community/hard-line-breaks`](https://github.com/quartz-community/hard-line-breaks)
|
||||
- Install: `npx quartz plugin add github:quartz-community/hard-line-breaks`
|
||||
- Function name: `Plugin.HardLineBreaks()`.
|
||||
- Source: [`quartz/plugins/transformers/linebreaks.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/linebreaks.ts).
|
||||
|
||||
+3
-12
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: Latex
|
||||
description: Renders LaTeX math expressions via KaTeX or Typst.
|
||||
title: "Latex"
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image:
|
||||
repository: "[quartz-community/latex](https://github.com/quartz-community/latex)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin adds LaTeX support to Quartz. See [[features/Latex|Latex]] for more information.
|
||||
@@ -18,13 +13,9 @@ This plugin accepts the following configuration options:
|
||||
|
||||
- `renderEngine`: the engine to use to render LaTeX equations. Can be `"katex"` for [KaTeX](https://katex.org/), `"mathjax"` for [MathJax](https://www.mathjax.org/) [SVG rendering](https://docs.mathjax.org/en/latest/output/svg.html), or `"typst"` for [Typst](https://typst.app/) (a new way to compose LaTeX equation). Defaults to KaTeX.
|
||||
- `customMacros`: custom macros for all LaTeX blocks. It takes the form of a key-value pair where the key is a new command name and the value is the expansion of the macro. For example: `{"\\R": "\\mathbb{R}"}`
|
||||
- `katexOptions`: Additional options passed to the KaTeX renderer. See the [KaTeX docs](https://katex.org/docs/options) for available options.
|
||||
- `mathJaxOptions`: Additional options passed to the MathJax renderer. See the [MathJax docs](https://docs.mathjax.org/en/latest/options/) for available options.
|
||||
- `typstOptions`: Additional options passed to the Typst renderer.
|
||||
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.Latex()`.
|
||||
- Source: [`quartz-community/latex`](https://github.com/quartz-community/latex)
|
||||
- Install: `npx quartz plugin add github:quartz-community/latex`
|
||||
- Function name: `Plugin.Latex()`.
|
||||
- Source: [`quartz/plugins/transformers/latex.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/latex.ts).
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
---
|
||||
title: NotFoundPage
|
||||
tags:
|
||||
- plugin/pageType
|
||||
image:
|
||||
- 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]
|
||||
> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page.
|
||||
@@ -14,6 +13,6 @@ This plugin has no configuration options.
|
||||
|
||||
## API
|
||||
|
||||
- Category: Page Type
|
||||
- Function name: `Plugin.NotFoundPage()` (internal plugin).
|
||||
- Source: [`quartz/plugins/pageTypes/404.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/pageTypes/404.ts)
|
||||
- Category: Emitter
|
||||
- Function name: `Plugin.NotFoundPage()`.
|
||||
- Source: [`quartz/plugins/emitters/404.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/404.tsx).
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
title: NoteProperties
|
||||
description: Displays frontmatter properties in a collapsible panel.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
new-in-v5: true
|
||||
repository: "[quartz-community/note-properties](https://github.com/quartz-community/note-properties)"
|
||||
enabled: true
|
||||
required: true
|
||||
---
|
||||
|
||||
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`
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: ObsidianFlavoredMarkdown
|
||||
description: Obsidian-specific Markdown extensions (wikilinks, callouts, highlights, tags, embeds).
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image:
|
||||
repository: "[quartz-community/obsidian-flavored-markdown](https://github.com/quartz-community/obsidian-flavored-markdown)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin provides support for [[Obsidian compatibility]].
|
||||
@@ -22,16 +17,13 @@ This plugin accepts the following configuration options:
|
||||
- `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.
|
||||
- `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.
|
||||
- `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.
|
||||
- `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.
|
||||
- `enableCheckbox`: If `true`, adds support for interactive checkboxes in content, including custom task characters (e.g. `- [?]`, `- [!]`, `- [/]`). Defaults to `false`.
|
||||
- `enableObsidianUri`: If `true` (default), marks `obsidian://` protocol links with a CSS class and data attribute for custom styling.
|
||||
|
||||
> [!note]
|
||||
> The `disableBrokenWikilinks` option previously lived on this plugin. It has moved to [[CrawlLinks]], which owns link resolution and can honor the configured `markdownLinkResolution` strategy when deciding whether a link is broken. Users upgrading from earlier Quartz v5 betas should move the option from `ObsidianFlavoredMarkdown` to `CrawlLinks`.
|
||||
- `enableCheckbox`: If `true`, adds support for interactive checkboxes in content. Defaults to `false`.
|
||||
- `disableBrokenWikilinks`: If `true`, replaces links to non-existent notes with a dimmed, disabled link. Defaults to `false`.
|
||||
|
||||
> [!warning]
|
||||
> Don't remove this plugin if you're using [[Obsidian compatibility|Obsidian]] to author the content!
|
||||
@@ -39,6 +31,5 @@ This plugin accepts the following configuration options:
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.ObsidianFlavoredMarkdown()`.
|
||||
- Source: [`quartz-community/obsidian-flavored-markdown`](https://github.com/quartz-community/obsidian-flavored-markdown)
|
||||
- Install: `npx quartz plugin add github:quartz-community/obsidian-flavored-markdown`
|
||||
- Function name: `Plugin.ObsidianFlavoredMarkdown()`.
|
||||
- Source: [`quartz/plugins/transformers/ofm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/ofm.ts)
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: OxHugoFlavoredMarkdown
|
||||
description: Compatibility for ox-hugo exported Org-mode files.
|
||||
tags:
|
||||
- plugin/transformer
|
||||
image:
|
||||
repository: "[quartz-community/ox-hugo](https://github.com/quartz-community/ox-hugo)"
|
||||
enabled: false
|
||||
required: false
|
||||
---
|
||||
|
||||
This plugin provides support for [ox-hugo](https://github.com/kaushalmodi/ox-hugo) compatibility. See [[OxHugo compatibility]] for more information.
|
||||
@@ -30,6 +25,5 @@ This plugin accepts the following configuration options:
|
||||
## API
|
||||
|
||||
- Category: Transformer
|
||||
- Function name: `ExternalPlugin.OxHugoFlavoredMarkdown()`.
|
||||
- Source: [`quartz-community/ox-hugo`](https://github.com/quartz-community/ox-hugo)
|
||||
- Install: `npx quartz plugin add github:quartz-community/ox-hugo`
|
||||
- Function name: `Plugin.OxHugoFlavoredMarkdown()`.
|
||||
- Source: [`quartz/plugins/transformers/oxhugofm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/oxhugofm.ts).
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
title: PageTitle
|
||||
description: Renders the site title as a home link.
|
||||
tags:
|
||||
- plugin/component
|
||||
image:
|
||||
repository: "[quartz-community/page-title](https://github.com/quartz-community/page-title)"
|
||||
enabled: true
|
||||
required: false
|
||||
---
|
||||
|
||||
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`
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user