mirror of
https://github.com/quartz-community/plugin-template.git
synced 2026-07-22 02:50:24 +00:00
docs: add AGENTS.md, ARCHITECTURE.md, and EXAMPLES.md for LLM-assisted plugin development
This commit is contained in:
parent
bc03ed7366
commit
ea06f6850c
3 changed files with 295 additions and 0 deletions
90
AGENTS.md
Normal file
90
AGENTS.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Quartz Community Plugin Template
|
||||
|
||||
Provider-agnostic instruction file for AI coding assistants developing Quartz community plugins.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This repository is a template for building, testing, and publishing Quartz community plugins. It uses a factory-function API where plugins are created by functions returning objects with a `name` and lifecycle hooks.
|
||||
|
||||
## Plugin Type Decision Tree
|
||||
|
||||
Plugins are not mutually exclusive. A single plugin can implement multiple types.
|
||||
|
||||
- **Transformer**: Modifies content during the build (remark/rehype). Use if you need to change how Markdown is parsed or rendered.
|
||||
- **Filter**: Decides which files to include in the final site. Use for drafts, private notes, or path-based exclusions.
|
||||
- **Emitter**: Generates new files (JSON, RSS, CNAME, etc.). Use for site-wide manifests or integration files.
|
||||
- **Page Type**: Defines custom routes and page generation logic. Use for virtual pages or non-Markdown content.
|
||||
- **Component**: Provides UI elements for Quartz layouts. Use for navigation, sidebars, or custom widgets.
|
||||
- **Bases View**: Registers custom views in the `@quartz-community/bases-page` system.
|
||||
|
||||
## Files to Modify
|
||||
|
||||
- `src/`: All plugin logic, components, and styles.
|
||||
- `package.json`: Plugin manifest (`quartz` field), dependencies, and metadata.
|
||||
- `src/i18n/`: Translations for multi-language support.
|
||||
|
||||
## Leave Alone
|
||||
|
||||
- `dist/`: Build output.
|
||||
- `.github/`: CI/CD workflows (unless customizing publishing).
|
||||
- `tsup.config.ts`: Build configuration.
|
||||
|
||||
## Plugin Creation Workflow
|
||||
|
||||
1. **Define Options**: Create an interface for plugin configuration in `src/types.ts`.
|
||||
2. **Implement Logic**: Create the plugin factory in a new file (e.g., `src/my-plugin.ts`).
|
||||
3. **Export**: Add the plugin to `src/index.ts`.
|
||||
4. **Manifest**: Update the `quartz` field in `package.json` with category and default options.
|
||||
5. **Test**: Add a test case in `src/tests/` and run `npm test`.
|
||||
6. **Build**: Run `npm run build` to verify the bundle.
|
||||
|
||||
## Package.json Quartz Manifest
|
||||
|
||||
The `quartz` field is required for discovery and configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"quartz": {
|
||||
"name": "my-plugin",
|
||||
"category": ["transformer", "component"],
|
||||
"defaultOptions": { "enabled": true },
|
||||
"optionSchema": { "enabled": { "type": "boolean" } },
|
||||
"components": { "MyComponent": { "defaultPosition": "right" } }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Import Patterns
|
||||
|
||||
- **Types**: Import from `@quartz-community/types`.
|
||||
- **Utils**: Import from `@quartz-community/utils`.
|
||||
- **Runtime**: Use `vfile` for content manipulation in transformers.
|
||||
|
||||
## i18n Setup
|
||||
|
||||
1. Add keys to `src/i18n/locales/en-US.ts`.
|
||||
2. Create other locales in `src/i18n/locales/`.
|
||||
3. Use the `i18n` helper in your plugin or component.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- **Missing Exports**: Forgetting to export the plugin factory from `src/index.ts`.
|
||||
- **Wrong Category**: Not matching the `category` in `package.json` with the implemented hooks.
|
||||
- **Peer Dependencies**: Adding `preact` or `vfile` as `dependencies` instead of `peerDependencies`.
|
||||
|
||||
## Testing Patterns
|
||||
|
||||
Use `vitest`. Mock the `BuildCtx` and `ProcessedContent` when testing transformers or emitters.
|
||||
|
||||
## Checklist Before Submission
|
||||
|
||||
- [ ] `npm run build` completes without errors.
|
||||
- [ ] `npm test` passes all cases.
|
||||
- [ ] `package.json` manifest is complete and accurate.
|
||||
- [ ] `README.md` documents all options.
|
||||
|
||||
## Build System Quirks
|
||||
|
||||
- **.inline.ts**: Files ending in `.inline.ts` are bundled as raw strings for client-side injection.
|
||||
- **.scss**: Styles are compiled to CSS strings and attached to components via `Component.css`.
|
||||
- **Branded Types**: Use `FullSlug` and `FilePath` from `@quartz-community/types` for path safety.
|
||||
73
ARCHITECTURE.md
Normal file
73
ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Architecture Reference
|
||||
|
||||
Machine-readable architecture overview for the Quartz community plugin template.
|
||||
|
||||
## Plugin Lifecycle
|
||||
|
||||
Quartz plugins are factory functions that return an object with a `name` and lifecycle hooks.
|
||||
|
||||
1. **Loading**: Quartz imports the plugin from the `externalPlugins` list in `quartz.config.ts`.
|
||||
2. **Initialization**: The factory function is called with user-provided options.
|
||||
3. **Build Integration**:
|
||||
- **Transformers**: Run during the `transform` phase (remark/rehype).
|
||||
- **Filters**: Run after transformation to prune the content list.
|
||||
- **Emitters**: Run during the `emit` phase to generate files.
|
||||
- **Page Types**: Run to generate virtual pages or custom routes.
|
||||
- **Components**: Rendered during the HTML generation phase.
|
||||
|
||||
## Build System
|
||||
|
||||
The template uses `tsup` for bundling and declaration output.
|
||||
|
||||
- **Inline Scripts**: Files ending in `.inline.ts` are bundled as raw strings for client-side injection.
|
||||
- **Styles**: `.scss` files are compiled to CSS strings and attached to components via `Component.css`.
|
||||
- **Entry Points**:
|
||||
- `index.ts`: Main plugin exports.
|
||||
- `types.ts`: Shared type definitions.
|
||||
- `components/index.ts`: UI component exports.
|
||||
|
||||
## Type System
|
||||
|
||||
The template relies on `@quartz-community/types` for core Quartz types.
|
||||
|
||||
- **Branded Types**: `FullSlug` and `FilePath` are used for path safety.
|
||||
- **vfile DataMap**: Augmented with `QuartzPluginData` for plugin-specific metadata.
|
||||
- **Plugin Interfaces**: `QuartzTransformerPlugin`, `QuartzFilterPlugin`, `QuartzEmitterPlugin`, `QuartzPageTypePlugin`, `QuartzComponentConstructor`.
|
||||
|
||||
## Export Conventions
|
||||
|
||||
- **Default Exports**: Used for components.
|
||||
- **Named Exports**: Used for plugin factories and types.
|
||||
- **Re-exports**: `src/index.ts` re-exports all public APIs.
|
||||
|
||||
## Dependency Management
|
||||
|
||||
- **peerDependencies**: `preact`, `vfile`, and `@jackyzha0/quartz` (optional).
|
||||
- **dependencies**: `@quartz-community/types`, `@quartz-community/utils`.
|
||||
- **devDependencies**: Build tools, linters, and test runners.
|
||||
|
||||
## Testing Infrastructure
|
||||
|
||||
- **vitest**: Test runner.
|
||||
- **test helpers**: Mock `BuildCtx` and `ProcessedContent` for plugin testing.
|
||||
|
||||
## CI/CD Pipeline
|
||||
|
||||
- **GitHub Actions**: Runs `npm run check` on PRs and publishes to npm on version tags (`v*`).
|
||||
|
||||
## Directory Structure
|
||||
|
||||
- `src/`: Source code.
|
||||
- `components/`: UI components.
|
||||
- `scripts/`: Client-side scripts (`.inline.ts`).
|
||||
- `styles/`: Component styles (`.scss`).
|
||||
- `i18n/`: Internationalization.
|
||||
- `util/`: Utility functions.
|
||||
- `index.ts`: Main entry point.
|
||||
- `types.ts`: Type definitions.
|
||||
- `transformer.ts`: Transformer implementation.
|
||||
- `filter.ts`: Filter implementation.
|
||||
- `emitter.ts`: Emitter implementation.
|
||||
- `dist/`: Build output.
|
||||
- `package.json`: Manifest and dependencies.
|
||||
- `tsup.config.ts`: Build configuration.
|
||||
132
EXAMPLES.md
Normal file
132
EXAMPLES.md
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
# Plugin Examples
|
||||
|
||||
Minimal, annotated examples for each Quartz plugin type.
|
||||
|
||||
## 1. Minimal Transformer
|
||||
|
||||
Wraps an existing remark plugin to enforce hard line breaks.
|
||||
|
||||
```ts
|
||||
import remarkBreaks from "remark-breaks";
|
||||
import type { QuartzTransformerPlugin } from "@quartz-community/types";
|
||||
|
||||
export const HardLineBreaks: QuartzTransformerPlugin<void> = () => ({
|
||||
name: "HardLineBreaks",
|
||||
markdownPlugins() {
|
||||
// Return a list of unified/remark plugins
|
||||
return [remarkBreaks];
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 2. Minimal Filter
|
||||
|
||||
Excludes pages marked as `draft: true` in frontmatter.
|
||||
|
||||
```ts
|
||||
import type { QuartzFilterPlugin } from "@quartz-community/types";
|
||||
|
||||
export const RemoveDrafts: QuartzFilterPlugin<void> = () => ({
|
||||
name: "RemoveDrafts",
|
||||
shouldPublish(_ctx, [_tree, vfile]) {
|
||||
// Access frontmatter from vfile data
|
||||
const draft = vfile.data?.frontmatter?.draft;
|
||||
// Return false to exclude the page from the build
|
||||
return draft !== true;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 3. Minimal Emitter
|
||||
|
||||
Writes a `CNAME` file to the output directory.
|
||||
|
||||
```ts
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { QuartzEmitterPlugin } from "@quartz-community/types";
|
||||
|
||||
export const CNAME: QuartzEmitterPlugin<{ domain: string }> = (opts) => ({
|
||||
name: "CNAME",
|
||||
async emit(ctx, _content, _resources) {
|
||||
// ctx.argv.output is the destination directory
|
||||
const filePath = path.join(ctx.argv.output, "CNAME");
|
||||
await fs.writeFile(filePath, opts.domain);
|
||||
// Return the list of emitted file paths
|
||||
return [filePath as any];
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 4. Minimal Component
|
||||
|
||||
Renders a simple spacer div with custom CSS.
|
||||
|
||||
```tsx
|
||||
import type { QuartzComponent, QuartzComponentConstructor } from "@quartz-community/types";
|
||||
|
||||
export default ((opts?: { height?: string }) => {
|
||||
const Component: QuartzComponent = () => {
|
||||
return <div class="spacer" style={{ height: opts?.height ?? "1rem" }} />;
|
||||
};
|
||||
|
||||
// Attach CSS string to the component
|
||||
Component.css = ".spacer { width: 100%; }";
|
||||
return Component;
|
||||
}) satisfies QuartzComponentConstructor;
|
||||
```
|
||||
|
||||
## 5. Minimal Page Type
|
||||
|
||||
Generates a virtual "About" page if it doesn't exist.
|
||||
|
||||
```ts
|
||||
import type { QuartzPageTypePlugin } from "@quartz-community/types";
|
||||
|
||||
export const AboutPage: QuartzPageTypePlugin<void> = () => ({
|
||||
name: "AboutPage",
|
||||
// Match the slug to handle
|
||||
match: (slug) => slug === "about",
|
||||
// Generate the page content
|
||||
generate: async (_ctx, _content) => ({
|
||||
slug: "about" as any,
|
||||
frontmatter: { title: "About" },
|
||||
content: "This is a virtual about page.",
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
## 6. Minimal Bases View Registration
|
||||
|
||||
Registers a custom view for the `@quartz-community/bases-page` system.
|
||||
|
||||
```ts
|
||||
import { viewRegistry } from "@quartz-community/bases-page";
|
||||
|
||||
export function init() {
|
||||
// Register a view that can be used in bases-page layouts
|
||||
viewRegistry.register("my-custom-view", (props) => {
|
||||
return <div>Custom View for {props.fileData.slug}</div>;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 7. Minimal i18n Setup
|
||||
|
||||
Per-plugin translations with a fallback mechanism.
|
||||
|
||||
```ts
|
||||
// src/i18n/locales/en-US.ts
|
||||
export default {
|
||||
hello: "Hello",
|
||||
};
|
||||
|
||||
// src/i18n/index.ts
|
||||
import enUS from "./locales/en-US";
|
||||
const locales = { "en-US": enUS };
|
||||
|
||||
export function i18n(locale: string) {
|
||||
// Fallback to en-US if locale is not found
|
||||
return locales[locale as keyof typeof locales] || enUS;
|
||||
}
|
||||
```
|
||||
Loading…
Reference in a new issue