From 7e8e299810c995ad4ea17ebc67a5eb5c1a0eba67 Mon Sep 17 00:00:00 2001 From: saberzero1 Date: Wed, 25 Feb 2026 16:07:03 +0100 Subject: [PATCH] docs: update README for v5 unified config system --- README.md | 272 ++++++++++-------------------------------------------- 1 file changed, 48 insertions(+), 224 deletions(-) diff --git a/README.md b/README.md index 67e8982..fea3d12 100644 --- a/README.md +++ b/README.md @@ -1,246 +1,70 @@ -# Quartz Community Plugin Template +# @quartz-community/note-properties -Production-ready template for building, testing, and publishing Quartz community plugins. It mirrors -Quartz's native plugin patterns and uses a factory-function API similar to Astro integrations: -plugins are created by functions that return objects with `name` and lifecycle hooks. +Parses frontmatter properties and renders them as a visible properties view on the page, similar to Obsidian's properties panel. -## Highlights - -- ✅ Quartz-compatible transformer/filter/emitter examples -- ✅ TypeScript-first with exported types for consumers -- ✅ `tsup` bundling + declaration output -- ✅ Vitest testing setup with example tests -- ✅ Linting/formatting with ESLint + Prettier -- ✅ CI workflow for checks and npm publishing -- ✅ Demonstrates CSS/JS resource injection and remark/rehype usage - -## Getting started +## Installation ```bash -npm install -npm run build +npx quartz plugin add github:quartz-community/note-properties ``` -## Usage in Quartz +## Usage -Install your plugin into a Quartz v5 site: +This plugin serves as both a **transformer** (parsing frontmatter) and a **component** (displaying the properties view). -```bash -npx quartz plugin add github:quartz-community/plugin-template +```yaml title="quartz.config.yaml" +plugins: + # Transformer (parses frontmatter) + - source: github:quartz-community/note-properties + enabled: true + options: + includeAll: false + includedProperties: + - description + - tags + - aliases + excludedProperties: [] + hidePropertiesView: false + delimiters: "---" + language: yaml + + # Component (displays properties in the page layout) + - source: github:quartz-community/note-properties + enabled: true + layout: + position: beforeBody + priority: 15 ``` -Then register it in `quartz.config.ts`: +For advanced use cases, you can override in TypeScript: -```ts +```ts title="quartz.ts (override)" import * as ExternalPlugin from "./.quartz/plugins"; -export default { - configuration: { - pageTitle: "My Garden", - }, - plugins: { - transformers: [ExternalPlugin.ExampleTransformer({ highlightToken: "==" })], - filters: [ExternalPlugin.ExampleFilter({ allowDrafts: false })], - emitters: [ExternalPlugin.ExampleEmitter({ manifestSlug: "plugin-manifest" })], - }, - externalPlugins: ["github:quartz-community/plugin-template"], -}; -``` - -## Plugin factory pattern (Astro-style) - -Quartz plugins are factory functions that return an object with a `name` and hook implementations. -This mirrors Astro's integration pattern (a function returning an object of hooks), which makes -composition and configuration explicit and predictable. - -```ts -import type { QuartzTransformerPlugin } from "@quartz-community/types"; - -export const MyTransformer: QuartzTransformerPlugin<{ enabled: boolean }> = (opts) => { - return { - name: "MyTransformer", - markdownPlugins() { - return []; - }, - }; -}; -``` - -## Examples included - -### Transformer - -`ExampleTransformer` shows how to: - -- apply a custom remark plugin -- run a rehype plugin -- inject CSS/JS resources -- perform a text transform hook - -```ts -import { ExampleTransformer } from "@quartz-community/plugin-template"; - -ExampleTransformer({ - highlightToken: "==", - headingClass: "example-plugin-heading", - enableGfm: true, - addHeadingSlugs: true, +ExternalPlugin.NoteProperties({ + includeAll: false, + includedProperties: ["description", "tags", "aliases"], + excludedProperties: [], + hidePropertiesView: false, + delimiters: "---", + language: "yaml", }); ``` -The transformer uses a custom remark plugin to convert `==highlight==` into bold text and a rehype -plugin to attach a class to all headings. It also injects a small inline CSS/JS snippet. +## Configuration -### Filter +| Option | Type | Default | Description | +| -------------------- | ---------- | ------------------------------------ | --------------------------------------------------------- | +| `includeAll` | `boolean` | `false` | Whether to include all frontmatter properties. | +| `includedProperties` | `string[]` | `["description", "tags", "aliases"]` | Properties to include when `includeAll` is `false`. | +| `excludedProperties` | `string[]` | `[]` | Properties to exclude when `includeAll` is `true`. | +| `hidePropertiesView` | `boolean` | `false` | Whether to hide the rendered properties view on the page. | +| `delimiters` | `string` | `"---"` | The frontmatter delimiter style. | +| `language` | `string` | `"yaml"` | The frontmatter language (`"yaml"` or `"toml"`). | -`ExampleFilter` demonstrates frontmatter-driven filtering: +## Documentation -```ts -ExampleFilter({ - allowDrafts: false, - excludeTags: ["private", "wip"], - excludePathPrefixes: ["_drafts/", "_private/"], -}); -``` - -### Emitter - -`ExampleEmitter` emits a JSON manifest of all pages: - -```ts -ExampleEmitter({ - manifestSlug: "plugin-manifest", - includeFrontmatter: true, - metadata: { project: "My Garden" }, - transformManifest: (json) => json.replace("My Garden", "Quartz"), -}); -``` - -## API reference - -### `ExampleTransformer(options)` - -| Option | Type | Default | Description | -| ----------------- | --------- | -------------------------- | ----------------------------- | -| `highlightToken` | `string` | `"=="` | Token used to highlight text. | -| `headingClass` | `string` | `"example-plugin-heading"` | Class added to headings. | -| `enableGfm` | `boolean` | `true` | Enables `remark-gfm`. | -| `addHeadingSlugs` | `boolean` | `true` | Enables `rehype-slug`. | - -### `ExampleFilter(options)` - -| Option | Type | Default | Description | -| --------------------- | ---------- | --------------------------- | ------------------------- | -| `allowDrafts` | `boolean` | `false` | Publish draft pages. | -| `excludeTags` | `string[]` | `["private"]` | Tags to exclude. | -| `excludePathPrefixes` | `string[]` | `["_drafts/", "_private/"]` | Path prefixes to exclude. | - -### `ExampleEmitter(options)` - -| Option | Type | Default | Description | -| --------------------- | -------------------------- | ----------------------------------------- | ----------------------------------------- | -| `manifestSlug` | `string` | `"plugin-manifest"` | Output filename (without extension). | -| `includeFrontmatter` | `boolean` | `true` | Include frontmatter in output. | -| `metadata` | `Record` | `{ generator: "Quartz Plugin Template" }` | Extra metadata in manifest. | -| `transformManifest` | `(json: string) => string` | `undefined` | Custom transformer for emitted JSON. | -| `manifestScriptClass` | `string` | `undefined` | Optional CSS class if rendered into HTML. | - -## Testing - -```bash -npm test -``` - -## Build and lint - -```bash -npm run build -npm run lint -npm run format -``` - -## Publishing - -Tags matching `v*` trigger the GitHub Actions publish workflow. Ensure `NPM_TOKEN` is set in the -repository secrets. - -## Component Plugins (UI Components) - -In addition to transformer/filter/emitter plugins, you can create **component plugins** that provide -UI elements for Quartz layouts. See `src/components/ExampleComponent.tsx` for a reference. - -### Component Pattern - -```tsx -import type { QuartzComponent, QuartzComponentConstructor } from "@quartz-community/types"; -import style from "./styles/example.scss"; -import script from "./scripts/example.inline.ts"; - -export default ((opts?: MyComponentOptions) => { - const Component: QuartzComponent = (props) => { - return
...
; - }; - - Component.css = style; - Component.afterDOMLoaded = script; - - return Component; -}) satisfies QuartzComponentConstructor; -``` - -### Client-Side Scripts - -Component scripts run in the browser and must handle Quartz's SPA navigation. Key patterns: - -1. **Use `@ts-nocheck`** - Client scripts run in a different context than build-time code -2. **Listen to `nav` event** - Fires after each page navigation (including initial load) -3. **Listen to `prenav` event** - Fires before navigation, use for saving state -4. **Use `window.addCleanup()`** - Register cleanup functions for event listeners -5. **Fetch `/static/contentIndex.json`** - Access page metadata for search, graph, etc. - -See `src/components/scripts/example.inline.ts` for a complete example with all patterns. - -### Common Helper Functions - -These utilities are commonly needed in component plugins: - -```js -function removeAllChildren(element) { - while (element.firstChild) element.removeChild(element.firstChild); -} - -function simplifySlug(slug) { - return slug.endsWith("/index") ? slug.slice(0, -6) : slug; -} - -function getCurrentSlug() { - let slug = window.location.pathname; - if (slug.startsWith("/")) slug = slug.slice(1); - if (slug.endsWith("/")) slug = slug.slice(0, -1); - return slug || "index"; -} -``` - -### State Persistence - -Use `localStorage` for persistent state (survives browser close) and `sessionStorage` for -temporary state (like scroll positions): - -```js -localStorage.setItem("myPlugin-state", JSON.stringify(state)); -sessionStorage.setItem("myPlugin-scrollTop", element.scrollTop.toString()); -``` - -## Migration Guide (from Quartz v4) - -When migrating a v4 component to a standalone plugin: - -1. **Replace Quartz imports** with `@quartz-community/types` -2. **Copy utility functions** (path helpers, DOM utils) into your plugin -3. **Use `@ts-nocheck`** for inline scripts that can't be type-checked -4. **Fetch data directly** from `/static/contentIndex.json` instead of using `fetchData` -5. **Handle both data formats**: `data.content || data` for contentIndex compatibility -6. **Test with both local and production builds** +See the [Quartz documentation](https://quartz.jzhao.xyz/plugins/Frontmatter) for more information. ## License