diff --git a/.github/workflows/build-preview.yaml b/.github/workflows/build-preview.yaml index a473aa6a6..0c71f4144 100644 --- a/.github/workflows/build-preview.yaml +++ b/.github/workflows/build-preview.yaml @@ -28,8 +28,19 @@ 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 ci + - name: Install Quartz plugins + run: npx quartz plugin install + - name: Check types and style run: npm run check diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8446cc86e..62e31d7a0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -3,10 +3,10 @@ name: Build and Test on: pull_request: branches: - - v4 + - v5 push: branches: - - v4 + - v5 workflow_dispatch: jobs: @@ -26,7 +26,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 - name: Cache dependencies uses: actions/cache@v5 @@ -36,8 +36,19 @@ 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 ci + - name: Install Quartz plugins + run: npx quartz plugin install + - name: Check types and style run: npm run check @@ -48,7 +59,7 @@ jobs: run: npx quartz build --bundleInfo -d docs publish-tag: - if: ${{ github.repository == 'jackyzha0/quartz' && github.ref == 'refs/heads/v4' }} + if: ${{ github.repository == 'jackyzha0/quartz' && github.ref == 'refs/heads/v5' }} runs-on: ubuntu-latest permissions: contents: write @@ -59,7 +70,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 - name: Get package version run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV - name: Create release tag diff --git a/.github/workflows/docker-build-push.yaml b/.github/workflows/docker-build-push.yaml index 26cf223f9..a00f95bb3 100644 --- a/.github/workflows/docker-build-push.yaml +++ b/.github/workflows/docker-build-push.yaml @@ -2,10 +2,10 @@ name: Docker build & push image on: push: - branches: [v4] + branches: [v5] tags: ["v*"] pull_request: - branches: [v4] + branches: [v5] paths: - .github/workflows/docker-build-push.yaml - quartz/** diff --git a/.gitignore b/.gitignore index 25d07db1c..8f1d76ace 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ tsconfig.tsbuildinfo private/ .replit replit.nix +.quartz/ +quartz/cli/tui/dist/ diff --git a/.prettierrc b/.prettierrc index 5788b66f1..3fdeccd6f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,5 +3,19 @@ "quoteProps": "as-needed", "trailingComma": "all", "tabWidth": 2, - "semi": false + "semi": false, + "overrides": [ + { + "files": "*.canvas", + "options": { + "parser": "json" + } + }, + { + "files": "*.base", + "options": { + "parser": "yaml" + } + } + ] } diff --git a/Dockerfile b/Dockerfile index f8a6f2684..e6c0a21e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,9 @@ FROM node:22-slim AS builder WORKDIR /usr/src/app COPY package.json . COPY package-lock.json* . -RUN npm ci +COPY quartz/ ./quartz/ +COPY quartz.lock.json . +RUN npm ci; npx quartz plugin install FROM node:22-slim WORKDIR /usr/src/app diff --git a/README.md b/README.md index 01e2c5889..bcdbbf476 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Quartz v4 +# Quartz v5 > “[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 diff --git a/docs/Base.base b/docs/Base.base new file mode 100644 index 000000000..bc878a40a --- /dev/null +++ b/docs/Base.base @@ -0,0 +1,124 @@ +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 diff --git a/docs/Canvas.canvas b/docs/Canvas.canvas new file mode 100644 index 000000000..317702ce6 --- /dev/null +++ b/docs/Canvas.canvas @@ -0,0 +1,321 @@ +{ + "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" + } + ] +} diff --git a/docs/advanced/architecture.md b/docs/advanced/architecture.md index 33da89d90..1bf4b52a9 100644 --- a/docs/advanced/architecture.md +++ b/docs/advanced/architecture.md @@ -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]() 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/). + 1. Parsing the command-line arguments using [yargs](http://yargs.js.org/). The `plugin` subcommand is also handled here for managing external plugins. 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.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. @@ -48,5 +48,79 @@ 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"`. -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]]. +## 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. + +### 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/` — Install a community plugin +- `npx quartz plugin update` — Update all plugins to latest commits +- `npx quartz plugin restore` — Restore plugins from locked commits in `quartz.lock.json` (used in CI/CD) +- `npx quartz plugin remove ` — 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 (``, ``, ``, `#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..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. diff --git a/docs/advanced/creating components.md b/docs/advanced/creating components.md index 84e038012..4224f2d96 100644 --- a/docs/advanced/creating components.md +++ b/docs/advanced/creating components.md @@ -1,5 +1,5 @@ --- -title: Creating your own Quartz components +title: Creating Component Plugins --- > [!warning] @@ -20,17 +20,31 @@ 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.** -## An Example Component +## Community Component Plugins -### Constructor +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. -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. +### Getting Started -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. +To create a new component plugin, you can use the official plugin template: -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. +```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" -```tsx {11-17} interface Options { favouriteNumber: number } @@ -39,28 +53,25 @@ const defaultOptions: Options = { favouriteNumber: 42, } -export default ((userOpts?: Options) => { - const opts = { ...userOpts, ...defaultOpts } - function YourComponent(props: QuartzComponentProps) { - if (opts.favouriteNumber < 0) { - return null - } +const MyComponent: QuartzComponentConstructor = (userOpts?: Options) => { + const opts = { ...defaultOptions, ...userOpts } + const Component: QuartzComponent = (props: QuartzComponentProps) => { + if (opts.favouriteNumber < 0) return null return

My favourite number is {opts.favouriteNumber}

} - return YourComponent -}) satisfies QuartzComponentConstructor + return Component +} + +export default MyComponent ``` ### 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 title="quartz/components/types.ts" -// simplified for sake of demonstration +```tsx export type QuartzComponentProps = { fileData: QuartzPluginData cfg: GlobalConfiguration @@ -70,50 +81,29 @@ export type QuartzComponentProps = { } ``` -- `fileData`: Any metadata [[making plugins|plugins]] may have added to the current page. +- `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`. -- `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`). +- `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. Helpful if you want to conditionally hide a component on mobile or desktop. +- `displayClass`: a utility class that indicates a preference from the user about how to render it in a mobile or desktop setting. ### Styling -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. +In community plugins, styles are bundled with the plugin. You can define styles using the `.css` property on the component: -Note that inlined styles **must** be plain vanilla CSS: - -```tsx {6-10} title="quartz/components/YourComponent.tsx" -export default (() => { - function YourComponent() { - return

Example Component

- } - - YourComponent.css = ` - p.red-text { - color: red; - } - ` - - return YourComponent -}) satisfies QuartzComponentConstructor +```tsx +Component.css = ` + .my-component { color: red; } +` ``` -Imported styles, however, can be from SCSS files: +For SCSS, you can import it and assign it to the `.css` property. The build system will handle the transformation: -```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

Example Component

- } - - YourComponent.css = styles - return YourComponent -}) satisfies QuartzComponentConstructor +```tsx +import styles from "./styles.scss" +Component.css = styles ``` > [!warning] @@ -121,128 +111,108 @@ export default (() => { ### Scripts and Interactivity -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. +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. -```tsx title="quartz/components/YourComponent.tsx" -export default (() => { - function YourComponent() { - return - } +- `.beforeDOMLoaded`: Executed _before_ the page is done loading. Used for prefetching or early initialization. +- `.afterDOMLoaded`: Executed once the page has been completely loaded. - 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). +If you need to create an `afterDOMLoaded` script that depends on page-specific elements that may change when navigating, listen for the `"nav"` event: ```ts document.addEventListener("nav", () => { // do page specific logic here - // e.g. attach event listeners const toggleSwitch = document.querySelector("#switch") as HTMLInputElement - toggleSwitch.addEventListener("change", switchTheme) - window.addCleanup(() => toggleSwitch.removeEventListener("change", switchTheme)) + if (toggleSwitch) { + toggleSwitch.addEventListener("change", switchTheme) + window.addCleanup(() => toggleSwitch.removeEventListener("change", switchTheme)) + } }) ``` -You can also add the equivalent of a `beforeunload` event for [[SPA Routing]] via the `prenav` event. +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: ```ts -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 -}) +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) ``` -It is best practice to track any event handlers via `window.addCleanup` to prevent memory leaks. -This will get called on page navigation. +It is best practice to track any event handlers via `window.addCleanup` to prevent memory leaks during SPA navigation. #### Importing Code -Of course, it isn't always practical (nor desired!) to write your code as a string literal in the component. +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: -Quartz supports importing component code through `.inline.ts` files. +```tsx title="src/index.ts" +import script from "./script.inline.ts" -```tsx title="quartz/components/YourComponent.tsx" -// @ts-ignore: typescript doesn't know about our inline bundling system -// so we need to silence the error -import script from "./scripts/graph.inline" - -export default (() => { - function YourComponent() { - return - } - - 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!") +const Component: QuartzComponent = (props) => { + return } +Component.afterDOMLoaded = script ``` -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. +The `inlineScriptPlugin` handles transpiling TypeScript to browser-compatible JavaScript during the build step, allowing you to write type-safe client-side code. -### Using a Component +### Installing Your Component -After creating your custom component, re-export it in `quartz/components/index.ts`: +Once your component is published (e.g., to GitHub or npm), users can install it using the Quartz CLI: -```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" - -export { ArticleTitle, Content, Darkmode, YourComponent } +```shell +npx quartz plugin add github:your-username/my-component ``` -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. +Then, they can add it to their `quartz.config.yaml`: -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 ( -
-

It's nested!

- -
- ) - } - - return AnotherComponent -}) satisfies QuartzComponentConstructor +```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 })], + }, + }, +}) +``` + +## Internal Components + +Quartz also has internal components that provide layout utilities. These live in `quartz/components/` and are primarily used for structural purposes: + +- `Component.Head()` — renders the `` tag +- `Component.Spacer()` — adds flexible space +- `Component.Flex()` — flexible layout container +- `Component.MobileOnly()` — shows component only on mobile +- `Component.DesktopOnly()` — shows component only on desktop +- `Component.ConditionalRender()` — conditionally renders based on page data + +See [[layout-components]] for more details on these utilities. + > [!hint] -> Look in `quartz/components` for more examples of components in Quartz as reference for your own components! +> 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. diff --git a/docs/advanced/index.md b/docs/advanced/index.md index 482258900..3d0da8000 100644 --- a/docs/advanced/index.md +++ b/docs/advanced/index.md @@ -1,3 +1,10 @@ --- 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 diff --git a/docs/advanced/making plugins.md b/docs/advanced/making plugins.md index f5cb19901..70616c0da 100644 --- a/docs/advanced/making plugins.md +++ b/docs/advanced/making plugins.md @@ -18,20 +18,52 @@ 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/ctx.ts`. It consists of +- `BuildCtx` is defined in `@quartz-community/types`. 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/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. +- `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. - `additionalHead`: a list of JSX elements or functions that return JSX elements to be added to the `` tag of the page. Functions receive the page's data as an argument and can conditionally render elements. -## Transformers +## 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 + +### Transformers Transformers **map** over content, taking a Markdown file and outputting modified content or adding metadata to the file itself. @@ -52,15 +84,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 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). +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). A good example of a transformer plugin that borrows from the `remark` and `rehype` ecosystems is the [[plugins/Latex|Latex]] plugin: -```ts title="quartz/plugins/transformers/latex.ts" +```ts import remarkMath from "remark-math" import rehypeKatex from "rehype-katex" import rehypeMathjax from "rehype-mathjax/svg" -import { QuartzTransformerPlugin } from "../types" +import { QuartzTransformerPlugin } from "@quartz-community/types" interface Options { renderEngine: "katex" | "mathjax" @@ -109,6 +141,8 @@ export const Latex: QuartzTransformerPlugin = (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", @@ -140,45 +174,50 @@ 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. @@ -197,8 +236,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 title="quartz/plugins/filters/draft.ts" -import { QuartzFilterPlugin } from "../types" +```ts +import { QuartzFilterPlugin } from "@quartz-community/types" export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({ name: "RemoveDrafts", @@ -210,7 +249,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. @@ -242,7 +281,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/plugins/emitters/helpers.ts` 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-community/utils` if you are creating files that contain text. `write` has the following signature: ```ts export type WriteOptions = (data: { @@ -262,26 +301,23 @@ 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/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`. +- 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`. For example, the following is a simplified version of the content page plugin that renders every single page. -```tsx title="quartz/plugins/emitters/contentPage.tsx" +```tsx +import { QuartzEmitterPlugin, FullPageLayout, QuartzComponentProps } from "@quartz-community/types" +import { renderPage, canonicalizeServer, pageResources, write } from "@quartz-community/utils" + 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() { + getQuartzComponents(ctx) { + const { head, header, beforeBody, pageBody, afterBody, left, right, footer } = ctx.cfg.layout return [head, ...header, ...beforeBody, pageBody, ...afterBody, ...left, ...right, footer] }, - async emit(ctx, content, resources, emit): Promise { + async emit(ctx, content, resources): Promise { const cfg = ctx.cfg.configuration const fps: FilePath[] = [] const allFiles = content.map((c) => c[1].data) @@ -297,8 +333,9 @@ export const ContentPage: QuartzEmitterPlugin = () => { allFiles, } - const content = renderPage(cfg, slug, componentData, opts, externalResources) - const fp = await emit({ + const content = renderPage(cfg, slug, componentData, {}, externalResources) + const fp = await write({ + ctx, content, slug: file.data.slug!, ext: ".html", @@ -312,7 +349,190 @@ export const ContentPage: QuartzEmitterPlugin = () => { } ``` -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. +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. -> [!hint] -> Look in `quartz/plugins` for more examples of plugins in Quartz as reference for your own plugins! +```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..template` in `quartz.config.yaml`. +- `body`: The Quartz component constructor that renders the page body content. + +### Providing Custom Frames + +Plugins can ship their own [[layout#Page Frames|page frames]] — custom page layouts that control how the HTML structure (sidebars, header, content area, footer) is arranged. This is useful for page types that need fundamentally different layouts (e.g. a fullscreen canvas, a presentation mode, a dashboard). + +To provide a custom frame: + +**1. Create the frame file:** + +```tsx title="src/frames/MyFrame.tsx" +import type { PageFrame, PageFrameProps } from "@quartz-community/types" +import type { ComponentChildren } from "preact" + +export const MyFrame: PageFrame = { + name: "my-frame", + css: ` +.page[data-frame="my-frame"] > #quartz-body { + grid-template-columns: 1fr; + grid-template-areas: "center"; +} +`, + render({ componentData, pageBody: Content, footer: Footer }: PageFrameProps): unknown { + const renderSlot = (C: (props: typeof componentData) => unknown): ComponentChildren => + C(componentData) as ComponentChildren + return ( +
+ {(Content as any)(componentData)} + {(Footer as any)(componentData)} +
+ ) + }, +} +``` + +Key requirements: + +- `name`: A unique string identifier. This is what page types and YAML config reference. +- `render()`: Receives all layout slots (header, sidebars, content, footer) and returns JSX for the inner page structure. +- `css` (optional): Frame-specific CSS. Scope it with `.page[data-frame="my-frame"]` selectors to avoid conflicts. + +**2. Re-export the frame:** + +```ts title="src/frames/index.ts" +export { MyFrame } from "./MyFrame" +``` + +**3. Declare the frame in `package.json`:** + +```json title="package.json" +{ + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + }, + "./frames": { + "import": "./dist/frames/index.js", + "types": "./dist/frames/index.d.ts" + } + }, + "quartz": { + "frames": { + "MyFrame": { "exportName": "MyFrame" } + } + } +} +``` + +The `"frames"` field in the `"quartz"` manifest maps export names to frame metadata. The key (e.g. `"MyFrame"`) must match the export name in `src/frames/index.ts`. + +**4. Add the frame entry point to your build config:** + +```ts title="tsup.config.ts" +export default defineConfig({ + entry: ["src/index.ts", "src/frames/index.ts"], + // ... +}) +``` + +**5. Reference the frame in your page type:** + +```ts +export const MyPageType: QuartzPageTypePlugin = () => ({ + name: "MyPageType", + frame: "my-frame", // References the frame by its name property + // ... +}) +``` + +When a user installs your plugin, Quartz automatically loads the frame from the `./frames` export and registers it in the Frame Registry. The frame is then available by name in any page type or YAML config override. + +> [!tip] +> See the [`canvas-page`](https://github.com/quartz-community/canvas-page) plugin for a complete real-world example of a plugin-provided frame. + +## Building and Testing + +```shell +# Build the plugin +npm run build +# or +npx tsup +``` + +## Installing Your Plugin + +```shell +# In your Quartz project +npx quartz plugin add github:your-username/my-plugin +``` + +This clones the plugin, builds it, and adds it to both `quartz.config.yaml` and `quartz.lock.json`. You can then configure it in your config: + +```yaml title="quartz.config.yaml" +plugins: + - source: github:your-username/my-plugin + enabled: true +``` + +Or via TS override in `quartz.ts`: + +```ts title="quartz.ts (override)" +import * as ExternalPlugin from "./.quartz/plugins" +// ... +transformers: [ExternalPlugin.MyPlugin()] +``` + +### Development Workflow + +During plugin development, you'll frequently install and uninstall your plugin to test changes. The following commands help manage this cycle: + +```shell +# Remove your plugin and clean up +npx quartz plugin remove my-plugin + +# Re-add after making changes +npx quartz plugin add github:your-username/my-plugin +``` + +If you've updated your `quartz.config.yaml` to reference a plugin that isn't installed yet, you can install it without manually running `add`: + +```shell +# Install all config-referenced plugins missing from the lockfile +npx quartz plugin resolve + +# Preview first without making changes +npx quartz plugin resolve --dry-run +``` + +To clean up plugins that are installed but no longer referenced in your config: + +```shell +# Remove orphaned plugins +npx quartz plugin prune + +# Preview first without making changes +npx quartz plugin prune --dry-run +``` + +> [!tip] +> Both `resolve` and `prune` fall back to `quartz.config.default.yaml` if no `quartz.config.yaml` is present. This is useful for CI environments where the default config is the source of truth. See [[cli/plugin#prune|prune]] and [[cli/plugin#resolve|resolve]] for full details. + +## Component Plugins + +For plugins that provide visual components (like Explorer, Graph, Search), see the [[creating components|creating component plugins]] guide. diff --git a/docs/build.md b/docs/build.md deleted file mode 100644 index 6005770dd..000000000 --- a/docs/build.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -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]]. diff --git a/docs/cli/build.md b/docs/cli/build.md new file mode 100644 index 000000000..5c07d4b88 --- /dev/null +++ b/docs/cli/build.md @@ -0,0 +1,65 @@ +--- +title: quartz build +aliases: + - build +--- + +The `build` command transforms your Markdown content into a static HTML website. It processes your files through the configured plugins and outputs the final site to a directory of your choice. + +## Flags + +| Flag | Shorthand | Description | Default | +| ----------------- | --------- | --------------------------------------------------------- | ----------------- | +| `--directory` | `-d` | The directory containing your Quartz project | Current directory | +| `--verbose` | `-v` | Enable detailed logging for debugging | `false` | +| `--output` | `-o` | The directory where the built site will be saved | `public` | +| `--serve` | | Start a local development server | `false` | +| `--watch` | | Rebuild the site when files change | `false` | +| `--port` | | The port for the development server | `8080` | +| `--wsPort` | | The port for the WebSocket hot-reload server | `3001` | +| `--baseDir` | | Set a base directory for the site (e.g. for GitHub Pages) | `/` | +| `--remoteDevHost` | | The hostname to use for the development server | `localhost` | +| `--bundleInfo` | | Output a JSON file with bundle size information | `false` | +| `--concurrency` | | Number of worker threads to use for building | CPU core count | + +## Examples + +### Basic Build + +Generate your site into the `public` folder. + +```shell +npx quartz build +``` + +### Development Mode + +Start a local server and watch for changes. This is the most common way to preview your site while writing. + +```shell +npx quartz build --serve +``` + +### Custom Output and Port + +Build to a specific folder and run the server on a different port. + +```shell +npx quartz build --serve --output dist --port 3000 +``` + +### Performance Tuning + +If you have a very large vault, you can limit the number of concurrent workers to save memory. + +```shell +npx quartz build --concurrency 2 +``` + +## Development Server + +The `--serve` flag starts a local web server. This server is intended for development and previewing only. It is not designed for production use. For information on how to deploy your site, see [[hosting]]. + +### Hot Reloading + +When running with `--serve`, Quartz automatically enables `--watch`. It uses a WebSocket connection (on the port specified by `--wsPort`) to notify your browser when a file has changed. The browser will then automatically refresh to show the latest version of your content. diff --git a/docs/cli/create.md b/docs/cli/create.md new file mode 100644 index 000000000..d3be213a1 --- /dev/null +++ b/docs/cli/create.md @@ -0,0 +1,84 @@ +--- +title: quartz create +--- + +The `create` command initializes a new Quartz project. It helps you set up your content folder, choose a configuration template, set your site's base URL, and configure how Quartz should handle your Markdown files. + +## Flags + +| Flag | Shorthand | Description | +| ------------- | --------- | --------------------------------------------------------------------- | +| `--template` | `-t` | Configuration template (`default`, `obsidian`, `ttrpg`, or `blog`) | +| `--directory` | `-d` | The directory where Quartz will be initialized | +| `--source` | `-s` | The source directory of your Markdown files | +| `--strategy` | `-X` | How to handle the source files (`new`, `copy`, or `symlink`) | +| `--links` | `-l` | How to resolve internal links (`absolute`, `shortest`, or `relative`) | +| `--baseUrl` | `-b` | Base URL for your site (e.g. `mysite.github.io/quartz`) | +| `--verbose` | `-v` | Enable detailed logging | + +## Templates + +When you run `quartz create`, you can choose a configuration template that pre-configures Quartz for your use case: + +- **Default**: A clean Quartz setup with sensible defaults. Best for starting from scratch. +- **Obsidian**: Optimized for Obsidian vaults with full Obsidian Flavored Markdown support (wikilinks, callouts, mermaid diagrams, etc.). Automatically sets link resolution to `shortest` and skips the link resolution prompt. +- **TTRPG**: Builds on the Obsidian template with the addition of the [Leaflet map plugin](https://github.com/quartz-community/external-quartz-leaflet-map-plugin) and [ITS Theme](https://github.com/saberzero1/quartz-themes) (`its-theme.ttrpg-dnd`). Great for D&D and TTRPG wikis. Also skips the link resolution prompt. +- **Blog**: A blog-focused setup with [recent notes](https://github.com/quartz-community/recent-notes) enabled (showing the 5 most recent posts with tags) and [comments](https://github.com/quartz-community/comments) enabled via giscus. You'll need to fill in the `TODO:` placeholder values in `quartz.config.yaml` with your own giscus repository details. + +## Base URL + +During setup, Quartz will ask for the base URL of your site. This is the URL where your site will be deployed (e.g. `mysite.github.io/quartz`). + +- Do **not** include the protocol (`https://`) — if you do, it will be automatically stripped. +- Trailing slashes are also removed automatically. +- See [[configuration]] for more details on how `baseUrl` is used. + +## Strategies + +When you run `quartz create`, you must choose a strategy for your content: + +- **new**: Creates a fresh, empty content folder. Use this if you are starting a new project from scratch. +- **copy**: Copies all files from your source directory into the Quartz content folder. This is the safest option for existing vaults as it doesn't touch your original files. +- **symlink**: Creates a symbolic link from the Quartz content folder to your source directory. Any changes you make in your source directory (e.g. in Obsidian) will be immediately reflected in Quartz. +- **move**: Moves your files from the source directory into the Quartz content folder. + +## Link Resolution + +Quartz needs to know how to interpret the internal links in your Markdown files: + +- **shortest**: Resolves links to the closest matching file name. This is the default for Obsidian. +- **absolute**: Resolves links relative to the root of your content folder. +- **relative**: Resolves links relative to the current file's location. + +> [!note] +> When using the **Obsidian** or **TTRPG** templates, link resolution is automatically set to `shortest` and the prompt is skipped. + +## Interactive Walkthrough + +If you run `npx quartz create` without any arguments, it will guide you through an interactive setup: + +1. **Choose a template**: Select a configuration template (`Default`, `Obsidian`, `TTRPG`, or `Blog`). +2. **Select a strategy**: Choose between `new`, `copy`, or `symlink`. +3. **Enter base URL**: Provide the URL where your site will be hosted. +4. **Select link resolution**: Choose how your links are formatted (skipped for Obsidian and TTRPG templates). +5. **Finish**: Quartz will set up the directory structure and create your configuration. + +## Example: Importing an Obsidian Vault + +To create a Quartz project that links directly to an existing Obsidian vault: + +```shell +npx quartz create --template obsidian --strategy symlink --source ~/Documents/MyVault +``` + +This command tells Quartz to use the Obsidian template (with full OFM support and shortest link resolution), look at your vault in `~/Documents/MyVault`, and use symbolic links so changes are synced. + +## Example: Setting Up a Blog + +To quickly set up a blog with recent notes and comments: + +```shell +npx quartz create --template blog --strategy new --baseUrl myblog.github.io +``` + +After setup, edit `quartz.config.yaml` to fill in your giscus repository details in the comments plugin section. diff --git a/docs/cli/index.md b/docs/cli/index.md new file mode 100644 index 000000000..1cdf15c93 --- /dev/null +++ b/docs/cli/index.md @@ -0,0 +1,46 @@ +--- +title: CLI Reference +--- + +The Quartz CLI is the primary way to interact with your Quartz project. It provides commands for creating new projects, building static sites, syncing with GitHub, and managing plugins. + +You can run the CLI using `npx quartz`. + +## Quick Reference + +| Command | Description | Example | +| --------- | ------------------------------------------------------- | ------------------------ | +| `create` | Initialize a new Quartz project with template selection | `npx quartz create` | +| `build` | Generate static HTML files | `npx quartz build` | +| `sync` | Sync content with GitHub | `npx quartz sync` | +| `upgrade` | Upgrade Quartz to the latest version | `npx quartz upgrade` | +| `update` | Update installed plugins | `npx quartz update` | +| `plugin` | Manage Quartz plugins | `npx quartz plugin list` | +| `tui` | Launch the interactive plugin manager | `npx quartz tui` | + +## Commands + +- [[cli/create|create]]: Initialize a new Quartz project with a choice of templates (default, obsidian, ttrpg, blog) and base URL configuration. +- [[cli/build|build]]: Build your Quartz site into static HTML. Includes a development server. +- [[cli/sync|sync]]: Push and pull changes between your local machine and GitHub. +- [[cli/upgrade|upgrade]]: Upgrade the Quartz framework to the latest version. +- [[cli/update|update]]: Update installed plugins to their latest versions. +- [[cli/restore|restore]]: Recover your content folder from the local cache. +- [[cli/migrate|migrate]]: Convert older configuration files to the new YAML format. +- [[cli/plugin|plugin]]: Install, add, remove, prune, resolve, and configure plugins from the command line. +- [[cli/tui|tui]]: Use a terminal interface to manage plugins and layout. + +## Help and Versioning + +To see a full list of available flags for any command, use the `--help` flag. + +```shell +npx quartz --help +npx quartz build --help +``` + +To check which version of Quartz you are currently running, use the `--version` flag. + +```shell +npx quartz --version +``` diff --git a/docs/cli/migrate.md b/docs/cli/migrate.md new file mode 100644 index 000000000..b44b2106a --- /dev/null +++ b/docs/cli/migrate.md @@ -0,0 +1,32 @@ +--- +title: quartz migrate +--- + +The `migrate` command helps you transition your project from Quartz 4 to Quartz v5 by converting your configuration files. + +## When to Use + +Use this command if you have an existing Quartz 4 project and want to upgrade to the new YAML-based configuration system introduced in v5. + +## What it Does + +When you run `npx quartz migrate`, the CLI performs several automated steps: + +1. **Read Configuration**: It parses your existing `quartz.config.ts` and `quartz.layout.ts` files. +2. **Map Plugins**: It identifies the plugins you are using and maps them to their v5 equivalents. +3. **Generate YAML**: It creates a new `quartz.config.yaml` file that contains all your settings, theme colors, and plugin configurations. +4. **Backup**: It keeps your old `.ts` files so you can refer back to them if needed. + +```shell +npx quartz migrate +``` + +## Verification + +After running the migration, you should check the following: + +- **Theme Colors**: Ensure your custom colors were correctly transferred to the `theme` section of `quartz.config.yaml`. +- **Plugin Options**: Verify that any custom options you passed to plugins (like `linkClickBehavior`) are present in the new config. +- **Layout**: Check that your component order in the `layout` section matches your previous setup. + +For a comprehensive guide on the entire migration process, including manual steps, see [[getting-started/migrating]]. diff --git a/docs/cli/plugin.md b/docs/cli/plugin.md new file mode 100644 index 000000000..8ba4796cc --- /dev/null +++ b/docs/cli/plugin.md @@ -0,0 +1,219 @@ +--- +title: quartz plugin +--- + +The `plugin` command is the heart of the Quartz v5 plugin management system. it allows you to install, configure, and update plugins directly from the command line. + +All plugins are stored in the `.quartz/plugins/` directory, and their versions are tracked in `quartz.lock.json`. + +## Subcommands + +### list + +List all currently installed plugins and their versions. + +```shell +npx quartz plugin list +``` + +### add + +Add a new plugin from a Git repository. + +```shell +npx quartz plugin add github:username/repo +``` + +To install from a specific branch or ref, append `#ref` to the source: + +```shell +npx quartz plugin add github:username/repo#my-branch +npx quartz plugin add git+https://github.com/username/repo.git#my-branch +npx quartz plugin add https://github.com/username/repo.git#my-branch +``` + +You can also add a plugin from a local directory. This is useful for local development or airgapped environments: + +```shell +npx quartz plugin add ./path/to/my-plugin +npx quartz plugin add ../sibling-plugin +npx quartz plugin add /absolute/path/to/plugin +``` + +Local plugins are symlinked into `.quartz/plugins/`, so any changes you make to the source directory are reflected immediately without re-installing. + +When a branch is specified, it is stored in the lockfile. All subsequent commands (`install`, `update`, `restore`, `check`, `resolve`) will respect that branch automatically. + +### remove + +Remove an installed plugin. + +```shell +npx quartz plugin remove plugin-name +``` + +### install + +Install all plugins listed in your `quartz.lock.json` file. This is useful when setting up the project on a new machine. + +```shell +npx quartz plugin install +``` + +### update + +Update specific plugins or all plugins to their latest versions. + +```shell +npx quartz plugin update plugin-name +npx quartz plugin update # updates all +``` + +### restore + +Restore plugins to the exact versions specified in the lockfile. Unlike `install`, this will downgrade plugins if the lockfile specifies an older version. This is recommended for CI/CD environments. + +```shell +npx quartz plugin restore +``` + +### enable / disable + +Toggle a plugin's status in your `quartz.config.yaml` without removing its files. + +```shell +npx quartz plugin enable plugin-name +npx quartz plugin disable plugin-name +``` + +### config + +View or modify the configuration for a specific plugin. + +```shell +# View config +npx quartz plugin config plugin-name + +# Set a value +npx quartz plugin config plugin-name --set key=value +``` + +### check + +Check if any of your installed plugins have updates available. + +```shell +npx quartz plugin check +``` + +### prune + +Remove installed plugins that are no longer referenced in your `quartz.config.yaml`. This is useful for cleaning up after removing plugin entries from your configuration. + +```shell +npx quartz plugin prune +``` + +Use `--dry-run` to preview which plugins would be removed without making changes: + +```shell +npx quartz plugin prune --dry-run +``` + +### resolve + +Install plugins that are listed in your `quartz.config.yaml` but missing from the lockfile. This is the inverse of `prune` — it ensures your installed plugins match your configuration. + +```shell +npx quartz plugin resolve +``` + +Use `--dry-run` to preview which plugins would be installed without making changes: + +```shell +npx quartz plugin resolve --dry-run +``` + +## Common Workflows + +### Adding and Enabling a Plugin + +To add a new plugin and start using it: + +1. Add the plugin: `npx quartz plugin add github:quartz-community/example` +2. Enable it: `npx quartz plugin enable example` + +### Updating Everything + +To keep your plugins fresh: + +```shell +npx quartz plugin update +``` + +### Managing Configuration + +If you want to change a plugin setting without opening the YAML file: + +```shell +npx quartz plugin config explorer --set useSavedState=true +``` + +### Cleaning Up Unused Plugins + +If you've removed plugins from your config and want to clean up leftover files: + +```shell +npx quartz plugin prune --dry-run # preview first +npx quartz plugin prune # remove orphaned plugins +``` + +### Setting Up from Config + +When setting up on a new machine or in CI, resolve any plugins referenced in your config that aren't yet installed: + +```shell +npx quartz plugin resolve +``` + +### Testing with Branches + +If a plugin author has a fix or feature on a separate branch, you can install it directly without waiting for a release to the default branch: + +```shell +# Install from a feature branch +npx quartz plugin add github:username/repo#fix/some-bug + +# Later, switch back to the default branch by re-adding without a ref +npx quartz plugin remove repo +npx quartz plugin add github:username/repo +``` + +The branch ref is tracked in `quartz.lock.json`, so `update` and `check` will continue to follow the specified branch until the plugin is re-added without one. + +Both `prune` and `resolve` will fall back to `quartz.config.default.yaml` if no `quartz.config.yaml` is present. + +### Local Plugin Development + +For local plugin development or airgapped environments, you can add a plugin from a local directory: + +```shell +npx quartz plugin add ./my-local-plugin +``` + +Local plugins are symlinked into `.quartz/plugins/`, so changes reflect immediately. When you run `update`, local plugins are rebuilt (npm install + npm run build) without any git operations. The `check` command will show local plugins with a "local" status instead of checking for remote updates. + +To switch a local plugin back to a git source: + +```shell +npx quartz plugin remove my-local-plugin +npx quartz plugin add github:username/my-local-plugin +``` + +## Interactive Mode + +Running the plugin command without any subcommand will launch the [[cli/tui|TUI]], which provides a visual interface for all these operations. + +```shell +npx quartz plugin +``` diff --git a/docs/cli/restore.md b/docs/cli/restore.md new file mode 100644 index 000000000..ebbdeaf73 --- /dev/null +++ b/docs/cli/restore.md @@ -0,0 +1,29 @@ +--- +title: quartz restore +--- + +The `restore` command is a safety mechanism that allows you to recover your content folder from a local cache. + +## When to Use + +You should use `restore` if: + +- A `quartz upgrade` failed and corrupted your content. +- You accidentally deleted files in your content folder. +- You encountered complex merge conflicts that you want to undo. + +## How it Works + +Quartz maintains a hidden cache of your content folder. Every time you run certain commands, Quartz ensures that a backup of your Markdown files exists. The `restore` command simply copies these files back into your main content directory. + +```shell +npx quartz restore +``` + +## Example Workflow + +If an update fails and leaves your project in a broken state: + +1. **Restore**: Run `npx quartz restore` to bring back your content. +2. **Clean**: Use Git to reset any other broken code files. +3. **Retry**: Attempt the update again or manually apply the changes you need. diff --git a/docs/cli/sync.md b/docs/cli/sync.md new file mode 100644 index 000000000..8d071fa98 --- /dev/null +++ b/docs/cli/sync.md @@ -0,0 +1,74 @@ +--- +title: quartz sync +--- + +The `sync` command automates the process of pushing your local changes to GitHub and pulling updates from your remote repository. It simplifies the Git workflow for users who want to keep their site updated without running manual Git commands. + +## Flags + +| Flag | Shorthand | Description | Default | +| ------------- | --------- | ------------------------------------ | ----------------- | +| `--directory` | `-d` | The directory of your Quartz project | Current directory | +| `--verbose` | `-v` | Enable detailed logging | `false` | +| `--commit` | | Whether to commit changes | `true` | +| `--no-commit` | | Skip committing changes | `false` | +| `--message` | `-m` | Custom commit message | `update content` | +| `--push` | | Whether to push changes to remote | `true` | +| `--no-push` | | Skip pushing changes | `false` | +| `--pull` | | Whether to pull changes from remote | `true` | +| `--no-pull` | | Skip pulling changes | `false` | + +## Workflow + +When you run `npx quartz sync`, Quartz performs the following steps: + +1. **Pull**: It fetches and merges changes from your remote GitHub repository. +2. **Add**: It stages all new and modified files in your project. +3. **Commit**: It creates a new commit with your changes. +4. **Push**: It sends your new commit to GitHub. + +## Common Workflows + +### Regular Sync + +The most common usage is to simply run the command with no flags. This pulls, commits, and pushes everything. + +```shell +npx quartz sync +``` + +### First Sync + +If you have just set up a new repository and haven't pushed anything yet, you might want to skip the pull step. + +```shell +npx quartz sync --no-pull +``` + +### Custom Commit Message + +You can provide a more descriptive message for your changes. + +```shell +npx quartz sync --message "add new notes about gardening" +``` + +### Sync from Another Device + +If you are working on a different computer and just want to get the latest changes without pushing anything back yet. + +```shell +npx quartz sync --no-push --no-commit +``` + +## Troubleshooting + +### Git Buffer + +If you have a very large number of changes, Git might occasionally fail due to buffer limits. If this happens, try syncing smaller batches of files or increasing your Git post buffer size. + +### Autostash + +Quartz uses `git pull --rebase --autostash` internally. This means if you have unstaged changes when you run `sync`, Quartz will temporarily hide them, pull the remote changes, and then bring your changes back. If a conflict occurs during this process, you will need to resolve it manually using standard Git tools. + +For more information on initial setup, see [[getting-started/installation]]. diff --git a/docs/cli/tui.md b/docs/cli/tui.md new file mode 100644 index 000000000..9b9aa9f52 --- /dev/null +++ b/docs/cli/tui.md @@ -0,0 +1,64 @@ +--- +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]]. diff --git a/docs/cli/update.md b/docs/cli/update.md new file mode 100644 index 000000000..28be49c97 --- /dev/null +++ b/docs/cli/update.md @@ -0,0 +1,38 @@ +--- +title: quartz update +--- + +The `update` command updates your installed plugins to their latest versions. It is a convenient shortcut for `npx quartz plugin update`. + +## Usage + +Update all installed plugins: + +```shell +npx quartz update +``` + +Update specific plugins by name: + +```shell +npx quartz update my-plugin another-plugin +``` + +## How it Works + +For each plugin, `update` fetches the latest commit from the plugin's remote repository and rebuilds it. If a plugin was installed from a specific branch (e.g., `github:user/repo#my-branch`), updates will track that branch instead of the default branch. Local plugins (added from a file path) are rebuilt without any git operations. The lockfile (`quartz.lock.json`) is updated with the new commit hashes. + +This is functionally identical to running: + +```shell +npx quartz plugin update +``` + +## Flags + +The `update` command supports the standard [[cli/index|common flags]] (`--directory`, `--verbose`). + +## See Also + +- [[cli/upgrade|quartz upgrade]] — upgrade the Quartz framework itself +- [[cli/plugin|quartz plugin]] — full plugin management (install, remove, enable, disable, etc.) diff --git a/docs/cli/upgrade.md b/docs/cli/upgrade.md new file mode 100644 index 000000000..14b14bc34 --- /dev/null +++ b/docs/cli/upgrade.md @@ -0,0 +1,46 @@ +--- +title: quartz upgrade +--- + +The `upgrade` command upgrades the Quartz framework itself to the latest version by pulling changes from the official Quartz repository. + +## Usage + +```shell +npx quartz upgrade +``` + +## How it Works + +When you run `npx quartz upgrade`, Quartz performs the following steps: + +1. **Backs up your content** — your content folder is cached locally to prevent data loss. +2. **Pulls the latest Quartz code** — fetches and merges from the official upstream repository (`upstream/v5`) using Git. +3. **Shows version changes** — displays the version transition (e.g., `v5.0.0 → v5.1.0`) or confirms you're already up to date. +4. **Updates dependencies** — runs `npm install` to ensure all packages match the new version. +5. **Restores plugins** — reinstalls plugins from `quartz.lock.json` to ensure compatibility. +6. **Checks plugin compatibility** — verifies that installed plugins are compatible with the new Quartz version. + +## Handling Conflicts + +Because Quartz allows you to customize almost every part of the code, upgrades can sometimes result in merge conflicts. This happens if you have modified a file that the Quartz team has also updated. + +If a conflict occurs: + +1. Git will mark the conflicting sections in the affected files. +2. You will need to open these files and manually choose which changes to keep. +3. After resolving the conflicts, you can commit the changes. + +## Recovery + +If an upgrade goes wrong or leaves your project in an unusable state, you can use the [[cli/restore|restore]] command to recover your content from the local cache. + +## Flags + +The `upgrade` command supports the standard [[cli/index|common flags]] (`--directory`, `--verbose`). + +## See Also + +- [[cli/update|quartz update]] — update installed plugins +- [[getting-started/upgrading|Upgrading Quartz]] — detailed upgrading guide +- [[cli/restore|quartz restore]] — recover content from cache diff --git a/docs/community.md b/docs/community.md new file mode 100644 index 000000000..6c72e1cd1 --- /dev/null +++ b/docs/community.md @@ -0,0 +1,60 @@ +--- +title: Community +--- + +Quartz has a vibrant community of users and contributors. This page highlights community-created plugins, tools, and resources that extend Quartz. + +> [!tip] Contributing +> Know of a great community resource? Submit a pull request to add it to this page! + +## Community Plugins + +Third-party plugins that extend Quartz functionality. Install them with the [[cli/plugin|plugin CLI]]: + +```bash +npx quartz plugin install +``` + + + + +_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. + + + + +_No community tools listed yet._ + +## Templates & Themes + +Custom themes, CSS snippets, and starter templates for Quartz sites. + + + + +_No community templates listed yet._ + +## Guides & Tutorials + +Community-written guides, blog posts, and tutorials about using Quartz. + + + + +_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). diff --git a/docs/configuration.md b/docs/configuration.md index 288139b29..ae92c9009 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 @@ -39,8 +42,9 @@ 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 [[cli/create|`npx quartz create`]]. The CLI automatically strips any `https://` or `http://` protocol prefixes and trailing slashes for you. - This should also include the subpath if you are [[hosting]] on GitHub pages without a custom domain. For example, if my repository is `jackyzha0/quartz`, GitHub pages would deploy to `https://jackyzha0.github.io/quartz` and the `baseUrl` would be `jackyzha0.github.io/quartz`. - - 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. + - 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. - `ignorePatterns`: a list of [glob]() 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. @@ -67,47 +71,124 @@ 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: [...], -} +```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) +- **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. -You can customize the behaviour of Quartz by adding, removing and reordering plugins in the `transformers`, `filters` and `emitters` fields. +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 resolve +``` + +To remove installed plugins that are no longer in your config: + +```shell +npx quartz plugin prune +``` + +Both commands support `--dry-run` to preview changes. See [[cli/plugin|the plugin CLI reference]] for full details. + +### Usage + +You can customize the behaviour of Quartz by adding, removing and reordering plugins in `quartz.config.yaml`. Each plugin entry specifies its source, whether it's enabled, execution order, and any options: + +```yaml title="quartz.config.yaml" +plugins: + - source: github:quartz-community/note-properties + enabled: true + options: + includeAll: false + includedProperties: + - description + - tags + - aliases + order: 5 + - source: github:quartz-community/created-modified-date + enabled: true + options: + priority: + - frontmatter + - git + - filesystem + order: 10 + - source: github:quartz-community/latex + enabled: true + options: + renderEngine: katex + order: 80 +``` > [!note] -> 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. +> 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]]. @@ -115,22 +196,35 @@ If you'd like to make your own plugins, see the [[making plugins|making custom p ## 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/Bases.md b/docs/features/Bases.md new file mode 100644 index 000000000..4df918b3a --- /dev/null +++ b/docs/features/Bases.md @@ -0,0 +1,21 @@ +--- +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) diff --git a/docs/features/Canvas.md b/docs/features/Canvas.md new file mode 100644 index 000000000..f1bda22a8 --- /dev/null +++ b/docs/features/Canvas.md @@ -0,0 +1,21 @@ +--- +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) diff --git a/docs/features/Docker Support.md b/docs/features/Docker Support.md index a7fb6a259..e64566f80 100644 --- a/docs/features/Docker Support.md +++ b/docs/features/Docker Support.md @@ -1,3 +1,9 @@ +--- +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. diff --git a/docs/features/Latex.md b/docs/features/Latex.md index fdc9d277b..65bf70be8 100644 --- a/docs/features/Latex.md +++ b/docs/features/Latex.md @@ -70,10 +70,9 @@ For example: ### Using mhchem -Add the following import to the top of `quartz/plugins/transformers/latex.ts` (before all the other -imports): +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): -```ts title="quartz/plugins/transformers/latex.ts" +```ts title="src/index.ts" import "katex/contrib/mhchem" ``` diff --git a/docs/features/Obsidian compatibility.md b/docs/features/Obsidian compatibility.md index e469f4866..414b2378e 100644 --- a/docs/features/Obsidian compatibility.md +++ b/docs/features/Obsidian compatibility.md @@ -12,6 +12,188 @@ 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 +![](https://youtu.be/v5LGaczJaf0) +![](https://www.youtube.com/watch?v=v5LGaczJaf0) +``` + +For example, the following embed is rendered from `![](https://youtu.be/v5LGaczJaf0)`: + +![](https://youtu.be/v5LGaczJaf0) + +### Tweet Embeds + +Tweets from Twitter/X are embedded as static blockquotes with a link to the original: + +```markdown +![](https://x.com/kepano/status/1882142872826442145) +![](https://twitter.com/kepano/status/1882142872826442145) +``` + +For example, the following embed is rendered from `![](https://x.com/kepano/status/1882142872826442145)`: + +![](https://x.com/kepano/status/1882142872826442145) + +### Block References + +Block references allow linking to specific blocks within a page: + +```markdown +Content paragraph. ^my-block + +[[Page#^my-block]] +``` + +### Obsidian URI Links + +Links using the `obsidian://` protocol are marked with a CSS class (`obsidian-uri`) and a `data-obsidian-uri` attribute, so you can style them differently from regular links. + +### Video Embeds + +Video files can be embedded using standard image syntax: + +```markdown +![](video.mp4) +![](video.webm) +``` + +### Embed in HTML + +By default, Obsidian does not render its Markdown syntax inside HTML blocks. Quartz extends this with the `enableInHtmlEmbed` option, which parses wikilinks, highlights, and tags inside raw HTML nodes. + ## Configuration This functionality is provided by the [[ObsidianFlavoredMarkdown]], [[Frontmatter]] and [[CrawlLinks]] plugins. See the plugin pages for customization options. diff --git a/docs/features/OxHugo compatibility.md b/docs/features/OxHugo compatibility.md index e22051146..b5b5f5672 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 + ExternalPlugin.FrontMatter({ delims: "+++", language: "toml" }), // ... - Plugin.OxHugoFlavouredMarkdown(), - Plugin.GitHubFlavoredMarkdown(), + ExternalPlugin.OxHugoFlavouredMarkdown(), + ExternalPlugin.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..67378f095 100644 --- a/docs/features/Roam Research compatibility.md +++ b/docs/features/Roam Research compatibility.md @@ -9,19 +9,31 @@ 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: [ // ... - Plugin.RoamFlavoredMarkdown(), - Plugin.ObsidianFlavoredMarkdown(), + ExternalPlugin.RoamFlavoredMarkdown(), + ExternalPlugin.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. ## Customization diff --git a/docs/features/SPA Routing.md b/docs/features/SPA Routing.md index 3004af977..d18aa2168 100644 --- a/docs/features/SPA Routing.md +++ b/docs/features/SPA Routing.md @@ -1,7 +1,13 @@ +--- +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.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 6862720e1..95df12c61 100644 --- a/docs/features/backlinks.md +++ b/docs/features/backlinks.md @@ -6,10 +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 `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` +- 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 f3545059d..66785ed47 100644 --- a/docs/features/breadcrumbs.md +++ b/docs/features/breadcrumbs.md @@ -8,28 +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 `Component.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" -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 +```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)" +ExternalPlugin.Breadcrumbs({ + spacerSymbol: "❯", + rootName: "Home", + resolveFrontmatterTitle: true, + showCurrentPage: true, }) ``` When passing in your own options, you can omit any or all of these fields if you'd like to keep the default value for that field. -You can also adjust where the breadcrumbs will be displayed by adjusting the [[layout]] (moving `Component.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 `Component.Breadcrumbs()` from `quartz.layout.ts`. -- Component: `quartz/components/Breadcrumbs.tsx` -- Style: `quartz/components/styles/breadcrumbs.scss` -- Script: inline at `quartz/components/Breadcrumbs.tsx` +- 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 6e5a25ca1..c588bae72 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,28 +33,54 @@ After entering both your repository and selecting the discussion category, Giscu ![[giscus-results.png]] -Finally, in `quartz.layout.ts`, edit the `afterBody` field of `sharedPageComponents` to include the following options but with the values you got from above: +Finally, in `quartz.config.yaml`, add the comments plugin with the following options (using the values you got from above): -```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' - } - }), -], +```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: [ + 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. @@ -106,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: [ - Component.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: [ + ExternalPlugin.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 dff75b44d..25e1d4d6a 100644 --- a/docs/features/darkmode.md +++ b/docs/features/darkmode.md @@ -6,12 +6,14 @@ 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 `Component.Darkmode()` from `quartz.layout.ts`. -- Component: `quartz/components/Darkmode.tsx` -- Style: `quartz/components/styles/darkmode.scss` -- Script: `quartz/components/scripts/darkmode.inline.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) You can also listen to the `themechange` event to perform any custom logic when the theme changes. diff --git a/docs/features/explorer.md b/docs/features/explorer.md index 797d4f1ac..f2a28be21 100644 --- a/docs/features/explorer.md +++ b/docs/features/explorer.md @@ -6,6 +6,30 @@ 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. @@ -17,42 +41,63 @@ Display names for folders get determined by the `title` frontmatter field in `fo ## Customization -Most configuration can be done by passing in options to `Component.Explorer()`. +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" -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 +```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({ + 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 `Component.Explorer()` 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]] -- 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/components/Explorer.tsx" +```ts title="@quartz-community/explorer" class FileTrieNode { isFolder: boolean children: Array @@ -60,7 +105,7 @@ class FileTrieNode { } ``` -```ts title="quartz/plugins/emitters/contentIndex.tsx" +```ts export type ContentDetails = { slug: FullSlug title: string @@ -74,7 +119,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 -Component.Explorer({ +Explorer({ sortFn: (a, b) => { if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) { return a.displayName.localeCompare(b.displayName, undefined, { @@ -114,8 +159,20 @@ 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" -Component.Explorer({ +```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) }, @@ -126,8 +183,8 @@ Component.Explorer({ Using this example, the display names of all `FileNodes` (folders + files) will be converted to full upper case. -```ts title="quartz.layout.ts" -Component.Explorer({ +```ts title="quartz.ts (override)" +Explorer({ mapFn: (node) => { node.displayName = node.displayName.toUpperCase() return node @@ -135,13 +192,16 @@ Component.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" -Component.Explorer({ +```ts title="quartz.ts (override)" +Explorer({ filterFn: (node) => { // set containing names of everything you want to filter out const omit = new Set(["authoring content", "tags", "advanced"]) @@ -158,8 +218,8 @@ Component.Explorer({ You can access the tags of a file by `node.data.tags`. -```ts title="quartz.layout.ts" -Component.Explorer({ +```ts title="quartz.ts (override)" +Explorer({ filterFn: (node) => { // exclude files with the tag "explorerexclude" return node.data?.tags?.includes("explorerexclude") !== true @@ -172,8 +232,8 @@ Component.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" -Component.Explorer({ +```ts title="quartz.ts (override)" +Explorer({ filterFn: undefined, // apply no filter function, every file and folder will visible }) ``` @@ -181,24 +241,24 @@ Component.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" -> import { Options } from "./quartz/components/Explorer" +> ```ts title="quartz.ts" +> import { ExplorerOptions } from "@quartz-community/explorer/components" > -> export const mapFn: Options["mapFn"] = (node) => { +> export const mapFn: ExplorerOptions["mapFn"] = (node) => { > // implement your function here > } -> export const filterFn: Options["filterFn"] = (node) => { +> export const filterFn: ExplorerOptions["filterFn"] = (node) => { > // implement your function here > } -> export const sortFn: Options["sortFn"] = (a, b) => { +> export const sortFn: ExplorerOptions["sortFn"] = (a, b) => { > // implement your function here > } > -> Component.Explorer({ +> Explorer({ > // ... your other options > mapFn, > filterFn, @@ -208,10 +268,10 @@ Component.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" -Component.Explorer({ +```ts title="quartz.ts (override)" +Explorer({ mapFn: (node) => { if (node.isFolder) { node.displayName = "📁 " + node.displayName diff --git a/docs/features/full-text search.md b/docs/features/full-text search.md index 85ec03006..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,8 +26,6 @@ It properly tokenizes Chinese, Korean, and Japenese characters and constructs se ## Customization -- 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 +- 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 19f086286..37540d473 100644 --- a/docs/features/graph view.md +++ b/docs/features/graph view.md @@ -9,6 +9,30 @@ 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. @@ -18,48 +42,50 @@ Additionally, similar to how browsers highlight visited links a different colour ## Customization -Most configuration can be done by passing in options to `Component.Graph()`. +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" -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 - }, -}) +```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: 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` +- 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 57547ddad..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}` @@ -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/v4/quartz/i18n/locales)! To contribute a translation, do the following things: +> We [gladly welcome translation PRs](https://github.com/jackyzha0/quartz/tree/v5/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. diff --git a/docs/features/index.md b/docs/features/index.md index 2997b3aa5..38c46f1e9 100644 --- a/docs/features/index.md +++ b/docs/features/index.md @@ -1,3 +1,48 @@ --- title: Feature List --- + +Quartz comes with a wide variety of features out of the box. Most features are powered by [[configuration#Plugins|plugins]] that can be configured, enabled, or disabled via `quartz.config.yaml`. + +## Content Features + +- [[Obsidian compatibility]] — Full support for Obsidian-flavored Markdown +- [[wikilinks]] — Link between notes using `[[wikilinks]]` syntax +- [[callouts]] — Obsidian-style callout blocks +- [[Latex]] — LaTeX math rendering +- [[Mermaid diagrams]] — Diagram support via Mermaid +- [[syntax highlighting]] — Code block highlighting with themes +- [[OxHugo compatibility]] — Support for ox-hugo Markdown +- [[Roam Research compatibility]] — Support for Roam Research syntax +- [[Citations]] — Academic citation support +- [[Canvas]] — Render Obsidian Canvas files as interactive pages +- [[Bases]] — Database-like views for your notes (tables, cards, galleries, and more) + +## Navigation & Discovery + +- [[full-text search]] — Search across all your notes +- [[graph view]] — Interactive graph visualization of note connections +- [[backlinks]] — See which notes link to the current page +- [[explorer]] — File tree sidebar for browsing notes +- [[breadcrumbs]] — Breadcrumb navigation trail +- [[table of contents]] — Per-page table of contents +- [[folder and tag listings]] — Browse notes by folder or tag +- [[recent notes]] — Display recently modified notes +- [[popover previews]] — Hover previews for internal links +- [[StackedPages|stacked pages]] — Andy Matuschak-style stacked sliding panes for tracing note connections +- [[EncryptedPages|encrypted pages]] — Password-protect individual pages with client-side encryption + +## Appearance & Reading + +- [[darkmode]] — Light and dark mode toggle +- [[reader mode]] — Distraction-free reading experience +- [[comments]] — Add comments via Giscus, Utterances, or other providers +- [[social images]] — Auto-generated Open Graph images for social sharing + +## Publishing & Deployment + +- [[RSS Feed]] — RSS feed generation for content syndication +- [[private pages]] — Control which pages are published +- [[SPA Routing]] — Single-page app navigation +- [[Docker Support]] — Build and deploy with Docker +- [[i18n]] — Internationalization with 30+ supported locales 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 d1c142916..a8f037766 100644 --- a/docs/features/reader mode.md +++ b/docs/features/reader mode.md @@ -6,15 +6,28 @@ 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 -Component.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` +- 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: diff --git a/docs/features/recent notes.md b/docs/features/recent notes.md index 75406e504..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 `Component.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 `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` +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/features/upcoming features.md b/docs/features/upcoming features.md deleted file mode 100644 index d45ebeda4..000000000 --- a/docs/features/upcoming features.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -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 diff --git a/docs/authoring content.md b/docs/getting-started/authoring-content.md similarity index 83% rename from docs/authoring content.md rename to docs/getting-started/authoring-content.md index 623357fc3..71afb68ac 100644 --- a/docs/authoring content.md +++ b/docs/getting-started/authoring-content.md @@ -1,8 +1,10 @@ --- title: Authoring Content +aliases: + - "authoring content" --- -All of the content in your Quartz should go in the `/content` folder. The content for the home page of your Quartz lives in `content/index.md`. If you've [[index#🪴 Get Started|setup Quartz]] already, this folder should already be initialized. Any Markdown in this folder will get processed by Quartz. +All of the content in your Quartz should go in the `/content` folder. The content for the home page of your Quartz lives in `content/index.md`. If you've [[index#🪴 Get Started|setup Quartz]] already, this folder should already be initialized. Any Markdown in this folder will get processed by Quartz. It is recommended that you use [Obsidian](https://obsidian.md/) as a way to edit and maintain your Quartz. It comes with a nice editor and graphical interface to preview, edit, and link your local files and attachments. @@ -40,7 +42,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 [[setting up your GitHub repository|already setup your GitHub repository]] and then do `npx quartz sync`. +First, make sure you've [[getting-started/installation|already setup your GitHub repository]] and then do `npx quartz sync`. ## Customization diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md new file mode 100644 index 000000000..dec263f12 --- /dev/null +++ b/docs/getting-started/index.md @@ -0,0 +1,17 @@ +--- +title: Getting Started +--- + +Welcome to Quartz! This section will walk you through setting up your digital garden from scratch. + +## Setup + +1. **[[getting-started/installation|Installation]]** — Clone Quartz, create your repository, and push your first sync +2. **[[getting-started/authoring-content|Authoring Content]]** — Write and organize your notes in the `content` folder +3. **[[build|Building]]** — Preview your site locally with `npx quartz build --serve` +4. **[[hosting|Hosting]]** — Deploy your Quartz site to the web + +## Upgrading & Migrating + +- **[[getting-started/upgrading|Upgrading Quartz]]** — Keep your Quartz installation up to date +- **[[getting-started/migrating|Migrating to Quartz 5]]** — Migrate from Quartz 4 or Quartz 3 diff --git a/docs/setting up your GitHub repository.md b/docs/getting-started/installation.md similarity index 94% rename from docs/setting up your GitHub repository.md rename to docs/getting-started/installation.md index 2a753e834..df927ec2f 100644 --- a/docs/setting up your GitHub repository.md +++ b/docs/getting-started/installation.md @@ -1,5 +1,7 @@ --- -title: Setting up your GitHub repository +title: "Installation" +aliases: + - "setting up your GitHub repository" --- First, make sure you have Quartz [[index#🪴 Get Started|cloned and setup locally]]. @@ -8,7 +10,7 @@ Then, create a new repository on GitHub.com. Do **not** initialize the new repos ![[github-init-repo-options.png]] -At the top of your repository on GitHub.com's Quick Setup page, click the clipboard to copy the remote repository URL. +At the top of your repository on GitHub.com's Quick Setup page, click the clipboard to copy the remote repository URL. ![[github-quick-setup.png]] diff --git a/docs/getting-started/migrating.md b/docs/getting-started/migrating.md new file mode 100644 index 000000000..518a5ef05 --- /dev/null +++ b/docs/getting-started/migrating.md @@ -0,0 +1,359 @@ +--- +title: "Migrating to Quartz 5" +aliases: + - "migrating from Quartz 3" + - "migrating from Quartz 4" +--- + +This guide covers migrating to Quartz 5 from previous versions. If you're already on Quartz 5 and want to update to the latest version, see [[getting-started/upgrading|Upgrading Quartz]] instead. + +## Migrating from Quartz 4 + +### Overview + +Quartz 5 introduces a community plugin system that fundamentally changes how plugins and components are managed. Most plugins that were built into Quartz 4 are now standalone community plugins maintained under the [quartz-community](https://github.com/quartz-community) organization. This guide walks through the changes needed to migrate your configuration. + +### What Changed + +- **Plugin system**: Plugins are now standalone Git repositories, installed via `npx quartz plugin add` +- **Import pattern**: Community plugins use `ExternalPlugin.X()` (from `.quartz/plugins`) instead of `Plugin.X()` (from `./quartz/plugins`) +- **Layout structure**: `quartz.layout.ts` is gone — layout position is now a per-plugin property in `quartz.config.yaml`, with `layout.groups` for flex containers (e.g. toolbar) and `layout.byPageType` for per-page-type overrides +- **Page Types**: A new plugin category for page rendering (content, folder, tag pages) +- **Component references**: In layout files, community components use `Plugin.X()` (from `.quartz/plugins`) instead of `Component.X()` (from `./quartz/components`) + +### Step-by-Step Migration + +#### 1. Set Up Quartz 5 with a Template + +The easiest way to migrate is to use `npx quartz create`, which generates a complete `quartz.config.yaml` from a template with all default plugins pre-configured: + +```shell +npx quartz create --template default --strategy copy --source /path/to/your/content +``` + +Available templates: `default`, `obsidian`, `ttrpg`, `blog`. Pick the one closest to your setup — `obsidian` is recommended if you use an Obsidian vault. + +> [!tip] Choosing a template +> Each template comes with all 30+ default plugins pre-configured. The main differences are content strategy (OFM support, link resolution) and optional plugins (comments, maps). You can customize everything in `quartz.config.yaml` afterward. + +After running `create`, install all the plugins referenced in the generated config: + +```shell +npx quartz plugin resolve +``` + +This reads your `quartz.config.yaml` and installs every plugin listed in it. No need to run 30 individual `npx quartz plugin add` commands. + +> [!note] Custom or optional plugins +> If you used optional plugins in v4 (comments, reader-mode, breadcrumbs, recent-notes, citations, etc.), add them after the initial setup: +> +> ```shell +> npx quartz plugin add github:quartz-community/comments +> npx quartz plugin add github:quartz-community/reader-mode +> npx quartz plugin add github:quartz-community/breadcrumbs +> npx quartz plugin add github:quartz-community/recent-notes +> ``` +> +> See [[plugins/index|Plugins]] for the full list of available community plugins. + +> [!info] Alternative: Use `npx quartz migrate` +> If you have an existing `quartz.config.ts` and `quartz.layout.ts` from v4, you can run `npx quartz migrate` instead. This reads your old config files and generates `quartz.config.yaml` with your existing settings. You'll still need to run `npx quartz plugin resolve` afterward to install the plugins. See [[cli/migrate|quartz migrate]] for details. + +#### 2. Update quartz.config.yaml + +**Before (v4):** + +```ts title="quartz.config.ts" +import * as Plugin from "./quartz/plugins" + +plugins: { + transformers: [ + Plugin.FrontMatter(), + Plugin.CreatedModifiedDate({ priority: ["frontmatter", "git", "filesystem"] }), + Plugin.Latex({ renderEngine: "katex" }), + ], + filters: [Plugin.RemoveDrafts()], + emitters: [ + Plugin.AliasRedirects(), + Plugin.ComponentResources(), + Plugin.ContentPage(), + Plugin.FolderPage(), + Plugin.TagPage(), + Plugin.ContentIndex({ enableSiteMap: true, enableRSS: true }), + Plugin.Assets(), + Plugin.Static(), + Plugin.NotFoundPage(), + ], +} +``` + +**After (v5):** + +```yaml title="quartz.config.yaml" +plugins: + - source: github:quartz-community/note-properties + enabled: true + options: + delimiters: "---" + language: yaml + order: 5 + - source: github:quartz-community/created-modified-date + enabled: true + options: + priority: + - frontmatter + - git + - filesystem + order: 10 + - source: github:quartz-community/latex + enabled: true + options: + renderEngine: katex + order: 80 + - source: github:quartz-community/remove-draft + enabled: true + - source: github:quartz-community/alias-redirects + enabled: true + - source: github:quartz-community/content-index + enabled: true + options: + enableSiteMap: true + enableRSS: true + - source: github:quartz-community/favicon + enabled: true + - source: github:quartz-community/og-image + enabled: true + - source: github:quartz-community/cname + enabled: true + - source: github:quartz-community/content-page + enabled: true + - source: github:quartz-community/folder-page + enabled: true + - source: github:quartz-community/tag-page + enabled: true + # ... more plugins +``` + +Key changes: + +- Plugins are now referenced by their GitHub source (`github:org/repo`) +- Plugin type (transformer, filter, emitter, pageType) is determined by the plugin's manifest, not by which array you place it in +- Execution order is controlled by the `order` field (lower numbers run first) +- Each plugin entry has `enabled`, `options`, `order`, and optionally `layout` fields +- Install community plugins with `npx quartz plugin add github:quartz-community/` + +#### 3. Update layout configuration + +**Before (v4):** + +```ts title="quartz.layout.ts" +import * as Component from "./quartz/components" + +export const sharedPageComponents: SharedLayout = { + head: Component.Head(), + header: [], + afterBody: [], + footer: Component.Footer({ links: { ... } }), +} + +export const defaultContentPageLayout: PageLayout = { + beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta(), Component.TagList()], + left: [Component.PageTitle(), Component.Search(), Component.Darkmode(), Component.Explorer()], + right: [Component.Graph(), Component.TableOfContents(), Component.Backlinks()], +} +``` + +**After (v5):** + +```yaml title="quartz.config.yaml" +plugins: + - source: github:quartz-community/breadcrumbs + enabled: true + layout: + position: beforeBody + priority: 5 + - source: github:quartz-community/article-title + enabled: true + layout: + position: beforeBody + priority: 10 + - source: github:quartz-community/content-meta + enabled: true + layout: + position: beforeBody + priority: 20 + - source: github:quartz-community/tag-list + enabled: true + layout: + position: beforeBody + priority: 30 + - source: github:quartz-community/page-title + enabled: true + layout: + position: left + priority: 10 + - source: github:quartz-community/search + enabled: true + layout: + position: left + priority: 20 + - source: github:quartz-community/darkmode + enabled: true + layout: + position: left + priority: 30 + - source: github:quartz-community/explorer + enabled: true + layout: + position: left + priority: 50 + - source: github:quartz-community/graph + enabled: true + layout: + position: right + priority: 10 + - source: github:quartz-community/backlinks + enabled: true + layout: + position: right + priority: 30 + - source: github:quartz-community/footer + enabled: true + options: + links: + GitHub: https://github.com/jackyzha0/quartz + Discord Community: https://discord.gg/cRFFHYye7t + +layout: + byPageType: + content: {} + folder: + exclude: + - reader-mode + positions: + right: [] + tag: + exclude: + - reader-mode + positions: + right: [] + "404": + positions: + beforeBody: [] + left: [] + right: [] +``` + +Key changes: + +- Layout position is now a property on each plugin entry (`layout.position`, `layout.priority`) +- `sharedPageComponents` is gone — all layout is plugin-driven +- Per-page-type overrides live in the `layout.byPageType` section +- Empty arrays (`[]`) clear a position for that page type +- The `exclude` field removes specific plugins from a page type + +#### 4. Update CI/CD + +Add `npx quartz plugin restore` to your build pipeline, before `npx quartz build`. This installs plugins from the lockfile at their pinned versions. + +If your CI uses `quartz.config.default.yaml` (or contributors may add plugins to config without updating the lockfile), also run `npx quartz plugin resolve` to install any config-referenced plugins that are missing from the lockfile: + +```shell +npx quartz plugin restore # install pinned plugins from lockfile +npx quartz plugin resolve # install any config-referenced plugins not yet in lockfile +npx quartz build +``` + +See [[hosting]] for detailed CI/CD examples and [[ci-cd]] for advanced configuration. + +#### 5. Commit and Deploy + +```shell +git add quartz.config.yaml quartz.lock.json +git commit -m "chore: migrate to Quartz 5 plugin system" +``` + +> [!tip] Cleaning up leftover plugins +> After migrating, you may have plugins installed from v4 that are no longer in your v5 config. Run `npx quartz plugin prune` to remove them. Use `--dry-run` first to preview what would be removed. + +### Plugin Reference Table + +Mapping v4 plugin names to v5 equivalents: + +| v4 | v5 | Type | +| ----------------------------------- | ------------------------------------------- | --------------------- | +| `Plugin.FrontMatter()` | `Plugin.FrontMatter()` (unchanged) | Internal | +| `Plugin.CreatedModifiedDate()` | `ExternalPlugin.CreatedModifiedDate()` | Community | +| `Plugin.SyntaxHighlighting()` | `ExternalPlugin.SyntaxHighlighting()` | Community | +| `Plugin.ObsidianFlavoredMarkdown()` | `ExternalPlugin.ObsidianFlavoredMarkdown()` | Community | +| `Plugin.GitHubFlavoredMarkdown()` | `ExternalPlugin.GitHubFlavoredMarkdown()` | Community | +| `Plugin.CrawlLinks()` | `ExternalPlugin.CrawlLinks()` | Community | +| `Plugin.Description()` | `ExternalPlugin.Description()` | Community | +| `Plugin.Latex()` | `ExternalPlugin.Latex()` | Community | +| `Plugin.RemoveDrafts()` | `ExternalPlugin.RemoveDrafts()` | Community | +| `Plugin.ContentPage()` | `ExternalPlugin.ContentPage()` | Community (pageTypes) | +| `Plugin.FolderPage()` | `ExternalPlugin.FolderPage()` | Community (pageTypes) | +| `Plugin.TagPage()` | `ExternalPlugin.TagPage()` | Community (pageTypes) | +| `Plugin.NotFoundPage()` | `Plugin.PageTypes.NotFoundPageType()` | Internal (pageTypes) | +| `Plugin.ComponentResources()` | `Plugin.ComponentResources()` (unchanged) | Internal | +| `Plugin.Assets()` | `Plugin.Assets()` (unchanged) | Internal | +| `Plugin.Static()` | `Plugin.Static()` (unchanged) | Internal | +| `Plugin.AliasRedirects()` | `ExternalPlugin.AliasRedirects()` | Community | +| `Plugin.ContentIndex()` | `ExternalPlugin.ContentIndex()` | Community | + +Component layout mapping: + +| v4 Layout | v5 Layout | +| ----------------------------- | ------------------------------------------ | +| `Component.Explorer()` | `Plugin.Explorer()` | +| `Component.Graph()` | `Plugin.Graph()` | +| `Component.Search()` | `Plugin.Search()` | +| `Component.Backlinks()` | `Plugin.Backlinks()` | +| `Component.Darkmode()` | `Plugin.Darkmode()` | +| `Component.Footer()` | `Plugin.Footer()` | +| `Component.TableOfContents()` | `Plugin.TableOfContents()` | +| `Component.Head()` | `Component.Head()` (unchanged, internal) | +| `Component.Spacer()` | `Component.Spacer()` (unchanged, internal) | + +--- + +## Migrating from Quartz 3 + +As you already have Quartz locally, you don't need to fork or clone it again. Simply just checkout the v4 branch, install the dependencies, restore plugins, and import your old vault. Then follow the [Quartz 4 migration steps above](#migrating-from-quartz-4) to get to v5. + +```bash +git fetch +git checkout v4 +git pull upstream v4 +npm i +npx quartz plugin restore +npx quartz create +``` + +If you get an error like `fatal: 'upstream' does not appear to be a git repository`, make sure you add `upstream` as a remote origin: + +```shell +git remote add upstream https://github.com/jackyzha0/quartz.git +``` + +When running `npx quartz create`, you will be prompted as to how to initialize your content folder. Here, you can choose to import or link your previous content folder and Quartz should work just as you expect it to. + +> [!note] +> If the existing content folder you'd like to use is at the _same_ path on a different branch, clone the repo again somewhere at a _different_ path in order to use it. + +### Key changes from Quartz 3 + +1. **Removing Hugo and `hugo-obsidian`**: Hugo worked well for earlier versions of Quartz but it also made it hard for people outside of the Golang and Hugo communities to fully understand what Quartz was doing under the hood and be able to properly customize it to their needs. Quartz now uses a Node-based static-site generation process which should lead to much more helpful error messages and an overall smoother user experience. +2. **Full-hot reload**: The many rough edges of how `hugo-obsidian` integrated with Hugo meant that watch mode didn't re-trigger `hugo-obsidian` to update the content index. This lead to a lot of weird cases where the watch mode output wasn't accurate. Quartz now uses a cohesive parse, filter, and emit pipeline which gets run on every change so hot-reloads are always accurate. +3. **Replacing Go template syntax with JSX**: Quartz 3 used [Go templates](https://pkg.go.dev/text/template) to create layouts for pages. However, the syntax isn't great for doing any sort of complex rendering (like [text processing](https://github.com/jackyzha0/quartz/blob/hugo/layouts/partials/textprocessing.html)) and it got very difficult to make any meaningful layout changes to Quartz 3. Quartz now uses an extension of JavaScript syntax called JSX which allows you to write layout code that looks like HTML in JavaScript which is significantly easier to understand and maintain. +4. **A new extensible [[configuration]] and [[configuration#Plugins|plugin]] system**: Quartz 3 was hard to configure without technical knowledge of how Hugo's partials worked. Extensions were even hard to make. Quartz 5's configuration and plugin system is designed to be extended by users while making updating to new versions of Quartz easy. + +### Things to update + +- You will need to update your deploy scripts. See the [[hosting]] guide for more details. +- Ensure that your default branch on GitHub is updated from `hugo` to `v5`. +- [[folder and tag listings|Folder and tag listings]] have also changed. + - Folder descriptions should go under `content//index.md` where `` is the name of the folder. + - Tag descriptions should go under `content/tags/.md` where `` is the name of the tag. +- Some HTML layout may not be the same between Quartz 3 and Quartz 5. If you depended on a particular HTML hierarchy or class names, you may need to update your custom CSS to reflect these changes. +- If you customized the layout of Quartz 3, you may need to translate these changes from Go templates back to JSX as Quartz 5 no longer uses Hugo. For components, check out the guide on [[creating components]] for more details on this. diff --git a/docs/getting-started/upgrading.md b/docs/getting-started/upgrading.md new file mode 100644 index 000000000..d85e16f7e --- /dev/null +++ b/docs/getting-started/upgrading.md @@ -0,0 +1,40 @@ +--- +title: "Upgrading Quartz" +aliases: + - upgrading +--- + +> [!note] +> This is specifically a guide for upgrading your Quartz to a more recent update. If you are coming from Quartz 4 or Quartz 3, check out the [[getting-started/migrating|migration guide]] for more info. + +To fetch the latest Quartz updates, simply run + +```bash +npx quartz upgrade +``` + +As Quartz uses [git](https://git-scm.com/) under the hood for versioning, upgrading effectively 'pulls' in the updates from the official Quartz GitHub repository. If you have local changes that might conflict with the updates, you may need to resolve these manually yourself (or, pull manually using `git pull origin upstream`). + +> [!hint] +> Quartz will try to cache your content before upgrading to try and prevent merge conflicts. If you get a conflict mid-merge, you can stop the merge and then run `npx quartz restore` to restore your content from the cache. + +If you have the [GitHub desktop app](https://desktop.github.com/), this will automatically open to help you resolve the conflicts. Otherwise, you will need to resolve this in a text editor like VSCode. For more help on resolving conflicts manually, check out the [GitHub guide on resolving merge conflicts](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line#competing-line-change-merge-conflicts). + +To update your installed plugins separately, use: + +```bash +npx quartz update +``` + +See the [[cli/update|CLI reference for update]] and [[cli/upgrade|CLI reference for upgrade]] for more details on available flags. + +### Cleaning Up Unused Plugins + +If you've removed plugins from your configuration during an upgrade, you can clean up the leftover files: + +```bash +npx quartz plugin prune --dry-run # preview what would be removed +npx quartz plugin prune # remove orphaned plugins +``` + +See the [[cli/plugin#prune|plugin prune reference]] for more details. diff --git a/docs/hosting.md b/docs/hosting.md index 7e50f6c4d..cc6fcd078 100644 --- a/docs/hosting.md +++ b/docs/hosting.md @@ -12,25 +12,31 @@ However, if you'd like to publish your site to the world, you need a way to host > [!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 restore` to install plugins from the lockfile. If contributors may add plugins to `quartz.config.yaml` without updating the lockfile, add `npx quartz plugin resolve` after `restore` in your build command to install any missing plugins. See [[cli/plugin#resolve|plugin resolve]] for details. + ## Cloudflare Pages 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 | `v4` | -| Framework preset | `None` | -| Build command | `npx quartz build` | -| Build output directory | `public` | +| Configuration option | Value | +| ---------------------- | ----------------------------------------------- | +| Production branch | `v5` | +| Framework preset | `None` | +| Build command | `npx quartz plugin restore && 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 build`). +> Cloudflare Pages performs a shallow clone by default, so if you rely on `git` for timestamps, it is recommended that you add `git fetch --unshallow &&` to the beginning of the build command (e.g., `git fetch --unshallow && npx quartz plugin restore && npx quartz build`). + +> [!note] +> For more detailed CI/CD configuration including caching and plugin management, see [[ci-cd]]. ## GitHub Pages @@ -42,7 +48,7 @@ name: Deploy Quartz site to GitHub Pages on: push: branches: - - v4 + - v5 permissions: contents: read @@ -65,6 +71,8 @@ jobs: node-version: 22 - name: Install Dependencies run: npm ci + - name: Restore Quartz plugins + run: npx quartz plugin restore - name: Build Quartz run: npx quartz build - name: Upload artifact @@ -140,11 +148,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 build` | +| Configuration option | Value | +| ----------------------------------------- | ----------------------------------------------- | +| Framework Preset | `Other` | +| Root Directory | `./` | +| Build and Output Settings > Build Command | `npx quartz plugin restore && npx quartz build` | 5. Press Deploy. Once it's live, you'll have 2 `*.vercel.app` URLs to view the page. @@ -153,7 +161,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.js` if necessary. +1. Update the `baseUrl` in `quartz.config.yaml` 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. @@ -165,7 +173,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.js` if necessary. +1. Update the `baseUrl` in `quartz.config.yaml` 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 @@ -175,7 +183,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 build`. +3. Under "Build command", enter `npx quartz plugin restore && 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. @@ -198,11 +206,12 @@ cache: # Cache modules in between jobs build: stage: build rules: - - if: '$CI_COMMIT_REF_NAME == "v4"' + - if: '$CI_COMMIT_REF_NAME == "v5"' before_script: - hash -r - npm ci --cache .npm --prefer-offline script: + - npx quartz plugin restore - npx quartz build artifacts: paths: @@ -213,7 +222,7 @@ build: pages: stage: deploy rules: - - if: '$CI_COMMIT_REF_NAME == "v4"' + - if: '$CI_COMMIT_REF_NAME == "v5"' script: - echo "Deploying to GitLab Pages..." artifacts: diff --git a/docs/index.md b/docs/index.md index bdd12f6dc..4a9c343db 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,5 @@ --- -title: Welcome to Quartz 4 +title: Welcome to Quartz 5 --- Quartz is a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites. Thousands of students, developers, and teachers are [[showcase|already using Quartz]] to publish personal notes, websites, and [digital gardens](https://jzhao.xyz/posts/networked-thought) to the web. @@ -11,13 +11,14 @@ Quartz requires **at least [Node](https://nodejs.org/) v22** and `npm` v10.9.2 t Then, in your terminal of choice, enter the following commands line by line: ```shell -git clone https://github.com/jackyzha0/quartz.git +git clone -b v5 https://github.com/jackyzha0/quartz.git cd quartz npm i +npx quartz plugin restore npx quartz create ``` -This will guide you through initializing your Quartz with content. Once you've done so, see how to: +This will guide you through initializing your Quartz with content, including choosing a [[cli/create#templates|project template]] and configuring your site's base URL. Once you've done so, see how to: 1. [[authoring content|Writing content]] in Quartz 2. [[configuration|Configure]] Quartz's behaviour @@ -26,9 +27,6 @@ This will guide you through initializing your Quartz with content. Once you've d 5. Sync your changes with [[setting up your GitHub repository|GitHub]] 6. [[hosting|Host]] Quartz online -If you prefer instructions in a video format you can try following Nicole van der Hoeven's -[video guide on how to set up Quartz!](https://www.youtube.com/watch?v=6s6DT1yN4dw&t=227s) - ## 🔧 Features - [[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 @@ -41,6 +39,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. 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 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. -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). +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. diff --git a/docs/layout-components.md b/docs/layout-components.md index 9a0b6396d..ca8c68f69 100644 --- a/docs/layout-components.md +++ b/docs/layout-components.md @@ -4,20 +4,93 @@ 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 // 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 + 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" @@ -25,24 +98,8 @@ 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 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 { @@ -50,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 -Component.DesktopOnly(Component.TableOfContents()) +```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 = { @@ -81,22 +190,5 @@ type ConditionalRenderConfig = { } ``` -### 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. +> [!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 3f73753f5..31bfea790 100644 --- a/docs/layout.md +++ b/docs/layout.md @@ -2,7 +2,12 @@ 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. The default page layouts can be found in `quartz.layout.ts`. +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]]. 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: @@ -31,14 +36,160 @@ 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 `` [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 4 doesn't place any components in the `header`. +> 2. `header` is a set of components that are laid out horizontally and appears _before_ the `beforeBody` section. This enables you to replicate the old Quartz 3 header bar where the title, search bar, and dark mode toggle. By default, Quartz doesn't place any components in the `header`. -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. +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: -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. +```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 + +layout: + groups: + toolbar: + direction: row + gap: 0.5rem + byPageType: + content: {} + folder: + exclude: + - reader-mode + positions: + right: [] + tag: + exclude: + - reader-mode + positions: + right: [] + "404": + positions: + beforeBody: [] + left: [] + right: [] +``` + +For advanced layout overrides using TypeScript (e.g. custom component wrappers or conditional logic), you can use the TS override in `quartz.ts`: + +```ts title="quartz.ts" +import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader" + +const config = await loadQuartzConfig() +export default config +export const layout = await loadQuartzLayout({ + defaults: { + // override default layout for all page types + }, + byPageType: { + content: { + // override layout for content pages only + }, + folder: { + // override layout for folder pages only + }, + }, +}) +``` + +Fields defined in `defaults` can be overridden by specific entries in `byPageType`. + +Community component plugins are installed via `npx quartz plugin add github:quartz-community/`. See [[layout-components]] for built-in layout utilities (Flex, MobileOnly, DesktopOnly, etc.). You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz. +### 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..template` in `quartz.config.yaml` +2. **Plugin-registered frame**: Frames registered by plugins via the Frame Registry (loaded from the plugin's `frames` export) +3. **Plugin declaration**: The `frame` property set in the page type plugin's source code +4. **Fallback**: `"default"` + +For example, to override canvas pages to use the minimal frame: + +```yaml title="quartz.config.yaml" +layout: + byPageType: + canvas: + template: minimal +``` + +#### Custom frames + +There are two ways to provide custom frames: + +**1. Plugin-provided frames (recommended for reusable frames):** + +Plugins can ship their own frames by declaring them in `package.json` and exporting them from a `./frames` subpath. See [[making plugins#Providing Custom Frames|the plugin guide]] for details. When a plugin with frames is installed, its frames are automatically registered in the Frame Registry and available by name. + +**2. Core frames (for project-specific frames):** + +You can also create frames directly in `quartz/components/frames/` by implementing the `PageFrame` interface and registering the frame in `quartz/components/frames/index.ts`. See the [[advanced/architecture|architecture overview]] for the full `PageFrame` interface. + +Frames are applied as a `data-frame` attribute on the `.page` element, which you can target in CSS: + +```scss +.page[data-frame="my-frame"] > #quartz-body { + /* custom grid layout */ +} +``` + +Frame CSS should be scoped with `[data-frame="name"]` selectors to avoid conflicts with other frames. + ### Layout breakpoints Quartz has different layouts depending on the width the screen viewing the website. @@ -58,9 +209,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 4, like Quartz 3, 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 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! 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. +> 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. diff --git a/docs/migrating from Quartz 3.md b/docs/migrating from Quartz 3.md deleted file mode 100644 index 2fdc73155..000000000 --- a/docs/migrating from Quartz 3.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -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//index.md` where `` is the name of the folder. - - Tag descriptions should go under `content/tags/.md` where `` 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. diff --git a/docs/philosophy.md b/docs/philosophy.md index af5510aac..5eea40078 100644 --- a/docs/philosophy.md +++ b/docs/philosophy.md @@ -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.ts` and `quartz.layout.ts` 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.yaml` 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 diff --git a/docs/plugins/AliasRedirects.md b/docs/plugins/AliasRedirects.md index 8c0365377..f8a48fd83 100644 --- a/docs/plugins/AliasRedirects.md +++ b/docs/plugins/AliasRedirects.md @@ -33,5 +33,6 @@ This plugin has no configuration options. ## API - Category: Emitter -- Function name: `Plugin.AliasRedirects()`. -- Source: [`quartz/plugins/emitters/aliases.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/aliases.ts). +- 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` diff --git a/docs/plugins/ArticleTitle.md b/docs/plugins/ArticleTitle.md new file mode 100644 index 000000000..742377520 --- /dev/null +++ b/docs/plugins/ArticleTitle.md @@ -0,0 +1,19 @@ +--- +title: ArticleTitle +tags: + - plugin/component +--- + +This plugin renders the article title from the page's frontmatter as an `

` 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` diff --git a/docs/plugins/Assets.md b/docs/plugins/Assets.md index 47589b2c3..6915a4926 100644 --- a/docs/plugins/Assets.md +++ b/docs/plugins/Assets.md @@ -16,5 +16,5 @@ This plugin has no configuration options. ## API - Category: Emitter -- Function name: `Plugin.Assets()`. -- Source: [`quartz/plugins/emitters/assets.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/assets.ts). +- Function name: `Plugin.Assets()` (internal plugin). +- Source: [`quartz/plugins/emitters/assets.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/emitters/assets.ts). diff --git a/docs/plugins/Backlinks.md b/docs/plugins/Backlinks.md new file mode 100644 index 000000000..78c13aa38 --- /dev/null +++ b/docs/plugins/Backlinks.md @@ -0,0 +1,34 @@ +--- +title: Backlinks +tags: + - plugin/component +--- + +Shows pages that link to the current page. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[backlinks]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `hideWhenEmpty`: Hide the backlinks section if the current page has no backlinks. Defaults to `true`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/backlinks + enabled: true + options: + hideWhenEmpty: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.Backlinks()`. +- Source: [`quartz-community/backlinks`](https://github.com/quartz-community/backlinks) +- Install: `npx quartz plugin add github:quartz-community/backlinks` diff --git a/docs/plugins/BasesPage.md b/docs/plugins/BasesPage.md new file mode 100644 index 000000000..e195fe524 --- /dev/null +++ b/docs/plugins/BasesPage.md @@ -0,0 +1,60 @@ +--- +title: BasesPage +tags: + - plugin/pageType + - plugin/component +--- + +This plugin provides support for [Obsidian Bases](https://obsidian.md/changelog/2025-04-15-desktop-v1.8.0/) (`.base` files) in Quartz. It reads `.base` files from your vault, resolves matching notes based on the query definition, and renders them as interactive database-like views with support for tables, lists, cards, and maps. It uses the `default` [[layout#Page Frames|page frame]] (three-column layout with sidebars). + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +## Features + +- **Table view**: Sortable columns with automatic type rendering (strings, numbers, booleans, arrays, links). +- **List view**: Compact list with metadata chips for each entry. +- **Cards view**: Card layout with optional image property support. +- **Map view**: Placeholder for future map-based visualization. +- **Multiple views**: A single `.base` file can define multiple views, displayed as switchable tabs. +- **Filters**: Recursive filter trees with `and`/`or`/`not` operators. +- **Formulas**: Computed properties via formula expressions. +- **Summaries**: Column-level aggregations (Sum, Average, Min, Max, Median, etc.). +- **Property configuration**: Custom display names for properties. +- **Link rendering**: Wikilinks and Markdown links within cell values are rendered as clickable links. + +## Configuration + +This plugin accepts the following configuration options: + +- `defaultViewType`: The default view type when none is specified in the `.base` file. Defaults to `"table"`. +- `customViews`: A map of custom view renderers. Keys are view type names. These override built-in renderers for the same type, or add new view types. Requires a TS override. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/bases-page + enabled: true +``` + +For custom view renderers, use a TS override in `quartz.ts`: + +```ts title="quartz.ts (override)" +import * as ExternalPlugin from "./.quartz/plugins" + +ExternalPlugin.BasesPage({ + defaultViewType: "table", + customViews: { + myView: ({ entries, view, basesData, total, locale }) => { + // return JSX + }, + }, +}) +``` + +## API + +- Category: Page Type, Component +- Function name: `ExternalPlugin.BasesPage()`. +- Source: [`quartz-community/bases-page`](https://github.com/quartz-community/bases-page) +- Install: `npx quartz plugin add github:quartz-community/bases-page` diff --git a/docs/plugins/Breadcrumbs.md b/docs/plugins/Breadcrumbs.md new file mode 100644 index 000000000..3f41aa0a1 --- /dev/null +++ b/docs/plugins/Breadcrumbs.md @@ -0,0 +1,40 @@ +--- +title: Breadcrumbs +tags: + - plugin/component +--- + +Navigation breadcrumb trail. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[breadcrumbs]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `spacerSymbol`: The symbol to use between breadcrumb items. Defaults to `"❯"`. +- `rootName`: The name of the root page. Defaults to `Home`. +- `resolveFrontmatterTitle`: Whether to use the `title` frontmatter field for breadcrumb items. Defaults to `true`. +- `showCurrentPage`: Whether to show the current page in the breadcrumb trail. Defaults to `true`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/breadcrumbs + enabled: true + options: + spacerSymbol: "❯" + rootName: Home + resolveFrontmatterTitle: true + showCurrentPage: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.Breadcrumbs()`. +- Source: [`quartz-community/breadcrumbs`](https://github.com/quartz-community/breadcrumbs) +- Install: `npx quartz plugin add github:quartz-community/breadcrumbs` diff --git a/docs/plugins/CNAME.md b/docs/plugins/CNAME.md index bc12b5acc..a84d1b750 100644 --- a/docs/plugins/CNAME.md +++ b/docs/plugins/CNAME.md @@ -18,5 +18,6 @@ This plugin has no configuration options. ## API - Category: Emitter -- Function name: `Plugin.CNAME()`. -- Source: [`quartz/plugins/emitters/cname.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/cname.ts). +- Function name: `ExternalPlugin.CNAME()`. +- Source: [`quartz-community/cname`](https://github.com/quartz-community/cname) +- Install: `npx quartz plugin add github:quartz-community/cname` diff --git a/docs/plugins/CanvasPage.md b/docs/plugins/CanvasPage.md new file mode 100644 index 000000000..3bbea0b3a --- /dev/null +++ b/docs/plugins/CanvasPage.md @@ -0,0 +1,53 @@ +--- +title: CanvasPage +tags: + - plugin/pageType +--- + +This plugin is a page type plugin that renders [JSON Canvas](https://jsoncanvas.org) (`.canvas`) files as interactive, pannable and zoomable canvas pages. It uses a custom `"canvas"` [[layout#Page Frames|page frame]] that provides a fullscreen, always-on canvas experience with a togglable left sidebar for navigation. It supports the full [JSON Canvas 1.0 spec](https://jsoncanvas.org/spec/1.0/), including text nodes with Markdown rendering, file nodes that link to other pages in your vault, link nodes for external URLs, and group nodes for visual organization. Edges between nodes are rendered as SVG paths with optional labels, arrow markers, and colors. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +This plugin accepts the following configuration options: + +- `enableInteraction`: Whether to enable pan and zoom interaction on the canvas. Default: `true{:ts}`. +- `initialZoom`: The initial zoom level when the canvas is first displayed. Default: `1{:ts}`. +- `minZoom`: The minimum zoom level allowed when zooming out. Default: `0.1{:ts}`. +- `maxZoom`: The maximum zoom level allowed when zooming in. Default: `5{:ts}`. + +### Canvas Frame + +The canvas-page plugin provides its own `"canvas"` page frame via the [[layout#Page Frames|Frame Registry]]. This frame: + +- Renders the canvas in **fullscreen mode** by default (100vw × 100vh), giving the canvas maximum screen space — leaning into the "endless canvas" concept of JSON Canvas. +- Provides a **togglable left sidebar** that slides in from the left edge. This is the only layout slot available — it renders the same components as the `left` sidebar on content pages (e.g., Explorer, Search, Page Title). +- The sidebar toggle button (hamburger/close icon) is positioned in the top-left corner. +- Canvas controls (zoom in, zoom out, reset) are positioned on the right side. +- On mobile, the sidebar overlays the canvas rather than pushing it aside. + +Users can override this frame via `quartz.config.yaml` if needed: + +```yaml title="quartz.config.yaml" +layout: + byPageType: + canvas: + template: default # Use standard three-column layout instead +``` + +### Features + +- **Text nodes**: Render Markdown content including headings, bold, italic, strikethrough, lists, links, and code blocks via [GFM](https://github.github.com/gfm/) support. +- **File nodes**: Link to other pages in your vault. Supports popover previews on hover. +- **Link nodes**: Reference external URLs. +- **Group nodes**: Visual grouping containers with optional labels and background colors. +- **Edges**: SVG connections between nodes with optional labels, arrow markers, and colors. Supports all four sides (top, right, bottom, left) and both preset colors (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` diff --git a/docs/plugins/Citations.md b/docs/plugins/Citations.md index b1a63a037..9a207ccad 100644 --- a/docs/plugins/Citations.md +++ b/docs/plugins/Citations.md @@ -20,5 +20,6 @@ This plugin accepts the following configuration options: ## API - Category: Transformer -- Function name: `Plugin.Citations()`. -- Source: [`quartz/plugins/transformers/citations.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/citations.ts). +- Function name: `ExternalPlugin.Citations()`. +- Source: [`quartz-community/citations`](https://github.com/quartz-community/citations) +- Install: `npx quartz plugin add github:quartz-community/citations` diff --git a/docs/plugins/Comments.md b/docs/plugins/Comments.md new file mode 100644 index 000000000..e2a127e73 --- /dev/null +++ b/docs/plugins/Comments.md @@ -0,0 +1,53 @@ +--- +title: Comments +tags: + - plugin/component +--- + +Comment system (giscus, utterances, etc.). + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[comments]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `provider`: The comment provider to use. Currently only `giscus` is supported. +- `options`: Provider-specific options. + - `repo`: The GitHub repository to use for comments. + - `repoId`: The ID of the GitHub repository. + - `category`: The discussion category to use. + - `categoryId`: The ID of the discussion category. + - `lang`: The language for the comment system. Defaults to `en`. + - `themeUrl`: URL to a folder with custom themes. + - `lightTheme`: Filename for the light theme CSS file. Defaults to `light`. + - `darkTheme`: Filename for the dark theme CSS file. Defaults to `dark`. + - `mapping`: How to map pages to discussions. Defaults to `url`. + - `strict`: Use strict title matching. Defaults to `true`. + - `reactionsEnabled`: Whether to enable reactions for the main post. Defaults to `true`. + - `inputPosition`: Where to put the comment input box relative to the comments. Defaults to `bottom`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/comments + enabled: true + options: + provider: giscus + options: + repo: jackyzha0/quartz + repoId: MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg + category: Announcements + categoryId: DIC_kwDOFxRnmM4B-Xg6 + lang: en +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.Comments()`. +- Source: [`quartz-community/comments`](https://github.com/quartz-community/comments) +- Install: `npx quartz plugin add github:quartz-community/comments` diff --git a/docs/plugins/ComponentResources.md b/docs/plugins/ComponentResources.md index 6e8c82ef8..71625691e 100644 --- a/docs/plugins/ComponentResources.md +++ b/docs/plugins/ComponentResources.md @@ -14,5 +14,5 @@ This plugin has no configuration options. ## API - Category: Emitter -- Function name: `Plugin.ComponentResources()`. -- Source: [`quartz/plugins/emitters/componentResources.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/componentResources.ts). +- Function name: `Plugin.ComponentResources()` (internal plugin). +- Source: [`quartz/plugins/emitters/componentResources.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/emitters/componentResources.ts). diff --git a/docs/plugins/ContentIndex.md b/docs/plugins/ContentIndex.md index 037f723bf..a7b560a6e 100644 --- a/docs/plugins/ContentIndex.md +++ b/docs/plugins/ContentIndex.md @@ -23,5 +23,6 @@ This plugin accepts the following configuration options: ## API - Category: Emitter -- Function name: `Plugin.ContentIndex()`. -- Source: [`quartz/plugins/emitters/contentIndex.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/contentIndex.ts). +- 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` diff --git a/docs/plugins/ContentMeta.md b/docs/plugins/ContentMeta.md new file mode 100644 index 000000000..0a5ff943a --- /dev/null +++ b/docs/plugins/ContentMeta.md @@ -0,0 +1,34 @@ +--- +title: ContentMeta +tags: + - plugin/component +--- + +This plugin displays content metadata below the article title, such as the creation date and estimated reading time. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +## Configuration + +This plugin accepts the following configuration options: + +- `showReadingTime`: Whether to display the estimated reading time. Defaults to `true`. +- `showComma`: Whether to display a comma between metadata items. Defaults to `true`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/content-meta + enabled: true + options: + showReadingTime: true + showComma: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.ContentMeta()`. +- Source: [`quartz-community/content-meta`](https://github.com/quartz-community/content-meta) +- Install: `npx quartz plugin add github:quartz-community/content-meta` diff --git a/docs/plugins/ContentPage.md b/docs/plugins/ContentPage.md index bd33e4ee1..7e71d20ae 100644 --- a/docs/plugins/ContentPage.md +++ b/docs/plugins/ContentPage.md @@ -1,10 +1,10 @@ --- title: ContentPage tags: - - plugin/emitter + - plugin/pageType --- -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. +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`. > [!note] > For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. @@ -13,6 +13,7 @@ This plugin has no configuration options. ## API -- Category: Emitter -- Function name: `Plugin.ContentPage()`. -- Source: [`quartz/plugins/emitters/contentPage.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/contentPage.tsx). +- 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` diff --git a/docs/plugins/CrawlLinks.md b/docs/plugins/CrawlLinks.md index 47b7bdd77..3c5aa281a 100644 --- a/docs/plugins/CrawlLinks.md +++ b/docs/plugins/CrawlLinks.md @@ -26,5 +26,6 @@ This plugin accepts the following configuration options: ## API - Category: Transformer -- Function name: `Plugin.CrawlLinks()`. -- Source: [`quartz/plugins/transformers/links.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/links.ts). +- 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` diff --git a/docs/plugins/CreatedModifiedDate.md b/docs/plugins/CreatedModifiedDate.md index 2d1eaeec1..ba04e9531 100644 --- a/docs/plugins/CreatedModifiedDate.md +++ b/docs/plugins/CreatedModifiedDate.md @@ -16,12 +16,13 @@ This plugin accepts the following configuration options: 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 `quartz.config.ts`. +> If you rely on `git` for dates, make sure `defaultDateType` is set to `modified` in `quartz.config.yaml`. > > 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: `Plugin.CreatedModifiedDate()`. -- Source: [`quartz/plugins/transformers/lastmod.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/lastmod.ts). +- 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` diff --git a/docs/plugins/CustomOgImages.md b/docs/plugins/CustomOgImages.md index 4b5bf0391..570e16db3 100644 --- a/docs/plugins/CustomOgImages.md +++ b/docs/plugins/CustomOgImages.md @@ -25,22 +25,29 @@ The Custom OG Images emitter plugin generates social media preview images for yo This plugin accepts the following configuration options: -```typescript title="quartz.config.ts" -import { CustomOgImages } from "./quartz/plugins/emitters/ogImage" +```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 +``` -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 - }), - ], - }, -} +For the TS override approach (needed for custom `imageStructure`): + +```ts title="quartz.ts (override)" +import { defaultImage } from "./quartz/plugins/emitters/ogImage" + +CustomOgImages({ + colorScheme: "lightMode", + width: 1200, + height: 630, + excludeRoot: false, + imageStructure: defaultImage, // custom JSX component — requires TS +}) ``` ### Configuration Options @@ -76,7 +83,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.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). +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). An example of a component using the header font could look like this: @@ -358,3 +365,10 @@ 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` diff --git a/docs/plugins/Darkmode.md b/docs/plugins/Darkmode.md new file mode 100644 index 000000000..1e9e372f8 --- /dev/null +++ b/docs/plugins/Darkmode.md @@ -0,0 +1,32 @@ +--- +title: Darkmode +tags: + - plugin/component +--- + +Dark mode toggle. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[darkmode]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `enabled`: Whether to enable the dark mode toggle. Defaults to `true`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/darkmode + enabled: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.Darkmode()`. +- Source: [`quartz-community/darkmode`](https://github.com/quartz-community/darkmode) +- Install: `npx quartz plugin add github:quartz-community/darkmode` diff --git a/docs/plugins/Description.md b/docs/plugins/Description.md index af1c8b7c2..a2d79591c 100644 --- a/docs/plugins/Description.md +++ b/docs/plugins/Description.md @@ -19,5 +19,6 @@ This plugin accepts the following configuration options: ## API - Category: Transformer -- Function name: `Plugin.Description()`. -- Source: [`quartz/plugins/transformers/description.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/description.ts). +- Function name: `ExternalPlugin.Description()`. +- Source: [`quartz-community/description`](https://github.com/quartz-community/description) +- Install: `npx quartz plugin add github:quartz-community/description` diff --git a/docs/plugins/EncryptedPages Demo.md b/docs/plugins/EncryptedPages Demo.md new file mode 100644 index 000000000..011ac31fb --- /dev/null +++ b/docs/plugins/EncryptedPages Demo.md @@ -0,0 +1,25 @@ +--- +title: Encrypted Pages Demo +password: quartz +tags: + - plugin/transformer +--- + +Congratulations! You've successfully decrypted this page. 🎉 + +This is a live demo of the [[EncryptedPages]] plugin. The content you're reading was encrypted at build time using AES-256-GCM and decrypted in your browser using the Web Crypto API. + +## What just happened? + +1. At build time, the plugin read the `password` field from this page's frontmatter and encrypted all content below the title. +2. When you visited this page, you were shown a password prompt instead of the page content. +3. After entering the correct password, the plugin derived an encryption key using PBKDF2 and decrypted the content client-side. +4. A `render` event was dispatched so other components (graph, explorer, etc.) could re-initialize with the decrypted content. + +## Password caching + +Your password has been cached in session storage. If there were other encrypted pages on this site, the plugin would automatically try this password before showing the prompt — so you'd only need to enter it once per session for pages that share the same password. + +## Try it yourself + +To add encrypted pages to your own Quartz site, install the plugin and add a `password` field to any page's frontmatter. See [[EncryptedPages]] for full setup instructions. diff --git a/docs/plugins/EncryptedPages.md b/docs/plugins/EncryptedPages.md new file mode 100644 index 000000000..667193955 --- /dev/null +++ b/docs/plugins/EncryptedPages.md @@ -0,0 +1,72 @@ +--- +title: EncryptedPages +tags: + - plugin/transformer + - plugin/filter +--- + +Password-protected encrypted pages. Encrypts page content at build time using AES-256-GCM and decrypts client-side with the Web Crypto API. Passwords are set per-page via frontmatter. + +> [!example] Live demo +> Try it yourself: [[EncryptedPages Demo]]. The password is `quartz`. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +## Usage + +Add a `password` field to any page's frontmatter to encrypt it: + +```yaml +--- +title: My Secret Page +password: mysecretpassword +--- +``` + +The page content will be encrypted at build time. Visitors must enter the correct password to view the content. + +Successful passwords are cached in the browser's session storage and automatically tried on other encrypted pages for convenience. + +## Configuration + +This plugin provides a transformer, a filter, and a component. + +### Transformer options + +- `visibility`: How encrypted pages appear in graph, explorer, and backlinks. `"visible"` shows the page normally, `"icon"` adds a lock indicator, `"hidden"` hides the page completely. Defaults to `"icon"`. +- `iterations`: PBKDF2 iteration count for key derivation. Higher values are more secure but slower to unlock. Defaults to `600000`. +- `passwordField`: Frontmatter field name that holds the page password. Defaults to `"password"`. + +### Filter options + +- `visibility`: Controls whether encrypted pages appear in search, RSS, and sitemap. When set to `"hidden"`, encrypted pages are excluded from content indices entirely. Defaults to `"icon"`. + +### Component options + +- `className`: CSS class for the component wrapper. Defaults to `"encrypted-page-wrapper"`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/encrypted-pages + enabled: true + options: + visibility: icon + iterations: 600000 + passwordField: password +``` + +## Security + +- Content is encrypted with AES-256-GCM using PBKDF2 SHA-256 key derivation. +- Plaintext is stripped from search indices and RSS feeds regardless of visibility setting. +- Passwords are set per-page in frontmatter. Avoid committing passwords to public repositories. +- This is client-side encryption of a static site. It protects against casual browsing but not against determined attackers with access to the page source. + +## API + +- Category: Transformer, Filter +- Function name: `ExternalPlugin.EncryptedPages()`, `ExternalPlugin.EncryptedPageFilter()`. +- Source: [`quartz-community/encrypted-pages`](https://github.com/quartz-community/encrypted-pages) +- Install: `npx quartz plugin add github:quartz-community/encrypted-pages` diff --git a/docs/plugins/ExplicitPublish.md b/docs/plugins/ExplicitPublish.md index 2fd929b92..42aae3b52 100644 --- a/docs/plugins/ExplicitPublish.md +++ b/docs/plugins/ExplicitPublish.md @@ -14,5 +14,6 @@ This plugin has no configuration options. ## API - Category: Filter -- Function name: `Plugin.ExplicitPublish()`. -- Source: [`quartz/plugins/filters/explicit.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/filters/explicit.ts). +- 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` diff --git a/docs/plugins/Explorer.md b/docs/plugins/Explorer.md new file mode 100644 index 000000000..66a8ea4a5 --- /dev/null +++ b/docs/plugins/Explorer.md @@ -0,0 +1,40 @@ +--- +title: Explorer +tags: + - plugin/component +--- + +File tree explorer sidebar. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[explorer]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `title`: The title of the explorer. Defaults to `Explorer`. +- `folderClickBehavior`: The behavior when a folder is clicked. Can be `"link"` to navigate or `"collapse"` to toggle. Defaults to `collapse`. +- `folderDefaultState`: The default state of folders. Can be `"collapsed"` or `"open"`. Defaults to `collapsed`. +- `useSavedState`: Whether to use local storage to save the state of the explorer. Defaults to `true`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/explorer + enabled: true + options: + title: Explorer + folderClickBehavior: collapse + folderDefaultState: collapsed + useSavedState: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.Explorer()`. +- Source: [`quartz-community/explorer`](https://github.com/quartz-community/explorer) +- Install: `npx quartz plugin add github:quartz-community/explorer` diff --git a/docs/plugins/Favicon.md b/docs/plugins/Favicon.md index a6d4d4e1b..488f6b562 100644 --- a/docs/plugins/Favicon.md +++ b/docs/plugins/Favicon.md @@ -15,5 +15,6 @@ This plugin has no configuration options. ## API - Category: Emitter -- Function name: `Plugin.Favicon()`. -- Source: [`quartz/plugins/emitters/favicon.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/favicon.ts). +- Function name: `ExternalPlugin.Favicon()`. +- Source: [`quartz-community/favicon`](https://github.com/quartz-community/favicon) +- Install: `npx quartz plugin add github:quartz-community/favicon` diff --git a/docs/plugins/FolderPage.md b/docs/plugins/FolderPage.md index 45cfa1574..dda680047 100644 --- a/docs/plugins/FolderPage.md +++ b/docs/plugins/FolderPage.md @@ -1,24 +1,23 @@ --- title: FolderPage tags: - - plugin/emitter + - plugin/pageType --- -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. +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. 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: - `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: Emitter -- Function name: `Plugin.FolderPage()`. -- Source: [`quartz/plugins/emitters/folderPage.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/folderPage.tsx). +- 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` diff --git a/docs/plugins/Footer.md b/docs/plugins/Footer.md new file mode 100644 index 000000000..b57027447 --- /dev/null +++ b/docs/plugins/Footer.md @@ -0,0 +1,34 @@ +--- +title: Footer +tags: + - plugin/component +--- + +This plugin renders a footer at the bottom of the page with a "Created with Quartz" message and a set of configurable links. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +## Configuration + +This plugin accepts the following configuration options: + +- `links`: A map of link labels to their URLs to display in the footer. Defaults to `{}`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/footer + enabled: true + options: + links: + GitHub: https://github.com/jackyzha0/quartz + Discord Community: https://discord.gg/cRFFHYye7t +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.Footer()`. +- Source: [`quartz-community/footer`](https://github.com/quartz-community/footer) +- Install: `npx quartz plugin add github:quartz-community/footer` diff --git a/docs/plugins/Frontmatter.md b/docs/plugins/Frontmatter.md index 9dfe53378..73ce92809 100644 --- a/docs/plugins/Frontmatter.md +++ b/docs/plugins/Frontmatter.md @@ -1,72 +1,107 @@ --- title: "Frontmatter" +aliases: + - note-properties + - Note Properties +description: "Parses frontmatter and displays note properties in a collapsible panel." tags: - plugin/transformer + - plugin/component +publish: true +enableToc: true --- -This plugin parses the frontmatter of the page using the [gray-matter](https://github.com/jonschlinkert/gray-matter) library. 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 and optionally displays selected properties in a collapsible panel. 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`. -> [!warning] -> This plugin must not be removed, otherwise Quartz will break. +### Default options -## List +```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 +``` -Quartz supports the following frontmatter: +## Properties panel -- 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` +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. +- **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. Automatically slugified. | +| Aliases | `aliases`, `alias` | Alternative names for the page, used for link resolution. | +| Permalink | `permalink` | Custom URL slug. Also added to aliases. | +| CSS classes | `cssclasses`, `cssclass` | CSS classes applied to the page body. | +| Social image | `socialImage`, `image`, `cover` | Image used for social media previews. | +| Social description | `socialDescription` | Description used specifically for social media previews. | +| Created date | `created`, `date` | When the note was created. | +| Modified date | `modified`, `lastmod`, `updated`, `last-modified` | When the note was last modified. Falls back to `created` if unset. | +| Published date | `published`, `publishDate`, `date` | When the note was published. | +| Publish | `publish` | Whether the note should be published. | +| Draft | `draft` | Whether the note is a draft. | +| Comments | `comments` | Whether comments are enabled for the note. | +| Language | `lang` | Language code for the note. | +| Enable TOC | `enableToc` | Whether to show the table of contents. | ## API -- Category: Transformer -- Function name: `Plugin.Frontmatter()`. -- Source: [`quartz/plugins/transformers/frontmatter.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/frontmatter.ts). +- 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` diff --git a/docs/plugins/GitHubFlavoredMarkdown.md b/docs/plugins/GitHubFlavoredMarkdown.md index 41fab6b23..00b62edeb 100644 --- a/docs/plugins/GitHubFlavoredMarkdown.md +++ b/docs/plugins/GitHubFlavoredMarkdown.md @@ -19,5 +19,6 @@ This plugin accepts the following configuration options: ## API - Category: Transformer -- Function name: `Plugin.GitHubFlavoredMarkdown()`. -- Source: [`quartz/plugins/transformers/gfm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/gfm.ts). +- 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` diff --git a/docs/plugins/Graph.md b/docs/plugins/Graph.md new file mode 100644 index 000000000..54e1de8a5 --- /dev/null +++ b/docs/plugins/Graph.md @@ -0,0 +1,77 @@ +--- +title: Graph +tags: + - plugin/component +--- + +Interactive graph visualization. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[graph view]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `localGraph`: Options for the local graph view. +- `globalGraph`: Options for the global graph view. + +Both `localGraph` and `globalGraph` accept the following options: + +- `drag`: Enable dragging nodes. Defaults to `true`. +- `zoom`: Enable zooming. Defaults to `true`. +- `depth`: The depth of the graph. Defaults to `1` for local and `-1` for global. +- `scale`: The initial scale of the graph. +- `repelForce`: The force that pushes nodes apart. +- `centerForce`: The force that pulls nodes to the center. +- `linkDistance`: The distance between linked nodes. +- `fontSize`: The font size of node labels. +- `opacityScale`: The scale of node opacity. +- `removeTags`: Tags to exclude from the graph. +- `showTags`: Whether to show tags in the graph. +- `enableRadial`: Whether to enable radial layout. +- `focusOnHover`: Whether to focus on the hovered node (global only). + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/graph + enabled: true + options: + localGraph: + drag: true + zoom: true + depth: 1 + scale: 1.1 + repelForce: 0.5 + centerForce: 0.3 + linkDistance: 30 + fontSize: 0.6 + opacityScale: 1 + removeTags: [] + showTags: true + enableRadial: false + globalGraph: + drag: true + zoom: true + depth: -1 + scale: 0.9 + repelForce: 0.5 + centerForce: 0.3 + linkDistance: 30 + fontSize: 0.6 + opacityScale: 1 + removeTags: [] + showTags: true + focusOnHover: true + enableRadial: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.Graph()`. +- Source: [`quartz-community/graph`](https://github.com/quartz-community/graph) +- Install: `npx quartz plugin add github:quartz-community/graph` diff --git a/docs/plugins/HardLineBreaks.md b/docs/plugins/HardLineBreaks.md index e24f7e129..8ff56f0ef 100644 --- a/docs/plugins/HardLineBreaks.md +++ b/docs/plugins/HardLineBreaks.md @@ -14,5 +14,6 @@ This plugin has no configuration options. ## API - Category: Transformer -- Function name: `Plugin.HardLineBreaks()`. -- Source: [`quartz/plugins/transformers/linebreaks.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/linebreaks.ts). +- 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` diff --git a/docs/plugins/Latex.md b/docs/plugins/Latex.md index eb77db229..96ab855c8 100644 --- a/docs/plugins/Latex.md +++ b/docs/plugins/Latex.md @@ -17,5 +17,6 @@ This plugin accepts the following configuration options: ## API - Category: Transformer -- Function name: `Plugin.Latex()`. -- Source: [`quartz/plugins/transformers/latex.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/latex.ts). +- Function name: `ExternalPlugin.Latex()`. +- Source: [`quartz-community/latex`](https://github.com/quartz-community/latex) +- Install: `npx quartz plugin add github:quartz-community/latex` diff --git a/docs/plugins/NotFoundPage.md b/docs/plugins/NotFoundPage.md index b67994329..a881e9f6c 100644 --- a/docs/plugins/NotFoundPage.md +++ b/docs/plugins/NotFoundPage.md @@ -1,10 +1,10 @@ --- title: NotFoundPage tags: - - plugin/emitter + - plugin/pageType --- -This plugin emits a 404 (Not Found) page for broken or non-existent URLs. +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. > [!note] > For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. @@ -13,6 +13,6 @@ This plugin has no configuration options. ## API -- Category: Emitter -- Function name: `Plugin.NotFoundPage()`. -- Source: [`quartz/plugins/emitters/404.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/404.tsx). +- 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) diff --git a/docs/plugins/NoteProperties.md b/docs/plugins/NoteProperties.md new file mode 100644 index 000000000..29dd55f37 --- /dev/null +++ b/docs/plugins/NoteProperties.md @@ -0,0 +1,17 @@ +--- +title: NoteProperties +tags: + - plugin/component +--- + +The NoteProperties plugin is documented under [[Frontmatter]]. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +## API + +- Category: Component +- Function name: `ExternalPlugin.NoteProperties()`. +- Source: [`quartz-community/note-properties`](https://github.com/quartz-community/note-properties) +- Install: `npx quartz plugin add github:quartz-community/note-properties` diff --git a/docs/plugins/ObsidianFlavoredMarkdown.md b/docs/plugins/ObsidianFlavoredMarkdown.md index 277c7720b..a67a048d4 100644 --- a/docs/plugins/ObsidianFlavoredMarkdown.md +++ b/docs/plugins/ObsidianFlavoredMarkdown.md @@ -17,12 +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. Defaults to `false`. +- `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. - `disableBrokenWikilinks`: If `true`, replaces links to non-existent notes with a dimmed, disabled link. Defaults to `false`. > [!warning] @@ -31,5 +32,6 @@ This plugin accepts the following configuration options: ## API - Category: Transformer -- Function name: `Plugin.ObsidianFlavoredMarkdown()`. -- Source: [`quartz/plugins/transformers/ofm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/ofm.ts) +- 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` diff --git a/docs/plugins/OxHugoFlavoredMarkdown.md b/docs/plugins/OxHugoFlavoredMarkdown.md index 5c2afeea6..8770b35e1 100644 --- a/docs/plugins/OxHugoFlavoredMarkdown.md +++ b/docs/plugins/OxHugoFlavoredMarkdown.md @@ -25,5 +25,6 @@ This plugin accepts the following configuration options: ## API - Category: Transformer -- Function name: `Plugin.OxHugoFlavoredMarkdown()`. -- Source: [`quartz/plugins/transformers/oxhugofm.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/oxhugofm.ts). +- 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` diff --git a/docs/plugins/PageTitle.md b/docs/plugins/PageTitle.md new file mode 100644 index 000000000..b9c228fd5 --- /dev/null +++ b/docs/plugins/PageTitle.md @@ -0,0 +1,19 @@ +--- +title: PageTitle +tags: + - plugin/component +--- + +This plugin renders the site-wide page title (configured via the `pageTitle` field in [[configuration]]) as a clickable link to the home page. It typically appears in the left sidebar. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +This plugin has no configuration options. The displayed title is controlled by the `pageTitle` field in `quartz.config.yaml`. + +## API + +- Category: Component +- Function name: `ExternalPlugin.PageTitle()`. +- Source: [`quartz-community/page-title`](https://github.com/quartz-community/page-title) +- Install: `npx quartz plugin add github:quartz-community/page-title` diff --git a/docs/plugins/ReaderMode.md b/docs/plugins/ReaderMode.md new file mode 100644 index 000000000..db3671792 --- /dev/null +++ b/docs/plugins/ReaderMode.md @@ -0,0 +1,32 @@ +--- +title: ReaderMode +tags: + - plugin/component +--- + +Distraction-free reading mode. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[reader mode]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `enabled`: Whether to enable reader mode. Defaults to `true`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/reader-mode + enabled: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.ReaderMode()`. +- Source: [`quartz-community/reader-mode`](https://github.com/quartz-community/reader-mode) +- Install: `npx quartz plugin add github:quartz-community/reader-mode` diff --git a/docs/plugins/RecentNotes.md b/docs/plugins/RecentNotes.md new file mode 100644 index 000000000..e7e2dd163 --- /dev/null +++ b/docs/plugins/RecentNotes.md @@ -0,0 +1,40 @@ +--- +title: RecentNotes +tags: + - plugin/component +--- + +Shows recently modified notes. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[recent notes]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `title`: The title of the recent notes section. Defaults to `Recent notes`. +- `limit`: The maximum number of recent notes to display. Defaults to `5`. +- `showTags`: Whether to display the tags for each note. Defaults to `true`. +- `linkToMore`: A slug to a page that shows more notes. Defaults to `""`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/recent-notes + enabled: true + options: + title: Recent notes + limit: 5 + showTags: true + linkToMore: "" +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.RecentNotes()`. +- Source: [`quartz-community/recent-notes`](https://github.com/quartz-community/recent-notes) +- Install: `npx quartz plugin add github:quartz-community/recent-notes` diff --git a/docs/plugins/RemoveDrafts.md b/docs/plugins/RemoveDrafts.md index 07fb4d0e4..32e333452 100644 --- a/docs/plugins/RemoveDrafts.md +++ b/docs/plugins/RemoveDrafts.md @@ -14,5 +14,6 @@ This plugin has no configuration options. ## API - Category: Filter -- Function name: `Plugin.RemoveDrafts()`. -- Source: [`quartz/plugins/filters/draft.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/filters/draft.ts). +- Function name: `ExternalPlugin.RemoveDrafts()`. +- Source: [`quartz-community/remove-draft`](https://github.com/quartz-community/remove-draft) +- Install: `npx quartz plugin add github:quartz-community/remove-draft` diff --git a/docs/plugins/RoamFlavoredMarkdown.md b/docs/plugins/RoamFlavoredMarkdown.md index 9d89477a2..7fbe75074 100644 --- a/docs/plugins/RoamFlavoredMarkdown.md +++ b/docs/plugins/RoamFlavoredMarkdown.md @@ -22,5 +22,6 @@ This plugin accepts the following configuration options: ## API - Category: Transformer -- Function name: `Plugin.RoamFlavoredMarkdown()`. -- Source: [`quartz/plugins/transformers/roam.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/roam.ts). +- Function name: `ExternalPlugin.RoamFlavoredMarkdown()`. +- Source: [`quartz-community/roam`](https://github.com/quartz-community/roam) +- Install: `npx quartz plugin add github:quartz-community/roam` diff --git a/docs/plugins/Search.md b/docs/plugins/Search.md new file mode 100644 index 000000000..1155544f2 --- /dev/null +++ b/docs/plugins/Search.md @@ -0,0 +1,32 @@ +--- +title: Search +tags: + - plugin/component +--- + +Full-text search functionality. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +See [[full-text search]] for detailed usage information. + +## Configuration + +This plugin accepts the following configuration options: + +- `enabled`: Whether to enable full-text search. Defaults to `true`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/search + enabled: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.Search()`. +- Source: [`quartz-community/search`](https://github.com/quartz-community/search) +- Install: `npx quartz plugin add github:quartz-community/search` diff --git a/docs/plugins/Spacer.md b/docs/plugins/Spacer.md new file mode 100644 index 000000000..d03932f3c --- /dev/null +++ b/docs/plugins/Spacer.md @@ -0,0 +1,19 @@ +--- +title: Spacer +tags: + - plugin/component +--- + +This plugin renders a flexible spacer element that pushes adjacent components apart within a layout group. It uses CSS `flex: 2 1 auto` to fill available space, making it useful for spacing out items in toolbars or sidebars (for example, separating the search bar from the darkmode toggle in the left sidebar toolbar). + +> [!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.Spacer()`. +- Source: [`quartz-community/spacer`](https://github.com/quartz-community/spacer) +- Install: `npx quartz plugin add github:quartz-community/spacer` diff --git a/docs/plugins/StackedPages.md b/docs/plugins/StackedPages.md new file mode 100644 index 000000000..b99a8a58e --- /dev/null +++ b/docs/plugins/StackedPages.md @@ -0,0 +1,59 @@ +--- +title: StackedPages +tags: + - plugin/component +--- + +Andy Matuschak-style stacked pages (sliding panes). Clicking internal links opens pages side by side in a horizontal stack, allowing you to trace your path through your notes. Each pane shows a full page and can be individually scrolled or closed. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. + +## Usage + +Once enabled, clicking any internal link on a page opens the linked page as a new pane to the right instead of navigating away. The URL updates with a `#stacked=slug1,slug2` hash encoding your current stack, so you can share or bookmark a specific trail of pages. + +Stacked pages are disabled on mobile by default (below 800px) since horizontal panning doesn't work well on small screens. On mobile, links navigate normally. + +### Interactions + +- **Click a link**: Opens the target page in a new pane to the right. If the maximum number of panes is reached, the leftmost pane is removed. +- **Close a pane**: Click the × button in the pane header to remove it from the stack. +- **Collapsed spines**: When panes overflow the viewport, earlier panes collapse to a thin vertical spine showing the page title. Click a spine to bring that pane back into focus. +- **Browser back/forward**: The full stack state is stored in the URL hash and integrated with browser history, so back/forward navigation works as expected. + +## Configuration + +This plugin accepts the following configuration options: + +- `paneWidth`: Width of each stacked pane in pixels. Defaults to `640`. +- `maxPanes`: Maximum number of panes visible at once. Defaults to `5`. +- `enableOnMobile`: Whether to enable stacked pages on mobile devices. Defaults to `false`. +- `mobileBreakpoint`: Viewport width (in pixels) below which the mobile behavior applies. Matches the Quartz mobile breakpoint. Defaults to `800`. +- `showSpines`: Whether to show collapsed spine headers when panes overflow. Defaults to `true`. +- `animateTransitions`: Whether to animate pane open/close transitions. Defaults to `true`. + +### Default options + +```yaml title="quartz.config.yaml" +- source: github:quartz-community/stacked-pages + enabled: true + layout: + position: afterBody + priority: 50 + display: all + options: + paneWidth: 640 + maxPanes: 5 + enableOnMobile: false + mobileBreakpoint: 800 + showSpines: true + animateTransitions: true +``` + +## API + +- Category: Component +- Function name: `ExternalPlugin.StackedPages()`. +- Source: [`quartz-community/stacked-pages`](https://github.com/quartz-community/stacked-pages) +- Install: `npx quartz plugin add github:quartz-community/stacked-pages` diff --git a/docs/plugins/Static.md b/docs/plugins/Static.md index 80bf5a158..f1d61c2a0 100644 --- a/docs/plugins/Static.md +++ b/docs/plugins/Static.md @@ -17,5 +17,5 @@ This plugin has no configuration options. ## API - Category: Emitter -- Function name: `Plugin.Static()`. -- Source: [`quartz/plugins/emitters/static.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/static.ts). +- Function name: `Plugin.Static()` (internal plugin). +- Source: [`quartz/plugins/emitters/static.ts`](https://github.com/jackyzha0/quartz/blob/v5/quartz/plugins/emitters/static.ts). diff --git a/docs/plugins/SyntaxHighlighting.md b/docs/plugins/SyntaxHighlighting.md index 6fb67dba0..23287c3a3 100644 --- a/docs/plugins/SyntaxHighlighting.md +++ b/docs/plugins/SyntaxHighlighting.md @@ -19,5 +19,6 @@ In addition, you can further override the colours in the `quartz/styles/syntax.s ## API - Category: Transformer -- Function name: `Plugin.SyntaxHighlighting()`. -- Source: [`quartz/plugins/transformers/syntax.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/syntax.ts). +- Function name: `ExternalPlugin.SyntaxHighlighting()`. +- Source: [`quartz-community/syntax-highlighting`](https://github.com/quartz-community/syntax-highlighting) +- Install: `npx quartz plugin add github:quartz-community/syntax-highlighting` diff --git a/docs/plugins/TableOfContents.md b/docs/plugins/TableOfContents.md index 0e9e4ea73..2a849cba7 100644 --- a/docs/plugins/TableOfContents.md +++ b/docs/plugins/TableOfContents.md @@ -17,10 +17,11 @@ This plugin accepts the following configuration options: - `collapseByDefault`: If `true`, the TOC will start in a collapsed state. Default is `false`. > [!warning] -> This plugin needs the `Component.TableOfContents` component in `quartz.layout.ts` to determine where to display the TOC. Without it, nothing will be displayed. They should always be added or removed together. +> This plugin needs the `Plugin.TableOfContents` component in `quartz.config.yaml` to determine where to display the TOC. Without it, nothing will be displayed. They should always be added or removed together. ## API - Category: Transformer -- Function name: `Plugin.TableOfContents()`. -- Source: [`quartz/plugins/transformers/toc.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/toc.ts). +- Function name: `ExternalPlugin.TableOfContentsTransformer()`. +- Source: [`quartz-community/table-of-contents`](https://github.com/quartz-community/table-of-contents) +- Install: `npx quartz plugin add github:quartz-community/table-of-contents` diff --git a/docs/plugins/TagList.md b/docs/plugins/TagList.md new file mode 100644 index 000000000..93c888a66 --- /dev/null +++ b/docs/plugins/TagList.md @@ -0,0 +1,19 @@ +--- +title: TagList +tags: + - plugin/component +--- + +This plugin renders the page's tags as a list of clickable links. Each tag links to its corresponding [[TagPage|tag page]], making it easy for readers to browse related content by topic. + +> [!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.TagList()`. +- Source: [`quartz-community/tag-list`](https://github.com/quartz-community/tag-list) +- Install: `npx quartz plugin add github:quartz-community/tag-list` diff --git a/docs/plugins/TagPage.md b/docs/plugins/TagPage.md index 9556363fe..6560c23f6 100644 --- a/docs/plugins/TagPage.md +++ b/docs/plugins/TagPage.md @@ -1,22 +1,21 @@ --- title: TagPage tags: - - plugin/emitter + - plugin/pageType --- -This plugin emits dedicated pages for each tag used in the content. See [[folder and tag listings]] for more information. +This plugin is a page type plugin that emits dedicated pages for each tag used in the content. It uses the `default` [[layout#Page Frames|page frame]] (three-column layout with sidebars). See [[folder and tag listings]] for more information. > [!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 `TagContent` component is used. If you want to modify the layout, you must edit it directly (`quartz/components/pages/TagContent.tsx`). - This plugin accepts the following configuration options: - `sort`: A function of type `(f1: QuartzPluginData, f2: QuartzPluginData) => number{:ts}` used to sort entries. Defaults to sorting by date and tie-breaking on lexographical order. ## API -- Category: Emitter -- Function name: `Plugin.TagPage()`. -- Source: [`quartz/plugins/emitters/tagPage.tsx`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/emitters/tagPage.tsx). +- Category: Page Type +- Function name: `ExternalPlugin.TagPage()`. +- Source: [`quartz-community/tag-page`](https://github.com/quartz-community/tag-page) +- Install: `npx quartz plugin add github:quartz-community/tag-page` diff --git a/docs/plugins/index.md b/docs/plugins/index.md index 298ff164c..14bfca989 100644 --- a/docs/plugins/index.md +++ b/docs/plugins/index.md @@ -1,3 +1,89 @@ --- title: Plugins --- + +Quartz's functionality is provided by a collection of first-party community plugins. Each plugin can be enabled, disabled, and configured via `quartz.config.yaml`. See [[configuration#Plugins|Configuration]] for details on how to manage plugins. + +> [!info] Internal vs Community Plugins +> Quartz has two kinds of plugins: +> +> - **Community plugins** are standalone repositories under [`quartz-community`](https://github.com/quartz-community). In TS overrides, they use `ExternalPlugin.X()` (imported from `.quartz/plugins`). +> - **Internal plugins** are built into Quartz core (Assets, Static, ComponentResources, NotFoundPage). In TS overrides, they use `Plugin.X()` (imported from `./quartz/plugins`). + +## Plugin types + +Quartz plugins fall into several categories: + +- **Transformers** process content during the build, e.g. parsing frontmatter, highlighting syntax, or resolving links. +- **Filters** decide which content files to include or exclude from the output. +- **Page Types** generate HTML pages — one per content file, folder, tag, canvas, or bases view. +- **Components** render UI elements in the page layout (sidebars, headers, footers, etc.). + +## First-party plugins + +### Transformers + +| Plugin | Repository | Enabled | Required | Description | +| -------------------------------- | --------------------------------------------------------------------------------------------------------------- | :-----: | :------: | ---------------------------------------------------------- | +| [[Frontmatter\|Note Properties]] | [`quartz-community/note-properties`](https://github.com/quartz-community/note-properties) | ✅ | ✅ | Parses frontmatter and displays note properties. | +| [[CreatedModifiedDate]] | [`quartz-community/created-modified-date`](https://github.com/quartz-community/created-modified-date) | ✅ | ❌ | Determines creation and modification dates. | +| [[SyntaxHighlighting]] | [`quartz-community/syntax-highlighting`](https://github.com/quartz-community/syntax-highlighting) | ✅ | ❌ | Syntax highlighting for code blocks. | +| [[ObsidianFlavoredMarkdown]] | [`quartz-community/obsidian-flavored-markdown`](https://github.com/quartz-community/obsidian-flavored-markdown) | ✅ | ❌ | Obsidian-specific Markdown extensions. | +| [[GitHubFlavoredMarkdown]] | [`quartz-community/github-flavored-markdown`](https://github.com/quartz-community/github-flavored-markdown) | ✅ | ❌ | GitHub Flavored Markdown support. | +| [[TableOfContents]] | [`quartz-community/table-of-contents`](https://github.com/quartz-community/table-of-contents) | ✅ | ❌ | Generates table of contents data from headings. | +| [[CrawlLinks]] | [`quartz-community/crawl-links`](https://github.com/quartz-community/crawl-links) | ✅ | ⚠️ | Parses and resolves links. Removing it is not recommended. | +| [[Description]] | [`quartz-community/description`](https://github.com/quartz-community/description) | ✅ | ❌ | Generates page descriptions for metadata. | +| [[Latex]] | [`quartz-community/latex`](https://github.com/quartz-community/latex) | ✅ | ❌ | Renders LaTeX math expressions. | +| [[Citations]] | [`quartz-community/citations`](https://github.com/quartz-community/citations) | ❌ | ❌ | Academic citation support via BibTeX. | +| [[HardLineBreaks]] | [`quartz-community/hard-line-breaks`](https://github.com/quartz-community/hard-line-breaks) | ❌ | ❌ | Treats single newlines as hard line breaks. | +| [[OxHugoFlavoredMarkdown]] | [`quartz-community/ox-hugo`](https://github.com/quartz-community/ox-hugo) | ❌ | ❌ | ox-hugo Markdown compatibility. | +| [[RoamFlavoredMarkdown]] | [`quartz-community/roam`](https://github.com/quartz-community/roam) | ❌ | ❌ | Roam Research Markdown compatibility. | + +### Filters + +| Plugin | Repository | Enabled | Required | Description | +| ------------------- | ------------------------------------------------------------------------------------------- | :-----: | :------: | --------------------------------------- | +| [[RemoveDrafts]] | [`quartz-community/remove-draft`](https://github.com/quartz-community/remove-draft) | ✅ | ❌ | Filters out pages marked as drafts. | +| [[ExplicitPublish]] | [`quartz-community/explicit-publish`](https://github.com/quartz-community/explicit-publish) | ❌ | ❌ | Only publishes pages explicitly marked. | + +### Page Types + +| Plugin | Repository | Enabled | Required | Description | +| --------------- | ----------------------------------------------------------------------------------- | :-----: | :------: | ----------------------------------------------- | +| [[ContentPage]] | [`quartz-community/content-page`](https://github.com/quartz-community/content-page) | ✅ | ❌ | Generates HTML pages for Markdown content. | +| [[FolderPage]] | [`quartz-community/folder-page`](https://github.com/quartz-community/folder-page) | ✅ | ❌ | Generates folder listing pages. | +| [[TagPage]] | [`quartz-community/tag-page`](https://github.com/quartz-community/tag-page) | ✅ | ❌ | Generates tag listing pages. | +| [[CanvasPage]] | [`quartz-community/canvas-page`](https://github.com/quartz-community/canvas-page) | ✅ | ❌ | Renders JSON Canvas files as interactive pages. | +| [[BasesPage]] | [`quartz-community/bases-page`](https://github.com/quartz-community/bases-page) | ✅ | ❌ | Renders Obsidian Bases files as database views. | + +### Emitters + +| Plugin | Repository | Enabled | Required | Description | +| ---------------------------- | ----------------------------------------------------------------------------------------- | :-----: | :------: | ----------------------------------------------- | +| [[AliasRedirects]] | [`quartz-community/alias-redirects`](https://github.com/quartz-community/alias-redirects) | ✅ | ❌ | Generates redirect pages for aliases. | +| [[ContentIndex]] | [`quartz-community/content-index`](https://github.com/quartz-community/content-index) | ✅ | ❌ | Generates sitemap, RSS feed, and content index. | +| [[Favicon]] | [`quartz-community/favicon`](https://github.com/quartz-community/favicon) | ✅ | ❌ | Emits the site favicon. | +| [[CustomOgImages\|OG Image]] | [`quartz-community/og-image`](https://github.com/quartz-community/og-image) | ✅ | ❌ | Generates Open Graph social preview images. | +| [[CNAME]] | [`quartz-community/cname`](https://github.com/quartz-community/cname) | ✅ | ❌ | Emits a CNAME file for custom domains. | + +### Components + +| Plugin | Repository | Enabled | Required | Description | +| ------------------------------ | ----------------------------------------------------------------------------------------- | :-----: | :------: | ------------------------------------------- | +| [[ArticleTitle]] | [`quartz-community/article-title`](https://github.com/quartz-community/article-title) | ✅ | ❌ | Renders the article title as an h1 heading. | +| [[ContentMeta]] | [`quartz-community/content-meta`](https://github.com/quartz-community/content-meta) | ✅ | ❌ | Displays creation date and reading time. | +| [[TagList]] | [`quartz-community/tag-list`](https://github.com/quartz-community/tag-list) | ❌ | ❌ | Renders tags as clickable links. | +| [[PageTitle]] | [`quartz-community/page-title`](https://github.com/quartz-community/page-title) | ✅ | ❌ | Renders the site title as a home link. | +| [[darkmode\|Darkmode]] | [`quartz-community/darkmode`](https://github.com/quartz-community/darkmode) | ✅ | ❌ | Toggle between light and dark themes. | +| [[reader mode\|Reader Mode]] | [`quartz-community/reader-mode`](https://github.com/quartz-community/reader-mode) | ✅ | ❌ | Distraction-free reading mode toggle. | +| [[explorer\|Explorer]] | [`quartz-community/explorer`](https://github.com/quartz-community/explorer) | ✅ | ❌ | File tree explorer sidebar. | +| [[graph view\|Graph View]] | [`quartz-community/graph`](https://github.com/quartz-community/graph) | ✅ | ❌ | Interactive link graph visualization. | +| [[full-text search\|Search]] | [`quartz-community/search`](https://github.com/quartz-community/search) | ✅ | ❌ | Full-text search functionality. | +| [[backlinks\|Backlinks]] | [`quartz-community/backlinks`](https://github.com/quartz-community/backlinks) | ✅ | ❌ | Shows pages that link to the current page. | +| [[breadcrumbs\|Breadcrumbs]] | [`quartz-community/breadcrumbs`](https://github.com/quartz-community/breadcrumbs) | ✅ | ❌ | Breadcrumb navigation trail. | +| [[comments\|Comments]] | [`quartz-community/comments`](https://github.com/quartz-community/comments) | ❌ | ❌ | Comment system integration (Giscus, etc.). | +| [[Footer]] | [`quartz-community/footer`](https://github.com/quartz-community/footer) | ✅ | ❌ | Page footer with configurable links. | +| [[recent notes\|Recent Notes]] | [`quartz-community/recent-notes`](https://github.com/quartz-community/recent-notes) | ❌ | ❌ | Displays a list of recently modified notes. | +| [[Spacer]] | [`quartz-community/spacer`](https://github.com/quartz-community/spacer) | ✅ | ❌ | Flexible spacer for layout groups. | +| [[EncryptedPages]] | [`quartz-community/encrypted-pages`](https://github.com/quartz-community/encrypted-pages) | ✅ | ❌ | Password-protected encrypted pages. | +| [[StackedPages]] | [`quartz-community/stacked-pages`](https://github.com/quartz-community/stacked-pages) | ✅ | ❌ | Andy Matuschak-style stacked sliding panes. | diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 000000000..fcc15bcb9 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,128 @@ +--- +title: Troubleshooting +--- + +Common issues and solutions when working with Quartz. + +## Build Errors + +### `Could not resolve ...` or missing module errors + +This usually means a plugin is not installed. Run: + +```bash +npx quartz plugin restore +``` + +This restores all plugins from your `quartz.lock.json` to `.quartz/plugins/`. + +### `tsc` type errors after updating + +After running `npx quartz upgrade`, type errors can occur if the update changed internal APIs that your `quartz.ts` overrides depend on. Check the changelog for breaking changes and update your overrides accordingly. + +### Build is slow + +Try increasing concurrency: + +```bash +npx quartz build --concurrency 8 +``` + +The default uses all available CPU cores. If you're on a memory-constrained environment (CI), reducing concurrency may actually help. + +## Plugin Issues + +### Plugin not loading after installation + +1. Verify the plugin appears in `quartz.config.yaml` under `plugins:` +2. Check that `enabled: true` is set +3. Run `npx quartz plugin list` to confirm it's installed +4. Run `npx quartz plugin check` to verify plugin health + +### Plugin options not taking effect + +Make sure your YAML indentation is correct. Options must be nested under the plugin entry: + +```yaml title="quartz.config.yaml" +plugins: + - source: github:quartz-community/some-plugin + enabled: true + options: + myOption: value # correct: nested under options +``` + +A common mistake is putting options at the wrong indentation level. + +### `ExternalPlugin.X is not a function` + +This means the plugin is referenced in `quartz.ts` but not installed. Either: + +- Install it: `npx quartz plugin add github:quartz-community/plugin-name` +- Or remove the reference from `quartz.ts` + +## Content Issues + +### Notes not showing up + +- Check that the file is in the `content/` folder +- Check that `draft: true` is not set in the frontmatter (the [[RemoveDrafts]] plugin filters these out) +- If using [[ExplicitPublish]], make sure `publish: true` is set in frontmatter +- Check your [[configuration]] `ignorePatterns` to make sure the file path is not excluded + +### Wikilinks not resolving + +- Make sure the [[ObsidianFlavoredMarkdown]] plugin is enabled +- Verify the target note exists in your content folder +- Check for case sensitivity issues in filenames + +### Images not displaying + +- Ensure images are in a folder that Quartz processes (typically `content/` or a subfolder) +- Check that the image path in your Markdown matches the actual file location +- The [[Assets]] emitter must be enabled (it is by default) + +## GitHub Sync Issues + +### `fatal: --[no-]autostash option is only valid with --rebase` + +You may have an outdated version of `git`. Update git to resolve this. + +### `fatal: The remote end hung up unexpectedly` + +This is usually due to Git's default buffer size being too small for your content. Increase it: + +```bash +git config http.postBuffer 524288000 +``` + +### Merge conflicts during sync + +If `npx quartz sync` encounters merge conflicts: + +1. Resolve the conflicts in your editor +2. Run `git add .` and `git commit` to complete the merge +3. Run `npx quartz sync --no-pull` to push + +If you want to start over, run `npx quartz restore` to recover your content from the cache. + +## Development Server Issues + +### Hot reload not working + +- Make sure you're using `--serve` mode: `npx quartz build --serve` +- Check that port 3001 (WebSocket) is not blocked — this is the default `--wsPort` used for hot reload notifications +- If developing remotely, use `--remoteDevHost` to set the correct WebSocket URL + +### Port already in use + +Change the port: + +```bash +npx quartz build --serve --port 3000 +``` + +## Still stuck? + +- Check the [GitHub Issues](https://github.com/jackyzha0/quartz/issues) for similar problems +- Ask in the [Discord Community](https://discord.gg/cRFFHYye7t) +- Run your command with `--verbose` for more detailed error output diff --git a/docs/upgrading.md b/docs/upgrading.md deleted file mode 100644 index a3a82754a..000000000 --- a/docs/upgrading.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: "Upgrading Quartz" ---- - -> [!note] -> This is specifically a guide for upgrading Quartz 4 version to a more recent update. If you are coming from Quartz 3, check out the [[migrating from Quartz 3|migration guide]] for more info. - -To fetch the latest Quartz updates, simply run - -```bash -npx quartz update -``` - -As Quartz uses [git](https://git-scm.com/) under the hood for versioning, updating effectively 'pulls' in the updates from the official Quartz GitHub repository. If you have local changes that might conflict with the updates, you may need to resolve these manually yourself (or, pull manually using `git pull origin upstream`). - -> [!hint] -> Quartz will try to cache your content before updating 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). diff --git a/index.d.ts b/index.d.ts index 9011ee38f..1dc0e2f82 100644 --- a/index.d.ts +++ b/index.d.ts @@ -9,6 +9,7 @@ interface CustomEventMap { nav: CustomEvent<{ url: FullSlug }> themechange: CustomEvent<{ theme: "light" | "dark" }> readermodechange: CustomEvent<{ mode: "on" | "off" }> + render: CustomEvent<{}> } type ContentIndex = Record diff --git a/package-lock.json b/package-lock.json index ff22d60fc..ec2ea8495 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,24 +1,21 @@ { "name": "@jackyzha0/quartz", - "version": "4.5.2", + "version": "5.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@jackyzha0/quartz", - "version": "4.5.2", + "version": "5.0.0", "license": "MIT", "dependencies": { "@clack/prompts": "^0.11.0", "@floating-ui/dom": "^1.7.4", "@myriaddreamin/rehype-typst": "^0.6.0", "@napi-rs/simple-git": "0.1.22", - "@tweenjs/tween.js": "^25.0.0", "ansi-truncate": "^1.4.0", "async-mutex": "^0.5.0", "chokidar": "^5.0.0", - "cli-spinner": "^0.2.10", - "d3": "^7.9.0", "esbuild-sass-plugin": "^3.6.0", "flexsearch": "^0.8.205", "github-slugger": "^2.0.0", @@ -28,6 +25,7 @@ "hast-util-to-jsx-runtime": "^2.3.6", "hast-util-to-string": "^3.0.1", "is-absolute-url": "^5.0.0", + "isomorphic-git": "^1.36.3", "js-yaml": "^4.1.1", "lightningcss": "^1.31.1", "mdast-util-find-and-replace": "^3.0.2", @@ -35,7 +33,6 @@ "mdast-util-to-string": "^4.0.0", "micromorph": "^0.4.5", "minimatch": "^10.1.1", - "pixi.js": "^8.15.0", "preact": "^10.28.2", "preact-render-to-string": "^6.6.5", "pretty-bytes": "^7.1.0", @@ -48,7 +45,6 @@ "rehype-pretty-code": "^0.14.1", "rehype-raw": "^7.0.0", "rehype-slug": "^6.0.0", - "remark": "^15.0.1", "remark-breaks": "^4.0.0", "remark-frontmatter": "^5.0.0", "remark-gfm": "^4.0.1", @@ -60,7 +56,6 @@ "satori": "^0.19.1", "serve-handler": "^6.1.6", "sharp": "^0.34.5", - "shiki": "^1.26.2", "source-map-support": "^0.5.21", "to-vfile": "^8.0.0", "toml": "^3.0.0", @@ -69,13 +64,15 @@ "vfile": "^6.0.3", "workerpool": "^10.0.1", "ws": "^8.19.0", + "yaml": "^2.8.2", "yargs": "^18.0.0" }, "bin": { "quartz": "quartz/bootstrap-cli.mjs" }, "devDependencies": { - "@types/d3": "^7.4.3", + "@quartz-community/types": "github:quartz-community/types", + "@quartz-community/utils": "github:quartz-community/utils", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", "@types/node": "^25.0.10", @@ -94,16 +91,17 @@ } }, "node_modules/@bufbuild/protobuf": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.10.2.tgz", - "integrity": "sha512-uFsRXwIGyu+r6AMdz+XijIIZJYpoWeYzILt5yZ2d3mCjQrWUTVpVD9WL/jZAbvp+Ed04rOhrsk7FiTcEDseB5A==", - "license": "(Apache-2.0 AND BSD-3-Clause)", - "peer": true + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", + "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/@citation-js/core": { - "version": "0.7.14", - "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.14.tgz", - "integrity": "sha512-dgeGqYDSQmn2MtnWZkwPGpJQPh43yr1lAAr9jl1NJ9pIY1RXUQxtlAUZVur0V9PHdbfQC+kkvB1KC3VpgVV3MA==", + "version": "0.7.21", + "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.21.tgz", + "integrity": "sha512-Vobv2/Yfnn6C6BVO/pvj7madQ7Mfzl83/jAWwixbemGF6ZThhGMz8++FD9hWHyHXDMYuLGa6fK68c2VsolZmTA==", + "license": "MIT", + "peer": true, "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -118,6 +116,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/@citation-js/date/-/date-0.5.1.tgz", "integrity": "sha512-1iDKAZ4ie48PVhovsOXQ+C6o55dWJloXqtznnnKy6CltJBQLIuLLuUqa8zlIvma0ZigjVjgDUhnVaNU1MErtZw==", + "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -126,14 +125,16 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/@citation-js/name/-/name-0.4.2.tgz", "integrity": "sha512-brSPsjs2fOVzSnARLKu0qncn6suWjHVQtrqSUrnqyaRH95r/Ad4wPF5EsoWr+Dx8HzkCGb/ogmoAzfCsqlTwTQ==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/@citation-js/plugin-bibjson": { - "version": "0.7.14", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibjson/-/plugin-bibjson-0.7.14.tgz", - "integrity": "sha512-Hcmk01KrpHwcl5uVoLE6TRaJRFg7/qUvpJDcKqx3LLLCsNbaBlISfRDeFETrjjipTetkX70RvtS7FfGUN58gCQ==", + "version": "0.7.21", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibjson/-/plugin-bibjson-0.7.21.tgz", + "integrity": "sha512-Q3eRpeV3pDqX91fvJ8xoYGJk4jB5MQD2woEr6GAoAauAzGVE19J5Lw0SksCHegoAn4z0ZbWMXtOq6rwZPtERbA==", + "license": "MIT", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2" @@ -146,9 +147,10 @@ } }, "node_modules/@citation-js/plugin-bibtex": { - "version": "0.7.14", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.7.14.tgz", - "integrity": "sha512-xHOHqhF6dthLRv46N9U+mQgYLiiWQHLvQWK9+mcBKz+/3NWge62Xb1oBouNWwLEPd5FV/8gp9fp7SOp93T0dUg==", + "version": "0.7.21", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.7.21.tgz", + "integrity": "sha512-O008pSsJgiYKn4+7gAWrbNpNdUH++aMeYmZaJ2oFQ8X1tcY5jNBxJcr0zZojNtUi5CVOaXXHQ0yIifoUhuF2Vg==", + "license": "MIT", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -162,9 +164,10 @@ } }, "node_modules/@citation-js/plugin-csl": { - "version": "0.7.14", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.7.14.tgz", - "integrity": "sha512-7AKB8lMz1IqdtoE33NnWIpteLYMuSl3xqT+Cax7sQKwAIJEoq2HBmb43Ja8xQQ36nREAupQJv1V6XksIAmYnCg==", + "version": "0.7.22", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.7.22.tgz", + "integrity": "sha512-/rGdtbeP3nS4uZDdEbQUHT8PrUcIs0da2t+sWMKYXoOhXQqfw3oJJ7p4tUD+R8lptyIR5Eq20/DFk/kQDdLpYg==", + "license": "MIT", "dependencies": { "@citation-js/date": "^0.5.0", "citeproc": "^2.4.6" @@ -198,9 +201,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", - "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", "license": "MIT", "optional": true, "dependencies": { @@ -208,9 +211,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "cpu": [ "ppc64" ], @@ -224,9 +227,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", "cpu": [ "arm" ], @@ -240,9 +243,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", "cpu": [ "arm64" ], @@ -256,9 +259,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", "cpu": [ "x64" ], @@ -272,9 +275,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", "cpu": [ "arm64" ], @@ -288,9 +291,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", "cpu": [ "x64" ], @@ -304,9 +307,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "cpu": [ "arm64" ], @@ -320,9 +323,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "cpu": [ "x64" ], @@ -336,9 +339,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", "cpu": [ "arm" ], @@ -352,9 +355,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "cpu": [ "arm64" ], @@ -368,9 +371,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", "cpu": [ "ia32" ], @@ -384,9 +387,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", "cpu": [ "loong64" ], @@ -400,9 +403,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", "cpu": [ "mips64el" ], @@ -416,9 +419,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", "cpu": [ "ppc64" ], @@ -432,9 +435,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "cpu": [ "riscv64" ], @@ -448,9 +451,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "cpu": [ "s390x" ], @@ -464,9 +467,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", "cpu": [ "x64" ], @@ -480,9 +483,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", "cpu": [ "arm64" ], @@ -496,9 +499,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "cpu": [ "x64" ], @@ -512,9 +515,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", "cpu": [ "arm64" ], @@ -528,9 +531,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "cpu": [ "x64" ], @@ -544,9 +547,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", "cpu": [ "arm64" ], @@ -560,9 +563,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "cpu": [ "x64" ], @@ -576,9 +579,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "cpu": [ "arm64" ], @@ -592,9 +595,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "cpu": [ "ia32" ], @@ -608,9 +611,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], @@ -624,21 +627,21 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", - "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", - "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.3", + "@floating-ui/core": "^1.7.4", "@floating-ui/utils": "^0.2.10" } }, @@ -1113,25 +1116,43 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", "engines": { - "node": "20 || >=22" + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@myriaddreamin/rehype-typst": { @@ -1650,9 +1671,9 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.4.tgz", - "integrity": "sha512-WYa2tUVV5HiArWPB3ydlOc4R2ivq0IDrlqhMi3l7mVsFEXNcTfxYFPIHXHXIh/ca/y/V5N4E1zecyxdIBjYnkQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -1670,25 +1691,25 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.4", - "@parcel/watcher-darwin-arm64": "2.5.4", - "@parcel/watcher-darwin-x64": "2.5.4", - "@parcel/watcher-freebsd-x64": "2.5.4", - "@parcel/watcher-linux-arm-glibc": "2.5.4", - "@parcel/watcher-linux-arm-musl": "2.5.4", - "@parcel/watcher-linux-arm64-glibc": "2.5.4", - "@parcel/watcher-linux-arm64-musl": "2.5.4", - "@parcel/watcher-linux-x64-glibc": "2.5.4", - "@parcel/watcher-linux-x64-musl": "2.5.4", - "@parcel/watcher-win32-arm64": "2.5.4", - "@parcel/watcher-win32-ia32": "2.5.4", - "@parcel/watcher-win32-x64": "2.5.4" + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.4.tgz", - "integrity": "sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", "cpu": [ "arm64" ], @@ -1706,9 +1727,9 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.4.tgz", - "integrity": "sha512-kphKy377pZiWpAOyTgQYPE5/XEKVMaj6VUjKT5VkNyUJlr2qZAn8gIc7CPzx+kbhvqHDT9d7EqdOqRXT6vk0zw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", "cpu": [ "arm64" ], @@ -1726,9 +1747,9 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.4.tgz", - "integrity": "sha512-UKaQFhCtNJW1A9YyVz3Ju7ydf6QgrpNQfRZ35wNKUhTQ3dxJ/3MULXN5JN/0Z80V/KUBDGa3RZaKq1EQT2a2gg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", "cpu": [ "x64" ], @@ -1746,9 +1767,9 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.4.tgz", - "integrity": "sha512-Dib0Wv3Ow/m2/ttvLdeI2DBXloO7t3Z0oCp4bAb2aqyqOjKPPGrg10pMJJAQ7tt8P4V2rwYwywkDhUia/FgS+Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", "cpu": [ "x64" ], @@ -1766,9 +1787,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.4.tgz", - "integrity": "sha512-I5Vb769pdf7Q7Sf4KNy8Pogl/URRCKu9ImMmnVKYayhynuyGYMzuI4UOWnegQNa2sGpsPSbzDsqbHNMyeyPCgw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", "cpu": [ "arm" ], @@ -1786,9 +1807,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.4.tgz", - "integrity": "sha512-kGO8RPvVrcAotV4QcWh8kZuHr9bXi9a3bSZw7kFarYR0+fGliU7hd/zevhjw8fnvIKG3J9EO5G6sXNGCSNMYPQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", "cpu": [ "arm" ], @@ -1806,9 +1827,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.4.tgz", - "integrity": "sha512-KU75aooXhqGFY2W5/p8DYYHt4hrjHZod8AhcGAmhzPn/etTa+lYCDB2b1sJy3sWJ8ahFVTdy+EbqSBvMx3iFlw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", "cpu": [ "arm64" ], @@ -1826,9 +1847,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.4.tgz", - "integrity": "sha512-Qx8uNiIekVutnzbVdrgSanM+cbpDD3boB1f8vMtnuG5Zau4/bdDbXyKwIn0ToqFhIuob73bcxV9NwRm04/hzHQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", "cpu": [ "arm64" ], @@ -1846,9 +1867,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.4.tgz", - "integrity": "sha512-UYBQvhYmgAv61LNUn24qGQdjtycFBKSK3EXr72DbJqX9aaLbtCOO8+1SkKhD/GNiJ97ExgcHBrukcYhVjrnogA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", "cpu": [ "x64" ], @@ -1866,9 +1887,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.4.tgz", - "integrity": "sha512-YoRWCVgxv8akZrMhdyVi6/TyoeeMkQ0PGGOf2E4omODrvd1wxniXP+DBynKoHryStks7l+fDAMUBRzqNHrVOpg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", "cpu": [ "x64" ], @@ -1886,9 +1907,9 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.4.tgz", - "integrity": "sha512-iby+D/YNXWkiQNYcIhg8P5hSjzXEHaQrk2SLrWOUD7VeC4Ohu0WQvmV+HDJokZVJ2UjJ4AGXW3bx7Lls9Ln4TQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", "cpu": [ "arm64" ], @@ -1906,9 +1927,9 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.4.tgz", - "integrity": "sha512-vQN+KIReG0a2ZDpVv8cgddlf67J8hk1WfZMMP7sMeZmJRSmEax5xNDNWKdgqSe2brOKTQQAs3aCCUal2qBHAyg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", "cpu": [ "ia32" ], @@ -1926,9 +1947,9 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.4.tgz", - "integrity": "sha512-3A6efb6BOKwyw7yk9ro2vus2YTt2nvcd56AuzxdMiVOxL9umDyN5PKkKfZ/gZ9row41SjVmTVQNWQhaRRGpOKw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", "cpu": [ "x64" ], @@ -1958,73 +1979,456 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@pixi/colord": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@pixi/colord/-/colord-2.9.6.tgz", - "integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==", - "license": "MIT" + "node_modules/@quartz-community/types": { + "version": "0.2.1", + "resolved": "git+ssh://git@github.com/quartz-community/types.git#0d62f52da4d3f50271f8a98d68702162d361640c", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "tsup": "^8.5.0", + "typescript": "^5.9.3", + "unified": "^11.0.5", + "vfile": "^6.0.3" + }, + "engines": { + "node": ">=22", + "npm": ">=10.9.2" + } + }, + "node_modules/@quartz-community/utils": { + "version": "0.1.0", + "resolved": "git+ssh://git@github.com/quartz-community/utils.git#eaa6160504bff1ddc82f2f9b8bdf62e64d291120", + "dev": true, + "license": "MIT", + "dependencies": { + "@quartz-community/types": "github:quartz-community/types", + "github-slugger": "^2.0.0", + "tsup": "^8.5.0", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=22", + "npm": ">=10.9.2" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@shikijs/core": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.26.2.tgz", - "integrity": "sha512-ORyu3MrY7dCC7FDLDsFSkBM9b/AT9/Y8rH+UQ07Rtek48pp0ZhQOMPTKolqszP4bBCas6FqTZQYt18BBamVl/g==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.22.0.tgz", + "integrity": "sha512-iAlTtSDDbJiRpvgL5ugKEATDtHdUVkqgHDm/gbD2ZS9c88mx7G1zSYjjOxp5Qa0eaW0MAQosFRmJSk354PRoQA==", + "license": "MIT", "dependencies": { - "@shikijs/engine-javascript": "1.26.2", - "@shikijs/engine-oniguruma": "1.26.2", - "@shikijs/types": "1.26.2", - "@shikijs/vscode-textmate": "^10.0.1", + "@shikijs/types": "3.22.0", + "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", - "hast-util-to-html": "^9.0.4" + "hast-util-to-html": "^9.0.5" } }, "node_modules/@shikijs/engine-javascript": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.26.2.tgz", - "integrity": "sha512-ngkIu9swLVo9Zt5QBtz5Sk08vmPcwuj01r7pPK/Zjmo2U2WyKMK4WMUMmkdQiUacdcLth0zt8u1onp4zhkFXKQ==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.22.0.tgz", + "integrity": "sha512-jdKhfgW9CRtj3Tor0L7+yPwdG3CgP7W+ZEqSsojrMzCjD1e0IxIbwUMDDpYlVBlC08TACg4puwFGkZfLS+56Tw==", + "license": "MIT", "dependencies": { - "@shikijs/types": "1.26.2", - "@shikijs/vscode-textmate": "^10.0.1", - "oniguruma-to-es": "^1.0.0" + "@shikijs/types": "3.22.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.26.2.tgz", - "integrity": "sha512-mlN7Qrs+w60nKrd7at7XkXSwz6728Pe34taDmHrG6LRHjzCqQ+ysg+/AT6/D2LMk0s2lsr71DjpI73430QP4/w==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.22.0.tgz", + "integrity": "sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==", + "license": "MIT", "dependencies": { - "@shikijs/types": "1.26.2", - "@shikijs/vscode-textmate": "^10.0.1" + "@shikijs/types": "3.22.0", + "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/langs": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-1.26.2.tgz", - "integrity": "sha512-o5cdPycB2Kw3IgncHxWopWPiTkjAj7dG01fLkkUyj3glb5ftxL/Opecq9F54opMlrgXy7ZIqDERvFLlUzsCOuA==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.22.0.tgz", + "integrity": "sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==", + "license": "MIT", "dependencies": { - "@shikijs/types": "1.26.2" + "@shikijs/types": "3.22.0" } }, "node_modules/@shikijs/themes": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-1.26.2.tgz", - "integrity": "sha512-y4Pn6PM5mODz/e3yF6jAUG7WLKJzqL2tJ5qMJCUkMUB1VRgtQVvoa1cHh7NScryGXyrYGJ8nPnRDhdv2rw0xpA==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.22.0.tgz", + "integrity": "sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==", + "license": "MIT", "dependencies": { - "@shikijs/types": "1.26.2" + "@shikijs/types": "3.22.0" } }, "node_modules/@shikijs/types": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.26.2.tgz", - "integrity": "sha512-PO2jucx2FIdlLBPYbIUlMtWSLs5ulcRcuV93cR3T65lkK5SJP4MGBRt9kmWGXiQc0f7+FHj/0BEawditZcI/fQ==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.22.0.tgz", + "integrity": "sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==", + "license": "MIT", "dependencies": { - "@shikijs/vscode-textmate": "^10.0.1", + "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.1.tgz", - "integrity": "sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg==" + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" }, "node_modules/@shuding/opentype.js": { "version": "1.4.0-beta.0", @@ -2054,308 +2458,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@tweenjs/tween.js": { - "version": "25.0.0", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-25.0.0.tgz", - "integrity": "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==", - "license": "MIT" - }, - "node_modules/@types/css-font-loading-module": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.12.tgz", - "integrity": "sha512-x2tZZYkSxXqWvTDgveSynfjq/T2HyiZHXb00j/+gy19yp70PHCizM48XFdjBCWH7eHBD0R5i/pw9yMBP/BH5uA==", - "license": "MIT" - }, - "node_modules/@types/d3": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", - "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", - "dev": true, - "dependencies": { - "@types/d3-array": "*", - "@types/d3-axis": "*", - "@types/d3-brush": "*", - "@types/d3-chord": "*", - "@types/d3-color": "*", - "@types/d3-contour": "*", - "@types/d3-delaunay": "*", - "@types/d3-dispatch": "*", - "@types/d3-drag": "*", - "@types/d3-dsv": "*", - "@types/d3-ease": "*", - "@types/d3-fetch": "*", - "@types/d3-force": "*", - "@types/d3-format": "*", - "@types/d3-geo": "*", - "@types/d3-hierarchy": "*", - "@types/d3-interpolate": "*", - "@types/d3-path": "*", - "@types/d3-polygon": "*", - "@types/d3-quadtree": "*", - "@types/d3-random": "*", - "@types/d3-scale": "*", - "@types/d3-scale-chromatic": "*", - "@types/d3-selection": "*", - "@types/d3-shape": "*", - "@types/d3-time": "*", - "@types/d3-time-format": "*", - "@types/d3-timer": "*", - "@types/d3-transition": "*", - "@types/d3-zoom": "*" - } - }, - "node_modules/@types/d3-array": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.5.tgz", - "integrity": "sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==", - "dev": true - }, - "node_modules/@types/d3-axis": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.2.tgz", - "integrity": "sha512-uGC7DBh0TZrU/LY43Fd8Qr+2ja1FKmH07q2FoZFHo1eYl8aj87GhfVoY1saJVJiq24rp1+wpI6BvQJMKgQm8oA==", - "dev": true, - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-brush": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.2.tgz", - "integrity": "sha512-2TEm8KzUG3N7z0TrSKPmbxByBx54M+S9lHoP2J55QuLU0VSQ9mE96EJSAOVNEqd1bbynMjeTS9VHmz8/bSw8rA==", - "dev": true, - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-chord": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.2.tgz", - "integrity": "sha512-abT/iLHD3sGZwqMTX1TYCMEulr+wBd0SzyOQnjYNLp7sngdOHYtNkMRI5v3w5thoN+BWtlHVDx2Osvq6fxhZWw==", - "dev": true - }, - "node_modules/@types/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==", - "dev": true - }, - "node_modules/@types/d3-contour": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.2.tgz", - "integrity": "sha512-k6/bGDoAGJZnZWaKzeB+9glgXCYGvh6YlluxzBREiVo8f/X2vpTEdgPy9DN7Z2i42PZOZ4JDhVdlTSTSkLDPlQ==", - "dev": true, - "dependencies": { - "@types/d3-array": "*", - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-delaunay": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", - "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==", - "dev": true - }, - "node_modules/@types/d3-dispatch": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.2.tgz", - "integrity": "sha512-rxN6sHUXEZYCKV05MEh4z4WpPSqIw+aP7n9ZN6WYAAvZoEAghEK1WeVZMZcHRBwyaKflU43PCUAJNjFxCzPDjg==", - "dev": true - }, - "node_modules/@types/d3-drag": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.2.tgz", - "integrity": "sha512-qmODKEDvyKWVHcWWCOVcuVcOwikLVsyc4q4EBJMREsoQnR2Qoc2cZQUyFUPgO9q4S3qdSqJKBsuefv+h0Qy+tw==", - "dev": true, - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-76pBHCMTvPLt44wFOieouXcGXWOF0AJCceUvaFkxSZEu4VDUdv93JfpMa6VGNFs01FHfuP4a5Ou68eRG1KBfTw==", - "dev": true - }, - "node_modules/@types/d3-ease": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", - "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==", - "dev": true - }, - "node_modules/@types/d3-fetch": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.2.tgz", - "integrity": "sha512-gllwYWozWfbep16N9fByNBDTkJW/SyhH6SGRlXloR7WdtAaBui4plTP+gbUgiEot7vGw/ZZop1yDZlgXXSuzjA==", - "dev": true, - "dependencies": { - "@types/d3-dsv": "*" - } - }, - "node_modules/@types/d3-force": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.4.tgz", - "integrity": "sha512-q7xbVLrWcXvSBBEoadowIUJ7sRpS1yvgMWnzHJggFy5cUZBq2HZL5k/pBSm0GdYWS1vs5/EDwMjSKF55PDY4Aw==", - "dev": true - }, - "node_modules/@types/d3-format": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", - "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", - "dev": true - }, - "node_modules/@types/d3-geo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.3.tgz", - "integrity": "sha512-bK9uZJS3vuDCNeeXQ4z3u0E7OeJZXjUgzFdSOtNtMCJCLvDtWDwfpRVWlyt3y8EvRzI0ccOu9xlMVirawolSCw==", - "dev": true, - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-9hjRTVoZjRFR6xo8igAJyNXQyPX6Aq++Nhb5ebrUF414dv4jr2MitM2fWiOY475wa3Za7TOS2Gh9fmqEhLTt0A==", - "dev": true - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", - "dev": true, - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", - "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", - "dev": true - }, - "node_modules/@types/d3-polygon": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", - "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==", - "dev": true - }, - "node_modules/@types/d3-quadtree": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", - "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==", - "dev": true - }, - "node_modules/@types/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==", - "dev": true - }, - "node_modules/@types/d3-scale": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.3.tgz", - "integrity": "sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==", - "dev": true, - "dependencies": { - "@types/d3-time": "*" - } - }, - "node_modules/@types/d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", - "dev": true - }, - "node_modules/@types/d3-selection": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.5.tgz", - "integrity": "sha512-xCB0z3Hi8eFIqyja3vW8iV01+OHGYR2di/+e+AiOcXIOrY82lcvWW8Ke1DYE/EUVMsBl4Db9RppSBS3X1U6J0w==", - "dev": true - }, - "node_modules/@types/d3-shape": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.1.tgz", - "integrity": "sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A==", - "dev": true, - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", - "dev": true - }, - "node_modules/@types/d3-time-format": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", - "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==", - "dev": true - }, - "node_modules/@types/d3-timer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", - "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==", - "dev": true - }, - "node_modules/@types/d3-transition": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.3.tgz", - "integrity": "sha512-/S90Od8Id1wgQNvIA8iFv9jRhCiZcGhPd2qX0bKF/PS+y0W5CrXKgIiELd2CvG1mlQrWK/qlYh3VxicqG1ZvgA==", - "dev": true, - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-zoom": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.3.tgz", - "integrity": "sha512-OWk1yYIIWcZ07+igN6BeoG6rqhnJ/pYe+R1qWFM2DtW49zsoSjgb9G5xB0ZXA8hh2jAzey1XuRmMSoXdKw8MDA==", - "dev": true, - "dependencies": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" - } - }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", "dependencies": { "@types/ms": "*" } }, - "node_modules/@types/earcut": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-3.0.0.tgz", - "integrity": "sha512-k/9fOUGO39yd2sCjrbAJvGDEQvRwRnQIZlBz43roGwUZo5SHAmyVvSFyaVVZkicRVCaDXPKlbxrUcBuJoSWunQ==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" - }, "node_modules/@types/estree-jsx": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.3.tgz", - "integrity": "sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", "dependencies": { "@types/estree": "*" } }, - "node_modules/@types/geojson": { - "version": "7946.0.10", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", - "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==", - "dev": true - }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -2364,68 +2495,77 @@ "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/katex": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", - "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==" + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "license": "MIT" }, "node_modules/@types/mathjax": { "version": "0.0.40", "resolved": "https://registry.npmjs.org/@types/mathjax/-/mathjax-0.0.40.tgz", - "integrity": "sha512-rHusx08LCg92WJxrsM3SPjvLTSvK5C+gealtSuhKbEOcUZfWlwigaFoPLf6Dfxhg4oryN5qP9Sj7zOQ4HYXINw==" + "integrity": "sha512-rHusx08LCg92WJxrsM3SPjvLTSvK5C+gealtSuhKbEOcUZfWlwigaFoPLf6Dfxhg4oryN5qP9Sj7zOQ4HYXINw==", + "license": "MIT" }, "node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", "dependencies": { "@types/unist": "*" } }, "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" }, "node_modules/@types/nlcst": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", "dependencies": { "@types/unist": "*" } }, "node_modules/@types/node": { - "version": "25.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz", - "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/pretty-time": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@types/pretty-time/-/pretty-time-1.1.5.tgz", "integrity": "sha512-5yl+BYwmnRWZb783W8YYoHXvPY8q/rp7ctHBVaGBB9RxlzGpHNJ72tGQMK7TrUSnxzl1dbDcBDuBCSbtfnSQGg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/source-map-support": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.10.tgz", "integrity": "sha512-tgVP2H469x9zq34Z0m/fgPewGhg/MLClalNOiPIzQlXrSS2YrKu/xCdSCKnEDwkFha51VKEKB6A9wW26/ZNwzA==", "dev": true, + "license": "MIT", "dependencies": { "source-map": "^0.6.0" } }, "node_modules/@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" }, "node_modules/@types/ws": { "version": "8.18.1", @@ -2448,46 +2588,65 @@ } }, "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" - }, - "node_modules/@webgpu/types": { - "version": "0.1.64", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.64.tgz", - "integrity": "sha512-84kRIAGV46LJTlJZWxShiOrNL30A+9KokD7RB3dRCIqODFjodS5tCD5yyiZ8kIReGVZSDfA3XkkwyyOIF6K62A==", - "license": "BSD-3-Clause" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" }, "node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz", + "integrity": "sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A==", "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=14.6" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dependencies": { - "debug": "^4.3.4" - }, + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", "engines": { "node": ">= 14" } }, "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -2497,9 +2656,9 @@ } }, "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -2517,41 +2676,77 @@ "fast-string-truncated-width": "^3.0.1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" }, "node_modules/array-iterate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/async-lock": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", + "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==", + "license": "MIT" + }, "node_modules/async-mutex": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "license": "MIT", "dependencies": { "tslib": "^2.4.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/base64-js": { "version": "1.5.1", @@ -2570,7 +2765,20 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/braces": { "version": "3.0.3", @@ -2585,9 +2793,9 @@ } }, "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -2602,31 +2810,100 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, - "node_modules/buffer-builder": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", - "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", - "license": "MIT/X11", - "peer": true - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bundle-require": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", + "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } }, "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/camelize": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", @@ -2640,6 +2917,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2649,6 +2927,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2658,6 +2937,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2667,6 +2947,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2676,6 +2957,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2699,15 +2981,14 @@ "node_modules/citeproc": { "version": "2.4.63", "resolved": "https://registry.npmjs.org/citeproc/-/citeproc-2.4.63.tgz", - "integrity": "sha512-68F95Bp4UbgZU/DBUGQn0qV3HDZLCdI9+Bb2ByrTaNJDL5VEm9LqaiNaxljsvoaExSLEXe1/r6n2Z06SCzW3/Q==" + "integrity": "sha512-68F95Bp4UbgZU/DBUGQn0qV3HDZLCdI9+Bb2ByrTaNJDL5VEm9LqaiNaxljsvoaExSLEXe1/r6n2Z06SCzW3/Q==", + "license": "CPAL-1.0 OR AGPL-1.0" }, - "node_modules/cli-spinner": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/cli-spinner/-/cli-spinner-0.2.10.tgz", - "integrity": "sha512-U0sSQ+JJvSLi1pAYuJykwiA8Dsr15uHEy85iCJ6A+0DjVxivr3d+N2Wjvodeg89uP5K6TswFkKBfAD7B3YSn/Q==", - "engines": { - "node": ">=0.10" - } + "node_modules/clean-git-ref": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==", + "license": "Apache-2.0" }, "node_modules/cliui": { "version": "9.0.1", @@ -2726,51 +3007,85 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" }, "node_modules/colorjs.io": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } }, "node_modules/content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", "dependencies": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.7.0" } }, "node_modules/css-background-parser": { @@ -2814,380 +3129,10 @@ "postcss-value-parser": "^4.0.2" } }, - "node_modules/d3": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", - "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", - "dependencies": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "dependencies": { - "d3-path": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-contour": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", - "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", - "dependencies": { - "d3-array": "^3.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", - "dependencies": { - "delaunator": "5" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "dependencies": { - "d3-dsv": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3202,9 +3147,10 @@ } }, "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", "dependencies": { "character-entities": "^2.0.0" }, @@ -3213,18 +3159,43 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/delaunator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", "dependencies": { - "robust-predicates": "^3.0.0" + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -3242,6 +3213,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", "dependencies": { "dequal": "^2.0.0" }, @@ -3250,27 +3222,46 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/earcut": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", - "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", - "license": "ISC" + "node_modules/diff3": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, "node_modules/emoji-regex-xs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", - "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-2.0.1.tgz", + "integrity": "sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } }, "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -3278,12 +3269,43 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -3291,32 +3313,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, "node_modules/esbuild-sass-plugin": { @@ -3334,9 +3356,10 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -3351,6 +3374,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -3362,6 +3386,7 @@ "version": "3.2.25", "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -3370,6 +3395,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -3382,26 +3408,41 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/eventemitter3": { + "node_modules/event-target-shim": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT" + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" }, @@ -3426,15 +3467,15 @@ } }, "node_modules/fast-string-truncated-width": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.1.tgz", - "integrity": "sha512-tHCvcq0zdQ0NoTG3LJ1VlepCq7m4eAVMsbNrta9IlYxCPvgyoVJPl0rUbi+jTCkJLRQKfadVKNBuAlaa4nQJIw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", "license": "MIT" }, "node_modules/fastq": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -3444,6 +3485,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", "dependencies": { "format": "^0.2.0" }, @@ -3456,6 +3498,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz", "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==", + "license": "MIT", "dependencies": { "node-fetch": "~2.6.1" } @@ -3464,6 +3507,7 @@ "version": "2.6.13", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz", "integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -3479,25 +3523,6 @@ } } }, - "node_modules/fetch-ponyfill/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/fetch-ponyfill/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/fetch-ponyfill/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/fflate": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", @@ -3516,15 +3541,31 @@ "node": ">=8" } }, + "node_modules/fix-dts-default-cjs-exports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", + "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "rollup": "^4.34.8" + } + }, "node_modules/flexsearch": { - "version": "0.8.205", - "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.8.205.tgz", - "integrity": "sha512-REFjMqy86DKkCTJ4gIE42c9MVm9t1vUWfEub/8taixYuhvyu4jd4XmFALk5VuKW4GH4VLav8A4BJboTsslHF1w==", + "version": "0.8.212", + "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.8.212.tgz", + "integrity": "sha512-wSyJr1GUWoOOIISRu+X2IXiOcVfg9qqBRyCPRUdLMIGJqPzMo+jMRlvE83t14v1j0dRMEaBbER/adQjp6Du2pw==", "funding": [ { "type": "github", "url": "https://github.com/ts-thomas" }, + { + "type": "paypal", + "url": "https://www.paypal.com/donate/?hosted_button_id=GEVR88FC9BWRW" + }, { "type": "opencollective", "url": "https://opencollective.com/flexsearch" @@ -3536,18 +3577,25 @@ { "type": "liberapay", "url": "https://liberapay.com/ts-thomas" - }, - { - "type": "paypal", - "url": "https://www.paypal.com/donate/?hosted_button_id=GEVR88FC9BWRW" - }, - { - "type": "bountysource", - "url": "https://salt.bountysource.com/teams/ts-thomas" } ], "license": "Apache-2.0" }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/format": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", @@ -3562,6 +3610,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3583,14 +3632,15 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "license": "MIT", "engines": { "node": ">=18" @@ -3599,11 +3649,49 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-tsconfig": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", - "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", "dev": true, + "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -3611,19 +3699,11 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/gifuct-js": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/gifuct-js/-/gifuct-js-2.1.2.tgz", - "integrity": "sha512-rI2asw77u0mGgwhV3qA+OEgYqaDn5UNqgs+Bx0FGwSpuqfYn+Ir6RQY5ENNQ8SbIiG/m5gVa7CD5RriO4f4Lsg==", - "license": "MIT", - "dependencies": { - "js-binary-schema-parser": "^2.0.3" - } - }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", - "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" }, "node_modules/glob-parent": { "version": "5.1.2", @@ -3638,9 +3718,9 @@ } }, "node_modules/globby": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-16.1.0.tgz", - "integrity": "sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.1.1.tgz", + "integrity": "sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==", "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", @@ -3657,10 +3737,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gray-matter": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", @@ -3675,14 +3768,16 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/gray-matter/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3696,11 +3791,49 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -3714,12 +3847,13 @@ } }, "node_modules/hast-util-from-dom": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.0.tgz", - "integrity": "sha512-d6235voAp/XR3Hh5uy7aGLbM3S4KamdW0WEgOaU1YoewnuYw4HXb5eRtv9g65m/RFGEfUY1Mw4UqCc5Y8L4Stg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", + "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", + "license": "ISC", "dependencies": { "@types/hast": "^3.0.0", - "hastscript": "^8.0.0", + "hastscript": "^9.0.0", "web-namespaces": "^2.0.0" }, "funding": { @@ -3728,9 +3862,10 @@ } }, "node_modules/hast-util-from-html": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz", - "integrity": "sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", @@ -3748,6 +3883,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "hast-util-from-dom": "^5.0.0", @@ -3759,46 +3895,17 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-html/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/hast-util-from-html/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-html/node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/hast-util-from-parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", - "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", - "hastscript": "^8.0.0", - "property-information": "^6.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" @@ -3808,15 +3915,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/hast-util-heading-rank": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -3829,6 +3932,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -3841,6 +3945,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -3850,9 +3955,10 @@ } }, "node_modules/hast-util-raw": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.1.tgz", - "integrity": "sha512-5m1gmba658Q+lO5uqL5YNGQWeh1MYWZbZmWrM5lncdcuiXuo5E2HT/CIOp0rLF8ksfSwiCVJ3twlgVRyTGThGA==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", @@ -3873,11 +3979,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-raw/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/hast-util-to-html": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", @@ -3901,21 +4002,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-html/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/hast-util-to-html/node_modules/property-information": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz", - "integrity": "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", @@ -3943,55 +4029,16 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/hast-util-to-jsx-runtime/node_modules/property-information": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz", - "integrity": "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hast-util-to-jsx-runtime/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-jsx-runtime/node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/hast-util-to-parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", - "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" @@ -4005,6 +4052,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -4014,9 +4062,10 @@ } }, "node_modules/hast-util-to-text": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.0.tgz", - "integrity": "sha512-EWiE1FSArNBPUo1cKWtzqgnuRQwEeQbQtnFJRYV1hb1BWDgrAlBU0ExptvZMM/KSA82cDpm2sFGf3Dmc5Mza3w==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", @@ -4028,15 +4077,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-text/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -4046,14 +4091,15 @@ } }, "node_modules/hastscript": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", - "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" }, "funding": { @@ -4077,34 +4123,25 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { "node": ">= 14" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4122,7 +4159,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "7.0.5", @@ -4139,19 +4177,17 @@ "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", "license": "MIT" }, - "node_modules/inline-style-parser": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", - "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", - "license": "MIT" + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "engines": { - "node": ">=12" - } + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" }, "node_modules/is-absolute-url": { "version": "5.0.0", @@ -4169,6 +4205,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4178,6 +4215,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" @@ -4187,6 +4225,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -4206,6 +4256,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4215,6 +4266,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4244,6 +4296,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4274,6 +4327,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -4281,17 +4335,70 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ismobilejs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", - "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "license": "MIT" }, - "node_modules/js-binary-schema-parser": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz", - "integrity": "sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg==", - "license": "MIT" + "node_modules/isomorphic-git": { + "version": "1.37.2", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.37.2.tgz", + "integrity": "sha512-HCQBBKmXIMPdHgYGstSBNp6MNmVcMQBbUqJF8xfywFmlpNseO4KKex59YlXqNxhRxmv3fUZwvNWvMyOdc1VvhA==", + "license": "MIT", + "dependencies": { + "async-lock": "^1.4.1", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^4.0.0", + "sha.js": "^2.4.12", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/isomorphic-git/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/js-yaml": { "version": "4.1.1", @@ -4306,9 +4413,9 @@ } }, "node_modules/katex": { - "version": "0.16.21", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz", - "integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==", + "version": "0.16.32", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.32.tgz", + "integrity": "sha512-ac0FzkRJlpw4WyH3Zu/OgU9LmPKqjHr6O2BxfSrBt8uJ1BhvH2YK3oJ4ut/K+O+6qQt2MGpdbn0MrffVEnnUDQ==", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -4321,18 +4428,11 @@ "katex": "cli.js" } }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4586,6 +4686,19 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/linebreak": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", @@ -4605,28 +4718,67 @@ "node": ">= 0.4" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/markdown-table": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", - "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mathjax-full": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz", - "integrity": "sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.1.tgz", + "integrity": "sha512-aUz9o16MGZdeiIBwZjAfUBTiJb7LRqzZEl1YOZ8zQMGYIyh1/nxRebxKxjDe9L+xcZCr2OHdzoFBMcd6VnLv9Q==", + "license": "Apache-2.0", "dependencies": { "esm": "^3.2.25", "mhchemparser": "^4.1.0", @@ -4638,6 +4790,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", @@ -4650,9 +4803,10 @@ } }, "node_modules/mdast-util-from-markdown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", - "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -4672,27 +4826,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-from-markdown/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/mdast-util-from-markdown/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/mdast-util-frontmatter": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -4707,9 +4845,10 @@ } }, "node_modules/mdast-util-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", - "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", @@ -4725,9 +4864,10 @@ } }, "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", @@ -4741,9 +4881,10 @@ } }, "node_modules/mdast-util-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", @@ -4760,6 +4901,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -4774,6 +4916,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -4790,6 +4933,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -4805,6 +4949,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -4820,9 +4965,10 @@ } }, "node_modules/mdast-util-mdx-expression": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", - "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -4837,9 +4983,10 @@ } }, "node_modules/mdast-util-mdx-jsx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz", - "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -4851,7 +4998,6 @@ "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^5.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" }, @@ -4860,40 +5006,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/mdast-util-mdxjs-esm": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -4911,6 +5028,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-newline-to-break/-/mdast-util-newline-to-break-2.0.0.tgz", "integrity": "sha512-MbgeFca0hLYIEx/2zGsszCSEJJ1JSCdiY5xQxRcLDDGa8EPvlLPupJ4DSajbMPAnC0je8jfb9TiUATnxxrHUog==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-find-and-replace": "^3.0.0" @@ -4921,9 +5039,10 @@ } }, "node_modules/mdast-util-phrasing": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz", - "integrity": "sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" @@ -4955,15 +5074,17 @@ } }, "node_modules/mdast-util-to-markdown": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", - "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" @@ -4973,15 +5094,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-markdown/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/mdast-util-to-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" }, @@ -5002,12 +5119,13 @@ "node_modules/mhchemparser": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz", - "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==" + "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==", + "license": "Apache-2.0" }, "node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "funding": [ { "type": "GitHub Sponsors", @@ -5018,6 +5136,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -5039,9 +5158,9 @@ } }, "node_modules/micromark-core-commonmark": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", - "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "funding": [ { "type": "GitHub Sponsors", @@ -5052,6 +5171,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", @@ -5075,6 +5195,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", "dependencies": { "fault": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -5090,6 +5211,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", @@ -5106,9 +5228,10 @@ } }, "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", @@ -5121,9 +5244,10 @@ } }, "node_modules/micromark-extension-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", @@ -5140,9 +5264,10 @@ } }, "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -5157,9 +5282,10 @@ } }, "node_modules/micromark-extension-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", - "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", @@ -5176,6 +5302,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" }, @@ -5185,9 +5312,10 @@ } }, "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", - "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", @@ -5201,9 +5329,10 @@ } }, "node_modules/micromark-extension-math": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.0.0.tgz", - "integrity": "sha512-iJ2Q28vBoEovLN5o3GO12CpqorQRYDPT+p4zW50tGwTfJB+iv/VnB6Ini+gqa24K97DwptMBBIvVX6Bjk49oyQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "license": "MIT", "dependencies": { "@types/katex": "^0.16.0", "devlop": "^1.0.0", @@ -5219,9 +5348,9 @@ } }, "node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "funding": [ { "type": "GitHub Sponsors", @@ -5232,6 +5361,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -5239,9 +5369,9 @@ } }, "node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "funding": [ { "type": "GitHub Sponsors", @@ -5252,6 +5382,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -5260,9 +5391,9 @@ } }, "node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -5273,15 +5404,16 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "funding": [ { "type": "GitHub Sponsors", @@ -5292,6 +5424,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -5300,9 +5433,9 @@ } }, "node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "funding": [ { "type": "GitHub Sponsors", @@ -5313,6 +5446,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -5321,9 +5455,9 @@ } }, "node_modules/micromark-util-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", - "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -5334,15 +5468,16 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "funding": [ { "type": "GitHub Sponsors", @@ -5353,14 +5488,15 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "funding": [ { "type": "GitHub Sponsors", @@ -5371,6 +5507,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -5378,9 +5515,9 @@ } }, "node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "funding": [ { "type": "GitHub Sponsors", @@ -5391,15 +5528,16 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "funding": [ { "type": "GitHub Sponsors", @@ -5410,14 +5548,15 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "funding": [ { "type": "GitHub Sponsors", @@ -5428,6 +5567,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -5436,39 +5576,9 @@ } }, "node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", "funding": [ { "type": "GitHub Sponsors", @@ -5479,14 +5589,47 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", "funding": [ { "type": "GitHub Sponsors", @@ -5497,14 +5640,15 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", "funding": [ { "type": "GitHub Sponsors", @@ -5515,6 +5659,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", @@ -5522,9 +5667,9 @@ } }, "node_modules/micromark-util-subtokenize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", - "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "funding": [ { "type": "GitHub Sponsors", @@ -5535,6 +5680,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -5543,9 +5689,9 @@ } }, "node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -5555,12 +5701,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "funding": [ { "type": "GitHub Sponsors", @@ -5570,7 +5717,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromatch": { "version": "4.0.8", @@ -5588,12 +5736,14 @@ "node_modules/micromorph": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/micromorph/-/micromorph-0.4.5.tgz", - "integrity": "sha512-Erasr0xiDvDeEhh7B/k7RFTwwfaAX10D7BMorNpokkwDh6XsRLYWDPaWF1m5JQeMSkGdqlEtQ8s68NcdDWuGgw==" + "integrity": "sha512-Erasr0xiDvDeEhh7B/k7RFTwwfaAX10D7BMorNpokkwDh6XsRLYWDPaWF1m5JQeMSkGdqlEtQ8s68NcdDWuGgw==", + "license": "MIT" }, "node_modules/mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5602,6 +5752,7 @@ "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "license": "MIT", "dependencies": { "mime-db": "~1.33.0" }, @@ -5609,30 +5760,75 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", + "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimisted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5" + } + }, "node_modules/mj-context-menu": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", - "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" + "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==", + "license": "Apache-2.0" + }, + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } }, "node_modules/moo": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", - "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==", + "license": "BSD-3-Clause" }, "node_modules/ms": { "version": "2.1.3", @@ -5640,10 +5836,23 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nlcst-to-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0" }, @@ -5663,6 +5872,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -5678,40 +5888,47 @@ } } }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/oniguruma-to-es": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-1.0.0.tgz", - "integrity": "sha512-kihvp0O4lFwf5tZMkfanwQLIZ9ORe9OeOFgZonH0BQeThgwfJiaZFeOfvvJVnJIM9TiVmx0RDD35hUJDR0++rQ==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { - "emoji-regex-xs": "^1.0.0", - "regex": "^5.1.1", - "regex-recursion": "^5.1.1" + "wrappy": "1" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz", + "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" } }, "node_modules/pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", - "license": "MIT" + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" }, "node_modules/parse-css-color": { "version": "0.2.1", @@ -5724,12 +5941,12 @@ } }, "node_modules/parse-entities": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", - "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", - "character-entities": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", @@ -5742,10 +5959,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, "node_modules/parse-latin": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", "@types/unist": "^3.0.0", @@ -5759,28 +5983,19 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/parse-latin/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/parse-numeric-range": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", - "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" - }, - "node_modules/parse-svg-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", - "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", - "license": "MIT" + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", + "license": "ISC" }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", "dependencies": { - "entities": "^4.4.0" + "entities": "^6.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -5789,7 +6004,8 @@ "node_modules/path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "license": "(WTFPL OR MIT)" }, "node_modules/path-parse": { "version": "1.0.7", @@ -5800,7 +6016,15 @@ "node_modules/path-to-regexp": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", - "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==" + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", @@ -5820,27 +6044,87 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pixi.js": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.15.0.tgz", - "integrity": "sha512-J/Ghze/K9fjHRlfwC2EMZ7vnMIhGo4ByKCsKMcS0AB12iT79nf9zzWKUTzMJ8QAQFqQfDOl5ULwmHMUdeih2zQ==", + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, "license": "MIT", "dependencies": { - "@pixi/colord": "^2.9.6", - "@types/css-font-loading-module": "^0.0.12", - "@types/earcut": "^3.0.0", - "@webgpu/types": "^0.1.40", - "@xmldom/xmldom": "^0.8.10", - "earcut": "^3.0.2", - "eventemitter3": "^5.0.1", - "gifuct-js": "^2.1.2", - "ismobilejs": "^1.1.1", - "parse-svg-path": "^0.1.2", - "tiny-lru": "^11.4.5" + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/pixijs" + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, "node_modules/postcss-value-parser": { @@ -5850,19 +6134,20 @@ "license": "MIT" }, "node_modules/preact": { - "version": "10.28.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz", - "integrity": "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==", + "version": "10.28.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz", + "integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" } }, "node_modules/preact-render-to-string": { - "version": "6.6.5", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.6.5.tgz", - "integrity": "sha512-O6MHzYNIKYaiSX3bOw0gGZfEbOmlIDtDfWwN1JJdc/T3ihzRT6tGGSEWE088dWrEDGa1u7101q+6fzQnO9XCPA==", + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.6.6.tgz", + "integrity": "sha512-EfqZJytnjJldV+YaaqhthU2oXsEf5e+6rDv957p+zxAvNfFLQOPfvBOTncscQ+akzu6Wrl7s3Pa0LjUQmWJsGQ==", "license": "MIT", "peerDependencies": { "preact": ">=10 || >= 11.0.0-0" @@ -5900,14 +6185,25 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/property-information": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.2.0.tgz", - "integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -5937,10 +6233,27 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/readdirp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", @@ -5957,34 +6270,38 @@ "node_modules/reading-time": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", - "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", + "license": "MIT" }, "node_modules/regex": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/regex/-/regex-5.1.1.tgz", - "integrity": "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" } }, "node_modules/regex-recursion": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-5.1.1.tgz", - "integrity": "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", "dependencies": { - "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, "node_modules/regex-utilities": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", - "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==" + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" }, "node_modules/rehype-autolink-headings": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz", "integrity": "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@ungap/structured-clone": "^1.0.0", @@ -5999,31 +6316,44 @@ } }, "node_modules/rehype-citation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/rehype-citation/-/rehype-citation-2.3.1.tgz", - "integrity": "sha512-bwSuB5SMilyS/vT7K7ByTxjeKda4GWJin6dHKKZyp5O2z+uLk2ySG7a5/IOmuGovoajN9AcYxTRE4kUiVTk51g==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/rehype-citation/-/rehype-citation-2.3.2.tgz", + "integrity": "sha512-apeGbeIYrfbirZZMZ0KY9tEZPnMlqomlGbQDNJfMoTV8wBSmLq8XyBywlfHrPLvchFIq9Mrn7g7SmXdQob+5lw==", "license": "MIT", "dependencies": { - "@citation-js/core": "^0.7.14", + "@citation-js/core": "^0.7.21", "@citation-js/date": "^0.5.1", "@citation-js/name": "^0.4.2", - "@citation-js/plugin-bibjson": "^0.7.14", - "@citation-js/plugin-bibtex": "^0.7.14", - "@citation-js/plugin-csl": "^0.7.14", + "@citation-js/plugin-bibjson": "^0.7.21", + "@citation-js/plugin-bibtex": "^0.7.21", + "@citation-js/plugin-csl": "^0.7.22", "citeproc": "^2.4.63", - "cross-fetch": "^4.0.0", - "hast-util-from-dom": "^5.0.0", - "hast-util-from-parse5": "^8.0.1", - "js-yaml": "^4.1.0", - "parse5": "^7.1.2", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0" + "cross-fetch": "^4.1.0", + "hast-util-from-dom": "^5.0.1", + "hast-util-from-parse5": "^8.0.3", + "js-yaml": "^4.1.1", + "parse5": "^8.0.0", + "unified": "^11.0.5", + "unist-util-visit": "^5.1.0" + } + }, + "node_modules/rehype-citation/node_modules/parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, "node_modules/rehype-katex": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/katex": "^0.16.0", @@ -6058,27 +6388,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-mathjax/node_modules/hastscript": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz", - "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/rehype-parse": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.0.tgz", - "integrity": "sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "hast-util-from-html": "^2.0.0", @@ -6113,6 +6427,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", @@ -6127,6 +6442,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "github-slugger": "^2.0.0", @@ -6139,25 +6455,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", - "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", - "dependencies": { - "@types/mdast": "^4.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/remark-breaks": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/remark-breaks/-/remark-breaks-4.0.0.tgz", "integrity": "sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-newline-to-break": "^2.0.0", @@ -6172,6 +6474,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-frontmatter": "^2.0.0", @@ -6205,6 +6508,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-math": "^3.0.0", @@ -6220,6 +6524,7 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -6252,6 +6557,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", + "license": "MIT", "dependencies": { "retext": "^9.0.0", "retext-smartypants": "^6.0.0", @@ -6266,6 +6572,7 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", @@ -6296,11 +6603,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -6309,6 +6627,7 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", "retext-latin": "^4.0.0", @@ -6324,6 +6643,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", "parse-latin": "^7.0.0", @@ -6335,9 +6655,10 @@ } }, "node_modules/retext-smartypants": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.1.0.tgz", - "integrity": "sha512-LDPXg95346bqFZnDMHo0S7Rq5p64+B+N8Vz733+wPMDtwb9rCOs9LIdIEhrUOU+TAywX9St+ocQWJt8wrzivcQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", @@ -6352,6 +6673,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "license": "MIT", "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", @@ -6363,9 +6685,9 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -6375,12 +6697,53 @@ "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } }, "node_modules/run-parallel": { "version": "1.2.0", @@ -6405,30 +6768,39 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" - }, "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, "node_modules/sass": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.2.tgz", - "integrity": "sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", "license": "MIT", "dependencies": { "chokidar": "^4.0.0", @@ -6446,14 +6818,13 @@ } }, "node_modules/sass-embedded": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.97.2.tgz", - "integrity": "sha512-lKJcskySwAtJ4QRirKrikrWMFa2niAuaGenY2ElHjd55IwHUiur5IdKu6R1hEmGYMs4Qm+6rlRW0RvuAkmcryg==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.97.3.tgz", + "integrity": "sha512-eKzFy13Nk+IRHhlAwP3sfuv+PzOrvzUkwJK2hdoCKYcWGSdmwFpeGpWmyewdw8EgBnsKaSBtgf/0b2K635ecSA==", "license": "MIT", "peer": true, "dependencies": { "@bufbuild/protobuf": "^2.5.0", - "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", @@ -6468,30 +6839,30 @@ "node": ">=16.0.0" }, "optionalDependencies": { - "sass-embedded-all-unknown": "1.97.2", - "sass-embedded-android-arm": "1.97.2", - "sass-embedded-android-arm64": "1.97.2", - "sass-embedded-android-riscv64": "1.97.2", - "sass-embedded-android-x64": "1.97.2", - "sass-embedded-darwin-arm64": "1.97.2", - "sass-embedded-darwin-x64": "1.97.2", - "sass-embedded-linux-arm": "1.97.2", - "sass-embedded-linux-arm64": "1.97.2", - "sass-embedded-linux-musl-arm": "1.97.2", - "sass-embedded-linux-musl-arm64": "1.97.2", - "sass-embedded-linux-musl-riscv64": "1.97.2", - "sass-embedded-linux-musl-x64": "1.97.2", - "sass-embedded-linux-riscv64": "1.97.2", - "sass-embedded-linux-x64": "1.97.2", - "sass-embedded-unknown-all": "1.97.2", - "sass-embedded-win32-arm64": "1.97.2", - "sass-embedded-win32-x64": "1.97.2" + "sass-embedded-all-unknown": "1.97.3", + "sass-embedded-android-arm": "1.97.3", + "sass-embedded-android-arm64": "1.97.3", + "sass-embedded-android-riscv64": "1.97.3", + "sass-embedded-android-x64": "1.97.3", + "sass-embedded-darwin-arm64": "1.97.3", + "sass-embedded-darwin-x64": "1.97.3", + "sass-embedded-linux-arm": "1.97.3", + "sass-embedded-linux-arm64": "1.97.3", + "sass-embedded-linux-musl-arm": "1.97.3", + "sass-embedded-linux-musl-arm64": "1.97.3", + "sass-embedded-linux-musl-riscv64": "1.97.3", + "sass-embedded-linux-musl-x64": "1.97.3", + "sass-embedded-linux-riscv64": "1.97.3", + "sass-embedded-linux-x64": "1.97.3", + "sass-embedded-unknown-all": "1.97.3", + "sass-embedded-win32-arm64": "1.97.3", + "sass-embedded-win32-x64": "1.97.3" } }, "node_modules/sass-embedded-all-unknown": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.97.2.tgz", - "integrity": "sha512-Fj75+vOIDv1T/dGDwEpQ5hgjXxa2SmMeShPa8yrh2sUz1U44bbmY4YSWPCdg8wb7LnwiY21B2KRFM+HF42yO4g==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.97.3.tgz", + "integrity": "sha512-t6N46NlPuXiY3rlmG6/+1nwebOBOaLFOOVqNQOC2cJhghOD4hh2kHNQQTorCsbY9S1Kir2la1/XLBwOJfui0xg==", "cpu": [ "!arm", "!arm64", @@ -6500,15 +6871,14 @@ ], "license": "MIT", "optional": true, - "peer": true, "dependencies": { - "sass": "1.97.2" + "sass": "1.97.3" } }, "node_modules/sass-embedded-android-arm": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.97.2.tgz", - "integrity": "sha512-BPT9m19ttY0QVHYYXRa6bmqmS3Fa2EHByNUEtSVcbm5PkIk1ntmYkG9fn5SJpIMbNmFDGwHx+pfcZMmkldhnRg==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.97.3.tgz", + "integrity": "sha512-cRTtf/KV/q0nzGZoUzVkeIVVFv3L/tS1w4WnlHapphsjTXF/duTxI8JOU1c/9GhRPiMdfeXH7vYNcMmtjwX7jg==", "cpu": [ "arm" ], @@ -6517,15 +6887,14 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-android-arm64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.97.2.tgz", - "integrity": "sha512-pF6I+R5uThrscd3lo9B3DyNTPyGFsopycdx0tDAESN6s+dBbiRgNgE4Zlpv50GsLocj/lDLCZaabeTpL3ubhYA==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.97.3.tgz", + "integrity": "sha512-aiZ6iqiHsUsaDx0EFbbmmA0QgxicSxVVN3lnJJ0f1RStY0DthUkquGT5RJ4TPdaZ6ebeJWkboV4bra+CP766eA==", "cpu": [ "arm64" ], @@ -6534,15 +6903,14 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-android-riscv64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.97.2.tgz", - "integrity": "sha512-fprI8ZTJdz+STgARhg8zReI2QhhGIT9G8nS7H21kc3IkqPRzhfaemSxEtCqZyvDbXPcgYiDLV7AGIReHCuATog==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.97.3.tgz", + "integrity": "sha512-zVEDgl9JJodofGHobaM/q6pNETG69uuBIGQHRo789jloESxxZe82lI3AWJQuPmYCOG5ElfRthqgv89h3gTeLYA==", "cpu": [ "riscv64" ], @@ -6551,15 +6919,14 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-android-x64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.97.2.tgz", - "integrity": "sha512-RswwSjURZxupsukEmNt2t6RGvuvIw3IAD5sDq1Pc65JFvWFY3eHqCmH0lG0oXqMg6KJcF0eOxHOp2RfmIm2+4w==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.97.3.tgz", + "integrity": "sha512-3ke0le7ZKepyXn/dKKspYkpBC0zUk/BMciyP5ajQUDy4qJwobd8zXdAq6kOkdiMB+d9UFJOmEkvgFJHl3lqwcw==", "cpu": [ "x64" ], @@ -6568,15 +6935,14 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-darwin-arm64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.97.2.tgz", - "integrity": "sha512-xcsZNnU1XZh21RE/71OOwNqPVcGBU0qT9A4k4QirdA34+ts9cDIaR6W6lgHOBR/Bnnu6w6hXJR4Xth7oFrefPA==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.97.3.tgz", + "integrity": "sha512-fuqMTqO4gbOmA/kC5b9y9xxNYw6zDEyfOtMgabS7Mz93wimSk2M1quQaTJnL98Mkcsl2j+7shNHxIS/qpcIDDA==", "cpu": [ "arm64" ], @@ -6585,15 +6951,14 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-darwin-x64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.97.2.tgz", - "integrity": "sha512-T/9DTMpychm6+H4slHCAsYJRJ6eM+9H9idKlBPliPrP4T8JdC2Cs+ZOsYqrObj6eOtAD0fGf+KgyNhnW3xVafA==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.97.3.tgz", + "integrity": "sha512-b/2RBs/2bZpP8lMkyZ0Px0vkVkT8uBd0YXpOwK7iOwYkAT8SsO4+WdVwErsqC65vI5e1e5p1bb20tuwsoQBMVA==", "cpu": [ "x64" ], @@ -6602,15 +6967,14 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-linux-arm": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.97.2.tgz", - "integrity": "sha512-yDRe1yifGHl6kibkDlRIJ2ZzAU03KJ1AIvsAh4dsIDgK5jx83bxZLV1ZDUv7a8KK/iV/80LZnxnu/92zp99cXQ==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.97.3.tgz", + "integrity": "sha512-2lPQ7HQQg4CKsH18FTsj2hbw5GJa6sBQgDsls+cV7buXlHjqF8iTKhAQViT6nrpLK/e8nFCoaRgSqEC8xMnXuA==", "cpu": [ "arm" ], @@ -6619,15 +6983,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-linux-arm64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.97.2.tgz", - "integrity": "sha512-Wh+nQaFer9tyE5xBPv5murSUZE/+kIcg8MyL5uqww6be9Iq+UmZpcJM7LUk+q8klQ9LfTmoDSNFA74uBqxD6IA==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.97.3.tgz", + "integrity": "sha512-IP1+2otCT3DuV46ooxPaOKV1oL5rLjteRzf8ldZtfIEcwhSgSsHgA71CbjYgLEwMY9h4jeal8Jfv3QnedPvSjg==", "cpu": [ "arm64" ], @@ -6636,15 +6999,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-linux-musl-arm": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.97.2.tgz", - "integrity": "sha512-GIO6xfAtahJAWItvsXZ3MD1HM6s8cKtV1/HL088aUpKJaw/2XjTCveiOO2AdgMpLNztmq9DZ1lx5X5JjqhS45g==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.97.3.tgz", + "integrity": "sha512-cBTMU68X2opBpoYsSZnI321gnoaiMBEtc+60CKCclN6PCL3W3uXm8g4TLoil1hDD6mqU9YYNlVG6sJ+ZNef6Lg==", "cpu": [ "arm" ], @@ -6653,15 +7015,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-linux-musl-arm64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.97.2.tgz", - "integrity": "sha512-NfUqZSjHwnHvpSa7nyNxbWfL5obDjNBqhHUYmqbHUcmqBpFfHIQsUPgXME9DKn1yBlBc3mWnzMxRoucdYTzd2Q==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.97.3.tgz", + "integrity": "sha512-Lij0SdZCsr+mNRSyDZ7XtJpXEITrYsaGbOTz5e6uFLJ9bmzUbV7M8BXz2/cA7bhfpRPT7/lwRKPdV4+aR9Ozcw==", "cpu": [ "arm64" ], @@ -6670,15 +7031,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-linux-musl-riscv64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.97.2.tgz", - "integrity": "sha512-qtM4dJ5gLfvyTZ3QencfNbsTEShIWImSEpkThz+Y2nsCMbcMP7/jYOA03UWgPfEOKSehQQ7EIau7ncbFNoDNPQ==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.97.3.tgz", + "integrity": "sha512-sBeLFIzMGshR4WmHAD4oIM7WJVkSoCIEwutzptFtGlSlwfNiijULp+J5hA2KteGvI6Gji35apR5aWj66wEn/iA==", "cpu": [ "riscv64" ], @@ -6687,15 +7047,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-linux-musl-x64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.97.2.tgz", - "integrity": "sha512-ZAxYOdmexcnxGnzdsDjYmNe3jGj+XW3/pF/n7e7r8y+5c6D2CQRrCUdapLgaqPt1edOPQIlQEZF8q5j6ng21yw==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.97.3.tgz", + "integrity": "sha512-/oWJ+OVrDg7ADDQxRLC/4g1+Nsz1g4mkYS2t6XmyMJKFTFK50FVI2t5sOdFH+zmMp+nXHKM036W94y9m4jjEcw==", "cpu": [ "x64" ], @@ -6704,15 +7063,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-linux-riscv64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.97.2.tgz", - "integrity": "sha512-reVwa9ZFEAOChXpDyNB3nNHHyAkPMD+FTctQKECqKiVJnIzv2EaFF6/t0wzyvPgBKeatA8jszAIeOkkOzbYVkQ==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.97.3.tgz", + "integrity": "sha512-l3IfySApLVYdNx0Kjm7Zehte1CDPZVcldma3dZt+TfzvlAEerM6YDgsk5XEj3L8eHBCgHgF4A0MJspHEo2WNfA==", "cpu": [ "riscv64" ], @@ -6721,15 +7079,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-linux-x64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.97.2.tgz", - "integrity": "sha512-bvAdZQsX3jDBv6m4emaU2OMTpN0KndzTAMgJZZrKUgiC0qxBmBqbJG06Oj/lOCoXGCxAvUOheVYpezRTF+Feog==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.97.3.tgz", + "integrity": "sha512-Kwqwc/jSSlcpRjULAOVbndqEy2GBzo6OBmmuBVINWUaJLJ8Kczz3vIsDUWLfWz/kTEw9FHBSiL0WCtYLVAXSLg==", "cpu": [ "x64" ], @@ -6738,15 +7095,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-unknown-all": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.97.2.tgz", - "integrity": "sha512-86tcYwohjPgSZtgeU9K4LikrKBJNf8ZW/vfsFbdzsRlvc73IykiqanufwQi5qIul0YHuu9lZtDWyWxM2dH/Rsg==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.97.3.tgz", + "integrity": "sha512-/GHajyYJmvb0IABUQHbVHf1nuHPtIDo/ClMZ81IDr59wT5CNcMe7/dMNujXwWugtQVGI5UGmqXWZQCeoGnct8Q==", "license": "MIT", "optional": true, "os": [ @@ -6755,15 +7111,14 @@ "!linux", "!win32" ], - "peer": true, "dependencies": { - "sass": "1.97.2" + "sass": "1.97.3" } }, "node_modules/sass-embedded-win32-arm64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.97.2.tgz", - "integrity": "sha512-Cv28q8qNjAjZfqfzTrQvKf4JjsZ6EOQ5FxyHUQQeNzm73R86nd/8ozDa1Vmn79Hq0kwM15OCM9epanDuTG1ksA==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.97.3.tgz", + "integrity": "sha512-RDGtRS1GVvQfMGAmVXNxYiUOvPzn9oO1zYB/XUM9fudDRnieYTcUytpNTQZLs6Y1KfJxgt5Y+giRceC92fT8Uw==", "cpu": [ "arm64" ], @@ -6772,15 +7127,14 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/sass-embedded-win32-x64": { - "version": "1.97.2", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.97.2.tgz", - "integrity": "sha512-DVxLxkeDCGIYeyHLAvWW3yy9sy5Ruk5p472QWiyfyyG1G1ASAR8fgfIY5pT0vE6Rv+VAKVLwF3WTspUYu7S1/Q==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.97.3.tgz", + "integrity": "sha512-SFRa2lED9UEwV6vIGeBXeBOLKF+rowF3WmNfb/BzhxmdAsKofCXrJ8ePW7OcDVrvNEbTOGwhsReIsF5sH8fVaw==", "cpu": [ "x64" ], @@ -6789,7 +7143,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=14.0.0" } @@ -6823,9 +7176,9 @@ } }, "node_modules/satori": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/satori/-/satori-0.19.1.tgz", - "integrity": "sha512-/XaT/JiWLfNlgjlQdde4wXB1/6F+FEze9c3OW2QIH0ywsfOrY57YOetgESWyOFHW3JfEQ6dJAo2U9Xwb7+DDAw==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/satori/-/satori-0.19.2.tgz", + "integrity": "sha512-71plFHWcq6WJBM5sf/n0eHOmTBiKLUB/G8du7SmLTTLHKEKrV3TPHGKcEVIoyjnbhnjvu9HhLyF9MATB/zzL7g==", "license": "MPL-2.0", "dependencies": { "@shuding/opentype.js": "1.4.0-beta.0", @@ -6844,19 +7197,11 @@ "node": ">=16" } }, - "node_modules/satori/node_modules/emoji-regex-xs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-2.0.1.tgz", - "integrity": "sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" @@ -6866,9 +7211,9 @@ } }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6881,6 +7226,7 @@ "version": "6.1.6", "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", + "license": "MIT", "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", @@ -6891,10 +7237,17 @@ "range-parser": "1.2.0" } }, + "node_modules/serve-handler/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, "node_modules/serve-handler/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6904,6 +7257,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6911,6 +7265,43 @@ "node": "*" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/sharp": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", @@ -6956,20 +7347,67 @@ } }, "node_modules/shiki": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.26.2.tgz", - "integrity": "sha512-iP7u2NA9A6JwRRCkIUREEX2cMhlYV5EBmbbSlfSRvPThwca8HBRbVkWuNWW+kw9+i6BSUZqqG6YeUs5dC2SjZw==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.22.0.tgz", + "integrity": "sha512-LBnhsoYEe0Eou4e1VgJACes+O6S6QC0w71fCSp5Oya79inkwkm15gQ1UF6VtQ8j/taMDh79hAB49WUk8ALQW3g==", + "license": "MIT", + "peer": true, "dependencies": { - "@shikijs/core": "1.26.2", - "@shikijs/engine-javascript": "1.26.2", - "@shikijs/engine-oniguruma": "1.26.2", - "@shikijs/langs": "1.26.2", - "@shikijs/themes": "1.26.2", - "@shikijs/types": "1.26.2", - "@shikijs/vscode-textmate": "^10.0.1", + "@shikijs/core": "3.22.0", + "@shikijs/engine-javascript": "3.22.0", + "@shikijs/engine-oniguruma": "3.22.0", + "@shikijs/langs": "3.22.0", + "@shikijs/themes": "3.22.0", + "@shikijs/types": "3.22.0", + "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -6980,6 +7418,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", "engines": { "node": ">=14.16" }, @@ -6991,6 +7430,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -7008,6 +7448,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -7017,36 +7458,49 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/speech-rule-engine": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz", - "integrity": "sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.1.2.tgz", + "integrity": "sha512-S6ji+flMEga+1QU79NDbwZ8Ivf0S/MpupQQiIC0rTpU/ZTKgcajijJJb1OcByBQDjrXCN1/DJtGz4ZJeBMPGJw==", + "license": "Apache-2.0", "dependencies": { - "commander": "9.2.0", - "wicked-good-xpath": "1.3.0", - "xmldom-sre": "0.1.31" + "@xmldom/xmldom": "0.9.8", + "commander": "13.1.0", + "wicked-good-xpath": "1.3.0" }, "bin": { "sre": "bin/sre" } }, "node_modules/speech-rule-engine/node_modules/commander": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", - "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", "engines": { - "node": "^12.20.0 || >=14" + "node": ">=18" } }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } }, "node_modules/string-width": { "version": "7.2.0", @@ -7072,9 +7526,10 @@ "license": "MIT" }, "node_modules/stringify-entities": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", - "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" @@ -7085,9 +7540,9 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -7103,26 +7558,60 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/style-to-js": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.16.tgz", - "integrity": "sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", "license": "MIT", "dependencies": { - "style-to-object": "1.0.8" + "style-to-object": "1.0.14" } }, "node_modules/style-to-object": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", - "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", "license": "MIT", "dependencies": { - "inline-style-parser": "0.2.4" + "inline-style-parser": "0.2.7" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" } }, "node_modules/supports-color": { @@ -7130,7 +7619,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -7158,7 +7646,6 @@ "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", "license": "MIT", - "peer": true, "dependencies": { "sync-message-port": "^1.0.0" }, @@ -7170,6 +7657,7 @@ "version": "0.4.5", "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.5.tgz", "integrity": "sha512-esiWJ7ixSKGpd9DJPBTC4ckChqdOjIwJfYhVHkcQ2Gnm41323p1TRmEI+esTQ9ppD+b5opps2OTEGTCGX5kF+g==", + "license": "MIT", "dependencies": { "buffer": "^5.7.1", "node-fetch": "^2.6.1" @@ -7178,29 +7666,136 @@ "node": ">=14" } }, - "node_modules/sync-message-port": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz", - "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==", + "node_modules/sync-fetch/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/sync-message-port": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.2.0.tgz", + "integrity": "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==", "license": "MIT", - "peer": true, "engines": { "node": ">=16.0.0" } }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/tiny-inflate": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "license": "MIT" }, - "node_modules/tiny-lru": { - "version": "11.4.5", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-11.4.5.tgz", - "integrity": "sha512-hkcz3FjNJfKXjV4mjQ1OrXSLAehg8Hw+cEZclOVT+5c/cWQWImQ9wolzTjth+dmmDe++p3bme3fTxz6Q4Etsqw==", - "license": "BSD-3-Clause", + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/to-regex-range": { @@ -7219,6 +7814,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-8.0.0.tgz", "integrity": "sha512-IcmH1xB5576MJc9qcfEC/m/nQCFt3fzMHz45sSlgJyTWjRbKW1HAkJpuf3DgE57YzIlZcwcBZA5ENQbBo4aLkg==", + "license": "MIT", "dependencies": { "vfile": "^6.0.0" }, @@ -7230,30 +7826,150 @@ "node_modules/toml": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/trough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsup": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", + "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.27.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "^0.7.6", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/tsup/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/tsup/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } }, "node_modules/tsx": { "version": "4.21.0", @@ -7261,6 +7977,7 @@ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" @@ -7275,6 +7992,20 @@ "fsevents": "~2.3.3" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -7289,10 +8020,17 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true, "license": "MIT" }, @@ -7306,6 +8044,12 @@ "tiny-inflate": "^1.0.0" } }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, "node_modules/unicorn-magic": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", @@ -7322,6 +8066,7 @@ "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -7336,15 +8081,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unified/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/unist-util-find-after": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -7354,15 +8095,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-find-after/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -7372,16 +8108,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-is/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unist-util-modify-children": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "array-iterate": "^2.0.0" @@ -7391,15 +8122,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-modify-children/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/unist-util-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -7408,15 +8135,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-position/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/unist-util-remove-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" @@ -7426,10 +8149,18 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-remove-position/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, "node_modules/unist-util-visit": { "version": "5.1.0", @@ -7450,6 +8181,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -7458,15 +8190,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-visit-children/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -7477,28 +8204,17 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-visit-parents/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/unist-util-visit/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, "node_modules/varint": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" @@ -7509,9 +8225,10 @@ } }, "node_modules/vfile-location": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz", - "integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" @@ -7521,32 +8238,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-location/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/vfile/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/vfile/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile/node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" @@ -7560,15 +8256,54 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wicked-good-xpath": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", - "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==" + "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==", + "license": "MIT" }, "node_modules/workerpool": { "version": "10.0.1", @@ -7577,9 +8312,9 @@ "license": "Apache-2.0" }, "node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -7593,6 +8328,12 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, "node_modules/ws": { "version": "8.19.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", @@ -7614,22 +8355,31 @@ } } }, - "node_modules/xmldom-sre": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", - "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==", - "engines": { - "node": ">=0.1" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", "engines": { "node": ">=10" } }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "license": "ISC", + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", @@ -7666,6 +8416,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" diff --git a/package.json b/package.json index e1d138a52..ea34c0b5f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@jackyzha0/quartz", "description": "🌱 publish your digital garden and notes as a website", "private": true, - "version": "4.5.2", + "version": "5.0.0", "type": "module", "author": "jackyzha0 ", "license": "MIT", @@ -17,7 +17,9 @@ "check": "tsc --noEmit && npx prettier . --check", "format": "npx prettier . --write", "test": "tsx --test", - "profile": "0x -D prof ./quartz/bootstrap-cli.mjs build --concurrency=1" + "profile": "0x -D prof ./quartz/bootstrap-cli.mjs build --concurrency=1", + "install-plugins": "npx tsx ./quartz/plugins/loader/install-plugins.ts", + "prebuild": "npm run install-plugins" }, "engines": { "npm": ">=10.9.2", @@ -39,12 +41,9 @@ "@floating-ui/dom": "^1.7.4", "@myriaddreamin/rehype-typst": "^0.6.0", "@napi-rs/simple-git": "0.1.22", - "@tweenjs/tween.js": "^25.0.0", "ansi-truncate": "^1.4.0", "async-mutex": "^0.5.0", "chokidar": "^5.0.0", - "cli-spinner": "^0.2.10", - "d3": "^7.9.0", "esbuild-sass-plugin": "^3.6.0", "flexsearch": "^0.8.205", "github-slugger": "^2.0.0", @@ -54,6 +53,7 @@ "hast-util-to-jsx-runtime": "^2.3.6", "hast-util-to-string": "^3.0.1", "is-absolute-url": "^5.0.0", + "isomorphic-git": "^1.36.3", "js-yaml": "^4.1.1", "lightningcss": "^1.31.1", "mdast-util-find-and-replace": "^3.0.2", @@ -61,7 +61,6 @@ "mdast-util-to-string": "^4.0.0", "micromorph": "^0.4.5", "minimatch": "^10.1.1", - "pixi.js": "^8.15.0", "preact": "^10.28.2", "preact-render-to-string": "^6.6.5", "pretty-bytes": "^7.1.0", @@ -74,7 +73,6 @@ "rehype-pretty-code": "^0.14.1", "rehype-raw": "^7.0.0", "rehype-slug": "^6.0.0", - "remark": "^15.0.1", "remark-breaks": "^4.0.0", "remark-frontmatter": "^5.0.0", "remark-gfm": "^4.0.1", @@ -86,7 +84,6 @@ "satori": "^0.19.1", "serve-handler": "^6.1.6", "sharp": "^0.34.5", - "shiki": "^1.26.2", "source-map-support": "^0.5.21", "to-vfile": "^8.0.0", "toml": "^3.0.0", @@ -95,10 +92,12 @@ "vfile": "^6.0.3", "workerpool": "^10.0.1", "ws": "^8.19.0", + "yaml": "^2.8.2", "yargs": "^18.0.0" }, "devDependencies": { - "@types/d3": "^7.4.3", + "@quartz-community/types": "github:quartz-community/types", + "@quartz-community/utils": "github:quartz-community/utils", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", "@types/node": "^25.0.10", diff --git a/quartz.config.default.yaml b/quartz.config.default.yaml new file mode 100644 index 000000000..10ab03bfb --- /dev/null +++ b/quartz.config.default.yaml @@ -0,0 +1,270 @@ +# yaml-language-server: $schema=./quartz/plugins/quartz-plugins.schema.json +configuration: + pageTitle: Quartz 5 + pageTitleSuffix: "" + enableSPA: true + enablePopovers: true + analytics: + provider: plausible + locale: en-US + baseUrl: quartz.jzhao.xyz + ignorePatterns: + - private + - templates + - .obsidian + defaultDateType: modified + theme: + fontOrigin: googleFonts + cdnCaching: true + typography: + header: Schibsted Grotesk + body: Source Sans Pro + code: IBM Plex Mono + colors: + lightMode: + light: "#faf8f8" + lightgray: "#e5e5e5" + gray: "#b8b8b8" + darkgray: "#4e4e4e" + dark: "#2b2b2b" + secondary: "#284b63" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#fff23688" + darkMode: + light: "#161618" + lightgray: "#393639" + gray: "#646464" + darkgray: "#d4d4d4" + dark: "#ebebec" + secondary: "#7b97aa" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#b3aa0288" +plugins: + - source: github:quartz-community/created-modified-date + enabled: true + options: + priority: + - frontmatter + - git + - filesystem + order: 10 + - source: github:quartz-community/syntax-highlighting + enabled: true + options: + theme: + light: github-light + dark: github-dark + keepBackground: false + order: 20 + - source: github:quartz-community/obsidian-flavored-markdown + enabled: true + options: + enableInHtmlEmbed: false + enableCheckbox: true + order: 30 + - source: github:quartz-community/github-flavored-markdown + enabled: true + order: 40 + - source: github:quartz-community/table-of-contents + enabled: true + order: 50 + - source: github:quartz-community/crawl-links + enabled: true + options: + markdownLinkResolution: shortest + order: 60 + - source: github:quartz-community/description + enabled: true + order: 70 + - source: github:quartz-community/latex + enabled: true + options: + renderEngine: katex + order: 80 + - source: github:quartz-community/citations + enabled: false + order: 85 + - source: github:quartz-community/hard-line-breaks + enabled: false + order: 90 + - source: github:quartz-community/ox-hugo + enabled: false + order: 91 + - source: github:quartz-community/roam + enabled: false + order: 92 + - source: github:quartz-community/remove-draft + enabled: true + - source: github:quartz-community/explicit-publish + enabled: false + - source: github:quartz-community/alias-redirects + enabled: true + - source: github:quartz-community/content-index + enabled: true + options: + enableSiteMap: true + enableRSS: true + - source: github:quartz-community/favicon + enabled: true + - source: github:quartz-community/og-image + enabled: true + - source: github:quartz-community/cname + enabled: true + - source: github:quartz-community/canvas-page + enabled: true + - source: github:quartz-community/content-page + enabled: true + - source: github:quartz-community/folder-page + enabled: true + - source: github:quartz-community/tag-page + enabled: true + - 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 + group: toolbar + groupOptions: + grow: true + - 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: false + layout: + position: beforeBody + priority: 30 + - source: github:quartz-community/page-title + enabled: true + layout: + position: left + priority: 10 + - source: github:quartz-community/darkmode + enabled: true + layout: + position: left + priority: 30 + group: toolbar + - source: github:quartz-community/reader-mode + enabled: true + layout: + position: left + priority: 35 + group: toolbar + - source: github:quartz-community/breadcrumbs + enabled: true + layout: + position: beforeBody + priority: 5 + condition: not-index + - source: github:quartz-community/comments + enabled: false + options: + provider: giscus + options: {} + layout: + position: afterBody + priority: 10 + - source: github:quartz-community/footer + enabled: true + options: + links: + GitHub: https://github.com/jackyzha0/quartz + Discord Community: https://discord.gg/cRFFHYye7t + - source: github:quartz-community/recent-notes + enabled: false + - source: github:quartz-community/spacer + enabled: true + options: {} + order: 25 + layout: + position: left + priority: 25 + display: mobile-only + - source: github:quartz-community/bases-page + enabled: true + options: {} + order: 50 + - source: github:quartz-community/note-properties + enabled: true + options: + includeAll: false + includedProperties: + - description + - tags + - aliases + excludedProperties: [] + hidePropertiesView: false + delimiters: --- + language: yaml + order: 5 + layout: + position: beforeBody + priority: 15 + display: all + - source: github:quartz-community/encrypted-pages + enabled: true + options: + visibility: icon + iterations: 600000 + passwordField: password + order: 900 + layout: + position: body + priority: 100 + display: all + - source: github:quartz-community/stacked-pages + enabled: true + layout: + position: afterBody + priority: 50 + display: all +layout: + groups: + toolbar: + priority: 35 + direction: row + gap: 0.5rem + byPageType: + "404": + positions: + beforeBody: [] + left: [] + right: [] + content: {} + folder: + exclude: + - reader-mode + positions: + right: [] + tag: + exclude: + - reader-mode + positions: + right: [] + canvas: {} + bases: {} diff --git a/quartz.config.ts b/quartz.config.ts deleted file mode 100644 index b3db3d60d..000000000 --- a/quartz.config.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { QuartzConfig } from "./quartz/cfg" -import * as Plugin from "./quartz/plugins" - -/** - * Quartz 4 Configuration - * - * See https://quartz.jzhao.xyz/configuration for more information. - */ -const config: QuartzConfig = { - configuration: { - pageTitle: "Quartz 4", - pageTitleSuffix: "", - enableSPA: true, - enablePopovers: true, - analytics: { - provider: "plausible", - }, - locale: "en-US", - baseUrl: "quartz.jzhao.xyz", - ignorePatterns: ["private", "templates", ".obsidian"], - defaultDateType: "modified", - theme: { - fontOrigin: "googleFonts", - cdnCaching: true, - typography: { - header: "Schibsted Grotesk", - body: "Source Sans Pro", - code: "IBM Plex Mono", - }, - colors: { - lightMode: { - light: "#faf8f8", - lightgray: "#e5e5e5", - gray: "#b8b8b8", - darkgray: "#4e4e4e", - dark: "#2b2b2b", - secondary: "#284b63", - tertiary: "#84a59d", - highlight: "rgba(143, 159, 169, 0.15)", - textHighlight: "#fff23688", - }, - darkMode: { - light: "#161618", - lightgray: "#393639", - gray: "#646464", - darkgray: "#d4d4d4", - dark: "#ebebec", - secondary: "#7b97aa", - tertiary: "#84a59d", - highlight: "rgba(143, 159, 169, 0.15)", - textHighlight: "#b3aa0288", - }, - }, - }, - }, - plugins: { - transformers: [ - Plugin.FrontMatter(), - Plugin.CreatedModifiedDate({ - priority: ["frontmatter", "git", "filesystem"], - }), - Plugin.SyntaxHighlighting({ - theme: { - light: "github-light", - dark: "github-dark", - }, - keepBackground: false, - }), - Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }), - Plugin.GitHubFlavoredMarkdown(), - Plugin.TableOfContents(), - Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }), - Plugin.Description(), - Plugin.Latex({ renderEngine: "katex" }), - ], - filters: [Plugin.RemoveDrafts()], - emitters: [ - Plugin.AliasRedirects(), - Plugin.ComponentResources(), - Plugin.ContentPage(), - Plugin.FolderPage(), - Plugin.TagPage(), - Plugin.ContentIndex({ - enableSiteMap: true, - enableRSS: true, - }), - Plugin.Assets(), - Plugin.Static(), - Plugin.Favicon(), - Plugin.NotFoundPage(), - // Comment out CustomOgImages to speed up build time - Plugin.CustomOgImages(), - ], - }, -} - -export default config diff --git a/quartz.layout.ts b/quartz.layout.ts deleted file mode 100644 index 970a5be34..000000000 --- a/quartz.layout.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { PageLayout, SharedLayout } from "./quartz/cfg" -import * as Component from "./quartz/components" - -// components shared across all pages -export const sharedPageComponents: SharedLayout = { - head: Component.Head(), - header: [], - afterBody: [], - footer: Component.Footer({ - links: { - GitHub: "https://github.com/jackyzha0/quartz", - "Discord Community": "https://discord.gg/cRFFHYye7t", - }, - }), -} - -// components for pages that display a single page (e.g. a single note) -export const defaultContentPageLayout: PageLayout = { - beforeBody: [ - Component.ConditionalRender({ - component: Component.Breadcrumbs(), - condition: (page) => page.fileData.slug !== "index", - }), - Component.ArticleTitle(), - Component.ContentMeta(), - Component.TagList(), - ], - left: [ - Component.PageTitle(), - Component.MobileOnly(Component.Spacer()), - Component.Flex({ - components: [ - { - Component: Component.Search(), - grow: true, - }, - { Component: Component.Darkmode() }, - { Component: Component.ReaderMode() }, - ], - }), - Component.Explorer(), - ], - right: [ - Component.Graph(), - Component.DesktopOnly(Component.TableOfContents()), - Component.Backlinks(), - ], -} - -// components for pages that display lists of pages (e.g. tags or folders) -export const defaultListPageLayout: PageLayout = { - beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta()], - left: [ - Component.PageTitle(), - Component.MobileOnly(Component.Spacer()), - Component.Flex({ - components: [ - { - Component: Component.Search(), - grow: true, - }, - { Component: Component.Darkmode() }, - ], - }), - Component.Explorer(), - ], - right: [], -} diff --git a/quartz.lock.json b/quartz.lock.json new file mode 100644 index 000000000..3ec6b2e8a --- /dev/null +++ b/quartz.lock.json @@ -0,0 +1,257 @@ +{ + "version": "1.0.0", + "plugins": { + "alias-redirects": { + "source": "github:quartz-community/alias-redirects", + "resolved": "https://github.com/quartz-community/alias-redirects.git", + "commit": "2913031a4989824754c0e550682a8d9c117ad569", + "installedAt": "2026-03-11T18:22:42.120Z" + }, + "article-title": { + "source": "github:quartz-community/article-title", + "resolved": "https://github.com/quartz-community/article-title.git", + "commit": "6b57785696ab3fd187ba91b218e5fde67b8533ee", + "installedAt": "2026-03-11T18:23:01.116Z" + }, + "backlinks": { + "source": "github:quartz-community/backlinks", + "resolved": "https://github.com/quartz-community/backlinks.git", + "commit": "c5f07804c9a050c4bf1d996454b1770a211d992b", + "installedAt": "2026-03-11T18:22:59.813Z" + }, + "bases-page": { + "source": "github:quartz-community/bases-page", + "resolved": "https://github.com/quartz-community/bases-page.git", + "commit": "d6d81c5442d89c68bf4c1cffb9d84614f378c671", + "installedAt": "2026-03-12T19:33:22.237Z" + }, + "breadcrumbs": { + "source": "github:quartz-community/breadcrumbs", + "resolved": "https://github.com/quartz-community/breadcrumbs.git", + "commit": "5687dccb6969be381407d8b8585846fe1f8f8913", + "installedAt": "2026-03-11T18:23:09.079Z" + }, + "canvas-page": { + "source": "github:quartz-community/canvas-page", + "resolved": "https://github.com/quartz-community/canvas-page.git", + "commit": "227b4c0c9f6d2ed63d56cbab6174008c314bf5c7", + "installedAt": "2026-03-12T19:33:23.417Z" + }, + "citations": { + "source": "github:quartz-community/citations", + "resolved": "https://github.com/quartz-community/citations.git", + "commit": "35f4c795f6a3a5763a7e5f283a13ed69a75cc8b1", + "installedAt": "2026-03-11T18:22:34.478Z" + }, + "cname": { + "source": "github:quartz-community/cname", + "resolved": "https://github.com/quartz-community/cname.git", + "commit": "251249077b372809b78fb679135f81ca9d81d3a8", + "installedAt": "2026-03-11T18:22:47.432Z" + }, + "comments": { + "source": "github:quartz-community/comments", + "resolved": "https://github.com/quartz-community/comments.git", + "commit": "8a76dfafc0742c1903212c4fc8e15f6fb5f9e99f", + "installedAt": "2026-03-12T19:33:25.149Z" + }, + "content-index": { + "source": "github:quartz-community/content-index", + "resolved": "https://github.com/quartz-community/content-index.git", + "commit": "2a207bb2db52c57a89b673182e9f74280dd81ee3", + "installedAt": "2026-03-11T18:22:43.468Z" + }, + "content-meta": { + "source": "github:quartz-community/content-meta", + "resolved": "https://github.com/quartz-community/content-meta.git", + "commit": "6381a7c2f7881640f845b13da7920e9c6524f219", + "installedAt": "2026-03-11T18:23:02.385Z" + }, + "content-page": { + "source": "github:quartz-community/content-page", + "resolved": "https://github.com/quartz-community/content-page.git", + "commit": "b8a3f3bb6a126256b12f55879d144ba2ac104b73", + "installedAt": "2026-03-11T18:22:51.572Z" + }, + "crawl-links": { + "source": "github:quartz-community/crawl-links", + "resolved": "https://github.com/quartz-community/crawl-links.git", + "commit": "5ccbcb5f3ac7b1c24fbcb34aa2454df06fe7031c", + "installedAt": "2026-03-11T18:22:30.563Z" + }, + "created-modified-date": { + "source": "github:quartz-community/created-modified-date", + "resolved": "https://github.com/quartz-community/created-modified-date.git", + "commit": "330621e98824efc34bcc061365076a0e30607235", + "installedAt": "2026-03-11T18:22:23.768Z" + }, + "darkmode": { + "source": "github:quartz-community/darkmode", + "resolved": "https://github.com/quartz-community/darkmode.git", + "commit": "672ad8da9899dadb5ec0e237864279541cde9d58", + "installedAt": "2026-03-12T19:33:28.700Z" + }, + "description": { + "source": "github:quartz-community/description", + "resolved": "https://github.com/quartz-community/description.git", + "commit": "76f05fb1ddcc412660ff247bb7ed532e2730c641", + "installedAt": "2026-03-11T18:22:31.873Z" + }, + "encrypted-pages": { + "source": "github:quartz-community/encrypted-pages", + "resolved": "https://github.com/quartz-community/encrypted-pages.git", + "commit": "4e26afa5b918f4399bea3028d5c250b987b44288", + "installedAt": "2026-03-12T19:33:29.813Z" + }, + "explicit-publish": { + "source": "github:quartz-community/explicit-publish", + "resolved": "https://github.com/quartz-community/explicit-publish.git", + "commit": "e6d37f711a44a8a30ff76796b1670ca852aa3157", + "installedAt": "2026-03-11T18:22:40.759Z" + }, + "explorer": { + "source": "github:quartz-community/explorer", + "resolved": "https://github.com/quartz-community/explorer.git", + "commit": "def459f31b02fdebdc22579cbeec2907829ff20f", + "installedAt": "2026-03-12T19:33:30.998Z" + }, + "favicon": { + "source": "github:quartz-community/favicon", + "resolved": "https://github.com/quartz-community/favicon.git", + "commit": "c389697fee691553920d44bab16ee06e79d2e080", + "installedAt": "2026-03-11T18:22:44.822Z" + }, + "folder-page": { + "source": "github:quartz-community/folder-page", + "resolved": "https://github.com/quartz-community/folder-page.git", + "commit": "0bb653d651626dece1e56fd7a08d3f2fb3a3cd8a", + "installedAt": "2026-03-11T18:22:52.983Z" + }, + "footer": { + "source": "github:quartz-community/footer", + "resolved": "https://github.com/quartz-community/footer.git", + "commit": "f0fe3d6ca24624d955a4f4e62e5aafabe053f29e", + "installedAt": "2026-03-11T18:23:11.638Z" + }, + "github-flavored-markdown": { + "source": "github:quartz-community/github-flavored-markdown", + "resolved": "https://github.com/quartz-community/github-flavored-markdown.git", + "commit": "628366ec62c1122da1eaef7c988d53bdaae3d19a", + "installedAt": "2026-03-11T18:22:27.866Z" + }, + "graph": { + "source": "github:quartz-community/graph", + "resolved": "https://github.com/quartz-community/graph.git", + "commit": "701bda442cf08f521e88ec326b12a7559320eef4", + "installedAt": "2026-03-12T19:33:34.250Z" + }, + "hard-line-breaks": { + "source": "github:quartz-community/hard-line-breaks", + "resolved": "https://github.com/quartz-community/hard-line-breaks.git", + "commit": "f8417e909a3c31d13463a6655c7ed903af3b34c5", + "installedAt": "2026-03-11T18:22:35.740Z" + }, + "latex": { + "source": "github:quartz-community/latex", + "resolved": "https://github.com/quartz-community/latex.git", + "commit": "2544fd13fa132493647480d8ce75f4432a6f1750", + "installedAt": "2026-03-11T18:22:33.240Z" + }, + "note-properties": { + "source": "github:quartz-community/note-properties", + "resolved": "https://github.com/quartz-community/note-properties.git", + "commit": "353531585033528eef9faa7eb2f27e377db7fa14", + "installedAt": "2026-03-12T19:33:36.033Z" + }, + "obsidian-flavored-markdown": { + "source": "github:quartz-community/obsidian-flavored-markdown", + "resolved": "https://github.com/quartz-community/obsidian-flavored-markdown.git", + "commit": "eda74e79eac746445b7d6941f90133bf97483cd7", + "installedAt": "2026-03-12T19:33:36.619Z" + }, + "og-image": { + "source": "github:quartz-community/og-image", + "resolved": "https://github.com/quartz-community/og-image.git", + "commit": "ab1f8e5ddcd3d9e9c55ea9f8f4163ae34cabe6ce", + "installedAt": "2026-03-11T18:22:46.168Z" + }, + "ox-hugo": { + "source": "github:quartz-community/ox-hugo", + "resolved": "https://github.com/quartz-community/ox-hugo.git", + "commit": "5e7399d6bcdd8a4824aad764952eeb8177e45591", + "installedAt": "2026-03-11T18:22:37.014Z" + }, + "page-title": { + "source": "github:quartz-community/page-title", + "resolved": "https://github.com/quartz-community/page-title.git", + "commit": "ad0e06a2fe2e2280217a445f167ee105edb8bde5", + "installedAt": "2026-03-11T18:23:05.089Z" + }, + "reader-mode": { + "source": "github:quartz-community/reader-mode", + "resolved": "https://github.com/quartz-community/reader-mode.git", + "commit": "1da1254ac74fd71cd950ff77ac6421db89469e06", + "installedAt": "2026-03-12T19:33:38.972Z" + }, + "recent-notes": { + "source": "github:quartz-community/recent-notes", + "resolved": "https://github.com/quartz-community/recent-notes.git", + "commit": "1220b39bec5a8d6178e4021cf87e42eeda2b5e39", + "installedAt": "2026-03-11T18:23:12.941Z" + }, + "remove-draft": { + "source": "github:quartz-community/remove-draft", + "resolved": "https://github.com/quartz-community/remove-draft.git", + "commit": "c44b2a1314cfe8ac4d4450a566ec9a122daba5f2", + "installedAt": "2026-03-11T18:22:39.521Z" + }, + "roam": { + "source": "github:quartz-community/roam", + "resolved": "https://github.com/quartz-community/roam.git", + "commit": "187f5d116ff13892a0012d608b8522eb3fecd028", + "installedAt": "2026-03-11T18:22:38.332Z" + }, + "search": { + "source": "github:quartz-community/search", + "resolved": "https://github.com/quartz-community/search.git", + "commit": "e9c10e521b95a14a512739b62a4159ab5afd5edf", + "installedAt": "2026-03-12T19:33:41.367Z" + }, + "spacer": { + "source": "github:quartz-community/spacer", + "resolved": "https://github.com/quartz-community/spacer.git", + "commit": "90e2f22e238ccccd5d2c38e6a236ccd2adbd9636", + "installedAt": "2026-03-11T18:23:14.251Z" + }, + "stacked-pages": { + "source": "github:quartz-community/stacked-pages", + "resolved": "https://github.com/quartz-community/stacked-pages.git", + "commit": "2d853d361d84211adda38e2c86973e706f265f9b", + "installedAt": "2026-03-13T23:15:30.401Z" + }, + "syntax-highlighting": { + "source": "github:quartz-community/syntax-highlighting", + "resolved": "https://github.com/quartz-community/syntax-highlighting.git", + "commit": "4593694be62ed55486d89b36f40a027a7b48233c", + "installedAt": "2026-03-12T19:33:42.554Z" + }, + "table-of-contents": { + "source": "github:quartz-community/table-of-contents", + "resolved": "https://github.com/quartz-community/table-of-contents.git", + "commit": "70b12d85cb873ce42d95111ffb4d8092644c1763", + "installedAt": "2026-03-12T19:33:43.169Z" + }, + "tag-list": { + "source": "github:quartz-community/tag-list", + "resolved": "https://github.com/quartz-community/tag-list.git", + "commit": "6014e0c4f688ece03a51674c98774fd9c021c3a1", + "installedAt": "2026-03-11T18:23:03.753Z" + }, + "tag-page": { + "source": "github:quartz-community/tag-page", + "resolved": "https://github.com/quartz-community/tag-page.git", + "commit": "dd0cd223c433722b3eb3ff7c93eec8eec49f76b5", + "installedAt": "2026-03-11T18:22:54.300Z" + } + } +} diff --git a/quartz.ts b/quartz.ts new file mode 100644 index 000000000..7a257d16b --- /dev/null +++ b/quartz.ts @@ -0,0 +1,5 @@ +import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader" + +const config = await loadQuartzConfig() +export default config +export const layout = await loadQuartzLayout() diff --git a/quartz/bootstrap-cli.mjs b/quartz/bootstrap-cli.mjs index 8b0b9268f..a49d61856 100755 --- a/quartz/bootstrap-cli.mjs +++ b/quartz/bootstrap-cli.mjs @@ -5,12 +5,77 @@ import { handleBuild, handleCreate, handleUpdate, + handleUpgrade, handleRestore, handleSync, } from "./cli/handlers.js" -import { CommonArgv, BuildArgv, CreateArgv, SyncArgv } from "./cli/args.js" +import { handleMigrate } from "./cli/migrate-handler.js" +import { + handlePluginInstall as handleGitPluginInstall, + handlePluginAdd, + handlePluginRemove, + handlePluginUpdate, + handlePluginRestore, + handlePluginList, + handlePluginEnable, + handlePluginDisable, + handlePluginConfig, + handlePluginCheck, + handlePluginPrune, + handlePluginResolve, +} from "./cli/plugin-git-handlers.js" +import { + CommonArgv, + BuildArgv, + CreateArgv, + SyncArgv, + PluginInstallArgv, + PluginUninstallArgv, + PluginSearchArgv, +} from "./cli/args.js" import { version } from "./cli/constants.js" +async function launchTui() { + const { join } = await import("path") + const { existsSync } = await import("fs") + const { spawn } = await import("child_process") + const tuiPath = join(process.cwd(), ".quartz", "plugins", "tui", "dist", "App.mjs") + + if (!existsSync(tuiPath)) { + console.error( + "TUI plugin not installed. Install with:\n" + + " npx quartz plugin add github:quartz-community/tui\n", + ) + process.exit(1) + } + + // OpenTUI requires Bun runtime (uses bun:ffi for Zig renderer) + return new Promise((resolve, reject) => { + const child = spawn("bun", ["run", tuiPath], { + stdio: "inherit", + cwd: process.cwd(), + }) + + child.on("error", (err) => { + if (err.code === "ENOENT") { + console.error( + "Error: Bun runtime not found. The TUI requires Bun to run.\n" + + "Install Bun: https://bun.sh/docs/installation", + ) + } + reject(err) + }) + + child.on("close", (code) => { + if (code === 0) { + resolve() + } else { + reject(new Error(`TUI exited with code ${code}`)) + } + }) + }) +} + yargs(hideBin(process.argv)) .scriptName("quartz") .version(version) @@ -18,8 +83,16 @@ yargs(hideBin(process.argv)) .command("create", "Initialize Quartz", CreateArgv, async (argv) => { await handleCreate(argv) }) - .command("update", "Get the latest Quartz updates", CommonArgv, async (argv) => { - await handleUpdate(argv) + .command( + "update [names..]", + "Update installed plugins to latest version", + CommonArgv, + async (argv) => { + await handleUpdate(argv) + }, + ) + .command("upgrade", "Upgrade Quartz to the latest version", CommonArgv, async (argv) => { + await handleUpgrade(argv) }) .command( "restore", @@ -35,6 +108,115 @@ yargs(hideBin(process.argv)) .command("build", "Build Quartz into a bundle of static HTML files", BuildArgv, async (argv) => { await handleBuild(argv) }) + .command("migrate", "Migrate old config to quartz.config.yaml", CommonArgv, async () => { + await handleMigrate() + }) + .command("tui", "Launch interactive plugin manager", CommonArgv, async () => { + await launchTui() + }) + .command( + "plugin [subcommand]", + "Manage Quartz plugins", + (yargs) => { + return yargs + .command("install", "Install plugins from quartz.lock.json", CommonArgv, async () => { + await handleGitPluginInstall() + }) + .command("add ", "Add plugins from Git repositories", CommonArgv, async (argv) => { + await handlePluginAdd(argv.repos) + }) + .command("remove ", "Remove installed plugins", CommonArgv, async (argv) => { + await handlePluginRemove(argv.names) + }) + .command( + "update [names..]", + "Update installed plugins to latest version", + CommonArgv, + async (argv) => { + await handlePluginUpdate(argv.names) + }, + ) + .command("list", "List all installed plugins", CommonArgv, async () => { + await handlePluginList() + }) + .command( + "restore", + "Restore plugins from lockfile (exact versions)", + CommonArgv, + async () => { + await handlePluginRestore() + }, + ) + .command( + "enable ", + "Enable plugins in quartz.config.yaml", + CommonArgv, + async (argv) => { + await handlePluginEnable(argv.names) + }, + ) + .command( + "disable ", + "Disable plugins in quartz.config.yaml", + CommonArgv, + async (argv) => { + await handlePluginDisable(argv.names) + }, + ) + .command( + "config ", + "View or set plugin configuration", + { + ...CommonArgv, + set: { + string: true, + describe: "Set a config value (key=value)", + }, + }, + async (argv) => { + await handlePluginConfig(argv.name, { set: argv.set }) + }, + ) + .command("check", "Check for plugin updates", CommonArgv, async () => { + await handlePluginCheck() + }) + .command( + "prune", + "Remove installed plugins no longer referenced in config", + { + ...CommonArgv, + "dry-run": { + boolean: true, + default: false, + describe: "show what would be pruned without making changes", + }, + }, + async (argv) => { + await handlePluginPrune({ dryRun: argv.dryRun }) + }, + ) + .command( + "resolve", + "Install plugins from config that are not yet in the lockfile", + { + ...CommonArgv, + "dry-run": { + boolean: true, + default: false, + describe: "show what would be resolved without making changes", + }, + }, + async (argv) => { + await handlePluginResolve({ dryRun: argv.dryRun }) + }, + ) + .demandCommand(0, "") + }, + async (argv) => { + if (!argv._.includes("plugin") || argv._.length > 1) return + await launchTui() + }, + ) .showHelpOnFail(false) .help() .strict() diff --git a/quartz/build.ts b/quartz/build.ts index b98f4a8a0..bc0340e7d 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -8,8 +8,8 @@ import { styleText } from "util" import { parseMarkdown } from "./processors/parse" import { filterContent } from "./processors/filter" import { emitContent } from "./processors/emit" -import cfg from "../quartz.config" -import { FilePath, joinSegments, slugifyFilePath } from "./util/path" +import cfg from "../quartz" +import { FilePath, FullSlug, joinSegments, slugifyFilePath } from "./util/path" import chokidar from "chokidar" import { ProcessedContent } from "./plugins/vfile" import { Argv, BuildCtx } from "./util/ctx" @@ -19,9 +19,40 @@ import { options } from "./util/sourcemap" import { Mutex } from "async-mutex" import { getStaticResourcesFromPlugins } from "./plugins" import { randomIdNonSecure } from "./util/random" -import { ChangeEvent } from "./plugins/types" +import { ChangeEvent, QuartzPageTypePluginInstance } from "./plugins/types" import { minimatch } from "minimatch" +function getPageTypeExtensions(ctx: BuildCtx): Set { + const extensions = new Set() + const pageTypes = (ctx.cfg.plugins.pageTypes ?? []) as unknown as QuartzPageTypePluginInstance[] + for (const pt of pageTypes) { + if (pt.fileExtensions) { + for (const ext of pt.fileExtensions) { + extensions.add(ext) + } + } + } + return extensions +} + +// For files whose extensions are handled by PageType plugins (e.g. .canvas, .base), +// add extension-stripped slug aliases so that wikilink resolution (CrawlLinks) maps +// `![[file.canvas]]` to the virtual-page slug `file` instead of the raw `file.canvas`. +function addVirtualPageSlugAliases(allSlugs: FullSlug[], extensions: Set): FullSlug[] { + const extra: FullSlug[] = [] + for (const slug of allSlugs) { + for (const ext of extensions) { + if (slug.endsWith(ext)) { + const stripped = slug.slice(0, -ext.length) as FullSlug + if (!allSlugs.includes(stripped) && !extra.includes(stripped)) { + extra.push(stripped) + } + } + } + } + return extra +} + type ContentMap = Map< FilePath, | { @@ -50,19 +81,21 @@ async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) { allSlugs: [], allFiles: [], incremental: false, + virtualPages: [], } const perf = new PerfTimer() const output = argv.output const pluginCount = Object.values(cfg.plugins).flat().length - const pluginNames = (key: "transformers" | "filters" | "emitters") => - cfg.plugins[key].map((plugin) => plugin.name) + const pluginNames = (key: "transformers" | "filters" | "emitters" | "pageTypes") => + (cfg.plugins[key] ?? []).map((plugin) => plugin.name) if (argv.verbose) { console.log(`Loaded ${pluginCount} plugins`) console.log(` Transformers: ${pluginNames("transformers").join(", ")}`) console.log(` Filters: ${pluginNames("filters").join(", ")}`) console.log(` Emitters: ${pluginNames("emitters").join(", ")}`) + console.log(` PageTypes: ${pluginNames("pageTypes").join(", ")}`) } const release = await mut.acquire() @@ -81,6 +114,14 @@ async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) { ctx.allFiles = allFiles ctx.allSlugs = allFiles.map((fp) => slugifyFilePath(fp as FilePath)) + // Add extension-stripped slug aliases for PageType-registered extensions + // so that wikilinks like ![[file.canvas]] resolve to virtual page slugs + const ptExtensions = getPageTypeExtensions(ctx) + if (ptExtensions.size > 0) { + const aliases = addVirtualPageSlugAliases(ctx.allSlugs, ptExtensions) + ctx.allSlugs.push(...aliases) + } + const parsedFiles = await parseMarkdown(ctx, filePaths) const filteredContent = filterContent(ctx, parsedFiles) @@ -255,6 +296,13 @@ async function rebuild(changes: ChangeEvent[], clientRefresh: () => void, buildD // update allFiles and then allSlugs with the consistent view of content map ctx.allFiles = Array.from(contentMap.keys()) ctx.allSlugs = ctx.allFiles.map((fp) => slugifyFilePath(fp as FilePath)) + + // Add extension-stripped slug aliases for PageType-registered extensions + const ptExtensions = getPageTypeExtensions(ctx) + if (ptExtensions.size > 0) { + const aliases = addVirtualPageSlugAliases(ctx.allSlugs, ptExtensions) + ctx.allSlugs.push(...aliases) + } let processedFiles = filterContent( ctx, Array.from(contentMap.values()) @@ -263,10 +311,40 @@ async function rebuild(changes: ChangeEvent[], clientRefresh: () => void, buildD ) let emittedFiles = 0 + + // Phase 1: Run PageTypeDispatcher first so it populates ctx.virtualPages + const dispatcher = cfg.plugins.emitters.find((e) => e.name === "PageTypeDispatcher") + if (dispatcher) { + ctx.virtualPages = [] + const emitFn = dispatcher.partialEmit ?? dispatcher.emit + const emitted = await emitFn(ctx, processedFiles, staticResources, changeEvents) + if (emitted !== null) { + if (Symbol.asyncIterator in emitted) { + for await (const file of emitted) { + emittedFiles++ + if (ctx.argv.verbose) { + console.log(`[emit:${dispatcher.name}] ${file}`) + } + } + } else { + emittedFiles += emitted.length + if (ctx.argv.verbose) { + for (const file of emitted) { + console.log(`[emit:${dispatcher.name}] ${file}`) + } + } + } + } + } + + // Phase 2: Run all other emitters with content extended by virtual pages + const contentWithVirtual = + ctx.virtualPages.length > 0 ? [...processedFiles, ...ctx.virtualPages] : processedFiles for (const emitter of cfg.plugins.emitters) { + if (emitter.name === "PageTypeDispatcher") continue // Try to use partialEmit if available, otherwise assume the output is static const emitFn = emitter.partialEmit ?? emitter.emit - const emitted = await emitFn(ctx, processedFiles, staticResources, changeEvents) + const emitted = await emitFn(ctx, contentWithVirtual, staticResources, changeEvents) if (emitted === null) { continue } diff --git a/quartz/cfg.ts b/quartz/cfg.ts index c97d613bb..bdb8ef1d7 100644 --- a/quartz/cfg.ts +++ b/quartz/cfg.ts @@ -1,6 +1,7 @@ import { ValidDateType } from "./components/Date" import { QuartzComponent } from "./components/types" import { ValidLocale } from "./i18n" +import { PluginSpecifier } from "./plugins/loader/types" import { PluginTypes } from "./plugins/types" import { Theme } from "./util/theme" @@ -88,6 +89,7 @@ export interface GlobalConfiguration { export interface QuartzConfig { configuration: GlobalConfiguration plugins: PluginTypes + externalPlugins?: PluginSpecifier[] } export interface FullPageLayout { @@ -99,6 +101,8 @@ export interface FullPageLayout { left: QuartzComponent[] right: QuartzComponent[] footer: QuartzComponent + /** Page frame name (e.g. "default", "full-width", "minimal"). Defaults to "default". */ + frame?: string } export type PageLayout = Pick diff --git a/quartz/cli/args.js b/quartz/cli/args.js index d2408e94b..a737b446f 100644 --- a/quartz/cli/args.js +++ b/quartz/cli/args.js @@ -15,6 +15,12 @@ export const CommonArgv = { export const CreateArgv = { ...CommonArgv, + template: { + string: true, + alias: ["t"], + choices: ["default", "obsidian", "ttrpg", "blog"], + describe: "template to use for initial configuration", + }, source: { string: true, alias: ["s"], @@ -26,6 +32,11 @@ export const CreateArgv = { choices: ["new", "copy", "symlink"], describe: "strategy for content folder setup", }, + baseUrl: { + string: true, + alias: ["b"], + describe: "base URL for your Quartz site (e.g. mysite.github.io/quartz)", + }, links: { string: true, alias: ["l"], @@ -106,3 +117,30 @@ export const BuildArgv = { describe: "how many threads to use to parse notes", }, } + +export const PluginInstallArgv = { + ...CommonArgv, + _: { + type: "string", + demandOption: true, + describe: "package names to install", + }, +} + +export const PluginUninstallArgv = { + ...CommonArgv, + _: { + type: "string", + demandOption: true, + describe: "package names to uninstall", + }, +} + +export const PluginSearchArgv = { + ...CommonArgv, + query: { + string: true, + alias: ["q"], + describe: "search query for plugins", + }, +} diff --git a/quartz/cli/constants.js b/quartz/cli/constants.js index f4a9ce52b..83c702af9 100644 --- a/quartz/cli/constants.js +++ b/quartz/cli/constants.js @@ -6,7 +6,8 @@ import { readFileSync } from "fs" */ export const ORIGIN_NAME = "origin" export const UPSTREAM_NAME = "upstream" -export const QUARTZ_SOURCE_BRANCH = "v4" +export const QUARTZ_SOURCE_BRANCH = "v5" +export const QUARTZ_SOURCE_REPO = "https://github.com/jackyzha0/quartz.git" export const cwd = process.cwd() export const cacheDir = path.join(cwd, ".quartz-cache") export const cacheFile = "./quartz/.quartz-cache/transpiled-build.mjs" diff --git a/quartz/cli/handlers.js b/quartz/cli/handlers.js index 9b68aede5..792f83f89 100644 --- a/quartz/cli/handlers.js +++ b/quartz/cli/handlers.js @@ -23,9 +23,24 @@ import { popContentFolder, stashContentFolder, } from "./helpers.js" +import { + handlePluginRestore, + handlePluginCheck, + handlePluginUpdate, +} from "./plugin-git-handlers.js" +import { + configExists, + createConfigFromDefault, + createConfigFromTemplate, + readPluginsJson, + writePluginsJson, + extractPluginName, + updateGlobalConfig, +} from "./plugin-data.js" import { UPSTREAM_NAME, QUARTZ_SOURCE_BRANCH, + QUARTZ_SOURCE_REPO, ORIGIN_NAME, version, fp, @@ -53,6 +68,8 @@ export async function handleCreate(argv) { let setupStrategy = argv.strategy?.toLowerCase() let linkResolutionStrategy = argv.links?.toLowerCase() const sourceDirectory = argv.source + let template = argv.template?.toLowerCase() + let baseUrl = argv.baseUrl // If all cmd arguments were provided, check if they're valid if (setupStrategy && linkResolutionStrategy) { @@ -104,6 +121,32 @@ export async function handleCreate(argv) { } } + // Template selection + if (!template) { + template = exitIfCancel( + await select({ + message: "Choose a template for your Quartz configuration", + options: [ + { value: "default", label: "Default", hint: "clean Quartz setup with sensible defaults" }, + { + value: "obsidian", + label: "Obsidian", + hint: "optimized for Obsidian vaults with full OFM support", + }, + { + value: "ttrpg", + label: "TTRPG", + hint: "Obsidian + map plugin + ITS Theme for D&D/TTRPG wikis", + }, + { + value: "blog", + label: "Blog", + hint: "recent notes and comments enabled for blogging", + }, + ], + }), + ) + } // Use cli process if cmd args werent provided if (!setupStrategy) { setupStrategy = exitIfCancel( @@ -181,12 +224,18 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. ) } + // Obsidian and TTRPG templates auto-set link resolution to "shortest" + const skipLinkPrompt = template === "obsidian" || template === "ttrpg" + if (skipLinkPrompt) { + linkResolutionStrategy = "shortest" + } + // Use cli process if cmd args werent provided if (!linkResolutionStrategy) { // get a preferred link resolution strategy linkResolutionStrategy = exitIfCancel( await select({ - message: `Choose how Quartz should resolve links in your content. This should match Obsidian's link format. You can change this later in \`quartz.config.ts\`.`, + message: `Choose how Quartz should resolve links in your content. This should match Obsidian's link format. You can change this later in \`quartz.config.yaml\`.`, options: [ { value: "shortest", @@ -206,23 +255,60 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. ) } - // now, do config changes - const configFilePath = path.join(cwd, "quartz.config.ts") - let configContent = await fs.promises.readFile(configFilePath, { encoding: "utf-8" }) - configContent = configContent.replace( - /markdownLinkResolution: '(.+)'/, - `markdownLinkResolution: '${linkResolutionStrategy}'`, - ) - await fs.promises.writeFile(configFilePath, configContent) + // Base URL prompt + if (!baseUrl) { + baseUrl = exitIfCancel( + await text({ + message: "Enter the base URL for your Quartz site (e.g. mysite.github.io/quartz)", + placeholder: "mysite.github.io", + validate(value) { + if (!value || value.trim().length === 0) { + return "Base URL cannot be empty" + } + }, + }), + ) + } + + // Strip protocol prefix if user included it + baseUrl = baseUrl.replace(/^https?:\/\//, "").replace(/\/+$/, "") + + // Create config if it doesn't exist + if (!configExists()) { + if (template && template !== "default") { + createConfigFromTemplate(template) + console.log(styleText("green", `Created quartz.config.yaml from '${template}' template`)) + } else { + createConfigFromTemplate("default") + console.log(styleText("green", "Created quartz.config.yaml from defaults")) + } + } + + // Update markdownLinkResolution in the crawl-links plugin options via YAML config + const json = readPluginsJson() + if (json?.plugins) { + const crawlLinksIndex = json.plugins.findIndex( + (p) => extractPluginName(p.source) === "crawl-links", + ) + if (crawlLinksIndex !== -1) { + json.plugins[crawlLinksIndex].options = { + ...json.plugins[crawlLinksIndex].options, + markdownLinkResolution: linkResolutionStrategy, + } + writePluginsJson(json) + } + } + + // Update baseUrl in configuration + updateGlobalConfig({ baseUrl }) // setup remote - execSync( - `git remote show upstream || git remote add upstream https://github.com/jackyzha0/quartz.git`, - { stdio: "ignore" }, - ) + execSync(`git remote show upstream || git remote add upstream ${QUARTZ_SOURCE_REPO}`, { + stdio: "ignore", + }) outro(`You're all set! Not sure what to do next? Try: - • Customizing Quartz a bit more by editing \`quartz.config.ts\` + • Customizing Quartz a bit more by editing \`quartz.config.yaml\` • Running \`npx quartz build --serve\` to preview your Quartz locally • Hosting your Quartz online (see: https://quartz.jzhao.xyz/hosting) `) @@ -487,16 +573,15 @@ export async function handleBuild(argv) { } /** - * Handles `npx quartz update` - * @param {*} argv arguments for `update` + * Handles `npx quartz upgrade` + * Upgrades the Quartz framework itself by pulling latest changes from upstream. + * @param {*} argv arguments for `upgrade` */ -export async function handleUpdate(argv) { +export async function handleUpgrade(argv) { const contentFolder = resolveContentPath(argv.directory) console.log(`\n${styleText(["bgGreen", "black"], ` Quartz v${version} `)} \n`) console.log("Backing up your content") - execSync( - `git remote show upstream || git remote add upstream https://github.com/jackyzha0/quartz.git`, - ) + execSync(`git remote show upstream || git remote add upstream ${QUARTZ_SOURCE_REPO}`) await stashContentFolder(contentFolder) console.log( "Pulling updates... you may need to resolve some `git` conflicts if you've made changes to components or plugins.", @@ -511,6 +596,16 @@ export async function handleUpdate(argv) { } await popContentFolder(contentFolder) + + // Read the new version after pulling + const newPkg = JSON.parse(fs.readFileSync("./package.json").toString()) + const newVersion = newPkg.version + if (newVersion !== version) { + console.log(styleText("cyan", `Upgraded Quartz: v${version} → v${newVersion}`)) + } else { + console.log(styleText("gray", `Quartz is already up to date (v${version})`)) + } + console.log("Ensuring dependencies are up to date") /* @@ -518,7 +613,7 @@ export async function handleUpdate(argv) { as it will be unable to find `npm`. This is often the case on systems where `npm` is installed via a package manager. - This means `npx quartz update` will not actually update dependencies + This means `npx quartz upgrade` will not actually update dependencies on Windows, without a manual `npm i` from the caller. However, by spawning a shell, we are able to call `npm.cmd`. @@ -532,10 +627,28 @@ export async function handleUpdate(argv) { const res = spawnSync("npm", ["i"], opts) if (res.status === 0) { - console.log(styleText("green", "Done!")) + console.log(styleText("green", "Dependencies updated!")) } else { console.log(styleText("red", "An error occurred above while installing dependencies.")) } + + console.log("Restoring plugins from lockfile...") + await handlePluginRestore() + + console.log("Checking plugin compatibility...") + await handlePluginCheck() + + console.log(styleText("green", "Done!")) +} + +/** + * Handles `npx quartz update` + * Shortcut for `npx quartz plugin update` — updates all installed plugins. + * @param {*} argv arguments for `update` + */ +export async function handleUpdate(argv) { + console.log(`\n${styleText(["bgGreen", "black"], ` Quartz v${version} `)} \n`) + await handlePluginUpdate(argv.names) } /** diff --git a/quartz/cli/helpers.js b/quartz/cli/helpers.js index 46b5018be..18c160b0b 100644 --- a/quartz/cli/helpers.js +++ b/quartz/cli/helpers.js @@ -33,7 +33,7 @@ export async function stashContentFolder(contentFolder) { } export function gitPull(origin, branch) { - const flags = ["--no-rebase", "--autostash", "-s", "recursive", "-X", "ours", "--no-edit"] + const flags = ["--no-rebase", "--autostash", "--no-edit"] const out = spawnSync("git", ["pull", ...flags, origin, branch], { stdio: "inherit" }) if (out.stderr) { throw new Error(styleText("red", `Error while pulling updates: ${out.stderr}`)) diff --git a/quartz/cli/migrate-handler.js b/quartz/cli/migrate-handler.js new file mode 100644 index 000000000..e148565dd --- /dev/null +++ b/quartz/cli/migrate-handler.js @@ -0,0 +1,191 @@ +import fs from "fs" +import path from "path" +import { spawnSync } from "child_process" +import { styleText } from "util" +import YAML from "yaml" + +const CWD = process.cwd() +const QUARTZ_TS_PATH = path.join(CWD, "quartz.ts") +const CONFIG_YAML_PATH = path.join(CWD, "quartz.config.yaml") +const DEFAULT_CONFIG_YAML_PATH = path.join(CWD, "quartz.config.default.yaml") +const LEGACY_DEFAULT_JSON_PATH = path.join(CWD, "quartz.plugins.default.json") +const LOCKFILE_PATH = path.join(CWD, "quartz.lock.json") +const PLUGINS_DIR = path.join(CWD, ".quartz", "plugins") +const PACKAGE_JSON_PATH = path.join(CWD, "package.json") + +function readJson(filePath) { + if (!fs.existsSync(filePath)) return null + try { + return JSON.parse(fs.readFileSync(filePath, "utf-8")) + } catch { + return null + } +} + +function hasTsx() { + const pkg = readJson(PACKAGE_JSON_PATH) + return Boolean(pkg?.devDependencies?.tsx || pkg?.dependencies?.tsx) +} + +function extractWithTsx() { + const script = ` + const { default: config } = await import("./quartz.ts") + const { layout } = await import("./quartz.ts") + const result = { + configuration: config?.configuration ?? null, + layoutInfo: { + defaults: { + afterBody: Array.isArray(layout?.defaults?.afterBody) ? layout.defaults.afterBody.length : 0, + hasFooter: Boolean(layout?.defaults?.footer), + }, + pageTypes: layout?.byPageType ? Object.keys(layout.byPageType) : [], + }, + } + console.log(JSON.stringify(result)) + ` + + const res = spawnSync("node", ["--import", "tsx/esm", "--input-type=module", "-e", script], { + encoding: "utf-8", + cwd: CWD, + }) + + if (res.error || res.status !== 0) { + return { ok: false, error: res.error ?? res.stderr } + } + + try { + return { ok: true, data: JSON.parse(res.stdout.trim()) } + } catch (error) { + return { ok: false, error } + } +} + +function readManifest(pluginDir) { + const pkgPath = path.join(pluginDir, "package.json") + if (!fs.existsSync(pkgPath)) return null + try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")) + return pkg.quartz ?? null + } catch { + return null + } +} + +function ensureLayoutDefaults(layout) { + if (!layout.groups) layout.groups = {} + if (!layout.groups.toolbar) { + layout.groups.toolbar = { direction: "row", gap: "0.5rem" } + } + if (!layout.byPageType) layout.byPageType = {} + if (!layout.byPageType["404"]) { + layout.byPageType["404"] = { positions: { beforeBody: [], left: [], right: [] } } + } else if (!layout.byPageType["404"].positions) { + layout.byPageType["404"].positions = { beforeBody: [], left: [], right: [] } + } + return layout +} + +function buildPluginEntry(name, entry) { + const pluginDir = path.join(PLUGINS_DIR, name) + const manifest = readManifest(pluginDir) + const source = entry?.source ?? `github:quartz-community/${name}` + const pluginEntry = { + source, + enabled: manifest?.defaultEnabled ?? true, + options: manifest?.defaultOptions ?? {}, + order: manifest?.defaultOrder ?? 50, + } + + if (manifest?.components) { + const component = Object.values(manifest.components).find((comp) => comp?.defaultPosition) + if (component?.defaultPosition) { + pluginEntry.layout = { + position: component.defaultPosition, + priority: component.defaultPriority ?? 50, + display: "all", + } + } + } + + return pluginEntry +} + +export async function handleMigrate() { + console.log(styleText("cyan", "Migrating Quartz configuration...")) + + if (!fs.existsSync(QUARTZ_TS_PATH)) { + console.log(styleText("red", "✗ quartz.ts not found. Aborting migration.")) + return + } + + if (fs.existsSync(CONFIG_YAML_PATH)) { + console.log(styleText("yellow", "⚠ quartz.config.yaml already exists. Overwriting.")) + } + + const defaultJson = readJson(DEFAULT_CONFIG_YAML_PATH) ?? readJson(LEGACY_DEFAULT_JSON_PATH) + let configuration = defaultJson?.configuration ?? {} + let layout = ensureLayoutDefaults(defaultJson?.layout ?? {}) + let layoutInfo = null + + console.log(styleText("gray", "→ Extracting configuration...")) + if (hasTsx()) { + const extracted = extractWithTsx() + if (extracted.ok) { + configuration = extracted.data?.configuration ?? configuration + layoutInfo = extracted.data?.layoutInfo ?? null + } else { + console.log(styleText("yellow", "⚠ Failed to import TS config with tsx. Using defaults.")) + } + } else { + console.log(styleText("yellow", "⚠ tsx not found. Using defaults.")) + } + + if (layoutInfo?.pageTypes?.length) { + for (const pageType of layoutInfo.pageTypes) { + if (!layout.byPageType[pageType]) { + layout.byPageType[pageType] = {} + } + } + } + + console.log(styleText("gray", "→ Reading plugin lockfile...")) + const lockfile = readJson(LOCKFILE_PATH) + const plugins = [] + + if (lockfile?.plugins) { + for (const [name, entry] of Object.entries(lockfile.plugins)) { + plugins.push(buildPluginEntry(name, entry)) + } + } else if (defaultJson?.plugins) { + console.log(styleText("yellow", "⚠ quartz.lock.json not found. Using default plugins.")) + for (const plugin of defaultJson.plugins) { + plugins.push(plugin) + } + } else { + console.log(styleText("yellow", "⚠ No lockfile or default plugins found. Writing empty list.")) + } + + const outputJson = { + configuration, + plugins, + layout, + } + + const header = "# yaml-language-server: $schema=./quartz/plugins/quartz-plugins.schema.json\n" + fs.writeFileSync(CONFIG_YAML_PATH, header + YAML.stringify(outputJson, { lineWidth: 120 })) + + const quartzTsTemplate = + 'import { loadQuartzConfig, loadQuartzLayout } from "./quartz/plugins/loader/config-loader"\n' + + "\n" + + "const config = await loadQuartzConfig()\n" + + "export default config\n" + + "export const layout = await loadQuartzLayout()\n" + + fs.writeFileSync(QUARTZ_TS_PATH, quartzTsTemplate) + + console.log(styleText("green", "✓ Created quartz.config.yaml")) + console.log(styleText("green", "✓ Replaced quartz.ts")) + console.log() + console.log(styleText("yellow", "⚠ Verify plugin options in quartz.config.yaml")) + console.log(styleText("gray", `Plugins migrated: ${plugins.length}`)) +} diff --git a/quartz/cli/plugin-data.js b/quartz/cli/plugin-data.js new file mode 100644 index 000000000..8171295f9 --- /dev/null +++ b/quartz/cli/plugin-data.js @@ -0,0 +1,358 @@ +import fs from "fs" +import path from "path" +import { execSync } from "child_process" +import YAML from "yaml" + +const LOCKFILE_PATH = path.join(process.cwd(), "quartz.lock.json") +const PLUGINS_DIR = path.join(process.cwd(), ".quartz", "plugins") +const CONFIG_YAML_PATH = path.join(process.cwd(), "quartz.config.yaml") +const DEFAULT_CONFIG_YAML_PATH = path.join(process.cwd(), "quartz.config.default.yaml") +const TEMPLATES_DIR = path.join(process.cwd(), "quartz", "cli", "templates") + +const LEGACY_PLUGINS_JSON_PATH = path.join(process.cwd(), "quartz.plugins.json") +const LEGACY_DEFAULT_PLUGINS_JSON_PATH = path.join(process.cwd(), "quartz.plugins.default.json") + +function resolveConfigPath() { + if (fs.existsSync(CONFIG_YAML_PATH)) return CONFIG_YAML_PATH + if (fs.existsSync(LEGACY_PLUGINS_JSON_PATH)) return LEGACY_PLUGINS_JSON_PATH + if (fs.existsSync(DEFAULT_CONFIG_YAML_PATH)) return DEFAULT_CONFIG_YAML_PATH + if (fs.existsSync(LEGACY_DEFAULT_PLUGINS_JSON_PATH)) return LEGACY_DEFAULT_PLUGINS_JSON_PATH + return CONFIG_YAML_PATH +} + +function resolveDefaultConfigPath() { + if (fs.existsSync(DEFAULT_CONFIG_YAML_PATH)) return DEFAULT_CONFIG_YAML_PATH + if (fs.existsSync(LEGACY_DEFAULT_PLUGINS_JSON_PATH)) return LEGACY_DEFAULT_PLUGINS_JSON_PATH + return DEFAULT_CONFIG_YAML_PATH +} + +function readFileAsData(filePath) { + if (!fs.existsSync(filePath)) return null + try { + const raw = fs.readFileSync(filePath, "utf-8") + if (filePath.endsWith(".yaml") || filePath.endsWith(".yml")) { + return YAML.parse(raw) + } + return JSON.parse(raw) + } catch { + return null + } +} + +function writeDataToFile(filePath, data) { + if (filePath.endsWith(".yaml") || filePath.endsWith(".yml")) { + const header = "# yaml-language-server: $schema=./quartz/plugins/quartz-plugins.schema.json\n" + fs.writeFileSync(filePath, header + YAML.stringify(data, { lineWidth: 120 })) + } else { + fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n") + } +} + +export function readPluginsJson() { + const configPath = resolveConfigPath() + return readFileAsData(configPath) +} + +export function writePluginsJson(data) { + const { $schema, ...rest } = data + writeDataToFile(CONFIG_YAML_PATH, rest) +} + +export function readDefaultPluginsJson() { + const defaultPath = resolveDefaultConfigPath() + return readFileAsData(defaultPath) +} + +export function readLockfile() { + if (!fs.existsSync(LOCKFILE_PATH)) return null + try { + return JSON.parse(fs.readFileSync(LOCKFILE_PATH, "utf-8")) + } catch { + return null + } +} + +export function writeLockfile(lockfile) { + if (lockfile.plugins) { + const sorted = {} + for (const key of Object.keys(lockfile.plugins).sort()) { + sorted[key] = lockfile.plugins[key] + } + lockfile = { ...lockfile, plugins: sorted } + } + fs.writeFileSync(LOCKFILE_PATH, JSON.stringify(lockfile, null, 2) + "\n") +} + +export function isLocalSource(source) { + if (source.startsWith("./") || source.startsWith("../") || source.startsWith("/")) { + return true + } + // Windows absolute paths (e.g. C:\ or D:/) + if (/^[A-Za-z]:[\\/]/.test(source)) { + return true + } + return false +} +export function extractPluginName(source) { + if (isLocalSource(source)) { + return path.basename(source.replace(/[\/]+$/, "")) + } + if (source.startsWith("github:")) { + const withoutPrefix = source.replace("github:", "") + const [repoPath] = withoutPrefix.split("#") + const parts = repoPath.split("/") + return parts[parts.length - 1] + } + if (source.startsWith("git+") || source.startsWith("https://")) { + const url = source.replace("git+", "") + const match = url.match(/\/([^/]+?)(?:\.git)?(?:#|$)/) + return match?.[1] ?? source + } + return source +} + +export function readManifestFromPackageJson(pluginDir) { + const pkgPath = path.join(pluginDir, "package.json") + if (!fs.existsSync(pkgPath)) return null + try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")) + return pkg.quartz ?? null + } catch { + return null + } +} + +export function parseGitSource(source) { + if (isLocalSource(source)) { + const resolved = path.resolve(source) + const name = path.basename(resolved) + return { name, url: resolved, ref: undefined, local: true } + } + if (source.startsWith("github:")) { + const [repoPath, ref] = source.replace("github:", "").split("#") + const [owner, repo] = repoPath.split("/") + return { name: repo, url: `https://github.com/${owner}/${repo}.git`, ref } + } + if (source.startsWith("git+")) { + const raw = source.replace("git+", "") + const [url, ref] = raw.split("#") + const name = path.basename(url, ".git") + return { name, url, ref } + } + if (source.startsWith("https://")) { + const [url, ref] = source.split("#") + const name = path.basename(url, ".git") + return { name, url, ref } + } + throw new Error(`Cannot parse plugin source: ${source}`) +} + +export function getGitCommit(pluginDir) { + try { + return execSync("git rev-parse HEAD", { cwd: pluginDir, encoding: "utf-8" }).trim() + } catch { + return "unknown" + } +} + +export function getPluginDir(name) { + return path.join(PLUGINS_DIR, name) +} + +export function pluginDirExists(name) { + return fs.existsSync(path.join(PLUGINS_DIR, name)) +} + +export function ensurePluginsDir() { + if (!fs.existsSync(PLUGINS_DIR)) { + fs.mkdirSync(PLUGINS_DIR, { recursive: true }) + } +} + +/** + * Merges quartz.config.yaml, quartz.lock.json, and on-disk manifest data + * into enriched plugin entries with: name, displayName, source, enabled, + * options, order, layout, category, installed, locked, manifest, + * currentCommit, modified. + */ +export function getEnrichedPlugins() { + const pluginsJson = readPluginsJson() + const lockfile = readLockfile() + + if (!pluginsJson?.plugins) return [] + + return pluginsJson.plugins.map((entry, index) => { + const name = extractPluginName(entry.source) + const pluginDir = path.join(PLUGINS_DIR, name) + const installed = fs.existsSync(pluginDir) + const locked = lockfile?.plugins?.[name] ?? null + const manifest = installed ? readManifestFromPackageJson(pluginDir) : null + const currentCommit = installed ? getGitCommit(pluginDir) : null + const modified = locked && currentCommit ? currentCommit !== locked.commit : false + + return { + index, + name, + displayName: manifest?.displayName ?? name, + source: entry.source, + enabled: entry.enabled ?? true, + options: entry.options ?? {}, + order: entry.order ?? 50, + layout: entry.layout ?? null, + category: manifest?.category ?? "unknown", + installed, + locked, + manifest, + currentCommit, + modified, + } + }) +} + +export function getLayoutConfig() { + const pluginsJson = readPluginsJson() + return pluginsJson?.layout ?? null +} + +export function getGlobalConfig() { + const pluginsJson = readPluginsJson() + return pluginsJson?.configuration ?? null +} + +export function updatePluginEntry(index, updates) { + const json = readPluginsJson() + if (!json?.plugins?.[index]) return false + Object.assign(json.plugins[index], updates) + writePluginsJson(json) + return true +} + +export function updateGlobalConfig(updates) { + const json = readPluginsJson() + if (!json) return false + json.configuration = { ...json.configuration, ...updates } + writePluginsJson(json) + return true +} + +export function updateLayoutConfig(layout) { + const json = readPluginsJson() + if (!json) return false + json.layout = layout + writePluginsJson(json) + return true +} + +export function reorderPlugin(fromIndex, toIndex) { + const json = readPluginsJson() + if (!json?.plugins) return false + const [moved] = json.plugins.splice(fromIndex, 1) + json.plugins.splice(toIndex, 0, moved) + writePluginsJson(json) + return true +} + +export function removePluginEntry(index) { + const json = readPluginsJson() + if (!json?.plugins?.[index]) return false + json.plugins.splice(index, 1) + writePluginsJson(json) + return true +} + +export function addPluginEntry(entry) { + const json = readPluginsJson() + if (!json) return false + if (!json.plugins) json.plugins = [] + json.plugins.push(entry) + writePluginsJson(json) + return true +} + +export function configExists() { + return fs.existsSync(CONFIG_YAML_PATH) || fs.existsSync(LEGACY_PLUGINS_JSON_PATH) +} + +export function createConfigFromDefault() { + const defaultData = readDefaultPluginsJson() + if (!defaultData) { + // No default available — create minimal config + const minimal = { + configuration: { + pageTitle: "Quartz", + enableSPA: true, + enablePopovers: true, + analytics: { provider: "plausible" }, + locale: "en-US", + baseUrl: "quartz.jzhao.xyz", + ignorePatterns: ["private", "templates", ".obsidian"], + defaultDateType: "created", + theme: { + cdnCaching: true, + typography: { + header: "Schibsted Grotesk", + body: "Source Sans Pro", + code: "IBM Plex Mono", + }, + colors: { + lightMode: { + light: "#faf8f8", + lightgray: "#e5e5e5", + gray: "#b8b8b8", + darkgray: "#4e4e4e", + dark: "#2b2b2b", + secondary: "#284b63", + tertiary: "#84a59d", + highlight: "rgba(143, 159, 169, 0.15)", + textHighlight: "#fff23688", + }, + darkMode: { + light: "#161618", + lightgray: "#393639", + gray: "#646464", + darkgray: "#d4d4d4", + dark: "#ebebec", + secondary: "#7b97aa", + tertiary: "#84a59d", + highlight: "rgba(143, 159, 169, 0.15)", + textHighlight: "#fff23688", + }, + }, + }, + }, + plugins: [], + layout: { groups: {}, byPageType: {} }, + } + writePluginsJson(minimal) + return minimal + } + + const { $schema, ...rest } = defaultData + writePluginsJson(rest) + return rest +} + +const VALID_TEMPLATES = ["default", "obsidian", "ttrpg", "blog"] + +export function createConfigFromTemplate(templateName) { + if (!VALID_TEMPLATES.includes(templateName)) { + throw new Error( + `Unknown template: ${templateName}. Valid templates: ${VALID_TEMPLATES.join(", ")}`, + ) + } + + const templatePath = path.join(TEMPLATES_DIR, `${templateName}.yaml`) + const templateData = readFileAsData(templatePath) + if (!templateData) { + // Template file missing — fall back to default config creation + return createConfigFromDefault() + } + + const { $schema, ...rest } = templateData + writePluginsJson(rest) + return rest +} + +export const PLUGINS_JSON_PATH = CONFIG_YAML_PATH +export const DEFAULT_PLUGINS_JSON_PATH = DEFAULT_CONFIG_YAML_PATH +export { LOCKFILE_PATH, PLUGINS_DIR } diff --git a/quartz/cli/plugin-git-handlers.js b/quartz/cli/plugin-git-handlers.js new file mode 100644 index 000000000..086e4d908 --- /dev/null +++ b/quartz/cli/plugin-git-handlers.js @@ -0,0 +1,1029 @@ +import fs from "fs" +import path from "path" +import { execSync } from "child_process" +import { styleText } from "util" +import { + readPluginsJson, + writePluginsJson, + readLockfile, + writeLockfile, + extractPluginName, + readManifestFromPackageJson, + parseGitSource, + getGitCommit, + PLUGINS_DIR, + LOCKFILE_PATH, + isLocalSource, +} from "./plugin-data.js" + +const INTERNAL_EXPORTS = new Set(["manifest", "default"]) + +function buildPlugin(pluginDir, name) { + try { + console.log(styleText("cyan", ` → ${name}: installing dependencies...`)) + execSync("npm install", { cwd: pluginDir, stdio: "ignore" }) + console.log(styleText("cyan", ` → ${name}: building...`)) + execSync("npm run build", { cwd: pluginDir, stdio: "ignore" }) + // Remove devDependencies after build — they are no longer needed and their + // presence can cause duplicate-singleton issues when a plugin ships its own + // copy of a shared dependency (e.g. bases-page's ViewRegistry). + execSync("npm prune --omit=dev", { cwd: pluginDir, stdio: "ignore" }) + // Symlink any peerDependencies that are co-installed Quartz plugins so that + // Node's module resolution finds the host copy instead of a stale nested one. + linkPeerPlugins(pluginDir) + return true + } catch (error) { + console.log(styleText("red", ` ✗ ${name}: build failed`)) + return false + } +} + +function needsBuild(pluginDir) { + const distDir = path.join(pluginDir, "dist") + return !fs.existsSync(distDir) +} + +/** + * After pruning devDependencies, peerDependencies that reference other Quartz + * plugins (e.g. @quartz-community/bases-page) won't be installed as npm + * packages — they're loaded by v5 as sibling plugins. To make Node's module + * resolution work, we symlink those peers to the co-installed plugin directory. + */ +function linkPeerPlugins(pluginDir) { + const pkgPath = path.join(pluginDir, "package.json") + if (!fs.existsSync(pkgPath)) return + + const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")) + const peers = pkg.peerDependencies ?? {} + + for (const peerName of Object.keys(peers)) { + // Only handle @quartz-community scoped packages — those are Quartz plugins + if (!peerName.startsWith("@quartz-community/")) continue + + // Check if this peer is already satisfied (e.g. installed as a regular dep) + const peerNodeModulesPath = path.join(pluginDir, "node_modules", ...peerName.split("/")) + if (fs.existsSync(peerNodeModulesPath)) continue + + // Find the sibling plugin by its npm package name + const siblingPlugin = findPluginByPackageName(peerName) + if (!siblingPlugin) continue + + // Create the scoped directory if needed + const scopeDir = path.join(pluginDir, "node_modules", peerName.split("/")[0]) + fs.mkdirSync(scopeDir, { recursive: true }) + + // Create a relative symlink to the sibling plugin + const target = path.relative(scopeDir, siblingPlugin) + fs.symlinkSync(target, peerNodeModulesPath, "dir") + } +} + +/** + * Search installed plugins for one whose package.json "name" matches the given + * npm package name (e.g. "@quartz-community/bases-page"). + */ +function findPluginByPackageName(packageName) { + if (!fs.existsSync(PLUGINS_DIR)) return null + + const plugins = fs.readdirSync(PLUGINS_DIR).filter((entry) => { + const entryPath = path.join(PLUGINS_DIR, entry) + return fs.statSync(entryPath).isDirectory() + }) + + for (const pluginDirName of plugins) { + const pkgPath = path.join(PLUGINS_DIR, pluginDirName, "package.json") + if (!fs.existsSync(pkgPath)) continue + try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")) + if (pkg.name === packageName) { + return path.join(PLUGINS_DIR, pluginDirName) + } + } catch {} + } + return null +} + +function parseExportsFromDts(content) { + const exports = [] + const exportMatches = content.matchAll(/export\s*{\s*([^}]+)\s*}(?:\s*from\s*['"]([^'"]+)['"])?/g) + for (const match of exportMatches) { + const fromModule = match[2] + if (fromModule?.startsWith("@")) continue + + const names = match[1] + .split(",") + .map((n) => n.trim()) + .filter(Boolean) + for (const name of names) { + const cleanName = name.split(" as ").pop()?.trim() || name.trim() + if (cleanName && !cleanName.startsWith("_") && !INTERNAL_EXPORTS.has(cleanName)) { + const finalName = cleanName.replace(/^type\s+/, "") + if (name.includes("type ")) { + exports.push(`type ${finalName}`) + } else { + exports.push(finalName) + } + } + } + } + return exports +} + +async function regeneratePluginIndex() { + if (!fs.existsSync(PLUGINS_DIR)) return + + const plugins = fs.readdirSync(PLUGINS_DIR).filter((name) => { + const pluginPath = path.join(PLUGINS_DIR, name) + return fs.statSync(pluginPath).isDirectory() + }) + + const exports = [] + + for (const pluginName of plugins) { + const pluginDir = path.join(PLUGINS_DIR, pluginName) + const distIndex = path.join(pluginDir, "dist", "index.d.ts") + + if (!fs.existsSync(distIndex)) continue + + const dtsContent = fs.readFileSync(distIndex, "utf-8") + const exportedNames = parseExportsFromDts(dtsContent) + + if (exportedNames.length > 0) { + const namedExports = exportedNames.filter((e) => !e.startsWith("type ")) + const typeExports = exportedNames.filter((e) => e.startsWith("type ")).map((e) => e.slice(5)) + + if (namedExports.length > 0) { + exports.push(`export { ${namedExports.join(", ")} } from "./${pluginName}"`) + } + if (typeExports.length > 0) { + exports.push(`export type { ${typeExports.join(", ")} } from "./${pluginName}"`) + } + } + } + + const indexContent = exports.join("\n") + "\n" + const indexPath = path.join(PLUGINS_DIR, "index.ts") + fs.writeFileSync(indexPath, indexContent) +} + +export async function handlePluginInstall() { + const lockfile = readLockfile() + + if (!lockfile) { + console.log( + styleText("yellow", "⚠ No quartz.lock.json found. Run 'npx quartz plugin add ' first."), + ) + return + } + + if (!fs.existsSync(PLUGINS_DIR)) { + fs.mkdirSync(PLUGINS_DIR, { recursive: true }) + } + + console.log(styleText("cyan", "→ Installing plugins from lockfile...")) + let installed = 0 + let failed = 0 + const pluginsToBuild = [] + + for (const [name, entry] of Object.entries(lockfile.plugins)) { + const pluginDir = path.join(PLUGINS_DIR, name) + + // Local plugin: ensure symlink exists + if (entry.commit === "local") { + try { + if (fs.existsSync(pluginDir)) { + const stat = fs.lstatSync(pluginDir) + if (stat.isSymbolicLink() && fs.readlinkSync(pluginDir) === entry.resolved) { + console.log(styleText("gray", ` ✓ ${name} (local) already linked`)) + installed++ + continue + } + // Wrong target or not a symlink — remove and re-link + if (stat.isSymbolicLink()) fs.unlinkSync(pluginDir) + else fs.rmSync(pluginDir, { recursive: true }) + } + if (!fs.existsSync(entry.resolved)) { + console.log(styleText("red", ` ✗ ${name}: local path missing: ${entry.resolved}`)) + failed++ + continue + } + fs.mkdirSync(path.dirname(pluginDir), { recursive: true }) + fs.symlinkSync(entry.resolved, pluginDir, "dir") + console.log(styleText("green", ` ✓ ${name} (local) linked`)) + pluginsToBuild.push({ name, pluginDir }) + installed++ + } catch { + console.log(styleText("red", ` ✗ ${name}: failed to link local path`)) + failed++ + } + continue + } + + if (fs.existsSync(pluginDir)) { + try { + const currentCommit = getGitCommit(pluginDir) + if (currentCommit === entry.commit && !needsBuild(pluginDir)) { + console.log( + styleText("gray", ` ✓ ${name}@${entry.commit.slice(0, 7)} already installed`), + ) + installed++ + continue + } + if (currentCommit !== entry.commit) { + console.log(styleText("cyan", ` → ${name}: updating to ${entry.commit.slice(0, 7)}...`)) + const fetchRef = entry.ref ? ` ${entry.ref}` : "" + execSync(`git fetch --depth 1 origin${fetchRef}`, { cwd: pluginDir, stdio: "ignore" }) + execSync(`git reset --hard ${entry.commit}`, { cwd: pluginDir, stdio: "ignore" }) + } + pluginsToBuild.push({ name, pluginDir }) + installed++ + } catch { + console.log(styleText("red", ` ✗ ${name}: failed to update`)) + failed++ + } + } else { + try { + console.log(styleText("cyan", ` → ${name}: cloning...`)) + const branchArg = entry.ref ? ` --branch ${entry.ref}` : "" + execSync(`git clone --depth 1${branchArg} ${entry.resolved} ${pluginDir}`, { + stdio: "ignore", + }) + if (entry.commit !== "unknown") { + execSync(`git fetch --depth 1 origin ${entry.commit}`, { + cwd: pluginDir, + stdio: "ignore", + }) + execSync(`git checkout ${entry.commit}`, { cwd: pluginDir, stdio: "ignore" }) + } + console.log(styleText("green", ` ✓ ${name}@${entry.commit.slice(0, 7)}`)) + pluginsToBuild.push({ name, pluginDir }) + installed++ + } catch { + console.log(styleText("red", ` ✗ ${name}: failed to clone`)) + failed++ + } + } + } + + if (pluginsToBuild.length > 0) { + console.log() + console.log(styleText("cyan", "→ Building plugins...")) + for (const { name, pluginDir } of pluginsToBuild) { + if (!buildPlugin(pluginDir, name)) { + failed++ + installed-- + } else { + console.log(styleText("green", ` ✓ ${name} built`)) + } + } + } + + await regeneratePluginIndex() + + console.log() + if (failed === 0) { + console.log(styleText("green", `✓ Installed ${installed} plugin(s)`)) + } else { + console.log(styleText("yellow", `⚠ Installed ${installed} plugin(s), ${failed} failed`)) + } +} + +export async function handlePluginAdd(sources) { + let lockfile = readLockfile() + if (!lockfile) { + lockfile = { version: "1.0.0", plugins: {} } + } + + if (!fs.existsSync(PLUGINS_DIR)) { + fs.mkdirSync(PLUGINS_DIR, { recursive: true }) + } + + const addedPlugins = [] + + for (const source of sources) { + try { + const { name, url, ref, local } = parseGitSource(source) + const pluginDir = path.join(PLUGINS_DIR, name) + + if (fs.existsSync(pluginDir)) { + console.log(styleText("yellow", `⚠ ${name} already exists. Use 'update' to refresh.`)) + continue + } + + if (local) { + // Local path: create symlink instead of git clone + const resolvedPath = path.resolve(url) + if (!fs.existsSync(resolvedPath)) { + console.log(styleText("red", `✗ Local path does not exist: ${resolvedPath}`)) + continue + } + console.log(styleText("cyan", `→ Adding ${name} from local path ${resolvedPath}...`)) + fs.mkdirSync(path.dirname(pluginDir), { recursive: true }) + fs.symlinkSync(resolvedPath, pluginDir, "dir") + lockfile.plugins[name] = { + source, + resolved: resolvedPath, + commit: "local", + installedAt: new Date().toISOString(), + } + addedPlugins.push({ name, pluginDir, source }) + console.log(styleText("green", `✓ Added ${name} (local symlink)`)) + } else { + console.log(styleText("cyan", `→ Adding ${name} from ${url}...`)) + + if (ref) { + execSync(`git clone --depth 1 --branch ${ref} ${url} ${pluginDir}`, { stdio: "ignore" }) + } else { + execSync(`git clone --depth 1 ${url} ${pluginDir}`, { stdio: "ignore" }) + } + + const commit = getGitCommit(pluginDir) + lockfile.plugins[name] = { + source, + resolved: url, + commit, + ...(ref && { ref }), + installedAt: new Date().toISOString(), + } + + addedPlugins.push({ name, pluginDir, source }) + console.log(styleText("green", `✓ Added ${name}@${commit.slice(0, 7)}`)) + } + } catch (error) { + console.log(styleText("red", `✗ Failed to add ${source}: ${error}`)) + } + } + + if (addedPlugins.length > 0) { + console.log() + console.log(styleText("cyan", "→ Building plugins...")) + for (const { name, pluginDir } of addedPlugins) { + if (buildPlugin(pluginDir, name)) { + console.log(styleText("green", ` ✓ ${name} built`)) + } + } + await regeneratePluginIndex() + } + + writeLockfile(lockfile) + const pluginsJson = readPluginsJson() + if (pluginsJson?.plugins) { + for (const { pluginDir, source } of addedPlugins) { + const manifest = readManifestFromPackageJson(pluginDir) + const newEntry = { + source, + enabled: manifest?.defaultEnabled ?? true, + options: manifest?.defaultOptions ?? {}, + order: manifest?.defaultOrder ?? 50, + } + + if (manifest?.components) { + const firstComponentKey = Object.keys(manifest.components)[0] + const comp = manifest.components[firstComponentKey] + if (comp?.defaultPosition) { + newEntry.layout = { + position: comp.defaultPosition, + priority: comp.defaultPriority ?? 50, + display: "all", + } + } + } + + pluginsJson.plugins.push(newEntry) + } + writePluginsJson(pluginsJson) + } + console.log() + console.log(styleText("gray", "Updated quartz.lock.json")) +} + +export async function handlePluginRemove(names) { + const lockfile = readLockfile() + if (!lockfile) { + console.log(styleText("yellow", "⚠ No plugins installed")) + return + } + + let removed = false + for (const name of names) { + const pluginDir = path.join(PLUGINS_DIR, name) + + if (!lockfile.plugins[name] && !fs.existsSync(pluginDir)) { + console.log(styleText("yellow", `⚠ ${name} is not installed`)) + continue + } + + console.log(styleText("cyan", `→ Removing ${name}...`)) + + if (fs.existsSync(pluginDir)) { + fs.rmSync(pluginDir, { recursive: true }) + } + + delete lockfile.plugins[name] + console.log(styleText("green", `✓ Removed ${name}`)) + removed = true + } + + if (removed) { + await regeneratePluginIndex() + } + + writeLockfile(lockfile) + const pluginsJson = readPluginsJson() + if (pluginsJson?.plugins) { + pluginsJson.plugins = pluginsJson.plugins.filter( + (plugin) => + !names.includes(extractPluginName(plugin.source)) && !names.includes(plugin.source), + ) + writePluginsJson(pluginsJson) + } + console.log() + console.log(styleText("gray", "Updated quartz.lock.json")) +} + +export async function handlePluginEnable(names) { + const json = readPluginsJson() + if (!json) { + console.log(styleText("red", "✗ No quartz.config.yaml found. Cannot enable plugins.")) + return + } + + for (const name of names) { + const entry = json.plugins.find( + (e) => extractPluginName(e.source) === name || e.source === name, + ) + if (!entry) { + console.log(styleText("yellow", `⚠ Plugin "${name}" not found in quartz.config.yaml`)) + continue + } + if (entry.enabled) { + console.log(styleText("gray", `✓ ${name} is already enabled`)) + continue + } + entry.enabled = true + console.log(styleText("green", `✓ Enabled ${name}`)) + } + + writePluginsJson(json) +} + +export async function handlePluginDisable(names) { + const json = readPluginsJson() + if (!json) { + console.log(styleText("red", "✗ No quartz.config.yaml found. Cannot disable plugins.")) + return + } + + for (const name of names) { + const entry = json.plugins.find( + (e) => extractPluginName(e.source) === name || e.source === name, + ) + if (!entry) { + console.log(styleText("yellow", `⚠ Plugin "${name}" not found in quartz.config.yaml`)) + continue + } + if (!entry.enabled) { + console.log(styleText("gray", `✓ ${name} is already disabled`)) + continue + } + entry.enabled = false + console.log(styleText("green", `✓ Disabled ${name}`)) + } + + writePluginsJson(json) +} + +export async function handlePluginConfig(name, options = {}) { + const json = readPluginsJson() + if (!json) { + console.log(styleText("red", "✗ No quartz.config.yaml found.")) + return + } + + const entry = json.plugins.find((e) => extractPluginName(e.source) === name || e.source === name) + if (!entry) { + console.log(styleText("red", `✗ Plugin "${name}" not found in quartz.config.yaml`)) + return + } + + if (options.set) { + const eqIndex = options.set.indexOf("=") + if (eqIndex === -1) { + console.log(styleText("red", "✗ Invalid format. Use: --set key=value")) + return + } + const key = options.set.slice(0, eqIndex) + let value = options.set.slice(eqIndex + 1) + + try { + value = JSON.parse(value) + } catch {} + + if (!entry.options) entry.options = {} + entry.options[key] = value + writePluginsJson(json) + console.log(styleText("green", `✓ Set ${name}.${key} = ${JSON.stringify(value)}`)) + } else { + console.log(styleText("bold", `Plugin: ${name}`)) + console.log(` Source: ${entry.source}`) + console.log(` Enabled: ${entry.enabled}`) + console.log(` Order: ${entry.order ?? 50}`) + if (entry.options && Object.keys(entry.options).length > 0) { + console.log(` Options:`) + for (const [k, v] of Object.entries(entry.options)) { + console.log(` ${k}: ${JSON.stringify(v)}`) + } + } else { + console.log(` Options: (none)`) + } + if (entry.layout) { + console.log(` Layout:`) + for (const [k, v] of Object.entries(entry.layout)) { + console.log(` ${k}: ${JSON.stringify(v)}`) + } + } + } +} + +export async function handlePluginCheck() { + const lockfile = readLockfile() + if (!lockfile || Object.keys(lockfile.plugins).length === 0) { + console.log(styleText("gray", "No plugins installed")) + return + } + + console.log(styleText("bold", "Checking for plugin updates...\n")) + + const results = [] + for (const [name, entry] of Object.entries(lockfile.plugins)) { + // Local plugins: show "local" status, skip git checks + if (entry.commit === "local") { + results.push({ + name, + installed: "local", + latest: "—", + status: "local", + }) + continue + } + + try { + const lsRemoteRef = entry.ref ? `refs/heads/${entry.ref}` : "HEAD" + const latestCommit = execSync(`git ls-remote ${entry.resolved} ${lsRemoteRef}`, { + encoding: "utf-8", + }) + .split("\t")[0] + .trim() + + const isCurrent = latestCommit === entry.commit + results.push({ + name, + installed: entry.commit.slice(0, 7), + latest: latestCommit.slice(0, 7), + status: isCurrent ? "up to date" : "update available", + }) + } catch { + results.push({ + name, + installed: entry.commit.slice(0, 7), + latest: "?", + status: "check failed", + }) + } + } + + const nameWidth = Math.max(6, ...results.map((r) => r.name.length)) + 2 + const header = `${"Plugin".padEnd(nameWidth)}${"Installed".padEnd(12)}${"Latest".padEnd(12)}Status` + console.log(styleText("bold", header)) + console.log("─".repeat(header.length)) + + for (const r of results) { + const color = + r.status === "up to date" || r.status === "local" + ? "green" + : r.status === "check failed" + ? "red" + : "yellow" + console.log( + `${r.name.padEnd(nameWidth)}${r.installed.padEnd(12)}${r.latest.padEnd(12)}${styleText( + color, + r.status, + )}`, + ) + } +} + +export async function handlePluginUpdate(names) { + const lockfile = readLockfile() + if (!lockfile) { + console.log(styleText("yellow", "⚠ No plugins installed")) + return + } + + const pluginsToUpdate = names || Object.keys(lockfile.plugins) + const updatedPlugins = [] + + for (const name of pluginsToUpdate) { + const entry = lockfile.plugins[name] + if (!entry) { + console.log(styleText("yellow", `⚠ ${name} is not installed`)) + continue + } + + const pluginDir = path.join(PLUGINS_DIR, name) + if (!fs.existsSync(pluginDir)) { + console.log( + styleText("yellow", `⚠ ${name} directory missing. Run 'npx quartz plugin install'.`), + ) + continue + } + + // Local plugins: just rebuild, no git operations + if (entry.commit === "local") { + console.log(styleText("cyan", `→ Rebuilding local plugin ${name}...`)) + updatedPlugins.push({ name, pluginDir }) + continue + } + + try { + console.log(styleText("cyan", `→ Updating ${name}...`)) + const fetchRef = entry.ref || "" + const resetTarget = entry.ref ? `origin/${entry.ref}` : "origin/HEAD" + execSync(`git fetch --depth 1 origin${fetchRef ? " " + fetchRef : ""}`, { + cwd: pluginDir, + stdio: "ignore", + }) + execSync(`git reset --hard ${resetTarget}`, { cwd: pluginDir, stdio: "ignore" }) + + const newCommit = getGitCommit(pluginDir) + if (newCommit !== entry.commit) { + entry.commit = newCommit + entry.installedAt = new Date().toISOString() + updatedPlugins.push({ name, pluginDir }) + console.log(styleText("green", `✓ Updated ${name} to ${newCommit.slice(0, 7)}`)) + } else { + console.log(styleText("gray", `✓ ${name} already up to date`)) + } + } catch (error) { + console.log(styleText("red", `✗ Failed to update ${name}: ${error}`)) + } + } + + if (updatedPlugins.length > 0) { + console.log() + console.log(styleText("cyan", "→ Rebuilding updated plugins...")) + for (const { name, pluginDir } of updatedPlugins) { + if (buildPlugin(pluginDir, name)) { + console.log(styleText("green", ` ✓ ${name} rebuilt`)) + } + } + await regeneratePluginIndex() + } + + writeLockfile(lockfile) + console.log() + console.log(styleText("gray", "Updated quartz.lock.json")) +} + +export async function handlePluginList() { + const lockfile = readLockfile() + if (!lockfile || Object.keys(lockfile.plugins).length === 0) { + console.log(styleText("gray", "No plugins installed")) + return + } + + console.log(styleText("bold", "Installed Plugins:")) + console.log() + + for (const [name, entry] of Object.entries(lockfile.plugins)) { + const pluginDir = path.join(PLUGINS_DIR, name) + const exists = fs.existsSync(pluginDir) + + // Local plugins: special display + if (entry.commit === "local") { + const isLinked = exists && fs.lstatSync(pluginDir).isSymbolicLink() + const status = isLinked ? styleText("green", "✓") : styleText("red", "✗") + console.log(` ${status} ${styleText("bold", name)}`) + console.log(` Source: ${entry.source}`) + console.log(` Type: local symlink`) + console.log(` Target: ${entry.resolved}`) + console.log(` Installed: ${new Date(entry.installedAt).toLocaleDateString()}`) + console.log() + continue + } + + let currentCommit = entry.commit + + if (exists) { + currentCommit = getGitCommit(pluginDir) + } + + const status = exists + ? currentCommit === entry.commit + ? styleText("green", "✓") + : styleText("yellow", "⚡") + : styleText("red", "✗") + + console.log(` ${status} ${styleText("bold", name)}`) + console.log(` Source: ${entry.source}`) + console.log(` Commit: ${entry.commit.slice(0, 7)}`) + if (currentCommit !== entry.commit && exists) { + console.log(` Current: ${currentCommit.slice(0, 7)} (modified)`) + } + console.log(` Installed: ${new Date(entry.installedAt).toLocaleDateString()}`) + console.log() + } +} + +export async function handlePluginRestore() { + const lockfile = readLockfile() + if (!lockfile) { + console.log(styleText("red", "✗ No quartz.lock.json found. Cannot restore.")) + console.log() + console.log("Run 'npx quartz plugin add ' to install plugins from scratch.") + return + } + + console.log(styleText("cyan", "→ Restoring plugins from lockfile...")) + console.log() + + const pluginsDir = path.join(process.cwd(), ".quartz", "plugins") + if (!fs.existsSync(pluginsDir)) { + fs.mkdirSync(pluginsDir, { recursive: true }) + } + + let installed = 0 + let failed = 0 + const restoredPlugins = [] + + for (const [name, entry] of Object.entries(lockfile.plugins)) { + const pluginDir = path.join(pluginsDir, name) + + if (fs.existsSync(pluginDir)) { + console.log(styleText("yellow", `⚠ ${name}: directory exists, skipping`)) + continue + } + + // Local plugin: re-symlink + if (entry.commit === "local") { + try { + if (!fs.existsSync(entry.resolved)) { + console.log(styleText("red", ` ✗ ${name}: local path missing: ${entry.resolved}`)) + failed++ + continue + } + fs.mkdirSync(path.dirname(pluginDir), { recursive: true }) + fs.symlinkSync(entry.resolved, pluginDir, "dir") + console.log(styleText("green", `✓ ${name} restored (local symlink)`)) + restoredPlugins.push({ name, pluginDir }) + installed++ + } catch { + console.log(styleText("red", `✗ ${name}: failed to restore local symlink`)) + failed++ + } + continue + } + + try { + console.log( + styleText("cyan", `→ ${name}: cloning ${entry.resolved}@${entry.commit.slice(0, 7)}...`), + ) + const branchArg = entry.ref ? ` --branch ${entry.ref}` : "" + execSync(`git clone${branchArg} ${entry.resolved} ${pluginDir}`, { stdio: "ignore" }) + execSync(`git checkout ${entry.commit}`, { cwd: pluginDir, stdio: "ignore" }) + console.log(styleText("green", `✓ ${name} restored`)) + restoredPlugins.push({ name, pluginDir }) + installed++ + } catch { + console.log(styleText("red", `✗ ${name}: failed to restore`)) + failed++ + } + } + + if (restoredPlugins.length > 0) { + console.log() + console.log(styleText("cyan", "→ Building restored plugins...")) + for (const { name, pluginDir } of restoredPlugins) { + if (!buildPlugin(pluginDir, name)) { + failed++ + installed-- + } else { + console.log(styleText("green", ` ✓ ${name} built`)) + } + } + await regeneratePluginIndex() + } + + console.log() + if (failed === 0) { + console.log(styleText("green", `✓ Restored ${installed} plugin(s)`)) + } else { + console.log(styleText("yellow", `⚠ Restored ${installed} plugin(s), ${failed} failed`)) + } +} + +export async function handlePluginPrune({ dryRun = false } = {}) { + const lockfile = readLockfile() + if (!lockfile || Object.keys(lockfile.plugins).length === 0) { + console.log(styleText("gray", "No plugins installed")) + return + } + + const pluginsJson = readPluginsJson() + const configuredNames = new Set( + (pluginsJson?.plugins ?? []).map((entry) => extractPluginName(entry.source)), + ) + + const orphans = Object.keys(lockfile.plugins).filter((name) => !configuredNames.has(name)) + + if (orphans.length === 0) { + console.log(styleText("green", "✓ No orphaned plugins found — nothing to prune")) + return + } + + console.log(`Found ${orphans.length} orphaned plugin(s):\n`) + for (const name of orphans) { + console.log(` ${styleText("yellow", name)} — in lockfile but not in config`) + } + console.log() + + if (dryRun) { + console.log(styleText("cyan", "Dry run — no changes made. Re-run without --dry-run to prune.")) + return + } + + let removed = 0 + for (const name of orphans) { + const pluginDir = path.join(PLUGINS_DIR, name) + + console.log(styleText("cyan", `→ Removing ${name}...`)) + + if (fs.existsSync(pluginDir)) { + fs.rmSync(pluginDir, { recursive: true }) + } + + delete lockfile.plugins[name] + console.log(styleText("green", `✓ Removed ${name}`)) + removed++ + } + + if (removed > 0) { + await regeneratePluginIndex() + } + + writeLockfile(lockfile) + console.log() + console.log(styleText("green", `✓ Pruned ${removed} plugin(s)`)) + console.log(styleText("gray", "Updated quartz.lock.json")) +} + +export async function handlePluginResolve({ dryRun = false } = {}) { + const pluginsJson = readPluginsJson() + if (!pluginsJson?.plugins || pluginsJson.plugins.length === 0) { + console.log(styleText("gray", "No plugins configured")) + return + } + + let lockfile = readLockfile() + if (!lockfile) { + lockfile = { version: "1.0.0", plugins: {} } + } + + if (!fs.existsSync(PLUGINS_DIR)) { + fs.mkdirSync(PLUGINS_DIR, { recursive: true }) + } + + // Find config entries whose source is a git/local-resolvable URL and not yet in lockfile + const missing = pluginsJson.plugins.filter((entry) => { + const name = extractPluginName(entry.source) + if (lockfile.plugins[name]) return false + // Only attempt sources that parseGitSource can handle (git URLs + local paths) + const src = entry.source + return ( + src.startsWith("github:") || + src.startsWith("git+") || + src.startsWith("https://") || + isLocalSource(src) + ) + }) + + if (missing.length === 0) { + console.log(styleText("green", "✓ All configured plugins are already installed")) + return + } + + console.log(`Found ${missing.length} uninstalled plugin(s) in config:\n`) + for (const entry of missing) { + const name = extractPluginName(entry.source) + console.log(` ${styleText("yellow", name)} — ${entry.source}`) + } + console.log() + + if (dryRun) { + console.log( + styleText("cyan", "Dry run — no changes made. Re-run without --dry-run to resolve."), + ) + return + } + + const installed = [] + let failed = 0 + + for (const entry of missing) { + try { + const { name, url, ref, local } = parseGitSource(entry.source) + const pluginDir = path.join(PLUGINS_DIR, name) + + if (fs.existsSync(pluginDir)) { + if (local) { + console.log(styleText("yellow", `⚠ ${name} directory already exists, updating lockfile`)) + lockfile.plugins[name] = { + source: entry.source, + resolved: url, + commit: "local", + installedAt: new Date().toISOString(), + } + installed.push({ name, pluginDir }) + continue + } + console.log(styleText("yellow", `⚠ ${name} directory already exists, updating lockfile`)) + const commit = getGitCommit(pluginDir) + lockfile.plugins[name] = { + source: entry.source, + resolved: url, + commit, + ...(ref && { ref }), + installedAt: new Date().toISOString(), + } + installed.push({ name, pluginDir }) + continue + } + + if (local) { + // Local path: symlink + const resolvedPath = path.resolve(url) + if (!fs.existsSync(resolvedPath)) { + console.log(styleText("red", `✗ Local path does not exist: ${resolvedPath}`)) + failed++ + continue + } + console.log(styleText("cyan", `→ Linking ${name} from ${resolvedPath}...`)) + fs.mkdirSync(path.dirname(pluginDir), { recursive: true }) + fs.symlinkSync(resolvedPath, pluginDir, "dir") + lockfile.plugins[name] = { + source: entry.source, + resolved: resolvedPath, + commit: "local", + installedAt: new Date().toISOString(), + } + installed.push({ name, pluginDir }) + console.log(styleText("green", `✓ Linked ${name} (local)`)) + } else { + console.log(styleText("cyan", `→ Cloning ${name} from ${url}...`)) + + if (ref) { + execSync(`git clone --depth 1 --branch ${ref} ${url} ${pluginDir}`, { stdio: "ignore" }) + } else { + execSync(`git clone --depth 1 ${url} ${pluginDir}`, { stdio: "ignore" }) + } + + const commit = getGitCommit(pluginDir) + lockfile.plugins[name] = { + source: entry.source, + resolved: url, + commit, + ...(ref && { ref }), + installedAt: new Date().toISOString(), + } + + installed.push({ name, pluginDir }) + console.log(styleText("green", `✓ Cloned ${name}@${commit.slice(0, 7)}`)) + } + } catch (error) { + console.log(styleText("red", `✗ Failed to resolve ${entry.source}: ${error}`)) + failed++ + } + } + + if (installed.length > 0) { + console.log() + console.log(styleText("cyan", "→ Building plugins...")) + for (const { name, pluginDir } of installed) { + if (!buildPlugin(pluginDir, name)) { + failed++ + } else { + console.log(styleText("green", ` ✓ ${name} built`)) + } + } + await regeneratePluginIndex() + } + + writeLockfile(lockfile) + console.log() + if (failed === 0) { + console.log(styleText("green", `✓ Resolved ${installed.length} plugin(s)`)) + } else { + console.log(styleText("yellow", `⚠ Resolved ${installed.length} plugin(s), ${failed} failed`)) + } + console.log(styleText("gray", "Updated quartz.lock.json")) +} diff --git a/quartz/cli/plugin-handlers.js b/quartz/cli/plugin-handlers.js new file mode 100644 index 000000000..8ee6e6cfe --- /dev/null +++ b/quartz/cli/plugin-handlers.js @@ -0,0 +1,130 @@ +import { styleText } from "util" +import { execSync, spawnSync } from "child_process" +import fs from "fs" +import path from "path" + +export async function handlePluginInstall(packageNames) { + console.log(`\n${styleText(["bgGreen", "black"], " Quartz Plugin Manager ")}\n`) + + if (packageNames.length === 0) { + console.log(styleText("red", "Error: No package names provided")) + console.log("Usage: npx quartz plugin install [package-name...]") + process.exit(1) + } + + console.log(`Installing ${packageNames.length} plugin(s)...`) + + const npmArgs = ["install", ...packageNames] + const result = spawnSync("npm", npmArgs, { stdio: "inherit" }) + + if (result.status !== 0) { + console.log(styleText("red", "Failed to install plugins")) + process.exit(1) + } + + console.log(styleText("green", "✓ Plugins installed successfully")) + console.log("\nAdd them to your quartz.config.yaml:") + + for (const pkg of packageNames) { + console.log(` import { Plugin } from "${pkg}"`) + } +} + +export async function handlePluginList() { + console.log(`\n${styleText(["bgGreen", "black"], " Quartz Plugin Manager ")}\n`) + + const packageJsonPath = path.join(process.cwd(), "package.json") + + if (!fs.existsSync(packageJsonPath)) { + console.log(styleText("red", "No package.json found")) + process.exit(1) + } + + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) + const allDeps = { + ...packageJson.dependencies, + ...packageJson.devDependencies, + } + + const quartzPlugins = Object.entries(allDeps).filter(([name]) => { + return ( + name.startsWith("@quartz/") || + name.startsWith("quartz-") || + name.startsWith("@quartz-community/") + ) + }) + + if (quartzPlugins.length === 0) { + console.log("No Quartz plugins found in this project.") + console.log("Install plugins with: npx quartz plugin install ") + return + } + + console.log(`Found ${quartzPlugins.length} Quartz plugin(s):\n`) + + for (const [name, version] of quartzPlugins) { + console.log(` ${styleText("cyan", name)}@${version}`) + } +} + +export async function handlePluginSearch(query) { + console.log(`\n${styleText(["bgGreen", "black"], " Quartz Plugin Manager ")}\n`) + + const searchQuery = query || "quartz-plugin" + + console.log(`Searching npm for packages matching "${searchQuery}"...`) + console.log(styleText("grey", "(This may take a moment)\n")) + + try { + const result = execSync(`npm search ${searchQuery} --json`, { encoding: "utf-8" }) + const packages = JSON.parse(result) + + const quartzPlugins = packages.filter( + (pkg) => + pkg.name.startsWith("@quartz/") || + pkg.name.startsWith("quartz-") || + pkg.name.startsWith("@quartz-community/"), + ) + + if (quartzPlugins.length === 0) { + console.log("No Quartz plugins found matching your query.") + return + } + + console.log(`Found ${quartzPlugins.length} Quartz plugin(s):\n`) + + for (const pkg of quartzPlugins.slice(0, 20)) { + console.log(` ${styleText("cyan", pkg.name)}@${pkg.version}`) + if (pkg.description) { + console.log(` ${styleText("grey", pkg.description)}`) + } + console.log() + } + } catch { + console.log(styleText("yellow", "Could not search npm. Try visiting:")) + console.log(" https://www.npmjs.com/search?q=quartz-plugin") + } +} + +export async function handlePluginUninstall(packageNames) { + console.log(`\n${styleText(["bgGreen", "black"], " Quartz Plugin Manager ")}\n`) + + if (packageNames.length === 0) { + console.log(styleText("red", "Error: No package names provided")) + console.log("Usage: npx quartz plugin uninstall [package-name...]") + process.exit(1) + } + + console.log(`Uninstalling ${packageNames.length} plugin(s)...`) + + const npmArgs = ["uninstall", ...packageNames] + const result = spawnSync("npm", npmArgs, { stdio: "inherit" }) + + if (result.status !== 0) { + console.log(styleText("red", "Failed to uninstall plugins")) + process.exit(1) + } + + console.log(styleText("green", "✓ Plugins uninstalled successfully")) + console.log(styleText("yellow", "Don't forget to remove them from your quartz.config.yaml!")) +} diff --git a/quartz/cli/templates/blog.yaml b/quartz/cli/templates/blog.yaml new file mode 100644 index 000000000..534cb967c --- /dev/null +++ b/quartz/cli/templates/blog.yaml @@ -0,0 +1,282 @@ +# yaml-language-server: $schema=../../plugins/quartz-plugins.schema.json +# Template: blog +# A blog-focused setup with recent notes and comments enabled. +configuration: + pageTitle: Quartz 5 + pageTitleSuffix: "" + enableSPA: true + enablePopovers: true + analytics: + provider: plausible + locale: en-US + baseUrl: quartz.jzhao.xyz + ignorePatterns: + - private + - templates + - .obsidian + defaultDateType: modified + theme: + fontOrigin: googleFonts + cdnCaching: true + typography: + header: Schibsted Grotesk + body: Source Sans Pro + code: IBM Plex Mono + colors: + lightMode: + light: "#faf8f8" + lightgray: "#e5e5e5" + gray: "#b8b8b8" + darkgray: "#4e4e4e" + dark: "#2b2b2b" + secondary: "#284b63" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#fff23688" + darkMode: + light: "#161618" + lightgray: "#393639" + gray: "#646464" + darkgray: "#d4d4d4" + dark: "#ebebec" + secondary: "#7b97aa" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#b3aa0288" +plugins: + - source: github:quartz-community/created-modified-date + enabled: true + options: + priority: + - frontmatter + - git + - filesystem + order: 10 + - source: github:quartz-community/syntax-highlighting + enabled: true + options: + theme: + light: github-light + dark: github-dark + keepBackground: false + order: 20 + - source: github:quartz-community/obsidian-flavored-markdown + enabled: true + options: + enableInHtmlEmbed: false + enableCheckbox: true + order: 30 + - source: github:quartz-community/github-flavored-markdown + enabled: true + order: 40 + - source: github:quartz-community/table-of-contents + enabled: true + order: 50 + - source: github:quartz-community/crawl-links + enabled: true + options: + markdownLinkResolution: shortest + order: 60 + - source: github:quartz-community/description + enabled: true + order: 70 + - source: github:quartz-community/latex + enabled: true + options: + renderEngine: katex + order: 80 + - source: github:quartz-community/citations + enabled: false + order: 85 + - source: github:quartz-community/hard-line-breaks + enabled: false + order: 90 + - source: github:quartz-community/ox-hugo + enabled: false + order: 91 + - source: github:quartz-community/roam + enabled: false + order: 92 + - source: github:quartz-community/remove-draft + enabled: true + - source: github:quartz-community/explicit-publish + enabled: false + - source: github:quartz-community/encrypted-pages + enabled: false + - source: github:quartz-community/stacked-pages + enabled: false + layout: + position: afterBody + priority: 50 + display: all + - source: github:quartz-community/alias-redirects + enabled: true + - source: github:quartz-community/content-index + enabled: true + options: + enableSiteMap: true + enableRSS: true + - source: github:quartz-community/favicon + enabled: true + - source: github:quartz-community/og-image + enabled: true + - source: github:quartz-community/cname + enabled: true + - source: github:quartz-community/canvas-page + enabled: true + - source: github:quartz-community/content-page + enabled: true + - source: github:quartz-community/folder-page + enabled: true + - source: github:quartz-community/tag-page + enabled: true + - 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 + group: toolbar + groupOptions: + grow: true + - 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: false + layout: + position: beforeBody + priority: 30 + - source: github:quartz-community/page-title + enabled: true + layout: + position: left + priority: 10 + - source: github:quartz-community/darkmode + enabled: true + layout: + position: left + priority: 30 + group: toolbar + - source: github:quartz-community/reader-mode + enabled: true + layout: + position: left + priority: 35 + group: toolbar + - source: github:quartz-community/breadcrumbs + enabled: true + layout: + position: beforeBody + priority: 5 + condition: not-index + - source: github:quartz-community/comments + enabled: true + options: + provider: giscus + options: + repo: "TODO:username/repo-name" + repoId: "TODO:your-repo-id" + category: Announcements + categoryId: "TODO:your-category-id" + mapping: url + strict: true + reactionsEnabled: true + inputPosition: bottom + lightTheme: light + darkTheme: dark + lang: en + layout: + position: afterBody + priority: 10 + - source: github:quartz-community/footer + enabled: true + options: + links: + GitHub: https://github.com/jackyzha0/quartz + Discord Community: https://discord.gg/cRFFHYye7t + - source: github:quartz-community/recent-notes + enabled: true + options: + title: Recent Notes + limit: 5 + linkToMore: false + showTags: true + layout: + position: left + priority: 25 + - source: github:quartz-community/spacer + enabled: true + options: {} + order: 25 + layout: + position: left + priority: 25 + display: mobile-only + - source: github:quartz-community/bases-page + enabled: true + options: {} + order: 50 + - source: github:quartz-community/note-properties + enabled: true + options: + includeAll: false + includedProperties: + - description + - tags + - aliases + excludedProperties: [] + hidePropertiesView: false + delimiters: "---" + language: yaml + order: 5 + layout: + position: beforeBody + priority: 15 + display: all +layout: + groups: + toolbar: + priority: 35 + direction: row + gap: 0.5rem + byPageType: + "404": + positions: + beforeBody: [] + left: [] + right: [] + content: {} + folder: + exclude: + - reader-mode + positions: + right: [] + tag: + exclude: + - reader-mode + positions: + right: [] + canvas: {} + bases: {} diff --git a/quartz/cli/templates/default.yaml b/quartz/cli/templates/default.yaml new file mode 100644 index 000000000..78201d4dc --- /dev/null +++ b/quartz/cli/templates/default.yaml @@ -0,0 +1,263 @@ +# yaml-language-server: $schema=../../plugins/quartz-plugins.schema.json +# Template: default +# A clean Quartz setup with sensible defaults. +configuration: + pageTitle: Quartz 5 + pageTitleSuffix: "" + enableSPA: true + enablePopovers: true + analytics: + provider: plausible + locale: en-US + baseUrl: quartz.jzhao.xyz + ignorePatterns: + - private + - templates + - .obsidian + defaultDateType: modified + theme: + fontOrigin: googleFonts + cdnCaching: true + typography: + header: Schibsted Grotesk + body: Source Sans Pro + code: IBM Plex Mono + colors: + lightMode: + light: "#faf8f8" + lightgray: "#e5e5e5" + gray: "#b8b8b8" + darkgray: "#4e4e4e" + dark: "#2b2b2b" + secondary: "#284b63" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#fff23688" + darkMode: + light: "#161618" + lightgray: "#393639" + gray: "#646464" + darkgray: "#d4d4d4" + dark: "#ebebec" + secondary: "#7b97aa" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#b3aa0288" +plugins: + - source: github:quartz-community/created-modified-date + enabled: true + options: + priority: + - frontmatter + - git + - filesystem + order: 10 + - source: github:quartz-community/syntax-highlighting + enabled: true + options: + theme: + light: github-light + dark: github-dark + keepBackground: false + order: 20 + - source: github:quartz-community/obsidian-flavored-markdown + enabled: true + options: + enableInHtmlEmbed: false + enableCheckbox: true + order: 30 + - source: github:quartz-community/github-flavored-markdown + enabled: true + order: 40 + - source: github:quartz-community/table-of-contents + enabled: true + order: 50 + - source: github:quartz-community/crawl-links + enabled: true + options: + markdownLinkResolution: shortest + order: 60 + - source: github:quartz-community/description + enabled: true + order: 70 + - source: github:quartz-community/latex + enabled: true + options: + renderEngine: katex + order: 80 + - source: github:quartz-community/citations + enabled: false + order: 85 + - source: github:quartz-community/hard-line-breaks + enabled: false + order: 90 + - source: github:quartz-community/ox-hugo + enabled: false + order: 91 + - source: github:quartz-community/roam + enabled: false + order: 92 + - source: github:quartz-community/remove-draft + enabled: true + - source: github:quartz-community/explicit-publish + enabled: false + - source: github:quartz-community/encrypted-pages + enabled: true + - source: github:quartz-community/stacked-pages + enabled: false + layout: + position: afterBody + priority: 50 + display: all + - source: github:quartz-community/alias-redirects + enabled: true + - source: github:quartz-community/content-index + enabled: true + options: + enableSiteMap: true + enableRSS: true + - source: github:quartz-community/favicon + enabled: true + - source: github:quartz-community/og-image + enabled: true + - source: github:quartz-community/cname + enabled: true + - source: github:quartz-community/canvas-page + enabled: true + - source: github:quartz-community/content-page + enabled: true + - source: github:quartz-community/folder-page + enabled: true + - source: github:quartz-community/tag-page + enabled: true + - 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 + group: toolbar + groupOptions: + grow: true + - 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: false + layout: + position: beforeBody + priority: 30 + - source: github:quartz-community/page-title + enabled: true + layout: + position: left + priority: 10 + - source: github:quartz-community/darkmode + enabled: true + layout: + position: left + priority: 30 + group: toolbar + - source: github:quartz-community/reader-mode + enabled: true + layout: + position: left + priority: 35 + group: toolbar + - source: github:quartz-community/breadcrumbs + enabled: true + layout: + position: beforeBody + priority: 5 + condition: not-index + - source: github:quartz-community/comments + enabled: false + options: + provider: giscus + options: {} + layout: + position: afterBody + priority: 10 + - source: github:quartz-community/footer + enabled: true + options: + links: + GitHub: https://github.com/jackyzha0/quartz + Discord Community: https://discord.gg/cRFFHYye7t + - source: github:quartz-community/recent-notes + enabled: false + - source: github:quartz-community/spacer + enabled: true + options: {} + order: 25 + layout: + position: left + priority: 25 + display: mobile-only + - source: github:quartz-community/bases-page + enabled: true + options: {} + order: 50 + - source: github:quartz-community/note-properties + enabled: true + options: + includeAll: false + includedProperties: + - description + - tags + - aliases + excludedProperties: [] + hidePropertiesView: false + delimiters: "---" + language: yaml + order: 5 + layout: + position: beforeBody + priority: 15 + display: all +layout: + groups: + toolbar: + priority: 35 + direction: row + gap: 0.5rem + byPageType: + "404": + positions: + beforeBody: [] + left: [] + right: [] + content: {} + folder: + exclude: + - reader-mode + positions: + right: [] + tag: + exclude: + - reader-mode + positions: + right: [] + canvas: {} + bases: {} diff --git a/quartz/cli/templates/obsidian.yaml b/quartz/cli/templates/obsidian.yaml new file mode 100644 index 000000000..0236c7a03 --- /dev/null +++ b/quartz/cli/templates/obsidian.yaml @@ -0,0 +1,277 @@ +# yaml-language-server: $schema=../../plugins/quartz-plugins.schema.json +# Template: obsidian +# Optimized for Obsidian vaults with full OFM support and shortest link resolution. +configuration: + pageTitle: Quartz 5 + pageTitleSuffix: "" + enableSPA: true + enablePopovers: true + analytics: + provider: plausible + locale: en-US + baseUrl: quartz.jzhao.xyz + ignorePatterns: + - private + - templates + - .obsidian + defaultDateType: modified + theme: + fontOrigin: googleFonts + cdnCaching: true + typography: + header: Schibsted Grotesk + body: Source Sans Pro + code: IBM Plex Mono + colors: + lightMode: + light: "#faf8f8" + lightgray: "#e5e5e5" + gray: "#b8b8b8" + darkgray: "#4e4e4e" + dark: "#2b2b2b" + secondary: "#284b63" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#fff23688" + darkMode: + light: "#161618" + lightgray: "#393639" + gray: "#646464" + darkgray: "#d4d4d4" + dark: "#ebebec" + secondary: "#7b97aa" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#b3aa0288" +plugins: + - source: github:quartz-community/created-modified-date + enabled: true + options: + priority: + - frontmatter + - git + - filesystem + order: 10 + - source: github:quartz-community/syntax-highlighting + enabled: true + options: + theme: + light: github-light + dark: github-dark + keepBackground: false + order: 20 + - source: github:quartz-community/obsidian-flavored-markdown + enabled: true + options: + comments: true + highlight: true + wikilinks: true + callouts: true + mermaid: true + parseTags: true + parseArrows: true + parseBlockReferences: true + enableInHtmlEmbed: false + enableYouTubeEmbed: true + enableVideoEmbed: true + enableCheckbox: true + order: 30 + - source: github:quartz-community/github-flavored-markdown + enabled: true + order: 40 + - source: github:quartz-community/table-of-contents + enabled: true + order: 50 + - source: github:quartz-community/crawl-links + enabled: true + options: + markdownLinkResolution: shortest + order: 60 + - source: github:quartz-community/description + enabled: true + order: 70 + - source: github:quartz-community/latex + enabled: true + options: + renderEngine: katex + order: 80 + - source: github:quartz-community/citations + enabled: false + order: 85 + - source: github:quartz-community/hard-line-breaks + enabled: true + order: 90 + - source: github:quartz-community/ox-hugo + enabled: false + order: 91 + - source: github:quartz-community/roam + enabled: false + order: 92 + - source: github:quartz-community/remove-draft + enabled: true + - source: github:quartz-community/explicit-publish + enabled: false + - source: github:quartz-community/encrypted-pages + enabled: true + - source: github:quartz-community/stacked-pages + enabled: false + layout: + position: afterBody + priority: 50 + display: all + - source: github:quartz-community/alias-redirects + enabled: true + - source: github:quartz-community/content-index + enabled: true + options: + enableSiteMap: true + enableRSS: true + - source: github:quartz-community/favicon + enabled: true + - source: github:quartz-community/og-image + enabled: true + - source: github:quartz-community/cname + enabled: true + - source: github:quartz-community/canvas-page + enabled: true + - source: github:quartz-community/content-page + enabled: true + - source: github:quartz-community/folder-page + enabled: true + - source: github:quartz-community/tag-page + enabled: true + - 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 + group: toolbar + groupOptions: + grow: true + - 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: false + layout: + position: beforeBody + priority: 30 + - source: github:quartz-community/page-title + enabled: true + layout: + position: left + priority: 10 + - source: github:quartz-community/darkmode + enabled: true + layout: + position: left + priority: 30 + group: toolbar + - source: github:quartz-community/reader-mode + enabled: true + layout: + position: left + priority: 35 + group: toolbar + - source: github:quartz-community/breadcrumbs + enabled: true + layout: + position: beforeBody + priority: 5 + condition: not-index + - source: github:quartz-community/comments + enabled: false + options: + provider: giscus + options: {} + layout: + position: afterBody + priority: 10 + - source: github:quartz-community/footer + enabled: true + options: + links: + GitHub: https://github.com/jackyzha0/quartz + Discord Community: https://discord.gg/cRFFHYye7t + - source: github:quartz-community/recent-notes + enabled: false + - source: github:quartz-community/spacer + enabled: true + options: {} + order: 25 + layout: + position: left + priority: 25 + display: mobile-only + - source: github:quartz-community/bases-page + enabled: true + options: {} + order: 50 + - source: github:quartz-community/note-properties + enabled: true + options: + includeAll: false + includedProperties: + - description + - tags + - aliases + excludedProperties: [] + hidePropertiesView: false + delimiters: "---" + language: yaml + order: 5 + layout: + position: beforeBody + priority: 15 + display: all + - source: github:saberzero1/quartz-themes + enabled: true + options: + theme: "default" +layout: + groups: + toolbar: + priority: 35 + direction: row + gap: 0.5rem + byPageType: + "404": + positions: + beforeBody: [] + left: [] + right: [] + content: {} + folder: + exclude: + - reader-mode + positions: + right: [] + tag: + exclude: + - reader-mode + positions: + right: [] + canvas: {} + bases: {} diff --git a/quartz/cli/templates/ttrpg.yaml b/quartz/cli/templates/ttrpg.yaml new file mode 100644 index 000000000..d37af8252 --- /dev/null +++ b/quartz/cli/templates/ttrpg.yaml @@ -0,0 +1,281 @@ +# yaml-language-server: $schema=../../plugins/quartz-plugins.schema.json +# Template: ttrpg +# Obsidian-based setup with map plugin and ITS Theme for TTRPG/D&D wikis. +configuration: + pageTitle: Quartz 5 + pageTitleSuffix: "" + enableSPA: true + enablePopovers: true + analytics: + provider: plausible + locale: en-US + baseUrl: quartz.jzhao.xyz + ignorePatterns: + - private + - templates + - .obsidian + defaultDateType: modified + theme: + fontOrigin: googleFonts + cdnCaching: true + typography: + header: Schibsted Grotesk + body: Source Sans Pro + code: IBM Plex Mono + colors: + lightMode: + light: "#faf8f8" + lightgray: "#e5e5e5" + gray: "#b8b8b8" + darkgray: "#4e4e4e" + dark: "#2b2b2b" + secondary: "#284b63" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#fff23688" + darkMode: + light: "#161618" + lightgray: "#393639" + gray: "#646464" + darkgray: "#d4d4d4" + dark: "#ebebec" + secondary: "#7b97aa" + tertiary: "#84a59d" + highlight: rgba(143, 159, 169, 0.15) + textHighlight: "#b3aa0288" +plugins: + - source: github:quartz-community/created-modified-date + enabled: true + options: + priority: + - frontmatter + - git + - filesystem + order: 10 + - source: github:quartz-community/syntax-highlighting + enabled: true + options: + theme: + light: github-light + dark: github-dark + keepBackground: false + order: 20 + - source: github:quartz-community/obsidian-flavored-markdown + enabled: true + options: + comments: true + highlight: true + wikilinks: true + callouts: true + mermaid: true + parseTags: true + parseArrows: true + parseBlockReferences: true + enableInHtmlEmbed: false + enableYouTubeEmbed: true + enableVideoEmbed: true + enableCheckbox: true + order: 30 + - source: github:quartz-community/github-flavored-markdown + enabled: true + order: 40 + - source: github:quartz-community/table-of-contents + enabled: true + order: 50 + - source: github:quartz-community/crawl-links + enabled: true + options: + markdownLinkResolution: shortest + order: 60 + - source: github:quartz-community/description + enabled: true + order: 70 + - source: github:quartz-community/latex + enabled: true + options: + renderEngine: katex + order: 80 + - source: github:quartz-community/citations + enabled: false + order: 85 + - source: github:quartz-community/hard-line-breaks + enabled: true + order: 90 + - source: github:quartz-community/ox-hugo + enabled: false + order: 91 + - source: github:quartz-community/roam + enabled: false + order: 92 + - source: github:quartz-community/remove-draft + enabled: true + - source: github:quartz-community/explicit-publish + enabled: false + - source: github:quartz-community/encrypted-pages + enabled: true + - source: github:quartz-community/stacked-pages + enabled: false + layout: + position: afterBody + priority: 50 + display: all + - source: github:quartz-community/alias-redirects + enabled: true + - source: github:quartz-community/content-index + enabled: true + options: + enableSiteMap: true + enableRSS: true + - source: github:quartz-community/favicon + enabled: true + - source: github:quartz-community/og-image + enabled: true + - source: github:quartz-community/cname + enabled: true + - source: github:quartz-community/canvas-page + enabled: true + - source: github:quartz-community/content-page + enabled: true + - source: github:quartz-community/folder-page + enabled: true + - source: github:quartz-community/tag-page + enabled: true + - 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 + group: toolbar + groupOptions: + grow: true + - 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: false + layout: + position: beforeBody + priority: 30 + - source: github:quartz-community/page-title + enabled: true + layout: + position: left + priority: 10 + - source: github:quartz-community/darkmode + enabled: true + layout: + position: left + priority: 30 + group: toolbar + - source: github:quartz-community/reader-mode + enabled: true + layout: + position: left + priority: 35 + group: toolbar + - source: github:quartz-community/breadcrumbs + enabled: true + layout: + position: beforeBody + priority: 5 + condition: not-index + - source: github:quartz-community/comments + enabled: false + options: + provider: giscus + options: {} + layout: + position: afterBody + priority: 10 + - source: github:quartz-community/footer + enabled: true + options: + links: + GitHub: https://github.com/jackyzha0/quartz + Discord Community: https://discord.gg/cRFFHYye7t + - source: github:quartz-community/recent-notes + enabled: false + - source: github:quartz-community/spacer + enabled: true + options: {} + order: 25 + layout: + position: left + priority: 25 + display: mobile-only + - source: github:quartz-community/bases-page + enabled: true + options: {} + order: 50 + - source: github:quartz-community/note-properties + enabled: true + options: + includeAll: false + includedProperties: + - description + - tags + - aliases + excludedProperties: [] + hidePropertiesView: false + delimiters: "---" + language: yaml + order: 5 + layout: + position: beforeBody + priority: 15 + display: all + # TTRPG-specific plugins + - source: github:quartz-community/external-quartz-leaflet-map-plugin + enabled: true + - source: github:saberzero1/quartz-themes + enabled: true + options: + theme: "its-theme" + variation: "ttrpg-dnd" +layout: + groups: + toolbar: + priority: 35 + direction: row + gap: 0.5rem + byPageType: + "404": + positions: + beforeBody: [] + left: [] + right: [] + content: {} + folder: + exclude: + - reader-mode + positions: + right: [] + tag: + exclude: + - reader-mode + positions: + right: [] + canvas: {} + bases: {} diff --git a/quartz/components/ArticleTitle.tsx b/quartz/components/ArticleTitle.tsx deleted file mode 100644 index 318aeb24e..000000000 --- a/quartz/components/ArticleTitle.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import { classNames } from "../util/lang" - -const ArticleTitle: QuartzComponent = ({ fileData, displayClass }: QuartzComponentProps) => { - const title = fileData.frontmatter?.title - if (title) { - return

{title}

- } else { - return null - } -} - -ArticleTitle.css = ` -.article-title { - margin: 2rem 0 0 0; -} -` - -export default (() => ArticleTitle) satisfies QuartzComponentConstructor diff --git a/quartz/components/Backlinks.tsx b/quartz/components/Backlinks.tsx deleted file mode 100644 index 0d34457f3..000000000 --- a/quartz/components/Backlinks.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import style from "./styles/backlinks.scss" -import { resolveRelative, simplifySlug } from "../util/path" -import { i18n } from "../i18n" -import { classNames } from "../util/lang" -import OverflowListFactory from "./OverflowList" - -interface BacklinksOptions { - hideWhenEmpty: boolean -} - -const defaultOptions: BacklinksOptions = { - hideWhenEmpty: true, -} - -export default ((opts?: Partial) => { - const options: BacklinksOptions = { ...defaultOptions, ...opts } - const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory() - - const Backlinks: QuartzComponent = ({ - fileData, - allFiles, - displayClass, - cfg, - }: QuartzComponentProps) => { - const slug = simplifySlug(fileData.slug!) - const backlinkFiles = allFiles.filter((file) => file.links?.includes(slug)) - if (options.hideWhenEmpty && backlinkFiles.length == 0) { - return null - } - return ( -
-

{i18n(cfg.locale).components.backlinks.title}

- - {backlinkFiles.length > 0 ? ( - backlinkFiles.map((f) => ( -
  • - - {f.frontmatter?.title} - -
  • - )) - ) : ( -
  • {i18n(cfg.locale).components.backlinks.noBacklinksFound}
  • - )} -
    -
    - ) - } - - Backlinks.css = style - Backlinks.afterDOMLoaded = overflowListAfterDOMLoaded - - return Backlinks -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/Body.tsx b/quartz/components/Body.tsx index 96b627883..d396f4d5d 100644 --- a/quartz/components/Body.tsx +++ b/quartz/components/Body.tsx @@ -1,13 +1,7 @@ -// @ts-ignore -import clipboardScript from "./scripts/clipboard.inline" -import clipboardStyle from "./styles/clipboard.scss" import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" const Body: QuartzComponent = ({ children }: QuartzComponentProps) => { return
    {children}
    } -Body.afterDOMLoaded = clipboardScript -Body.css = clipboardStyle - export default (() => Body) satisfies QuartzComponentConstructor diff --git a/quartz/components/Breadcrumbs.tsx b/quartz/components/Breadcrumbs.tsx deleted file mode 100644 index 5144a314d..000000000 --- a/quartz/components/Breadcrumbs.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import breadcrumbsStyle from "./styles/breadcrumbs.scss" -import { FullSlug, SimpleSlug, resolveRelative, simplifySlug } from "../util/path" -import { classNames } from "../util/lang" -import { trieFromAllFiles } from "../util/ctx" - -type CrumbData = { - displayName: string - path: string -} - -interface BreadcrumbOptions { - /** - * Symbol between crumbs - */ - spacerSymbol: string - /** - * Name of first crumb - */ - rootName: string - /** - * Whether to look up frontmatter title for folders (could cause performance problems with big vaults) - */ - resolveFrontmatterTitle: boolean - /** - * Whether to display the current page in the breadcrumbs. - */ - showCurrentPage: boolean -} - -const defaultOptions: BreadcrumbOptions = { - spacerSymbol: "❯", - rootName: "Home", - resolveFrontmatterTitle: true, - showCurrentPage: true, -} - -function formatCrumb(displayName: string, baseSlug: FullSlug, currentSlug: SimpleSlug): CrumbData { - return { - displayName: displayName.replaceAll("-", " "), - path: resolveRelative(baseSlug, currentSlug), - } -} - -export default ((opts?: Partial) => { - const options: BreadcrumbOptions = { ...defaultOptions, ...opts } - const Breadcrumbs: QuartzComponent = ({ - fileData, - allFiles, - displayClass, - ctx, - }: QuartzComponentProps) => { - const trie = (ctx.trie ??= trieFromAllFiles(allFiles)) - const slugParts = fileData.slug!.split("/") - const pathNodes = trie.ancestryChain(slugParts) - - if (!pathNodes) { - return null - } - - const crumbs: CrumbData[] = pathNodes.map((node, idx) => { - const crumb = formatCrumb(node.displayName, fileData.slug!, simplifySlug(node.slug)) - if (idx === 0) { - crumb.displayName = options.rootName - } - - // For last node (current page), set empty path - if (idx === pathNodes.length - 1) { - crumb.path = "" - } - - return crumb - }) - - if (!options.showCurrentPage) { - crumbs.pop() - } - - return ( - - ) - } - Breadcrumbs.css = breadcrumbsStyle - - return Breadcrumbs -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/Comments.tsx b/quartz/components/Comments.tsx deleted file mode 100644 index a7315214f..000000000 --- a/quartz/components/Comments.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import { classNames } from "../util/lang" -// @ts-ignore -import script from "./scripts/comments.inline" - -type Options = { - provider: "giscus" - options: { - repo: `${string}/${string}` - repoId: string - category: string - categoryId: string - themeUrl?: string - lightTheme?: string - darkTheme?: string - mapping?: "url" | "title" | "og:title" | "specific" | "number" | "pathname" - strict?: boolean - reactionsEnabled?: boolean - inputPosition?: "top" | "bottom" - lang?: string - } -} - -function boolToStringBool(b: boolean): string { - return b ? "1" : "0" -} - -export default ((opts: Options) => { - const Comments: QuartzComponent = ({ displayClass, fileData, cfg }: QuartzComponentProps) => { - // check if comments should be displayed according to frontmatter - const disableComment: boolean = - typeof fileData.frontmatter?.comments !== "undefined" && - (!fileData.frontmatter?.comments || fileData.frontmatter?.comments === "false") - if (disableComment) { - return <> - } - - return ( -
    - ) - } - - Comments.afterDOMLoaded = script - - return Comments -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/ContentMeta.tsx b/quartz/components/ContentMeta.tsx deleted file mode 100644 index e378bccee..000000000 --- a/quartz/components/ContentMeta.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Date, getDate } from "./Date" -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" -import readingTime from "reading-time" -import { classNames } from "../util/lang" -import { i18n } from "../i18n" -import { JSX } from "preact" -import style from "./styles/contentMeta.scss" - -interface ContentMetaOptions { - /** - * Whether to display reading time - */ - showReadingTime: boolean - showComma: boolean -} - -const defaultOptions: ContentMetaOptions = { - showReadingTime: true, - showComma: true, -} - -export default ((opts?: Partial) => { - // Merge options with defaults - const options: ContentMetaOptions = { ...defaultOptions, ...opts } - - function ContentMetadata({ cfg, fileData, displayClass }: QuartzComponentProps) { - const text = fileData.text - - if (text) { - const segments: (string | JSX.Element)[] = [] - - if (fileData.dates) { - segments.push() - } - - // Display reading time if enabled - if (options.showReadingTime) { - const { minutes, words: _words } = readingTime(text) - const displayedTime = i18n(cfg.locale).components.contentMeta.readingTime({ - minutes: Math.ceil(minutes), - }) - segments.push({displayedTime}) - } - - return ( -

    - {segments} -

    - ) - } else { - return null - } - } - - ContentMetadata.css = style - - return ContentMetadata -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/Darkmode.tsx b/quartz/components/Darkmode.tsx deleted file mode 100644 index afc23d758..000000000 --- a/quartz/components/Darkmode.tsx +++ /dev/null @@ -1,48 +0,0 @@ -// @ts-ignore -import darkmodeScript from "./scripts/darkmode.inline" -import styles from "./styles/darkmode.scss" -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import { i18n } from "../i18n" -import { classNames } from "../util/lang" - -const Darkmode: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { - return ( - - ) -} - -Darkmode.beforeDOMLoaded = darkmodeScript -Darkmode.css = styles - -export default (() => Darkmode) satisfies QuartzComponentConstructor diff --git a/quartz/components/Date.tsx b/quartz/components/Date.tsx index 0a92cc4c3..15be573e8 100644 --- a/quartz/components/Date.tsx +++ b/quartz/components/Date.tsx @@ -12,7 +12,7 @@ export type ValidDateType = keyof Required["dates"] export function getDate(cfg: GlobalConfiguration, data: QuartzPluginData): Date | undefined { if (!cfg.defaultDateType) { throw new Error( - `Field 'defaultDateType' was not set in the configuration object of quartz.config.ts. See https://quartz.jzhao.xyz/configuration#general-configuration for more details.`, + `Field 'defaultDateType' was not set in the configuration object of quartz.config.yaml. See https://quartz.jzhao.xyz/configuration#general-configuration for more details.`, ) } return data.dates?.[cfg.defaultDateType] diff --git a/quartz/components/DesktopOnly.tsx b/quartz/components/DesktopOnly.tsx index ee80137be..b163eb9d5 100644 --- a/quartz/components/DesktopOnly.tsx +++ b/quartz/components/DesktopOnly.tsx @@ -3,7 +3,11 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro export default ((component: QuartzComponent) => { const Component = component const DesktopOnly: QuartzComponent = (props: QuartzComponentProps) => { - return + return ( +
    + +
    + ) } DesktopOnly.displayName = component.displayName diff --git a/quartz/components/Explorer.tsx b/quartz/components/Explorer.tsx deleted file mode 100644 index e4cbcabae..000000000 --- a/quartz/components/Explorer.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import style from "./styles/explorer.scss" - -// @ts-ignore -import script from "./scripts/explorer.inline" -import { classNames } from "../util/lang" -import { i18n } from "../i18n" -import { FileTrieNode } from "../util/fileTrie" -import OverflowListFactory from "./OverflowList" -import { concatenateResources } from "../util/resources" - -type OrderEntries = "sort" | "filter" | "map" - -export interface Options { - title?: string - folderDefaultState: "collapsed" | "open" - folderClickBehavior: "collapse" | "link" - useSavedState: boolean - sortFn: (a: FileTrieNode, b: FileTrieNode) => number - filterFn: (node: FileTrieNode) => boolean - mapFn: (node: FileTrieNode) => void - order: OrderEntries[] -} - -const defaultOptions: Options = { - folderDefaultState: "collapsed", - folderClickBehavior: "link", - useSavedState: true, - mapFn: (node) => { - return node - }, - sortFn: (a, b) => { - // Sort order: folders first, then files. Sort folders and files alphabeticall - if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) { - // numeric: true: Whether numeric collation should be used, such that "1" < "2" < "10" - // sensitivity: "base": Only strings that differ in base letters compare as unequal. Examples: a ≠ b, a = á, a = A - return a.displayName.localeCompare(b.displayName, undefined, { - numeric: true, - sensitivity: "base", - }) - } - - if (!a.isFolder && b.isFolder) { - return 1 - } else { - return -1 - } - }, - filterFn: (node) => node.slugSegment !== "tags", - order: ["filter", "map", "sort"], -} - -export type FolderState = { - path: string - collapsed: boolean -} - -let numExplorers = 0 -export default ((userOpts?: Partial) => { - const opts: Options = { ...defaultOptions, ...userOpts } - const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory() - - const Explorer: QuartzComponent = ({ cfg, displayClass }: QuartzComponentProps) => { - const id = `explorer-${numExplorers++}` - - return ( -
    - - -
    - -
    - - -
    - ) - } - - Explorer.css = style - Explorer.afterDOMLoaded = concatenateResources(script, overflowListAfterDOMLoaded) - return Explorer -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/Footer.tsx b/quartz/components/Footer.tsx deleted file mode 100644 index cff28cbb9..000000000 --- a/quartz/components/Footer.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import style from "./styles/footer.scss" -import { version } from "../../package.json" -import { i18n } from "../i18n" - -interface Options { - links: Record -} - -export default ((opts?: Options) => { - const Footer: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { - const year = new Date().getFullYear() - const links = opts?.links ?? [] - return ( -
    -

    - {i18n(cfg.locale).components.footer.createdWith}{" "} - Quartz v{version} © {year} -

    -
      - {Object.entries(links).map(([text, link]) => ( -
    • - {text} -
    • - ))} -
    -
    - ) - } - - Footer.css = style - return Footer -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/Graph.tsx b/quartz/components/Graph.tsx deleted file mode 100644 index 907372e93..000000000 --- a/quartz/components/Graph.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -// @ts-ignore -import script from "./scripts/graph.inline" -import style from "./styles/graph.scss" -import { i18n } from "../i18n" -import { classNames } from "../util/lang" - -export interface D3Config { - drag: boolean - zoom: boolean - depth: number - scale: number - repelForce: number - centerForce: number - linkDistance: number - fontSize: number - opacityScale: number - removeTags: string[] - showTags: boolean - focusOnHover?: boolean - enableRadial?: boolean -} - -interface GraphOptions { - localGraph: Partial | undefined - globalGraph: Partial | undefined -} - -const defaultOptions: GraphOptions = { - localGraph: { - drag: true, - zoom: true, - depth: 1, - scale: 1.1, - repelForce: 0.5, - centerForce: 0.3, - linkDistance: 30, - fontSize: 0.6, - opacityScale: 1, - showTags: true, - removeTags: [], - focusOnHover: false, - enableRadial: false, - }, - globalGraph: { - drag: true, - zoom: true, - depth: -1, - scale: 0.9, - repelForce: 0.5, - centerForce: 0.2, - linkDistance: 30, - fontSize: 0.6, - opacityScale: 1, - showTags: true, - removeTags: [], - focusOnHover: true, - enableRadial: true, - }, -} - -export default ((opts?: Partial) => { - const Graph: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { - const localGraph = { ...defaultOptions.localGraph, ...opts?.localGraph } - const globalGraph = { ...defaultOptions.globalGraph, ...opts?.globalGraph } - return ( -
    -

    {i18n(cfg.locale).components.graph.title}

    -
    -
    - -
    -
    -
    -
    -
    - ) - } - - Graph.css = style - Graph.afterDOMLoaded = script - - return Graph -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index 23183ca8c..0c1a20468 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -4,7 +4,7 @@ import { CSSResourceToStyleElement, JSResourceToScriptElement } from "../util/re import { googleFontHref, googleFontSubsetHref } from "../util/theme" import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import { unescapeHTML } from "../util/escape" -import { CustomOgImagesEmitterName } from "../plugins/emitters/ogImage" +import { CustomOgImagesEmitterName } from "../../.quartz/plugins" export default (() => { const Head: QuartzComponent = ({ cfg, diff --git a/quartz/components/MobileOnly.tsx b/quartz/components/MobileOnly.tsx index 29958cf0c..2c108358e 100644 --- a/quartz/components/MobileOnly.tsx +++ b/quartz/components/MobileOnly.tsx @@ -3,7 +3,11 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro export default ((component: QuartzComponent) => { const Component = component const MobileOnly: QuartzComponent = (props: QuartzComponentProps) => { - return + return ( +
    + +
    + ) } MobileOnly.displayName = component.displayName diff --git a/quartz/components/OverflowList.tsx b/quartz/components/OverflowList.tsx deleted file mode 100644 index 12d97b6d4..000000000 --- a/quartz/components/OverflowList.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { JSX } from "preact" - -const OverflowList = ({ - children, - ...props -}: JSX.HTMLAttributes & { id: string }) => { - return ( -
      - {children} -
    • -
    - ) -} - -let numLists = 0 -export default () => { - const id = `list-${numLists++}` - - return { - OverflowList: (props: JSX.HTMLAttributes) => ( - - ), - overflowListAfterDOMLoaded: ` -document.addEventListener("nav", (e) => { - const observer = new IntersectionObserver((entries) => { - for (const entry of entries) { - const parentUl = entry.target.parentElement - if (!parentUl) return - if (entry.isIntersecting) { - parentUl.classList.remove("gradient-active") - } else { - parentUl.classList.add("gradient-active") - } - } - }) - - const ul = document.getElementById("${id}") - if (!ul) return - - const end = ul.querySelector(".overflow-end") - if (!end) return - - observer.observe(end) - window.addCleanup(() => observer.disconnect()) -}) -`, - } -} diff --git a/quartz/components/PageTitle.tsx b/quartz/components/PageTitle.tsx deleted file mode 100644 index 53ee8240a..000000000 --- a/quartz/components/PageTitle.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { pathToRoot } from "../util/path" -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import { classNames } from "../util/lang" -import { i18n } from "../i18n" - -const PageTitle: QuartzComponent = ({ fileData, cfg, displayClass }: QuartzComponentProps) => { - const title = cfg?.pageTitle ?? i18n(cfg.locale).propertyDefaults.title - const baseDir = pathToRoot(fileData.slug!) - return ( -

    - {title} -

    - ) -} - -PageTitle.css = ` -.page-title { - font-size: 1.75rem; - margin: 0; - font-family: var(--titleFont); -} -` - -export default (() => PageTitle) satisfies QuartzComponentConstructor diff --git a/quartz/components/ReaderMode.tsx b/quartz/components/ReaderMode.tsx deleted file mode 100644 index 4b3165e6e..000000000 --- a/quartz/components/ReaderMode.tsx +++ /dev/null @@ -1,38 +0,0 @@ -// @ts-ignore -import readerModeScript from "./scripts/readermode.inline" -import styles from "./styles/readermode.scss" -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import { i18n } from "../i18n" -import { classNames } from "../util/lang" - -const ReaderMode: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { - return ( - - ) -} - -ReaderMode.beforeDOMLoaded = readerModeScript -ReaderMode.css = styles - -export default (() => ReaderMode) satisfies QuartzComponentConstructor diff --git a/quartz/components/RecentNotes.tsx b/quartz/components/RecentNotes.tsx deleted file mode 100644 index 2c32feadf..000000000 --- a/quartz/components/RecentNotes.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import { FullSlug, SimpleSlug, resolveRelative } from "../util/path" -import { QuartzPluginData } from "../plugins/vfile" -import { byDateAndAlphabetical } from "./PageList" -import style from "./styles/recentNotes.scss" -import { Date, getDate } from "./Date" -import { GlobalConfiguration } from "../cfg" -import { i18n } from "../i18n" -import { classNames } from "../util/lang" - -interface Options { - title?: string - limit: number - linkToMore: SimpleSlug | false - showTags: boolean - filter: (f: QuartzPluginData) => boolean - sort: (f1: QuartzPluginData, f2: QuartzPluginData) => number -} - -const defaultOptions = (cfg: GlobalConfiguration): Options => ({ - limit: 3, - linkToMore: false, - showTags: true, - filter: () => true, - sort: byDateAndAlphabetical(cfg), -}) - -export default ((userOpts?: Partial) => { - const RecentNotes: QuartzComponent = ({ - allFiles, - fileData, - displayClass, - cfg, - }: QuartzComponentProps) => { - const opts = { ...defaultOptions(cfg), ...userOpts } - const pages = allFiles.filter(opts.filter).sort(opts.sort) - const remaining = Math.max(0, pages.length - opts.limit) - return ( -
    -

    {opts.title ?? i18n(cfg.locale).components.recentNotes.title}

    -
      - {pages.slice(0, opts.limit).map((page) => { - const title = page.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title - const tags = page.frontmatter?.tags ?? [] - - return ( -
    • -
      - - {page.dates && ( -

      - -

      - )} - {opts.showTags && ( - - )} -
      -
    • - ) - })} -
    - {opts.linkToMore && remaining > 0 && ( -

    - - {i18n(cfg.locale).components.recentNotes.seeRemainingMore({ remaining })} - -

    - )} -
    - ) - } - - RecentNotes.css = style - return RecentNotes -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/Search.tsx b/quartz/components/Search.tsx deleted file mode 100644 index 6e932d2ef..000000000 --- a/quartz/components/Search.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import style from "./styles/search.scss" -// @ts-ignore -import script from "./scripts/search.inline" -import { classNames } from "../util/lang" -import { i18n } from "../i18n" - -export interface SearchOptions { - enablePreview: boolean -} - -const defaultOptions: SearchOptions = { - enablePreview: true, -} - -export default ((userOpts?: Partial) => { - const Search: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { - const opts = { ...defaultOptions, ...userOpts } - const searchPlaceholder = i18n(cfg.locale).components.search.searchBarPlaceholder - return ( -
    - -
    -
    - -
    -
    -
    -
    - ) - } - - Search.afterDOMLoaded = script - Search.css = style - - return Search -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/TableOfContents.tsx b/quartz/components/TableOfContents.tsx deleted file mode 100644 index bbccf82a2..000000000 --- a/quartz/components/TableOfContents.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import legacyStyle from "./styles/legacyToc.scss" -import modernStyle from "./styles/toc.scss" -import { classNames } from "../util/lang" - -// @ts-ignore -import script from "./scripts/toc.inline" -import { i18n } from "../i18n" -import OverflowListFactory from "./OverflowList" -import { concatenateResources } from "../util/resources" - -interface Options { - layout: "modern" | "legacy" -} - -const defaultOptions: Options = { - layout: "modern", -} - -let numTocs = 0 -export default ((opts?: Partial) => { - const layout = opts?.layout ?? defaultOptions.layout - const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory() - const TableOfContents: QuartzComponent = ({ - fileData, - displayClass, - cfg, - }: QuartzComponentProps) => { - if (!fileData.toc) { - return null - } - - const id = `toc-${numTocs++}` - return ( -
    - - - {fileData.toc.map((tocEntry) => ( -
  • - - {tocEntry.text} - -
  • - ))} -
    -
    - ) - } - - TableOfContents.css = modernStyle - TableOfContents.afterDOMLoaded = concatenateResources(script, overflowListAfterDOMLoaded) - - const LegacyTableOfContents: QuartzComponent = ({ fileData, cfg }: QuartzComponentProps) => { - if (!fileData.toc) { - return null - } - return ( -
    - -

    {i18n(cfg.locale).components.tableOfContents.title}

    -
    - -
    - ) - } - LegacyTableOfContents.css = legacyStyle - - return layout === "modern" ? TableOfContents : LegacyTableOfContents -}) satisfies QuartzComponentConstructor diff --git a/quartz/components/TagList.tsx b/quartz/components/TagList.tsx deleted file mode 100644 index c73ed392a..000000000 --- a/quartz/components/TagList.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { FullSlug, resolveRelative } from "../util/path" -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -import { classNames } from "../util/lang" - -const TagList: QuartzComponent = ({ fileData, displayClass }: QuartzComponentProps) => { - const tags = fileData.frontmatter?.tags - if (tags && tags.length > 0) { - return ( -
      - {tags.map((tag) => { - const linkDest = resolveRelative(fileData.slug!, `tags/${tag}` as FullSlug) - return ( -
    • - - {tag} - -
    • - ) - })} -
    - ) - } else { - return null - } -} - -TagList.css = ` -.tags { - list-style: none; - display: flex; - padding-left: 0; - gap: 0.4rem; - margin: 1rem 0; - flex-wrap: wrap; -} - -.section-li > .section > .tags { - justify-content: flex-end; -} - -.tags > li { - display: inline-block; - white-space: nowrap; - margin: 0; - overflow-wrap: normal; -} - -a.internal.tag-link { - border-radius: 8px; - background-color: var(--highlight); - padding: 0.2rem 0.4rem; - margin: 0 0.1rem; -} -` - -export default (() => TagList) satisfies QuartzComponentConstructor diff --git a/quartz/components/external.ts b/quartz/components/external.ts new file mode 100644 index 000000000..0113445a3 --- /dev/null +++ b/quartz/components/external.ts @@ -0,0 +1,23 @@ +import { componentRegistry } from "./registry" +import { QuartzComponent, QuartzComponentConstructor } from "./types" + +export function External( + name: string, + options?: Options, +): QuartzComponent { + const registered = componentRegistry.get(name) + if (!registered) { + throw new Error( + `External component "${name}" not found. ` + + `Make sure the plugin is installed and components are loaded before layouts are evaluated.`, + ) + } + + const { component } = registered + + if (typeof component === "function") { + return (component as QuartzComponentConstructor)(options as Options) + } + + return component as QuartzComponent +} diff --git a/quartz/components/frames/DefaultFrame.tsx b/quartz/components/frames/DefaultFrame.tsx new file mode 100644 index 000000000..d46c120d4 --- /dev/null +++ b/quartz/components/frames/DefaultFrame.tsx @@ -0,0 +1,61 @@ +import { PageFrame, PageFrameProps } from "./types" +import HeaderConstructor from "../Header" + +const Header = HeaderConstructor() + +/** + * The default page frame — three-column layout with left sidebar, center + * content (header + body + afterBody), and right sidebar, followed by a footer. + * + * This is the original Quartz layout, extracted from renderPage.tsx. + */ +export const DefaultFrame: PageFrame = { + name: "default", + render({ + componentData, + header, + beforeBody, + pageBody: Content, + afterBody, + left, + right, + footer: Footer, + }: PageFrameProps) { + return ( + <> + +
    + + +
    + +
    + +