diff --git a/PLUGIN_MANAGEMENT_STRATEGY.md b/PLUGIN_MANAGEMENT_STRATEGY.md index 9a84e1134..ca7f297ae 100644 --- a/PLUGIN_MANAGEMENT_STRATEGY.md +++ b/PLUGIN_MANAGEMENT_STRATEGY.md @@ -13,7 +13,7 @@ - [File Ownership Model](#file-ownership-model) - [quartz.config.yaml — The Source of Truth](#quartzconfigyaml--the-source-of-truth) - [Plugin Manifest](#plugin-manifest) -- [Thin Template Files](#thin-template-files) + 16: #RZ|- [Thin Template File](#thin-template-file) - [Plugin Ordering & Dependencies](#plugin-ordering--dependencies) - [Layout System](#layout-system) - [JSON Schema](#json-schema) @@ -31,10 +31,9 @@ Users must manually edit multiple files to use a plugin: -1. **`quartz.config.ts` → `externalPlugins` array**: List of `"github:org/repo"` strings — declares _what_ to install -2. **`quartz.config.ts` → `plugins.transformers/filters/emitters/pageTypes` arrays**: Plugin factory calls with options — declares _how_ to use plugins -3. **`quartz.layout.ts`**: Layout configuration for component-providing plugins (Explorer, Graph, Search, etc.) -4. **`quartz.lock.json`**: Tracks installed versions/commits (managed by CLI) +1. **`quartz.config.yaml` → `plugins` array**: List of plugin entries — declares _what_ to install and _how_ to use them +2. **`quartz.ts`**: Thin wrapper that exports configuration and layout +3. **`quartz.lock.json`**: Tracks installed versions/commits (managed by CLI) Additionally: @@ -42,20 +41,19 @@ Additionally: - **No dependencies**: Plugins cannot declare that they need other plugins. - **No ordering**: Plugin execution order is determined by manual array position. - **Update = apply**: No way to check for available updates without also installing them. -- **TypeScript config**: `quartz.config.ts` and `quartz.layout.ts` are not safely machine-editable by external tools (Quartz Syncer). -- **Merge conflicts on update**: `npx quartz update` pulls upstream via git. Since `quartz.config.ts` and `quartz.layout.ts` are the primary files users edit, merge conflicts are frequent and frustrating. +- **TypeScript config**: `quartz.ts` is not safely machine-editable by external tools (Quartz Syncer). +- **Merge conflicts on update**: `npx quartz update` pulls upstream via git. Since `quartz.config.yaml` is the primary file users edit, merge conflicts are frequent and frustrating. --- ## Architecture Overview -Introduce a machine-readable **`quartz.config.yaml`** as the single source of truth for all user configuration. The existing TypeScript files become thin, upstream-owned templates that read from this YAML file. +52: #TZ|Introduce a machine-readable **`quartz.config.yaml`** as the single source of truth for all user configuration. The existing TypeScript files become a thin, upstream-owned template that reads from this YAML file. ``` quartz-site/ ├── quartz/ # Upstream framework code -├── quartz.config.ts # Upstream template — reads from YAML -├── quartz.layout.ts # Upstream template — reads from YAML +57: #QS|├── quartz.ts # Upstream template — reads from YAML ├── quartz.config.default.yaml # Upstream defaults (reference/seed file) ├── quartz.config.yaml # USER-OWNED — all user configuration ├── quartz.lock.json # CLI-managed — installed plugin versions @@ -69,10 +67,9 @@ quartz-site/ ## File Ownership Model | File | Owner | Tracked by upstream? | User edits? | Updated by `npx quartz update`? | -| ---------------------------- | -------- | --------------------- | ------------------------- | ------------------------------- | +| ---------------------------- | -------- | --------------------- | ------------------------- | ------------------------------- | ---------------------- | --- | | `quartz/` | Upstream | Yes | No (power users only) | Yes | -| `quartz.config.ts` | Upstream | Yes | **No** — thin template | Yes | -| `quartz.layout.ts` | Upstream | Yes | **No** — thin template | Yes | +| 74: #PY | | `quartz.ts` | Upstream | Yes | **No** — thin template | Yes | | `quartz.config.default.yaml` | Upstream | Yes | No — reference only | Yes | | `quartz.config.yaml` | **User** | No (user's fork only) | **Yes** — source of truth | **Never** | | `quartz.lock.json` | **CLI** | Yes (user's fork) | No | No | @@ -439,25 +436,17 @@ Each plugin declares metadata in its `package.json` under a `quartz` field, or i ## Thin Template Files -### quartz.config.ts - -```typescript -import { loadQuartzConfig } from "./quartz/plugins/loader/config-loader" - -// Configuration and plugins are loaded from quartz.config.yaml. -// Users should edit quartz.config.yaml instead of this file. -export default await loadQuartzConfig() -``` - -### quartz.layout.ts - -```typescript -import { loadQuartzLayout } from "./quartz/plugins/loader/config-loader" - -// Layout is assembled from plugin declarations in quartz.config.yaml. -// Users should edit quartz.config.yaml instead of this file. -export const layout = await loadQuartzLayout() -``` +441: #NR|## Thin Template File +442: #WP| +443: #YN|### quartz.ts +444: #SB| +445: #SH|`typescript +446: #QW|import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader" +447: #XM| +448: #ZH|const config = await loadQuartzConfig() +449: #MN|export default config +450: #WJ|export const layout = await loadQuartzLayout() +451: #YX|` ### What `loadQuartzConfig()` Does @@ -817,7 +806,7 @@ This causes: ### Solution: Conflict-Free by Design -With this architecture, `quartz.config.ts` and `quartz.layout.ts` are upstream-owned templates that users never edit. All user customization is in `quartz.config.yaml`, which upstream never ships or modifies. +With this architecture, `quartz.ts` is an upstream-owned template that users never edit. All user customization is in `quartz.config.yaml`, which upstream never ships or modifies. ### Updated `npx quartz update` Flow @@ -835,7 +824,7 @@ With this architecture, `quartz.config.ts` and `quartz.layout.ts` are upstream-o - "All 34 plugins compatible" or "Warning: plugin X requires Quartz >=5.3.0" ``` -Since the user's configuration lives in `quartz.config.yaml` (not tracked upstream) and the `.ts` files are thin templates (no user modifications), `git merge` applies cleanly. +Since the user's configuration lives in `quartz.config.yaml` (not tracked upstream) and the `quartz.ts` file is a thin template (no user modifications), `git merge` applies cleanly. ### Edge Case: Power Users @@ -881,10 +870,10 @@ A `npx quartz migrate` command handles the one-time conversion: 2. Reads `quartz.lock.json` for installed plugin metadata 3. Imports `quartz.layout.ts` and inspects the layout object 4. Generates `quartz.config.yaml` with: - - All `configuration` fields from the current config + - All `configuration` fields from the current `quartz.config.yaml` - All plugins (built-in and external) with their current options - Layout positions inferred from the layout object -5. Replaces `quartz.config.ts` and `quartz.layout.ts` with thin templates +5. Replaces `quartz.config.ts` and `quartz.layout.ts` with the consolidated `quartz.ts` wrapper 6. Prints migration summary ### For Plugin Authors @@ -903,7 +892,8 @@ Plugins without the extended manifest fields still load with sensible defaults ( ### Backward Compatibility -- A `quartz.config.ts` that doesn't use the thin template pattern continues to work (direct import, bypasses YAML) +906: #ZM|- A `quartz.ts` that doesn't use the thin template pattern continues to work (direct import, bypasses YAML) + - If `quartz.config.yaml` doesn't exist, `plugin-data.js` falls back to `quartz.plugins.json` for backward compatibility - Plugins without the extended manifest fields still load normally - The migration is opt-in via `npx quartz migrate` @@ -936,9 +926,9 @@ Plugins without the extended manifest fields still load with sensible defaults ( ### Phase 4: Thin Templates -14. **`quartz.config.ts` template** — Replace with thin loader template -15. **`quartz.layout.ts` template** — Replace with thin loader template -16. **Build pipeline update** — Ensure `build.ts` works with the new config loading path +938: #VY|### Phase 4: Thin Template +939: #PW|14. **`quartz.ts` template** — Replace with thin loader template +940: #MV|15. **Build pipeline update** — Ensure `build.ts` works with the new config loading path ### Phase 5: Plugin Author Support diff --git a/QUARTZ_SYNCER_V5.md b/QUARTZ_SYNCER_V5.md index 5d8ef0e6f..59066ccb5 100644 --- a/QUARTZ_SYNCER_V5.md +++ b/QUARTZ_SYNCER_V5.md @@ -22,18 +22,18 @@ Notes and decisions for implementing Quartz v5 plugin management support in Quar ## Overview of Changes -Quartz v5 moves all user configuration from TypeScript files (`quartz.config.ts`, `quartz.layout.ts`) into a single YAML file (`quartz.config.yaml`). This eliminates the need for AST parsing or TypeScript manipulation — Syncer can now manage the entire Quartz configuration through plain YAML read/write operations. +Quartz v5 moves all user configuration from TypeScript files (`quartz.config.ts`, `quartz.layout.ts`) into a single YAML file (`quartz.config.yaml`). This eliminates the need for AST parsing or TypeScript manipulation — Syncer can now manage the entire Quartz configuration through plain YAML read/write operations. In v5, these TypeScript files are consolidated into a single `quartz.ts` wrapper. **Before (v4):** -- Configuration spread across `quartz.config.ts` (TypeScript) and `quartz.layout.ts` (TypeScript) +- Configuration spread across `quartz.config.ts` (TypeScript) and `quartz.layout.ts` (TypeScript) in v4 - Syncer could not safely edit these files (no TS parser in isomorphic-git/LightningFS environment) - Plugin management required manual file editing **After (v5):** - All user configuration in `quartz.config.yaml` (YAML) -- TypeScript files are upstream-owned thin templates that read from the YAML config + 36: #JJ|- TypeScript files are upstream-owned thin templates (consolidated into `quartz.ts`) that read from the YAML config - Syncer can fully manage configuration via YAML read/write → git commit → push --- @@ -41,11 +41,10 @@ Quartz v5 moves all user configuration from TypeScript files (`quartz.config.ts` ## File Ownership Model | File | Owner | Syncer Can Edit? | Notes | -| ---------------------------- | -------- | ---------------- | ------------------------------------------------------------- | +| ---------------------------- | -------- | ---------------- | ------------------------------------------------------------- | ------ | --------------------------------------------- | | `quartz.config.yaml` | **User** | **Yes** | The source of truth. Syncer's primary interface. | | `quartz.config.default.yaml` | Upstream | **No** | Reference only. Seed file copied on `npx quartz create`. | -| `quartz.config.ts` | Upstream | **No** | Thin template. Just imports from YAML loader. | -| `quartz.layout.ts` | Upstream | **No** | Thin template. Just imports from YAML loader. | +| 47: #RS | | `quartz.ts` | Upstream | **No** | Thin template. Just imports from YAML loader. | | `quartz.lock.json` | CLI | Read only | Tracks installed plugin versions/commits. Useful for display. | | `.quartz/plugins/` | CLI | **No** | Git clones managed by CLI. `.gitignore`d. | | `content/` | User | **Yes** | Existing Syncer behavior unchanged. | @@ -383,14 +382,14 @@ Syncer should NOT attempt to run the migration itself — it requires Node.js/ts ### Post-Migration -After migration, `quartz.config.ts` and `quartz.layout.ts` become thin templates: - -```typescript -// quartz.config.ts -import { loadQuartzConfig } from "./quartz/plugins/loader/config-loader" -export default await loadQuartzConfig() -``` - +386: #TT|After migration, `quartz.ts` becomes a thin template: +387: #JV| +388: #SH|`typescript +389: #TW|import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader" +390: #QW|const config = await loadQuartzConfig() +391: #WJ|export default config +392: #KJ|export const layout = await loadQuartzLayout() +393: #WV|` Syncer should not modify these files. --- diff --git a/docs/advanced/architecture.md b/docs/advanced/architecture.md index d7dabc7fd..9e98483d9 100644 --- a/docs/advanced/architecture.md +++ b/docs/advanced/architecture.md @@ -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.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: + 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: 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 `
` and `` respectively. 3. Finally, each emitter plugin is responsible for emitting and writing it's own emitted files to disk. @@ -51,7 +51,7 @@ This question is best answered by tracing what happens when a user (you!) runs ` ## Plugin System -### External Plugin Architecture +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`. diff --git a/docs/advanced/creating components.md b/docs/advanced/creating components.md index d74610b7d..af7d6037f 100644 --- a/docs/advanced/creating components.md +++ b/docs/advanced/creating components.md @@ -84,7 +84,7 @@ export type QuartzComponentProps = { - `fileData`: Any metadata 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.ts`. +- `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. - `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. @@ -156,19 +156,34 @@ Once your component is published (e.g., to GitHub or npm), users can install it npx quartz plugin add github:your-username/my-component ``` -Then, they can use it in their `quartz.layout.ts`: +Then, they can add it to their `quartz.config.yaml`: -```ts title="quartz.layout.ts" -import * as Plugin from "./.quartz/plugins" +```yaml title="quartz.config.yaml" +plugins: + - source: github:your-username/my-component + enabled: true + options: + favouriteNumber: 42 + layout: + position: left + priority: 60 +``` -export const layout = { - defaults: { ... }, +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()], + left: [Plugin.MyComponent({ favouriteNumber: 42 })], }, }, -} +}) ``` ## Internal Components diff --git a/docs/advanced/making plugins.md b/docs/advanced/making plugins.md index f920d8e2d..d8bcfc5cb 100644 --- a/docs/advanced/making plugins.md +++ b/docs/advanced/making plugins.md @@ -351,7 +351,7 @@ export const ContentPage: QuartzEmitterPlugin = () => { ### Page Types -Page types define how a category of pages is rendered. They are configured in the `pageTypes` array in `quartz.config.ts`. +Page types define how a category of pages is rendered. They are configured in the `pageTypes` array in `quartz.config.yaml`. ```ts export type QuartzPageTypePluginInstance = { @@ -383,9 +383,17 @@ npx tsup npx quartz plugin add github:your-username/my-plugin ``` -Then add the plugin to the appropriate array in `quartz.config.ts`: +Then add the plugin to your `quartz.config.yaml`: -```ts +```yaml title="quartz.config.yaml" +plugins: + - source: github:your-username/my-plugin + enabled: true +``` + +Or via TS override in `quartz.ts`: + +```ts title="quartz.ts (override)" import * as ExternalPlugin from "./.quartz/plugins" // ... transformers: [ExternalPlugin.MyPlugin()] diff --git a/docs/configuration.md b/docs/configuration.md index 73c89287b..b78c69587 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2,18 +2,21 @@ 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.ts` or changing [[layout|the layout]] in `quartz.layout.ts`. +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`. > [!tip] -> 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! +> 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! The configuration of Quartz can be broken down into two main parts: -```ts title="quartz.config.ts" -const config: QuartzConfig = { - configuration: { ... }, - plugins: { ... }, -} +```yaml title="quartz.config.yaml" +configuration: + pageTitle: "My Site" + # ... general configuration +plugins: + - source: github:quartz-community/some-plugin + enabled: true + # ... plugin entries ``` ## General Configuration @@ -67,15 +70,32 @@ You can think of Quartz plugins as a series of transformations over content. ![[quartz transform pipeline.png]] -```ts title="quartz.config.ts" -plugins: { - transformers: [...], - filters: [...], - emitters: [...], - pageTypes: [...], -} +```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 ``` +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) @@ -85,25 +105,32 @@ plugins: { Quartz distinguishes between internal plugins that are bundled with Quartz and community plugins that are installed separately. -```ts title="quartz.config.ts" -import * as Plugin from "./quartz/plugins" // internal plugins -import * as ExternalPlugin from "./.quartz/plugins" // community plugins +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 `Plugin.FrontMatter()`) are bundled with Quartz. Community plugins (like `ExternalPlugin.Explorer()`) are installed separately. +Internal plugins (like `FrontMatter`) are bundled with Quartz. Community plugins are installed separately and referenced by their `github:org/repo` source. ### Community Plugins -The `externalPlugins` array in your configuration declares which community plugin repositories to install. Each entry is a GitHub repository reference. +To install a community plugin, you can use the following command: -```ts title="quartz.config.ts" -externalPlugins: [ - "github:quartz-community/explorer", - "github:quartz-community/syntax-highlighting", - // ... other community plugins -], +```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 a community plugin, you can use the following command: ```shell @@ -114,41 +141,72 @@ This adds the plugin to `externalPlugins` and installs it to `.quartz/plugins/`. ### Usage -You can customize the behaviour of Quartz by adding, removing and reordering plugins in the `transformers`, `filters`, `emitters`, and `pageTypes` fields. You can mix internal and external plugins as needed. +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: -```ts title="quartz.config.ts" -transformers: [ - Plugin.FrontMatter(), // internal - ExternalPlugin.CreatedModifiedDate({ - // community - priority: ["frontmatter", "git", "filesystem"], - }), - ExternalPlugin.Latex({ renderEngine: "katex" }), // community with options -] +```yaml title="quartz.config.yaml" +plugins: + - source: github:quartz-community/note-properties + enabled: true + options: + includeAll: false + includedProperties: + - description + - tags + - aliases + order: 5 + - source: github:quartz-community/created-modified-date + enabled: true + options: + priority: + - frontmatter + - git + - filesystem + order: 10 + - source: github:quartz-community/latex + enabled: true + options: + renderEngine: katex + order: 80 ``` +> [!note] +> For advanced options that require JavaScript (e.g. callback functions), use the TS override in `quartz.ts`. See the plugin-specific documentation for details. + You can see a list of all plugins and their configuration options [[tags/plugin|here]]. If you'd like to make your own plugins, see the [[making plugins|making custom plugins]] guide. ## Fonts -Fonts can be specified as a `string` or a `FontSpecification`: +Fonts can be specified as a simple string or with advanced options in `quartz.config.yaml`: -```ts -// string -typography: { - header: "Schibsted Grotesk", - ... -} - -// FontSpecification -typography: { - header: { - name: "Schibsted Grotesk", - weights: [400, 700], - includeItalic: true, - }, - ... -} +```yaml title="quartz.config.yaml" +configuration: + theme: + typography: + header: Schibsted Grotesk + body: Source Sans Pro + code: IBM Plex Mono +``` + +For more control over font weights and italics, use the TS override in `quartz.ts`: + +```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", + }, + }, +}) +export default config +export const layout = await loadQuartzLayout() ``` diff --git a/docs/features/OxHugo compatibility.md b/docs/features/OxHugo compatibility.md index e22051146..1872d8ca8 100644 --- a/docs/features/OxHugo compatibility.md +++ b/docs/features/OxHugo compatibility.md @@ -8,18 +8,42 @@ 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. -```typescript title="quartz.config.ts" +```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 +``` + +For the TS override approach: + +```ts title="quartz.ts (override)" plugins: { transformers: [ - Plugin.FrontMatter({ delims: "+++", language: "toml" }), // if toml frontmatter + Plugin.FrontMatter({ delims: "+++", language: "toml" }), // ... Plugin.OxHugoFlavouredMarkdown(), Plugin.GitHubFlavoredMarkdown(), // ... ], -}, +} ``` +> [!note] +> In YAML, plugin execution order is controlled by the `order` field. Lower numbers execute first. Ensure `ox-hugo` has a lower `order` than `obsidian-flavored-markdown`. + ## Usage 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. diff --git a/docs/features/Roam Research compatibility.md b/docs/features/Roam Research compatibility.md index 41ea88569..42736184c 100644 --- a/docs/features/Roam Research compatibility.md +++ b/docs/features/Roam Research compatibility.md @@ -9,7 +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. -```typescript title="quartz.config.ts" +```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: + +```ts title="quartz.ts (override)" plugins: { transformers: [ // ... @@ -17,11 +29,14 @@ plugins: { Plugin.ObsidianFlavoredMarkdown(), // ... ], -}, +} ``` > [!warning] -> As seen above placement of `Plugin.RoamFlavoredMarkdown()` within `quartz.config.ts` is very important. It must come before `Plugin.ObsidianFlavoredMarkdown()`. +> 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. + +> [!warning] +> In YAML, plugin execution order is controlled by the `order` field. Ensure the `roam` plugin has a lower `order` value than `obsidian-flavored-markdown` so it runs first. ## Customization diff --git a/docs/features/SPA Routing.md b/docs/features/SPA Routing.md index 3004af977..7e80b9bea 100644 --- a/docs/features/SPA Routing.md +++ b/docs/features/SPA Routing.md @@ -4,4 +4,4 @@ Under the hood, this is done by hijacking page navigations and instead fetching ## Configuration -- Disable SPA Routing: set the `enableSPA` field of the [[configuration]] in `quartz.config.ts` to be `false`. +- Disable SPA Routing: set the `enableSPA` field of the [[configuration]] in `quartz.config.yaml` to be `false`. diff --git a/docs/features/backlinks.md b/docs/features/backlinks.md index be9b2ab71..95df12c61 100644 --- a/docs/features/backlinks.md +++ b/docs/features/backlinks.md @@ -6,9 +6,12 @@ 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: delete all usages of `Plugin.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 `Plugin.Backlinks({ hideWhenEmpty: false })`. +- 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) diff --git a/docs/features/breadcrumbs.md b/docs/features/breadcrumbs.md index d2c54dad2..3da2d4d13 100644 --- a/docs/features/breadcrumbs.md +++ b/docs/features/breadcrumbs.md @@ -8,27 +8,46 @@ 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 by passing in options to `Plugin.Breadcrumbs()`. +Most configuration can be done via the `options` section of the breadcrumbs plugin entry in `quartz.config.yaml`. For example, here's what the default configuration looks like: -```typescript title="quartz.layout.ts" +```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)" Plugin.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 + spacerSymbol: "❯", + rootName: "Home", + resolveFrontmatterTitle: true, + showCurrentPage: true, }) ``` When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field. -You can also adjust where the breadcrumbs will be displayed by adjusting the [[layout]] (moving `Plugin.Breadcrumbs()` up or down) +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]]). Want to customize it even more? -- Removing breadcrumbs: delete all usages of `Plugin.Breadcrumbs()` from `quartz.layout.ts`. +- 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) diff --git a/docs/features/comments.md b/docs/features/comments.md index b7f156922..7b27ecfe1 100644 --- a/docs/features/comments.md +++ b/docs/features/comments.md @@ -6,6 +6,9 @@ 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! @@ -30,26 +33,49 @@ After entering both your repository and selecting the discussion category, Giscu ![[giscus-results.png]] -Finally, in `quartz.layout.ts`, edit the `afterBody` field of the `defaults` layout to include the following options but with the values you got from above: +Finally, in `quartz.config.yaml`, edit the `afterBody` field of the `defaults` layout to include the following options but with the values you got from above: -```ts title="quartz.layout.ts" -afterBody: [ - Plugin.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' - } - }), -], +```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 +``` + +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: [ + Plugin.Comments({ + provider: "giscus", + options: { + repo: "jackyzha0/quartz", + repoId: "MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg", + category: "Announcements", + categoryId: "DIC_kwDOFxRnmM4B-Xg6", + lang: "en", + }, + }), + ], + }, +}) ``` > [!note] @@ -109,19 +135,39 @@ 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/`: -```ts -afterBody: [ - Plugin.Comments({ - provider: 'giscus', - options: { - // Other options +```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/ +``` - 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/ - } - }), -], +```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: [ + Plugin.Comments({ + provider: "giscus", + options: { + // Other options... + themeUrl: "https://example.com/static/giscus", + lightTheme: "light-theme", + darkTheme: "dark-theme", + }, + }), + ], + }, +}) ``` #### Conditionally display comments diff --git a/docs/features/darkmode.md b/docs/features/darkmode.md index e5c030c31..25e1d4d6a 100644 --- a/docs/features/darkmode.md +++ b/docs/features/darkmode.md @@ -6,9 +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: delete all usages of `Plugin.Darkmode()` from `quartz.layout.ts`. +- 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) diff --git a/docs/features/explorer.md b/docs/features/explorer.md index 8cf2c18af..f2a28be21 100644 --- a/docs/features/explorer.md +++ b/docs/features/explorer.md @@ -17,21 +17,15 @@ The Explorer is available as a community plugin from GitHub: npm install github:quartz-community/explorer --legacy-peer-deps ``` -Then import it in your `quartz.layout.ts`: +Then add it to your `quartz.config.yaml`: -```typescript title="quartz.layout.ts" -import { Explorer } from "@quartz-community/explorer" - -// Create once and reuse -const explorerComponent = Explorer() - -export const defaultContentPageLayout: PageLayout = { - // ... other layout config - left: [ - // ... other components - explorerComponent, - ], -} +```yaml title="quartz.config.yaml" +plugins: + - source: github:quartz-community/explorer + enabled: true + layout: + position: left + priority: 50 ``` ## Features @@ -51,26 +45,50 @@ Most configuration can be done by passing in options to `Explorer()`. For example, here's what the default configuration looks like: -```typescript title="quartz.layout.ts" +```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 { Explorer } from "@quartz-community/explorer" + +// Advanced: pass callback functions that can't be expressed in YAML 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 + sortFn: (a, b) => { + /* ... */ + }, + filterFn: (node) => { + /* ... */ + }, + mapFn: (node) => { + /* ... */ + }, order: ["filter", "map", "sort"], }) + +const config = await loadQuartzConfig() +export default config +export const layout = await loadQuartzLayout() ``` When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field. Want to customize it even more? -- Removing explorer: remove `explorerComponent` from `quartz.layout.ts` +- Removing explorer: remove the `explorer` entry from `quartz.config.yaml` or set `enabled: false` - (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]] @@ -141,7 +159,19 @@ These examples show the basic usage of `sort`, `map` and `filter`. Using this example, the explorer will alphabetically sort everything. -```ts title="quartz.layout.ts" +```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)" Explorer({ sortFn: (a, b) => { return a.displayName.localeCompare(b.displayName) @@ -153,7 +183,7 @@ Explorer({ Using this example, the display names of all `FileNodes` (folders + files) will be converted to full upper case. -```ts title="quartz.layout.ts" +```ts title="quartz.ts (override)" Explorer({ mapFn: (node) => { node.displayName = node.displayName.toUpperCase() @@ -162,12 +192,15 @@ 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.layout.ts" +```ts title="quartz.ts (override)" Explorer({ filterFn: (node) => { // set containing names of everything you want to filter out @@ -185,7 +218,7 @@ Explorer({ You can access the tags of a file by `node.data.tags`. -```ts title="quartz.layout.ts" +```ts title="quartz.ts (override)" Explorer({ filterFn: (node) => { // exclude files with the tag "explorerexclude" @@ -199,7 +232,7 @@ 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.layout.ts" +```ts title="quartz.ts (override)" Explorer({ filterFn: undefined, // apply no filter function, every file and folder will visible }) @@ -208,11 +241,11 @@ Explorer({ ## Advanced examples > [!tip] -> When writing more complicated functions, the `layout` file can start to look very cramped. +> When writing more complicated functions, the `quartz.ts` 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.layout.ts" +> ```ts title="quartz.ts" > import { ExplorerOptions } from "@quartz-community/explorer/components" > > export const mapFn: ExplorerOptions["mapFn"] = (node) => { @@ -235,9 +268,9 @@ Explorer({ ### Add emoji prefix -To add emoji prefixes (📁 for folders, 📄 for files), you could use a map function like this: +To add emoji prefixes (📁 for folders, 📄 for files), you could use a map function in `quartz.ts`: -```ts title="quartz.layout.ts" +```ts title="quartz.ts (override)" Explorer({ mapFn: (node) => { if (node.isFolder) { diff --git a/docs/features/full-text search.md b/docs/features/full-text search.md index a8b2161d5..6ba4e7717 100644 --- a/docs/features/full-text search.md +++ b/docs/features/full-text search.md @@ -6,6 +6,9 @@ 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`). @@ -23,6 +26,6 @@ It properly tokenizes Chinese, Korean, and Japenese characters and constructs se ## Customization -- Removing search: delete all usages of `Plugin.Search()` from `quartz.layout.ts`. +- 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) diff --git a/docs/features/graph view.md b/docs/features/graph view.md index 2cc7e7403..37540d473 100644 --- a/docs/features/graph view.md +++ b/docs/features/graph view.md @@ -20,21 +20,15 @@ The Graph View is available as a community plugin from GitHub: npm install github:quartz-community/graph --legacy-peer-deps ``` -Then import it in your `quartz.layout.ts`: +Then add it to your `quartz.config.yaml`: -```typescript title="quartz.layout.ts" -import { Graph } from "@quartz-community/graph" - -// Create once and reuse -const graphComponent = Graph() - -export const defaultContentPageLayout: PageLayout = { - // ... other layout config - right: [ - // ... other components - graphComponent, - ], -} +```yaml title="quartz.config.yaml" +plugins: + - source: github:quartz-community/graph + enabled: true + layout: + position: right + priority: 10 ``` ## Features @@ -52,43 +46,46 @@ Most configuration can be done by passing in options to `Graph()`. For example, here's what the default configuration looks like: -```typescript title="quartz.layout.ts" -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 - focusOnHover: true, // dim non-connected nodes on hover - enableRadial: true, // whether to constrain the graph, similar to Obsidian - }, -}) +```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 ``` 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 `graphComponent` from `quartz.layout.ts` +- Removing graph view: remove the `graph` entry from `quartz.config.yaml` or set `enabled: false` - Component source: https://github.com/quartz-community/graph diff --git a/docs/features/i18n.md b/docs/features/i18n.md index 05f188be9..58f72da08 100644 --- a/docs/features/i18n.md +++ b/docs/features/i18n.md @@ -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.ts`. +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`. The locale field generally follows a certain format: `{language}-{REGION}` diff --git a/docs/features/popover previews.md b/docs/features/popover previews.md index 9b70149ef..bd128e221 100644 --- a/docs/features/popover previews.md +++ b/docs/features/popover previews.md @@ -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.ts` to be `false`. +- Remove popovers: set the `enablePopovers` field in `quartz.config.yaml` to be `false`. - Style: `quartz/components/styles/popover.scss` - Script: `quartz/components/scripts/popover.inline.ts` diff --git a/docs/features/private pages.md b/docs/features/private pages.md index eed6d3c1a..bb296af78 100644 --- a/docs/features/private pages.md +++ b/docs/features/private pages.md @@ -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.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. +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. > [!note] > Bash's glob syntax is slightly different from fast-glob's and using bash's syntax may lead to unexpected results. diff --git a/docs/features/reader mode.md b/docs/features/reader mode.md index d08c37d04..a8f037766 100644 --- a/docs/features/reader mode.md +++ b/docs/features/reader mode.md @@ -6,13 +6,23 @@ 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, you can remove the component from your layout configuration in `quartz.layout.ts`: +Reader Mode is enabled by default. To disable it, set `enabled: false` in your `quartz.config.yaml`: -```ts -// Remove or comment out this line -Plugin.ReaderMode(), +```yaml title="quartz.config.yaml" +plugins: + - source: github:quartz-community/reader-mode + enabled: false +``` + +Or remove the plugin entirely: + +```bash +npx quartz plugin remove github:quartz-community/reader-mode ``` - Install: `npx quartz plugin add github:quartz-community/reader-mode` diff --git a/docs/features/recent notes.md b/docs/features/recent notes.md index 89f711a4b..439ccd5d1 100644 --- a/docs/features/recent notes.md +++ b/docs/features/recent notes.md @@ -3,15 +3,20 @@ 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 using `Plugin.RecentNotes` in `quartz.layout.ts`. +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. ## Customization -- Changing the title from "Recent notes": pass in an additional parameter to `Plugin.RecentNotes({ title: "Recent writing" })` -- Changing the number of recent notes: pass in an additional parameter to `Plugin.RecentNotes({ limit: 5 })` -- Display the note's tags (defaults to true): `Plugin.RecentNotes({ showTags: false })` -- Show a 'see more' link: pass in an additional parameter to `Plugin.RecentNotes({ linkToMore: "tags/components" })`. This field should be a full slug to a page that exists. -- Customize filtering: pass in an additional parameter to `Plugin.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 `Plugin.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`. +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 +- 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) diff --git a/docs/layout-components.md b/docs/layout-components.md index 8d2260842..ca8c68f69 100644 --- a/docs/layout-components.md +++ b/docs/layout-components.md @@ -4,33 +4,70 @@ 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. -> [!note] -> In the examples below, `Component.` refers to internal layout utilities (imported from `./quartz/components`), while `Plugin.` refers to community plugins (imported from `./.quartz/plugins`). See [[layout]] for more details. +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. -```typescript -type FlexConfig = { - components: { - Component: QuartzComponent - 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" - gap?: string -} +### 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 ``` -### Example Usage +The `groupOptions` field on each plugin entry supports the following flex item properties: -```typescript +| 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: [ { @@ -44,8 +81,25 @@ Component.Flex({ }) ``` +```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" + }[] + direction?: "row" | "row-reverse" | "column" | "column-reverse" + wrap?: "nowrap" | "wrap" | "wrap-reverse" + gap?: string +} +``` + > [!note] Overriding behavior -> 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. +> 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. > > ```scss > .flex-component { @@ -53,29 +107,81 @@ Component.Flex({ > } > ``` -## `MobileOnly` Component +## `MobileOnly` / `DesktopOnly` Components -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. +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. -### Example Usage +### YAML Configuration -```typescript +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)" Component.MobileOnly(Component.Spacer()) ``` -## `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 +```ts title="quartz.ts (override)" Component.DesktopOnly(Plugin.TableOfContents()) ``` ## `ConditionalRender` Component -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. +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", +}) +``` ```typescript type ConditionalRenderConfig = { @@ -84,22 +190,5 @@ type ConditionalRenderConfig = { } ``` -### Example Usage - -```typescript -Component.ConditionalRender({ - component: Plugin.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: Plugin.Breadcrumbs(), - condition: (page) => page.fileData.slug !== "index", -}) -``` - -The example above would hide breadcrumbs on the root `index.md` page. +> [!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. diff --git a/docs/layout.md b/docs/layout.md index fc32bd4b8..293f3274a 100644 --- a/docs/layout.md +++ b/docs/layout.md @@ -4,7 +4,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.layout.ts` using a `defaults` + `byPageType` structure. +In v5, the layout is defined in `quartz.config.yaml` using a `defaults` + `byPageType` structure. - `defaults` contains layout components shared across ALL page types (head, header, afterBody, footer). - `byPageType` contains per-page-type overrides (content, folder, tag, 404) for beforeBody, left, and right sections. @@ -38,47 +38,101 @@ These correspond to following parts of the page: > 1. `head` is a single component that renders the `` [tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head) in the HTML. This doesn't appear visually on the page and is only is responsible for metadata about the document like the tab title, scripts, and styles. > 2. `header` is a set of components that are laid out horizontally and appears _before_ the `beforeBody` section. This enables you to replicate the old Quartz 3 header bar where the title, search bar, and dark mode toggle. By default, Quartz doesn't place any components in the `header`. -### Configuration +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: -Layout components are imported from two main sources: +```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/footer + enabled: true + options: + links: + GitHub: https://github.com/jackyzha0/quartz + Discord Community: https://discord.gg/cRFFHYye7t -```ts title="quartz.layout.ts" -import * as Component from "./quartz/components" // internal HOC components -import * as Plugin from "./.quartz/plugins" // community component plugins +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: [] ``` -Internal components (`Component.Head()`, `Component.Spacer()`, `Component.Flex()`, `Component.MobileOnly()`, `Component.DesktopOnly()`, `Component.ConditionalRender()`) are layout utilities. Community component plugins (`Plugin.Explorer()`, `Plugin.Search()`, `Plugin.Darkmode()`, etc.) provide the actual UI features. +For advanced layout overrides using TypeScript (e.g. custom component wrappers or conditional logic), you can use the TS override in `quartz.ts`: -Here is a simplified example of the layout structure: +```ts title="quartz.ts" +import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader" -```ts title="quartz.layout.ts" -export const layout = { +const config = await loadQuartzConfig() +export default config +export const layout = await loadQuartzLayout({ defaults: { - head: Component.Head(), - header: [], - afterBody: [], - footer: Plugin.Footer({ links: { ... } }), + // override default layout for all page types }, byPageType: { content: { - beforeBody: [Plugin.ArticleTitle(), Plugin.ContentMeta(), Plugin.TagList()], - left: [Plugin.PageTitle(), Plugin.Search(), Plugin.Explorer()], - right: [Plugin.Graph(), Plugin.TableOfContents(), Plugin.Backlinks()], + // override layout for content pages only }, folder: { - beforeBody: [Plugin.Breadcrumbs(), Plugin.ArticleTitle()], - left: [Plugin.PageTitle(), Plugin.Search(), Plugin.Explorer()], - right: [], + // override layout for folder pages only }, - tag: { ... }, - "404": { beforeBody: [], left: [], right: [] }, }, -} +}) ``` 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/