diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 42adb4474..f73eb9666 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,11 +1,20 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file - version: 2 updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" + groups: + production-dependencies: + applies-to: "version-updates" + patterns: + - "*" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + ci-dependencies: + applies-to: "version-updates" + patterns: + - "*" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 56107cf49..f0fc1fd18 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,6 +7,7 @@ on: push: branches: - v4 + workflow_dispatch: jobs: build-and-test: @@ -18,17 +19,17 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -47,22 +48,22 @@ jobs: run: npx quartz build --bundleInfo publish-tag: - if: ${{ github.repository == 'jackyzha0/quartz' }} + if: ${{ github.repository == 'jackyzha0/quartz' && github.ref == 'refs/heads/v4' }} runs-on: ubuntu-latest permissions: contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Get package version run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV - name: Create release tag - uses: pkgdeps/git-tag-action@v2 + uses: pkgdeps/git-tag-action@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} github_repo: ${{ github.repository }} diff --git a/.github/workflows/docker-build-push.yaml b/.github/workflows/docker-build-push.yaml new file mode 100644 index 000000000..308aee3c6 --- /dev/null +++ b/.github/workflows/docker-build-push.yaml @@ -0,0 +1,88 @@ +name: Docker build & push image + +on: + push: + branches: [v4] + tags: ["v*"] + pull_request: + branches: [v4] + paths: + - .github/workflows/docker-build-push.yaml + - quartz/** + workflow_dispatch: + +jobs: + build: + if: ${{ github.repository == 'jackyzha0/quartz' }} # Comment this out if you want to publish your own images on a fork! + runs-on: ubuntu-latest + steps: + - name: Set lowercase repository owner environment variable + run: | + echo "OWNER_LOWERCASE=${OWNER,,}" >> ${GITHUB_ENV} + env: + OWNER: "${{ github.repository_owner }}" + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v5.0.0 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + install: true + driver-opts: | + image=moby/buildkit:master + network=host + - name: Install cosign + if: github.event_name != 'pull_request' + uses: sigstore/cosign-installer@v3.7.0 + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + if: github.event_name != 'pull_request' + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata tags and labels on PRs + if: github.event_name == 'pull_request' + id: meta-pr + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ env.OWNER_LOWERCASE }}/quartz + tags: | + type=raw,value=sha-${{ env.GITHUB_SHA_SHORT }} + labels: | + org.opencontainers.image.source="https://github.com/${{ github.repository_owner }}/quartz" + - name: Extract metadata tags and labels for main, release or tag + if: github.event_name != 'pull_request' + id: meta + uses: docker/metadata-action@v5 + with: + flavor: | + latest=auto + images: ghcr.io/${{ env.OWNER_LOWERCASE }}/quartz + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}}.{{minor}}.{{patch}} + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} + type=raw,value=sha-${{ env.GITHUB_SHA_SHORT }} + labels: | + maintainer=${{ github.repository_owner }} + org.opencontainers.image.source="https://github.com/${{ github.repository_owner }}/quartz" + + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@v6 + with: + push: ${{ github.event_name != 'pull_request' }} + build-args: | + GIT_SHA=${{ env.GITHUB_SHA }} + DOCKER_LABEL=sha-${{ env.GITHUB_SHA_SHORT }} + tags: ${{ steps.meta.outputs.tags || steps.meta-pr.outputs.tags }} + labels: ${{ steps.meta.outputs.labels || steps.meta-pr.outputs.labels }} + cache-from: type=gha + cache-to: type=gha diff --git a/.node-version b/.node-version new file mode 100644 index 000000000..805b5a4e0 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v20.9.0 diff --git a/Dockerfile b/Dockerfile index 1d9e5915f..4493853e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-slim as builder +FROM node:20-slim AS builder WORKDIR /usr/src/app COPY package.json . COPY package-lock.json* . diff --git a/docs/advanced/creating components.md b/docs/advanced/creating components.md index 27369abf2..628d5aa29 100644 --- a/docs/advanced/creating components.md +++ b/docs/advanced/creating components.md @@ -129,11 +129,11 @@ export default (() => { return } - YourComponent.beforeDOM = ` + YourComponent.beforeDOMLoaded = ` console.log("hello from before the page loads!") ` - YourComponent.afterDOM = ` + YourComponent.afterDOMLoaded = ` document.getElementById('btn').onclick = () => { alert('button clicked!') } @@ -180,7 +180,7 @@ export default (() => { return } - YourComponent.afterDOM = script + YourComponent.afterDOMLoaded = script return YourComponent }) satisfies QuartzComponentConstructor ``` diff --git a/docs/advanced/making plugins.md b/docs/advanced/making plugins.md index b2bacf0aa..9925d16c9 100644 --- a/docs/advanced/making plugins.md +++ b/docs/advanced/making plugins.md @@ -27,7 +27,7 @@ The following sections will go into detail for what methods can be implemented f - `cfg`: The full Quartz [[configuration]] - `allSlugs`: a list of all the valid content slugs (see [[paths]] for more information on what a `ServerSlug` is) - `StaticResources` is defined in `quartz/resources.tsx`. It consists of - - `css`: a list of URLs for stylesheets that should be loaded + - `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. ## Transformers @@ -85,8 +85,10 @@ export const Latex: QuartzTransformerPlugin = (opts?: Options) => { if (engine === "katex") { return { css: [ - // base css - "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css", + { + // base css + content: "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css", + }, ], js: [ { @@ -260,11 +262,11 @@ export const ContentPage: QuartzEmitterPlugin = () => { ...defaultContentPageLayout, pageBody: Content(), } - const { head, header, beforeBody, pageBody, left, right, footer } = layout + const { head, header, beforeBody, pageBody, afterBody, left, right, footer } = layout return { name: "ContentPage", getQuartzComponents() { - return [head, ...header, ...beforeBody, pageBody, ...left, ...right, footer] + return [head, ...header, ...beforeBody, pageBody, ...afterBody, ...left, ...right, footer] }, async emit(ctx, content, resources, emit): Promise { const cfg = ctx.cfg.configuration diff --git a/docs/advanced/paths.md b/docs/advanced/paths.md index 9455b9819..16f6388d1 100644 --- a/docs/advanced/paths.md +++ b/docs/advanced/paths.md @@ -48,4 +48,4 @@ Here are the main types of slugs with a rough description of each type of path: - `SimpleSlug`: cannot be relative and shouldn't have `/index` as an ending or a file extension. It _can_ however have a trailing slash to indicate a folder path. - `RelativeURL`: must start with `.` or `..` to indicate it's a relative URL. Shouldn't have `/index` as an ending or a file extension but can contain a trailing slash. -To get a clearer picture of how these relate to each other, take a look at the path tests in `quartz/path.test.ts`. +To get a clearer picture of how these relate to each other, take a look at the path tests in `quartz/util/path.test.ts`. diff --git a/docs/authoring content.md b/docs/authoring content.md index d872a964f..178f44af8 100644 --- a/docs/authoring content.md +++ b/docs/authoring content.md @@ -29,6 +29,7 @@ Some common frontmatter fields that are natively supported by Quartz: - `title`: Title of the page. If it isn't provided, Quartz will use the name of the file as the title. - `description`: Description of the page used for link previews. +- `permalink`: A custom URL for the page that will remain constant even if the path to the file changes. - `aliases`: Other names for this note. This is a list of strings. - `tags`: Tags for this note. - `draft`: Whether to publish the page or not. This is one way to make [[private pages|pages private]] in Quartz. diff --git a/docs/build.md b/docs/build.md index 144768757..6005770dd 100644 --- a/docs/build.md +++ b/docs/build.md @@ -21,3 +21,7 @@ This will start a local web server to run your Quartz on your computer. Open a w > - `--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/configuration.md b/docs/configuration.md index 6c4c92850..1622da6fa 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -21,6 +21,7 @@ const config: QuartzConfig = { This part of the configuration concerns anything that can affect the whole site. The following is a list breaking down all the things you can configure: - `pageTitle`: title of the site. This is also used when generating the [[RSS Feed]] for your site. +- `pageTitleSuffix`: a string added to the end of the page title. This only applies to the browser tab title, not the title shown at the top of the page. - `enableSPA`: whether to enable [[SPA Routing]] on your site. - `enablePopovers`: whether to enable [[popover previews]] on your site. - `analytics`: what to use for analytics on your site. Values can be @@ -31,6 +32,8 @@ This part of the configuration concerns anything that can affect the whole site. - `{ provider: 'goatcounter', websiteId: 'my-goatcounter-id' }` (managed) or `{ provider: 'goatcounter', websiteId: 'my-goatcounter-id', host: 'my-goatcounter-domain.com', scriptSrc: 'https://my-url.to/counter.js' }` (self-hosted) use [GoatCounter](https://goatcounter.com); - `{ provider: 'posthog', apiKey: '', host: '' }`: use [Posthog](https://posthog.com/); - `{ provider: 'tinylytics', siteId: '' }`: use [Tinylytics](https://tinylytics.app/); + - `{ provider: 'cabin' }` or `{ provider: 'cabin', host: 'https://cabin.example.com' }` (custom domain): use [Cabin](https://withcabin.com); + - `{provider: 'clarity', projectId: ' [!warning] +> As seen above placement of `Plugin.RoamFlavoredMarkdown()` within `quartz.config.ts` is very important. It must come before `Plugin.ObsidianFlavoredMarkdown()`. + +## Customization + +This functionality is provided by the [[RoamFlavoredMarkdown]] plugin. See the plugin page for customization options. diff --git a/docs/features/comments.md b/docs/features/comments.md new file mode 100644 index 000000000..48037735a --- /dev/null +++ b/docs/features/comments.md @@ -0,0 +1,127 @@ +--- +title: Comments +tags: + - component +--- + +Quartz also has the ability to hook into various providers to enable readers to leave comments on your site. + +![[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! + +## Providers + +### Giscus + +First, make sure that the [[setting up your GitHub repository|GitHub]] repository you are using for your Quartz meets the following requirements: + +1. The **repository is [public](https://docs.github.com/en/github/administering-a-repository/managing-repository-settings/setting-repository-visibility#making-a-repository-public)**, otherwise visitors will not be able to view the discussion. +2. The **[giscus](https://github.com/apps/giscus) app is installed**, otherwise visitors will not be able to comment and react. +3. The **Discussions feature is turned on** by [enabling it for your repository](https://docs.github.com/en/github/administering-a-repository/managing-repository-settings/enabling-or-disabling-github-discussions-for-a-repository). + +Then, use the [Giscus site](https://giscus.app/#repository) to figure out what your `repoId` and `categoryId` should be. Make sure you select `Announcements` for the Discussion category. + +![[giscus-repo.png]] + +![[giscus-discussion.png]] + +After entering both your repository and selecting the discussion category, Giscus will compute some IDs that you'll need to provide back to Quartz. You won't need to manually add the script yourself as Quartz will handle that part for you but will need these values in the next step! + +![[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: + +```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', + } + }), +], +``` + +### 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. + +```ts +type Options = { + provider: "giscus" + options: { + repo: `${string}/${string}` + repoId: string + category: string + categoryId: string + + // Url to folder with custom themes + // defaults to 'https://${cfg.baseUrl}/static/giscus' + themeUrl?: string + + // filename for light theme .css file + // defaults to 'light' + lightTheme?: string + + // filename for dark theme .css file + // defaults to 'dark' + darkTheme?: string + + // how to map pages -> discussions + // defaults to 'url' + mapping?: "url" | "title" | "og:title" | "specific" | "number" | "pathname" + + // use strict title matching + // defaults to true + strict?: boolean + + // whether to enable reactions for the main post + // defaults to true + reactionsEnabled?: boolean + + // where to put the comment input box relative to the comments + // defaults to 'bottom' + inputPosition?: "top" | "bottom" + } +} +``` + +#### Custom CSS theme + +Quartz supports custom theme for Giscus. To use a custom CSS theme, place the `.css` file inside the `quartz/static` folder and set the configuration values. + +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 + + themeUrl: "https://example.com/static/giscus", // corresponds to quartz/static/giscus/ + lightTheme: "light-theme", // corresponds to light-theme.css in quartz/static/giscus/ + darkTheme: "dark-theme", // corresponds to dark-theme.css quartz/static/giscus/ + } + }), +], +``` + +#### Conditionally display comments + +Quartz can conditionally display the comment box based on a field `comments` in the frontmatter. By default, all pages will display comments, to disable it for a specific page, set `comments` to `false`. + +``` +--- +title: Comments disabled here! +comments: false +--- +``` diff --git a/docs/features/folder and tag listings.md b/docs/features/folder and tag listings.md index d330f1479..3190709d3 100644 --- a/docs/features/folder and tag listings.md +++ b/docs/features/folder and tag listings.md @@ -30,4 +30,4 @@ As with folder listings, you can also provide a description and title for a tag ## Customization -The folder listings are a functionality of the [[FolderPage]] plugin, the tag listings of the [[TagPage]] plugin. See the plugin pages for customization options. +Quartz allows you to define a custom sort ordering for content on both page types. The folder listings are a functionality of the [[FolderPage]] plugin, the tag listings of the [[TagPage]] plugin. See the plugin pages for customization options. diff --git a/docs/features/social images.md b/docs/features/social images.md new file mode 100644 index 000000000..0822651f4 --- /dev/null +++ b/docs/features/social images.md @@ -0,0 +1,401 @@ +--- +title: "Social Media Preview Cards" +--- + +A lot of social media platforms can display a rich preview for your website when sharing a link (most notably, a cover image, a title and a description). Quartz automatically handles most of this for you with reasonable defaults, but for more control, you can customize these by setting [[social images#Frontmatter Properties]]. +Quartz can also dynamically generate and use new cover images for every page to be used in link previews on social media for you. To get started with this, set `generateSocialImages: true` in `quartz.config.ts`. + +## Showcase + +After enabling `generateSocialImages` in `quartz.config.ts`, the social media link preview for [[authoring content | Authoring Content]] looks like this: + +| Light | Dark | +| ----------------------------------- | ---------------------------------- | +| ![[social-image-preview-light.png]] | ![[social-image-preview-dark.png]] | + +For testing, it is recommended to use [opengraph.xyz](https://www.opengraph.xyz/) to see what the link to your page will look like on various platforms (more info under [[social images#local testing]]). + +## Customization + +You can customize how images will be generated in the quartz config. + +For example, here's what the default configuration looks like if you set `generateSocialImages: true`: + +```typescript title="quartz.config.ts" +generateSocialImages: { + 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) +} +``` + +--- + +### Frontmatter Properties + +> [!tip] Hint +> +> Overriding social media preview properties via frontmatter still works even if `generateSocialImages` is disabled. + +The following properties can be used to customize your link previews: + +| Property | Alias | Summary | +| ------------------- | ---------------- | ----------------------------------- | +| `socialDescription` | `description` | Description to be used for preview. | +| `socialImage` | `image`, `cover` | Link to preview image. | + +The `socialImage` property should contain a link to an image relative to `quartz/static`. If you have a folder for all your images in `quartz/static/my-images`, an example for `socialImage` could be `"my-images/cover.png"`. + +> [!info] Info +> +> The priority for what image will be used for the cover image looks like the following: `frontmatter property > generated image (if enabled) > default image`. +> +> The default image (`quartz/static/og-image.png`) will only be used as a fallback if nothing else is set. If `generateSocialImages` is enabled, it will be treated as the new default per page, but can be overwritten by setting the `socialImage` frontmatter property for that page. + +--- + +### Fully customized image generation + +You can fully customize how the images being generated look by passing your own component to `generateSocialImages.imageStructure`. This component takes html/css + some page metadata/config options and converts it to an image using [satori](https://github.com/vercel/satori). Vercel provides an [online playground](https://og-playground.vercel.app/) that can be used to preview how your html/css looks like as a picture. This is ideal for prototyping your custom design. + +It is recommended to write your own image components in `quartz/util/og.tsx` or any other `.tsx` file, as passing them to the config won't work otherwise. An example of the default image component can be found in `og.tsx` in `defaultImage()`. + +> [!tip] Hint +> +> Satori only supports a subset of all valid CSS properties. All supported properties can be found in their [documentation](https://github.com/vercel/satori#css). + +Your custom image component should have the `SocialImageOptions["imageStructure"]` type, to make development easier for you. Using a component of this type, you will be passed the following variables: + +```ts +imageStructure: ( + cfg: GlobalConfiguration, // global Quartz config (useful for getting theme colors and other info) + userOpts: UserOpts, // options passed to `generateSocialImage` + title: string, // title of current page + description: string, // description of current page + fonts: SatoriOptions["fonts"], // header + body font +) => JSXInternal.Element +``` + +Now, you can let your creativity flow and design your own image component! For reference and some cool tips, you can check how the markup for the default image looks. + +> [!example] Examples +> +> Here are some examples for markup you may need to get started: +> +> - Get a theme color +> +> `cfg.theme.colors[colorScheme].`, where `` corresponds to a key in `ColorScheme` (defined at the top of `quartz/util/theme.ts`) +> +> - Use the page title/description +> +> `

{title}

`/`

{description}

` +> +> - Use a font family +> +> Detailed in the Fonts chapter below + +--- + +### 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). + +An example of a component using the header font could look like this: + +```tsx title="socialImage.tsx" +export const myImage: SocialImageOptions["imageStructure"] = (...) => { + return

Cool Header!

+} +``` + +> [!example]- Local fonts +> +> For cases where you use a local fonts under `static` folder, make sure to set the correct `@font-face` in `custom.scss` +> +> ```scss title="custom.scss" +> @font-face { +> font-family: "Newsreader"; +> font-style: normal; +> font-weight: normal; +> font-display: swap; +> src: url("/static/Newsreader.woff2") format("woff2"); +> } +> ``` +> +> Then in `quartz/util/og.tsx`, you can load the satori fonts like so: +> +> ```tsx title="quartz/util/og.tsx" +> const headerFont = joinSegments("static", "Newsreader.woff2") +> const bodyFont = joinSegments("static", "Newsreader.woff2") +> +> export async function getSatoriFont(cfg: GlobalConfiguration): Promise { +> const headerWeight: FontWeight = 700 +> const bodyWeight: FontWeight = 400 +> +> const url = new URL(`https://${cfg.baseUrl ?? "example.com"}`) +> +> const [header, body] = await Promise.all( +> [headerFont, bodyFont].map((font) => +> fetch(`${url.toString()}/${font}`).then((res) => res.arrayBuffer()), +> ), +> ) +> +> return [ +> { name: cfg.theme.typography.header, data: header, weight: headerWeight, style: "normal" }, +> { name: cfg.theme.typography.body, data: body, weight: bodyWeight, style: "normal" }, +> ] +> } +> ``` +> +> This font then can be used with your custom structure + +### Local testing + +To test how the full preview of your page is going to look even before deploying, you can forward the port you're serving quartz on. In VSCode, this can easily be achieved following [this guide](https://code.visualstudio.com/docs/editor/port-forwarding) (make sure to set `Visibility` to `public` if testing on external tools like [opengraph.xyz](https://www.opengraph.xyz/)). + +If you have `generateSocialImages` enabled, you can check out all generated images under `public/static/social-images`. + +## Technical info + +Images will be generated as `.webp` files, which helps to keep images small (the average image takes ~`19kB`). They are also compressed further using [sharp](https://sharp.pixelplumbing.com/). + +When using images, the appropriate [Open Graph](https://ogp.me/) and [Twitter](https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started) meta tags will be set to ensure they work and look as expected. + +## Examples + +Besides the template for the default image generation (found under `quartz/util/og.tsx`), you can also add your own! To do this, you can either edit the source code of that file (not recommended) or create a new one (e.g. `customSocialImage.tsx`, source shown below). + +After adding that file, you can update `quartz.config.ts` to use your image generation template as follows: + +```ts +// Import component at start of file +import { customImage } from "./quartz/util/customSocialImage.tsx" + +// In main config +const config: QuartzConfig = { + ... + generateSocialImages: { + ... + imageStructure: customImage, // tells quartz to use your component when generating images + }, +} +``` + +The following example will generate images that look as follows: + +| Light | Dark | +| ------------------------------------------ | ----------------------------------------- | +| ![[custom-social-image-preview-light.png]] | ![[custom-social-image-preview-dark.png]] | + +This example (and the default template) use colors and fonts from your theme specified in the quartz config. Fonts get passed in as a prop, where `fonts[0]` will contain the header font and `fonts[1]` will contain the body font (more info in the [[#fonts]] section). + +```tsx +import { SatoriOptions } from "satori/wasm" +import { GlobalConfiguration } from "../cfg" +import { SocialImageOptions, UserOpts } from "./imageHelper" +import { QuartzPluginData } from "../plugins/vfile" + +export const customImage: SocialImageOptions["imageStructure"] = ( + cfg: GlobalConfiguration, + userOpts: UserOpts, + title: string, + description: string, + fonts: SatoriOptions["fonts"], + fileData: QuartzPluginData, +) => { + // How many characters are allowed before switching to smaller font + const fontBreakPoint = 22 + const useSmallerFont = title.length > fontBreakPoint + + const { colorScheme } = userOpts + return ( +
+
+

+ {title} +

+

+ {description} +

+
+
+
+ ) +} +``` + +> [!example]- Advanced example +> +> The following example includes a customized social image with a custom background and formatted date. +> +> ```typescript title="custom-og.tsx" +> export const og: SocialImageOptions["Component"] = ( +> cfg: GlobalConfiguration, +> fileData: QuartzPluginData, +> { colorScheme }: Options, +> title: string, +> description: string, +> fonts: SatoriOptions["fonts"], +> ) => { +> let created: string | undefined +> let reading: string | undefined +> if (fileData.dates) { +> created = formatDate(getDate(cfg, fileData)!, cfg.locale) +> } +> const { minutes, text: _timeTaken, words: _words } = readingTime(fileData.text!) +> reading = i18n(cfg.locale).components.contentMeta.readingTime({ +> minutes: Math.ceil(minutes), +> }) +> +> const Li = [created, reading] +> +> return ( +>
style={{ +> position: "relative", +> display: "flex", +> flexDirection: "row", +> alignItems: "flex-start", +> height: "100%", +> width: "100%", +> backgroundImage: `url("https://${cfg.baseUrl}/static/og-image.jpeg")`, +> backgroundSize: "100% 100%", +> }} +> > +>
style={{ +> position: "absolute", +> top: 0, +> left: 0, +> right: 0, +> bottom: 0, +> background: "radial-gradient(circle at center, transparent, rgba(0, 0, 0, 0.4) 70%)", +> }} +> /> +>
style={{ +> display: "flex", +> height: "100%", +> width: "100%", +> flexDirection: "column", +> justifyContent: "flex-start", +> alignItems: "flex-start", +> gap: "1.5rem", +> paddingTop: "4rem", +> paddingBottom: "4rem", +> marginLeft: "4rem", +> }} +> > +> src={`"https://${cfg.baseUrl}/static/icon.jpeg"`} +> style={{ +> position: "relative", +> backgroundClip: "border-box", +> borderRadius: "6rem", +> }} +> width={80} +> /> +>
style={{ +> display: "flex", +> flexDirection: "column", +> textAlign: "left", +> fontFamily: fonts[0].name, +> }} +> > +>

style={{ +> color: cfg.theme.colors[colorScheme].light, +> fontSize: "3rem", +> fontWeight: 700, +> marginRight: "4rem", +> fontFamily: fonts[0].name, +> }} +> > +> {title} +>

+>
    style={{ +> color: cfg.theme.colors[colorScheme].gray, +> gap: "1rem", +> fontSize: "1.5rem", +> fontFamily: fonts[1].name, +> }} +> > +> {Li.map((item, index) => { +> if (item) { +> return
  • {item}
  • +> } +> })} +>
+>
+>

style={{ +> color: cfg.theme.colors[colorScheme].light, +> fontSize: "1.5rem", +> overflow: "hidden", +> marginRight: "8rem", +> textOverflow: "ellipsis", +> display: "-webkit-box", +> WebkitLineClamp: 7, +> WebkitBoxOrient: "vertical", +> lineClamp: 7, +> fontFamily: fonts[1].name, +> }} +> > +> {description} +>

+>
+>
+> ) +> } +> ``` diff --git a/docs/features/syntax highlighting.md b/docs/features/syntax highlighting.md index 16fef2575..bf9baaeee 100644 --- a/docs/features/syntax highlighting.md +++ b/docs/features/syntax highlighting.md @@ -95,6 +95,16 @@ const [age, setAge] = useState(50) const [name, setName] = useState("Taylor") ``` +### Inline Highlighting + +Append {:lang} to the end of inline code to highlight it like a regular code block. + +``` +This is an array `[1, 2, 3]{:js}` of numbers 1 through 3. +``` + +This is an array `[1, 2, 3]{:js}` of numbers 1 through 3. + ### Line numbers Syntax highlighting has line numbers configured automatically. If you want to start line numbers at a specific number, use `showLineNumbers{number}`: diff --git a/docs/features/upcoming features.md b/docs/features/upcoming features.md index 76adda00e..d45ebeda4 100644 --- a/docs/features/upcoming features.md +++ b/docs/features/upcoming features.md @@ -2,22 +2,11 @@ draft: true --- -## high priority backlog - -- static dead link detection -- block links: https://help.obsidian.md/Linking+notes+and+files/Internal+links#Link+to+a+block+in+a+note -- note/header/block transcludes: https://help.obsidian.md/Linking+notes+and+files/Embedding+files -- docker support - ## misc backlog -- breadcrumbs component +- static dead link detection - cursor chat extension -- https://giscus.app/ extension - sidenotes? https://github.com/capnfabs/paperesque - direct match in search using double quotes - https://help.obsidian.md/Advanced+topics/Using+Obsidian+URI -- audio/video embed styling - Canvas -- parse all images in page: use this for page lists if applicable? -- CV mode? with print stylesheet diff --git a/docs/hosting.md b/docs/hosting.md index e5ef9a615..8b945a24b 100644 --- a/docs/hosting.md +++ b/docs/hosting.md @@ -57,18 +57,18 @@ jobs: build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Fetch all history for git info - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18.14 + node-version: 22 - name: Install Dependencies run: npm ci - name: Build Quartz run: npx quartz build - name: Upload artifact - uses: actions/upload-pages-artifact@v2 + uses: actions/upload-pages-artifact@v3 with: path: public @@ -81,7 +81,7 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 ``` Then: @@ -182,37 +182,33 @@ Using `docs.example.com` is an example of a subdomain. They're a simple way of c ## GitLab Pages -In your local Quartz, create a new file `.gitlab-ci.yaml`. +In your local Quartz, create a new file `.gitlab-ci.yml`. -```yaml title=".gitlab-ci.yaml" +```yaml title=".gitlab-ci.yml" stages: - build - deploy -variables: - NODE_VERSION: "18.14" +image: node:20 +cache: # Cache modules in between jobs + key: $CI_COMMIT_REF_SLUG + paths: + - .npm/ build: stage: build rules: - if: '$CI_COMMIT_REF_NAME == "v4"' before_script: - - apt-get update -q && apt-get install -y nodejs npm - - npm install -g n - - n $NODE_VERSION - hash -r - - npm ci + - npm ci --cache .npm --prefer-offline script: - npx quartz build artifacts: paths: - public - cache: - paths: - - ~/.npm/ - key: "${CI_COMMIT_REF_SLUG}-node-${CI_COMMIT_REF_NAME}" tags: - - docker + - gitlab-org-docker pages: stage: deploy @@ -251,6 +247,28 @@ server { } ``` +### Using Apache + +Here's an example of how to do this with Apache: + +```apache title=".htaccess" +RewriteEngine On + +ErrorDocument 404 /404.html + +# Rewrite rule for .html extension removal (with directory check) +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI}.html -f +RewriteRule ^(.*)$ $1.html [L] + +# Handle directory requests explicitly +RewriteCond %{REQUEST_FILENAME} -d +RewriteRule ^(.*)/$ $1/index.html [L] +``` + +Don't forget to activate brotli / gzip compression. + ### Using Caddy Here's and example of how to do this with Caddy: diff --git a/docs/images/custom-social-image-preview-dark.png b/docs/images/custom-social-image-preview-dark.png new file mode 100644 index 000000000..60c4e85c0 Binary files /dev/null and b/docs/images/custom-social-image-preview-dark.png differ diff --git a/docs/images/custom-social-image-preview-light.png b/docs/images/custom-social-image-preview-light.png new file mode 100644 index 000000000..046a40708 Binary files /dev/null and b/docs/images/custom-social-image-preview-light.png differ diff --git a/docs/images/giscus-discussion.png b/docs/images/giscus-discussion.png new file mode 100644 index 000000000..939af624f Binary files /dev/null and b/docs/images/giscus-discussion.png differ diff --git a/docs/images/giscus-example.png b/docs/images/giscus-example.png new file mode 100644 index 000000000..f59f52ba1 Binary files /dev/null and b/docs/images/giscus-example.png differ diff --git a/docs/images/giscus-repo.png b/docs/images/giscus-repo.png new file mode 100644 index 000000000..bfabc5692 Binary files /dev/null and b/docs/images/giscus-repo.png differ diff --git a/docs/images/giscus-results.png b/docs/images/giscus-results.png new file mode 100644 index 000000000..b25c75158 Binary files /dev/null and b/docs/images/giscus-results.png differ diff --git a/docs/images/quartz layout.png b/docs/images/quartz layout.png deleted file mode 100644 index 03435f7d5..000000000 Binary files a/docs/images/quartz layout.png and /dev/null differ diff --git a/docs/images/quartz-layout-desktop.png b/docs/images/quartz-layout-desktop.png new file mode 100644 index 000000000..461d7916a Binary files /dev/null and b/docs/images/quartz-layout-desktop.png differ diff --git a/docs/images/quartz-layout-mobile.png b/docs/images/quartz-layout-mobile.png new file mode 100644 index 000000000..ad6c09e12 Binary files /dev/null and b/docs/images/quartz-layout-mobile.png differ diff --git a/docs/images/quartz-layout-tablet.png b/docs/images/quartz-layout-tablet.png new file mode 100644 index 000000000..6349f2975 Binary files /dev/null and b/docs/images/quartz-layout-tablet.png differ diff --git a/docs/images/social-image-preview-dark.png b/docs/images/social-image-preview-dark.png new file mode 100644 index 000000000..c12545166 Binary files /dev/null and b/docs/images/social-image-preview-dark.png differ diff --git a/docs/images/social-image-preview-light.png b/docs/images/social-image-preview-light.png new file mode 100644 index 000000000..ca0bdbc75 Binary files /dev/null and b/docs/images/social-image-preview-light.png differ diff --git a/docs/index.md b/docs/index.md index 87cf024a3..e41c1711e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ Quartz is a fast, batteries-included static-site generator that transforms Markd ## 🪴 Get Started -Quartz requires **at least [Node](https://nodejs.org/) v18.14** and `npm` v9.3.1 to function correctly. Ensure you have this installed on your machine before continuing. +Quartz requires **at least [Node](https://nodejs.org/) v20** and `npm` v9.3.1 to function correctly. Ensure you have this installed on your machine before continuing. Then, in your terminal of choice, enter the following commands line by line: @@ -31,7 +31,7 @@ If you prefer instructions in a video format you can try following Nicole van de ## 🔧 Features -- [[Obsidian compatibility]], [[full-text search]], [[graph view]], note transclusion, [[wikilinks]], [[backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]] and [many more](./features) right out of the box +- [[Obsidian compatibility]], [[full-text search]], [[graph view]], note transclusion, [[wikilinks]], [[backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]], [[comments]] and [many more](./features) right out of the box - Hot-reload for both configuration and content - Simple JSX layouts and [[creating components|page components]] - [[SPA Routing|Ridiculously fast page loads]] and tiny bundle sizes diff --git a/docs/layout.md b/docs/layout.md index 3fabeb79c..d8427c4cd 100644 --- a/docs/layout.md +++ b/docs/layout.md @@ -12,15 +12,20 @@ export interface FullPageLayout { header: QuartzComponent[] // laid out horizontally beforeBody: QuartzComponent[] // laid out vertically pageBody: QuartzComponent // single component - left: QuartzComponent[] // vertical on desktop, horizontal on mobile - right: QuartzComponent[] // vertical on desktop, horizontal on mobile + afterBody: QuartzComponent[] // laid out vertically + left: QuartzComponent[] // vertical on desktop and tablet, horizontal on mobile + right: QuartzComponent[] // vertical on desktop, horizontal on tablet and mobile footer: QuartzComponent // single component } ``` These correspond to following parts of the page: -![[quartz layout.png|800]] +| Layout | Preview | +| ------------------------------- | ----------------------------------- | +| Desktop (width > 1200px) | ![[quartz-layout-desktop.png\|800]] | +| Tablet (800px < width < 1200px) | ![[quartz-layout-tablet.png\|800]] | +| Mobile (width < 800px) | ![[quartz-layout-mobile.png\|800]] | > [!note] > There are two additional layout fields that are _not_ shown in the above diagram. @@ -32,6 +37,23 @@ Quartz **components**, like plugins, can take in additional properties as config See [a list of all the components](component.md) for all available components along with their configuration options. You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz. +### Layout breakpoints + +Quartz has different layouts depending on the width the screen viewing the website. + +The breakpoints for layouts can be configured in `variables.scss`. + +- `mobile`: screen width below this size will use mobile layout. +- `desktop`: screen width above this size will use desktop layout. +- Screen width between `mobile` and `desktop` width will use the tablet layout. + +```scss +$breakpoints: ( + mobile: 800px, + desktop: 1200px, +); +``` + ### 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. diff --git a/docs/plugins/CreatedModifiedDate.md b/docs/plugins/CreatedModifiedDate.md index 5d772aaa0..f4134c478 100644 --- a/docs/plugins/CreatedModifiedDate.md +++ b/docs/plugins/CreatedModifiedDate.md @@ -11,7 +11,7 @@ This plugin determines the created, modified, and published dates for a document This plugin accepts the following configuration options: -- `priority`: The data sources to consult for date information. Highest priority first. Possible values are `"frontmatter"`, `"git"`, and `"filesystem"`. Defaults to `"frontmatter", "git", "filesystem"]`. +- `priority`: The data sources to consult for date information. Highest priority first. Possible values are `"frontmatter"`, `"git"`, and `"filesystem"`. Defaults to `["frontmatter", "git", "filesystem"]`. > [!warning] > If you rely on `git` for dates, make sure `defaultDateType` is set to `modified` in `quartz.config.ts`. diff --git a/docs/plugins/FolderPage.md b/docs/plugins/FolderPage.md index ead8e75ff..45cfa1574 100644 --- a/docs/plugins/FolderPage.md +++ b/docs/plugins/FolderPage.md @@ -11,10 +11,12 @@ Example: [[advanced/|Advanced]] > [!note] > For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. -This plugin has no configuration options. - 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 diff --git a/docs/plugins/Latex.md b/docs/plugins/Latex.md index ac4367841..9ef37ff5d 100644 --- a/docs/plugins/Latex.md +++ b/docs/plugins/Latex.md @@ -11,7 +11,12 @@ This plugin adds LaTeX support to Quartz. See [[features/Latex|Latex]] for more This plugin accepts the following configuration options: -- `renderEngine`: the engine to use to render LaTeX equations. Can be `"katex"` for [KaTeX](https://katex.org/) or `"mathjax"` for [MathJax](https://www.mathjax.org/) [SVG rendering](https://docs.mathjax.org/en/latest/output/svg.html). Defaults to KaTeX. +- `renderEngine`: the engine to use to render LaTeX equations. Can be `"katex"` for [KaTeX](https://katex.org/), `"mathjax"` for [MathJax](https://www.mathjax.org/) [SVG rendering](https://docs.mathjax.org/en/latest/output/svg.html), or `"typst"` for [Typst](https://typst.app/) (a new way to compose LaTeX equation). Defaults to KaTeX. +- `customMacros`: custom macros for all LaTeX blocks. It takes the form of a key-value pair where the key is a new command name and the value is the expansion of the macro. For example: `{"\\R": "\\mathbb{R}"}` + +> [!note] Typst support +> +> Currently, typst doesn't support inline-math ## API diff --git a/docs/plugins/RoamFlavoredMarkdown.md b/docs/plugins/RoamFlavoredMarkdown.md new file mode 100644 index 000000000..9d89477a2 --- /dev/null +++ b/docs/plugins/RoamFlavoredMarkdown.md @@ -0,0 +1,26 @@ +--- +title: RoamFlavoredMarkdown +tags: + - plugin/transformer +--- + +This plugin provides support for [Roam Research](https://roamresearch.com) compatibility. See [[Roam Research Compatibility]] for more information. + +> [!note] +> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page. + +This plugin accepts the following configuration options: + +- `orComponent`: If `true` (default), converts Roam `{{ or:ONE|TWO|THREE }}` shortcodes into HTML Dropdown options. +- `TODOComponent`: If `true` (default), converts Roam `{{[[TODO]]}}` shortcodes into HTML check boxes. +- `DONEComponent`: If `true` (default), converts Roam `{{[[DONE]]}}` shortcodes into checked HTML check boxes. +- `videoComponent`: If `true` (default), converts Roam `{{[[video]]:URL}}` shortcodes into embeded HTML video. +- `audioComponent`: If `true` (default), converts Roam `{{[[audio]]:URL}}` shortcodes into embeded HTML audio. +- `pdfComponent`: If `true` (default), converts Roam `{{[[pdf]]:URL}}` shortcodes into embeded HTML PDF viewer. +- `blockquoteComponent`: If `true` (default), converts Roam `{{[[>]]}}` shortcodes into Quartz blockquotes. + +## 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). diff --git a/docs/plugins/TagPage.md b/docs/plugins/TagPage.md index 9c704b380..9556363fe 100644 --- a/docs/plugins/TagPage.md +++ b/docs/plugins/TagPage.md @@ -9,10 +9,12 @@ This plugin emits dedicated pages for each tag used in the content. See [[folder > [!note] > For information on how to add, remove or configure plugins, see the [[configuration#Plugins|Configuration]] page. -This plugin has no configuration options. - 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 diff --git a/docs/showcase.md b/docs/showcase.md index c33f34c8e..67bb755ff 100644 --- a/docs/showcase.md +++ b/docs/showcase.md @@ -7,26 +7,28 @@ Want to see what Quartz can do? Here are some cool community gardens: - [Quartz Documentation (this site!)](https://quartz.jzhao.xyz/) - [Jacky Zhao's Garden](https://jzhao.xyz/) - [Socratica Toolbox](https://toolbox.socratica.info/) -- [oldwinter の数字花园](https://garden.oldwinter.top/) +- [Morrowind Modding Wiki](https://morrowind-modding.github.io/) - [Aaron Pham's Garden](https://aarnphm.xyz/) -- [The Quantum Garden](https://quantumgardener.blog/) -- [Abhijeet's Math Wiki](https://abhmul.github.io/quartz/Math-Wiki/) -- [Matt Dunn's Second Brain](https://mattdunn.info/) -- [Pelayo Arbues' Notes](https://pelayoarbues.github.io/) -- [Vince Imbat's Talahardin](https://vinceimbat.com/) +- [The Pond](https://turntrout.com/welcome) +- [Pelayo Arbues' Notes](https://pelayoarbues.com/) +- [Stanford CME 302 Numerical Linear Algebra](https://ericdarve.github.io/NLA/) +- [A Pattern Language - Christopher Alexander (Architecture)](https://patternlanguage.cc/) +- [oldwinter の数字花园](https://garden.oldwinter.top/) +- [Eilleen's Everything Notebook](https://quartz.eilleeenz.com/) - [🧠🌳 Chad's Mind Garden](https://www.chadly.net/) - [Pedro MC Fernandes's Topo da Mente](https://www.pmcf.xyz/topo-da-mente/) - [Mau Camargo's Notkesto](https://notes.camargomau.com/) -- [Caicai's Novels](https://imoko.cc/blog/caicai/) -- [🌊 Collapsed Wave](https://collapsedwave.com/) - [Sideny's 3D Artist's Handbook](https://sidney-eliot.github.io/3d-artists-handbook/) -- [Mike's AI Garden 🤖🪴](https://mwalton.me/) - [Brandon Boswell's Garden](https://brandonkboswell.com) - [Scaling Synthesis - A hypertext research notebook](https://scalingsynthesis.com/) +- [Simon's Second Brain: Crafted, Curated, Connected, Compounded](https://brain.ssp.sh/) +- [Data Engineering Vault: A Second Brain Knowledge Network](https://vault.ssp.sh/) - [Data Dictionary 🧠](https://glossary.airbyte.com/) -- [sspaeti.com's Second Brain](https://brain.sspaeti.com/) - [🪴Aster's notebook](https://notes.asterhu.com) +- [Gatekeeper Wiki](https://www.gatekeeper.wiki) +- [Ellie's Notes](https://ellie.wtf) - [🥷🏻🌳🍃 Computer Science & Thinkering Garden](https://notes.yxy.ninja) -- [A Pattern Language - Christopher Alexander (Architecture)](https://patternlanguage.cc/) +- [Eledah's Crystalline](https://blog.eledah.ir/) +- [🌓 Projects & Privacy - FOSS, tech, law](https://be-far.com) If you want to see your own on here, submit a [Pull Request adding yourself to this file](https://github.com/jackyzha0/quartz/blob/v4/docs/showcase.md)! diff --git a/globals.d.ts b/globals.d.ts index ee13005c9..6cf30f8a1 100644 --- a/globals.d.ts +++ b/globals.d.ts @@ -4,6 +4,10 @@ export declare global { type: K, listener: (this: Document, ev: CustomEventMap[K]) => void, ): void + removeEventListener( + type: K, + listener: (this: Document, ev: CustomEventMap[K]) => void, + ): void dispatchEvent(ev: CustomEventMap[K] | UIEvent): void } interface Window { diff --git a/package-lock.json b/package-lock.json index 58d334df3..1933fa5b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,47 +1,51 @@ { "name": "@jackyzha0/quartz", - "version": "4.2.3", + "version": "4.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@jackyzha0/quartz", - "version": "4.2.3", + "version": "4.4.0", "license": "MIT", "dependencies": { - "@clack/prompts": "^0.7.0", - "@floating-ui/dom": "^1.6.3", - "@napi-rs/simple-git": "0.1.16", + "@clack/prompts": "^0.8.1", + "@floating-ui/dom": "^1.6.12", + "@myriaddreamin/rehype-typst": "^0.5.0-rc7", + "@napi-rs/simple-git": "0.1.19", + "@tweenjs/tween.js": "^25.0.0", "async-mutex": "^0.5.0", "chalk": "^5.3.0", - "chokidar": "^3.6.0", + "chokidar": "^4.0.1", "cli-spinner": "^0.2.10", "d3": "^7.9.0", - "esbuild-sass-plugin": "^2.16.1", + "esbuild-sass-plugin": "^3.3.1", "flexsearch": "0.7.43", "github-slugger": "^2.0.0", - "globby": "^14.0.1", + "globby": "^14.0.2", "gray-matter": "^4.0.3", - "hast-util-to-html": "^9.0.1", - "hast-util-to-jsx-runtime": "^2.3.0", - "hast-util-to-string": "^3.0.0", + "hast-util-to-html": "^9.0.3", + "hast-util-to-jsx-runtime": "^2.3.2", + "hast-util-to-string": "^3.0.1", "is-absolute-url": "^4.0.1", "js-yaml": "^4.1.0", - "lightningcss": "^1.24.1", + "lightningcss": "^1.28.1", "mdast-util-find-and-replace": "^3.0.1", - "mdast-util-to-hast": "^13.1.0", + "mdast-util-to-hast": "^13.2.0", "mdast-util-to-string": "^4.0.0", + "mermaid": "^11.4.0", "micromorph": "^0.4.5", - "preact": "^10.20.1", - "preact-render-to-string": "^6.4.2", + "pixi.js": "^8.5.2", + "preact": "^10.24.3", + "preact-render-to-string": "^6.5.11", "pretty-bytes": "^6.1.1", "pretty-time": "^1.1.0", "reading-time": "^1.5.0", "rehype-autolink-headings": "^7.1.0", - "rehype-citation": "^2.0.0", - "rehype-katex": "^7.0.0", + "rehype-citation": "^2.2.2", + "rehype-katex": "^7.0.1", "rehype-mathjax": "^6.0.0", - "rehype-pretty-code": "^0.13.0", + "rehype-pretty-code": "^0.14.0", "rehype-raw": "^7.0.0", "rehype-slug": "^6.0.0", "remark": "^15.0.1", @@ -50,20 +54,22 @@ "remark-gfm": "^4.0.0", "remark-math": "^6.0.0", "remark-parse": "^11.0.0", - "remark-rehype": "^11.1.0", - "remark-smartypants": "^2.1.0", - "rfdc": "^1.3.1", - "rimraf": "^5.0.7", - "serve-handler": "^6.1.5", - "shiki": "^1.6.0", + "remark-rehype": "^11.1.1", + "remark-smartypants": "^3.0.2", + "rfdc": "^1.4.1", + "rimraf": "^6.0.1", + "satori": "^0.11.3", + "serve-handler": "^6.1.6", + "sharp": "^0.33.5", + "shiki": "^1.23.1", "source-map-support": "^0.5.21", "to-vfile": "^8.0.0", "toml": "^3.0.0", - "unified": "^11.0.4", + "unified": "^11.0.5", "unist-util-visit": "^5.0.0", - "vfile": "^6.0.1", - "workerpool": "^9.1.1", - "ws": "^8.15.1", + "vfile": "^6.0.3", + "workerpool": "^9.2.0", + "ws": "^8.18.0", "yargs": "^17.7.2" }, "bin": { @@ -74,21 +80,43 @@ "@types/d3": "^7.4.3", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", - "@types/node": "^20.12.5", + "@types/node": "^22.9.0", "@types/pretty-time": "^1.1.5", "@types/source-map-support": "^0.5.10", - "@types/ws": "^8.5.10", - "@types/yargs": "^17.0.32", - "esbuild": "^0.19.9", - "prettier": "^3.2.4", - "tsx": "^4.9.3", - "typescript": "^5.4.5" + "@types/ws": "^8.5.13", + "@types/yargs": "^17.0.33", + "esbuild": "^0.24.0", + "prettier": "^3.3.3", + "tsx": "^4.19.2", + "typescript": "^5.6.3" }, "engines": { - "node": ">=18.14", + "node": "20 || >=22", "npm": ">=9.3.1" } }, + "node_modules/@antfu/install-pkg": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.4.1.tgz", + "integrity": "sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^0.2.0", + "tinyexec": "^0.3.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@asamuzakjp/dom-selector": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz", @@ -99,10 +127,61 @@ "is-potential-custom-element-name": "^1.0.1" } }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.0.tgz", + "integrity": "sha512-o+UlMLt49RvtCASlOMW0AkHnabN9wR9rwCCherxO0yG4Npy34GkvrAqdXQvrhNs+jh+gkK8gB8Lf05qL/O7KWg==", + "license": "MIT" + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.0.tgz", + "integrity": "sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ==", + "peer": true + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "license": "Apache-2.0" + }, "node_modules/@citation-js/core": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.9.tgz", - "integrity": "sha512-fSbkB32JayDChZnAYC/kB+sWHRvxxL7ibVetyBOyzOc+5aCnjb6UVsbcfhnkOIEyAMoRRvWDyFmakEoTtA5ttQ==", + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.14.tgz", + "integrity": "sha512-dgeGqYDSQmn2MtnWZkwPGpJQPh43yr1lAAr9jl1NJ9pIY1RXUQxtlAUZVur0V9PHdbfQC+kkvB1KC3VpgVV3MA==", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -130,9 +209,9 @@ } }, "node_modules/@citation-js/plugin-bibjson": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibjson/-/plugin-bibjson-0.7.9.tgz", - "integrity": "sha512-YNCWIrkhqZ3cZKewHkLBixABo2PvOWnU+8dBx6KfN47ysdECR76xENe86YYpJ0ska2D5ZnTP0jKZIrUHQoxYfQ==", + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibjson/-/plugin-bibjson-0.7.14.tgz", + "integrity": "sha512-Hcmk01KrpHwcl5uVoLE6TRaJRFg7/qUvpJDcKqx3LLLCsNbaBlISfRDeFETrjjipTetkX70RvtS7FfGUN58gCQ==", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2" @@ -145,9 +224,9 @@ } }, "node_modules/@citation-js/plugin-bibtex": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.7.9.tgz", - "integrity": "sha512-gIJpCd6vmmTOcRfDrSOjtoNhw2Mi94UwFxmgJ7GwkXyTYcNheW5VlMMo1tlqjakJGARQ0eOsKcI57gSPqJSS2g==", + "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==", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -161,9 +240,9 @@ } }, "node_modules/@citation-js/plugin-csl": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.7.9.tgz", - "integrity": "sha512-mbD7CnUiPOuVnjeJwo+d0RGUcY0PE8n01gHyjq0qpTeS42EGmQ9+LzqfsTUVWWBndTwc6zLRuIF1qFAUHKE4oA==", + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.7.14.tgz", + "integrity": "sha512-7AKB8lMz1IqdtoE33NnWIpteLYMuSl3xqT+Cax7sQKwAIJEoq2HBmb43Ja8xQQ36nREAupQJv1V6XksIAmYnCg==", "dependencies": { "@citation-js/date": "^0.5.0", "citeproc": "^2.4.6" @@ -176,23 +255,23 @@ } }, "node_modules/@clack/core": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.3.tgz", - "integrity": "sha512-5ZGyb75BUBjlll6eOa1m/IZBxwk91dooBWhPSL67sWcLS0zt9SnswRL0l26TVdBhb0wnWORRxUn//uH6n4z7+A==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.4.tgz", + "integrity": "sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw==", "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "node_modules/@clack/prompts": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.7.0.tgz", - "integrity": "sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.8.1.tgz", + "integrity": "sha512-I263nEUNbX4lPTX93trl1fkIvGrGlz6nUYkqOddF0ZmjqcxUgUlXmpUIUqfapirRKJrFddvwF+qdZgg8cSqF7g==", "bundleDependencies": [ "is-unicode-supported" ], "dependencies": { - "@clack/core": "^0.3.3", + "@clack/core": "0.3.4", "is-unicode-supported": "*", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" @@ -209,10 +288,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", - "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", + "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==", "cpu": [ "ppc64" ], @@ -221,13 +310,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", - "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz", + "integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==", "cpu": [ "arm" ], @@ -236,13 +325,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", - "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz", + "integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==", "cpu": [ "arm64" ], @@ -251,13 +340,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", - "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz", + "integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==", "cpu": [ "x64" ], @@ -266,13 +355,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz", + "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==", "cpu": [ "arm64" ], @@ -281,13 +370,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", - "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz", + "integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==", "cpu": [ "x64" ], @@ -296,13 +385,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", - "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz", + "integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==", "cpu": [ "arm64" ], @@ -311,13 +400,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", - "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz", + "integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==", "cpu": [ "x64" ], @@ -326,13 +415,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", - "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz", + "integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==", "cpu": [ "arm" ], @@ -341,13 +430,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", - "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz", + "integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==", "cpu": [ "arm64" ], @@ -356,13 +445,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", - "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz", + "integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==", "cpu": [ "ia32" ], @@ -371,13 +460,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", - "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz", + "integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==", "cpu": [ "loong64" ], @@ -386,13 +475,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", - "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz", + "integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==", "cpu": [ "mips64el" ], @@ -401,13 +490,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", - "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz", + "integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==", "cpu": [ "ppc64" ], @@ -416,13 +505,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", - "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz", + "integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==", "cpu": [ "riscv64" ], @@ -431,13 +520,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", - "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz", + "integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==", "cpu": [ "s390x" ], @@ -446,13 +535,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", - "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz", + "integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==", "cpu": [ "x64" ], @@ -461,13 +550,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", - "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz", + "integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==", "cpu": [ "x64" ], @@ -476,13 +565,29 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", - "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz", + "integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==", "cpu": [ "x64" ], @@ -491,13 +596,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", - "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz", + "integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==", "cpu": [ "x64" ], @@ -506,13 +611,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", - "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz", + "integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==", "cpu": [ "arm64" ], @@ -521,13 +626,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", - "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz", + "integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==", "cpu": [ "ia32" ], @@ -536,13 +641,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", - "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz", + "integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==", "cpu": [ "x64" ], @@ -551,7 +656,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@floating-ui/core": { @@ -563,18 +668,400 @@ } }, "node_modules/@floating-ui/dom": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", - "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", "dependencies": { - "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.0" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", - "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.1.33.tgz", + "integrity": "sha512-jP9h6v/g0BIZx0p7XGJJVtkVnydtbgTgt9mVNcGDYwaa7UhdHdI9dvoq+gKj9sijMSJKxUPEG2JyjsgXjxL7Kw==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^0.4.0", + "@antfu/utils": "^0.7.10", + "@iconify/types": "^2.0.0", + "debug": "^4.3.6", + "kolorist": "^1.8.0", + "local-pkg": "^0.5.0", + "mlly": "^1.7.1" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } }, "node_modules/@isaacs/cliui": { "version": "8.0.2", @@ -592,31 +1079,257 @@ "node": ">=12" } }, - "node_modules/@napi-rs/simple-git": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git/-/simple-git-0.1.16.tgz", - "integrity": "sha512-C5wRPw9waqL2jk3jEDeJv+f7ScuO3N0a39HVdyFLkwKxHH4Sya4ZbzZsu2JLi6eEqe7RuHipHL6mC7B2OfYZZw==", + "node_modules/@mermaid-js/parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.3.0.tgz", + "integrity": "sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA==", + "license": "MIT", + "dependencies": { + "langium": "3.0.0" + } + }, + "node_modules/@myriaddreamin/rehype-typst": { + "version": "0.5.0-rc7", + "resolved": "https://registry.npmjs.org/@myriaddreamin/rehype-typst/-/rehype-typst-0.5.0-rc7.tgz", + "integrity": "sha512-oIUmJzV8c+PZoV4TZwSupN9e06EaC2i0DpjU6NPe6y0HE7MoPOd35s6i+RjdSNPDguqBdP2MO4VaqnGahQW/ig==", + "license": "MIT", + "dependencies": { + "@myriaddreamin/typst-ts-node-compiler": "^0.5.0-rc7", + "@types/hast": "^3.0.0", + "@types/katex": "^0.16.0", + "hast-util-from-html-isomorphic": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "https-proxy-agent": "^7.0.2", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.0" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler/-/typst-ts-node-compiler-0.5.0-rc8.tgz", + "integrity": "sha512-RpMkKYyH7DDJwfX4hMhCkCbby5+rU7UMqRbCe6jmkvrW+FhW5YDxATYnRVEQLgRjbLwGDV5bECLr2/9no+Tn7A==", + "license": "Apache-2.0", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@napi-rs/simple-git-android-arm-eabi": "0.1.16", - "@napi-rs/simple-git-android-arm64": "0.1.16", - "@napi-rs/simple-git-darwin-arm64": "0.1.16", - "@napi-rs/simple-git-darwin-x64": "0.1.16", - "@napi-rs/simple-git-linux-arm-gnueabihf": "0.1.16", - "@napi-rs/simple-git-linux-arm64-gnu": "0.1.16", - "@napi-rs/simple-git-linux-arm64-musl": "0.1.16", - "@napi-rs/simple-git-linux-x64-gnu": "0.1.16", - "@napi-rs/simple-git-linux-x64-musl": "0.1.16", - "@napi-rs/simple-git-win32-arm64-msvc": "0.1.16", - "@napi-rs/simple-git-win32-x64-msvc": "0.1.16" + "@myriaddreamin/typst-ts-node-compiler-android-arm-eabi": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-android-arm64": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-darwin-arm64": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-darwin-x64": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-linux-arm-gnueabihf": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-linux-arm64-gnu": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-linux-arm64-musl": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-linux-x64-gnu": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-linux-x64-musl": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-win32-arm64-msvc": "0.5.0-rc8", + "@myriaddreamin/typst-ts-node-compiler-win32-x64-msvc": "0.5.0-rc8" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-android-arm-eabi": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-android-arm-eabi/-/typst-ts-node-compiler-android-arm-eabi-0.5.0-rc8.tgz", + "integrity": "sha512-gSd1Nw4FNGixQTRo4isntK2Utupu4yfKRMTgmB6aLn57GVf6Z6NDA4YLw0lQ8dNB4OYceX1wMXmjnoLZGiTk6Q==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-android-arm64": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-android-arm64/-/typst-ts-node-compiler-android-arm64-0.5.0-rc8.tgz", + "integrity": "sha512-1eSqCcLASxbdcicxFtYoXrBz4Rm7uhhWu/0DQ8Qo7bvNkzHuRtc4KkyuCZ6NCb/WzWuR4He20ySJZJRZurpgOQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-darwin-arm64": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-darwin-arm64/-/typst-ts-node-compiler-darwin-arm64-0.5.0-rc8.tgz", + "integrity": "sha512-KKty+9lpfzogptuQs78JaFLijucrIdUxnYrCqWR2wHTgc0rnQaqHyec0HQ0oApNDc6u59xURebglQ/nHAVa+WQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-darwin-x64": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-darwin-x64/-/typst-ts-node-compiler-darwin-x64-0.5.0-rc8.tgz", + "integrity": "sha512-e1P7GkyBV34h9eTDceZDC3qC0stDSN30R1gbZyniHOWu+qIKp0+RgQOLbkMj1Bk+vsOYGtb3zlqRJGEOCImz8w==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-linux-arm-gnueabihf": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-linux-arm-gnueabihf/-/typst-ts-node-compiler-linux-arm-gnueabihf-0.5.0-rc8.tgz", + "integrity": "sha512-HX19C6kWO8aeg+Ki4pQm2TTmYYLZEW653QwZEoCluAlX7O5HoGxCbsFLnE7v3+ag1dwBcoI2oH5czuKLI7GRvA==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-linux-arm64-gnu": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-linux-arm64-gnu/-/typst-ts-node-compiler-linux-arm64-gnu-0.5.0-rc8.tgz", + "integrity": "sha512-ElCka7rGGnB5nmY/Ei6fhS8JWNFRJDTagW1NM2feGvEazpMxDOQDWPg/bUXnUp7RS68L67gyXJSNFlHNWJM6/w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-linux-arm64-musl": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-linux-arm64-musl/-/typst-ts-node-compiler-linux-arm64-musl-0.5.0-rc8.tgz", + "integrity": "sha512-RbaI/i0rVzu2fyCcUPj89Zt/kmpHqJvxS/VRtbXR6xjXBUBisheRLvmWJrDdMMLf2mS0cwRPxQHGKCOSmB6U5A==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-linux-x64-gnu": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-linux-x64-gnu/-/typst-ts-node-compiler-linux-x64-gnu-0.5.0-rc8.tgz", + "integrity": "sha512-Mi2TruUZ97ZP920fMdvebRVYfMBxQZXnt14f0CqCy4tmg9sI7/ymBaGhT0vIo7A01cWr1DeTtoE4qUrOzXcDyA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-linux-x64-musl": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-linux-x64-musl/-/typst-ts-node-compiler-linux-x64-musl-0.5.0-rc8.tgz", + "integrity": "sha512-I/GTNDl3Pb9/TyBRPtJqXuykkZ3d07PrSxnUKo1CelpJCk6S3h1BY0vl/3OwpENWGzy0FJehzkF0F8//3XzCgg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-win32-arm64-msvc": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-win32-arm64-msvc/-/typst-ts-node-compiler-win32-arm64-msvc-0.5.0-rc8.tgz", + "integrity": "sha512-G0c+IqUDPdUDnTKyFl1ajf47oGgV1asc3aYtl23U71RK4R0ILnyycgGjE/5E8hD0CLodq5xMV+zW+17TZ4VX0A==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@myriaddreamin/typst-ts-node-compiler-win32-x64-msvc": { + "version": "0.5.0-rc8", + "resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-node-compiler-win32-x64-msvc/-/typst-ts-node-compiler-win32-x64-msvc-0.5.0-rc8.tgz", + "integrity": "sha512-qlZXCfLDUm1btpESBa4onU2ky7ALwdj369dAmgslNKyOl5JN8RYcyf9Hm7fp8WeVlxVjH2/2zJgPysAHf+SSRw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git/-/simple-git-0.1.19.tgz", + "integrity": "sha512-jMxvwzkKzd3cXo2EB9GM2ic0eYo2rP/BS6gJt6HnWbsDO1O8GSD4k7o2Cpr2YERtMpGF/MGcDfsfj2EbQPtrXw==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/simple-git-android-arm-eabi": "0.1.19", + "@napi-rs/simple-git-android-arm64": "0.1.19", + "@napi-rs/simple-git-darwin-arm64": "0.1.19", + "@napi-rs/simple-git-darwin-x64": "0.1.19", + "@napi-rs/simple-git-freebsd-x64": "0.1.19", + "@napi-rs/simple-git-linux-arm-gnueabihf": "0.1.19", + "@napi-rs/simple-git-linux-arm64-gnu": "0.1.19", + "@napi-rs/simple-git-linux-arm64-musl": "0.1.19", + "@napi-rs/simple-git-linux-powerpc64le-gnu": "0.1.19", + "@napi-rs/simple-git-linux-s390x-gnu": "0.1.19", + "@napi-rs/simple-git-linux-x64-gnu": "0.1.19", + "@napi-rs/simple-git-linux-x64-musl": "0.1.19", + "@napi-rs/simple-git-win32-arm64-msvc": "0.1.19", + "@napi-rs/simple-git-win32-x64-msvc": "0.1.19" } }, "node_modules/@napi-rs/simple-git-android-arm-eabi": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-android-arm-eabi/-/simple-git-android-arm-eabi-0.1.16.tgz", - "integrity": "sha512-dbrCL0Pl5KZG7x7tXdtVsA5CO6At5ohDX3myf5xIYn9kN4jDFxsocl8bNt6Vb/hZQoJd8fI+k5VlJt+rFhbdVw==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-android-arm-eabi/-/simple-git-android-arm-eabi-0.1.19.tgz", + "integrity": "sha512-XryEH/hadZ4Duk/HS/HC/cA1j0RHmqUGey3MsCf65ZS0VrWMqChXM/xlTPWuY5jfCc/rPubHaqI7DZlbexnX/g==", "cpu": [ "arm" ], @@ -629,9 +1342,9 @@ } }, "node_modules/@napi-rs/simple-git-android-arm64": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-android-arm64/-/simple-git-android-arm64-0.1.16.tgz", - "integrity": "sha512-xYz+TW5J09iK8SuTAKK2D5MMIsBUXVSs8nYp7HcMi8q6FCRO7yJj96YfP9PvKsc/k64hOyqGmL5DhCzY9Cu1FQ==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-android-arm64/-/simple-git-android-arm64-0.1.19.tgz", + "integrity": "sha512-ZQ0cPvY6nV9p7zrR9ZPo7hQBkDAcY/CHj3BjYNhykeUCiSNCrhvwX+WEeg5on8M1j4d5jcI/cwVG2FslfiByUg==", "cpu": [ "arm64" ], @@ -644,9 +1357,9 @@ } }, "node_modules/@napi-rs/simple-git-darwin-arm64": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-darwin-arm64/-/simple-git-darwin-arm64-0.1.16.tgz", - "integrity": "sha512-XfgsYqxhUE022MJobeiX563TJqyQyX4FmYCnqrtJwAfivESVeAJiH6bQIum8dDEYMHXCsG7nL8Ok0Dp8k2m42g==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-darwin-arm64/-/simple-git-darwin-arm64-0.1.19.tgz", + "integrity": "sha512-viZB5TYgjA1vH+QluhxZo0WKro3xBA+1xSzYx8mcxUMO5gnAoUMwXn0ZO/6Zy6pai+aGae+cj6XihGnrBRu3Pg==", "cpu": [ "arm64" ], @@ -659,9 +1372,9 @@ } }, "node_modules/@napi-rs/simple-git-darwin-x64": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-darwin-x64/-/simple-git-darwin-x64-0.1.16.tgz", - "integrity": "sha512-tkEVBhD6vgRCbeWsaAQqM3bTfpIVGeitamPPRVSbsq8qgzJ5Dx6ZedH27R7KSsA/uao7mZ3dsrNLXbu1Wy5MzA==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-darwin-x64/-/simple-git-darwin-x64-0.1.19.tgz", + "integrity": "sha512-6dNkzSNUV5X9rsVYQbpZLyJu4Gtkl2vNJ3abBXHX/Etk0ILG5ZasO3ncznIANZQpqcbn/QPHr49J2QYAXGoKJA==", "cpu": [ "x64" ], @@ -673,10 +1386,25 @@ "node": ">= 10" } }, + "node_modules/@napi-rs/simple-git-freebsd-x64": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-freebsd-x64/-/simple-git-freebsd-x64-0.1.19.tgz", + "integrity": "sha512-sB9krVIchzd20FjI2ZZ8FDsTSsXLBdnwJ6CpeVyrhXHnoszfcqxt49ocZHujAS9lMpXq7i2Nv1EXJmCy4KdhwA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@napi-rs/simple-git-linux-arm-gnueabihf": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm-gnueabihf/-/simple-git-linux-arm-gnueabihf-0.1.16.tgz", - "integrity": "sha512-R6VAyNnp/yRaT7DV1Ao3r67SqTWDa+fNq2LrNy0Z8gXk2wB9ZKlrxFtLPE1WSpWknWtyRDLpRlsorh7Evk7+7w==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm-gnueabihf/-/simple-git-linux-arm-gnueabihf-0.1.19.tgz", + "integrity": "sha512-6HPn09lr9N1n5/XKfP8Np53g4fEXVxOFqNkS6rTH3Rm1lZHdazTRH62RggXLTguZwjcE+MvOLvoTIoR5kAS8+g==", "cpu": [ "arm" ], @@ -689,9 +1417,9 @@ } }, "node_modules/@napi-rs/simple-git-linux-arm64-gnu": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm64-gnu/-/simple-git-linux-arm64-gnu-0.1.16.tgz", - "integrity": "sha512-LAGI0opFKw/HBMCV2qIBK3uWSEW9h4xd2ireZKLJy8DBPymX6NrWIamuxYNyCuACnFdPRxR4LaRFy4J5ZwuMdw==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm64-gnu/-/simple-git-linux-arm64-gnu-0.1.19.tgz", + "integrity": "sha512-G0gISckt4cVDp3oh5Z6PV3GHJrJO6Z8bIS+9xA7vTtKdqB1i5y0n3cSFLlzQciLzhr+CajFD27doW4lEyErQ/Q==", "cpu": [ "arm64" ], @@ -704,9 +1432,9 @@ } }, "node_modules/@napi-rs/simple-git-linux-arm64-musl": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm64-musl/-/simple-git-linux-arm64-musl-0.1.16.tgz", - "integrity": "sha512-I57Ph0F0Yn2KW93ep+V1EzKhACqX0x49vvSiapqIsdDA2PifdEWLc1LJarBolmK7NKoPqKmf6lAKKO9lhiZzkg==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-arm64-musl/-/simple-git-linux-arm64-musl-0.1.19.tgz", + "integrity": "sha512-OwTRF+H4IZYxmDFRi1IrLMfqbdIpvHeYbJl2X94NVsLVOY+3NUHvEzL3fYaVx5urBaMnIK0DD3wZLbcueWvxbA==", "cpu": [ "arm64" ], @@ -718,10 +1446,40 @@ "node": ">= 10" } }, + "node_modules/@napi-rs/simple-git-linux-powerpc64le-gnu": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-powerpc64le-gnu/-/simple-git-linux-powerpc64le-gnu-0.1.19.tgz", + "integrity": "sha512-p7zuNNVyzpRvkCt2RIGv9FX/WPcPbZ6/FRUgUTZkA2WU33mrbvNqSi4AOqCCl6mBvEd+EOw5NU4lS9ORRJvAEg==", + "cpu": [ + "powerpc64le" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/simple-git-linux-s390x-gnu": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-s390x-gnu/-/simple-git-linux-s390x-gnu-0.1.19.tgz", + "integrity": "sha512-6N2vwJUPLiak8GLrS0a3is0gSb0UwI2CHOOqtvQxPmv+JVI8kn3vKiUscsktdDb0wGEPeZ8PvZs0y8UWix7K4g==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@napi-rs/simple-git-linux-x64-gnu": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-x64-gnu/-/simple-git-linux-x64-gnu-0.1.16.tgz", - "integrity": "sha512-AZYYFY2V7hlcQASPEOWyOa3e1skzTct9QPzz0LiDM3f/hCFY/wBaU2M6NC5iG3d2Kr38heuyFS/+JqxLm5WaKA==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-x64-gnu/-/simple-git-linux-x64-gnu-0.1.19.tgz", + "integrity": "sha512-61YfeO1J13WK7MalLgP3QlV6of2rWnVw1aqxWkAgy/lGxoOFSJ4Wid6ANVCEZk4tJpPX/XNeneqkUz5xpeb2Cw==", "cpu": [ "x64" ], @@ -734,9 +1492,9 @@ } }, "node_modules/@napi-rs/simple-git-linux-x64-musl": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-x64-musl/-/simple-git-linux-x64-musl-0.1.16.tgz", - "integrity": "sha512-9TyMcYSBJwjT8jwjY9m24BZbu7ozyWTjsmYBYNtK3B0Um1Ov6jthSNneLVvouQ6x+k3Ow+00TiFh6bvmT00r8g==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-linux-x64-musl/-/simple-git-linux-x64-musl-0.1.19.tgz", + "integrity": "sha512-cCTWNpMJnN3PrUBItWcs3dQKCydsIasbrS3laMzq8k7OzF93Zrp2LWDTPlLCO9brbBVpBzy2Qk5Xg9uAfe/Ukw==", "cpu": [ "x64" ], @@ -749,9 +1507,9 @@ } }, "node_modules/@napi-rs/simple-git-win32-arm64-msvc": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-win32-arm64-msvc/-/simple-git-win32-arm64-msvc-0.1.16.tgz", - "integrity": "sha512-uslJ1WuAHCYJWui6xjsyT47SjX6KOHDtClmNO8hqKz1pmDSNY7AjyUY8HxvD1lK9bDnWwc4JYhikS9cxCqHybw==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-win32-arm64-msvc/-/simple-git-win32-arm64-msvc-0.1.19.tgz", + "integrity": "sha512-sWavb1BjeLKKBA+PbTsRSSzVNfb7V/dOpaJvkgR5d2kWFn/AHmCZHSSj/3nyZdYf0BdDC+DIvqk3daAEZ6QMVw==", "cpu": [ "arm64" ], @@ -764,9 +1522,9 @@ } }, "node_modules/@napi-rs/simple-git-win32-x64-msvc": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-win32-x64-msvc/-/simple-git-win32-x64-msvc-0.1.16.tgz", - "integrity": "sha512-SoEaVeCZCDF1MP+M9bMSXsZWgEjk4On9GWADO5JOulvzR1bKjk0s9PMHwe/YztR9F0sJzrCxwtvBZowhSJsQPg==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@napi-rs/simple-git-win32-x64-msvc/-/simple-git-win32-x64-msvc-0.1.19.tgz", + "integrity": "sha512-FmNuPoK4+qwaSCkp8lm3sJlrxk374enW+zCE5ZksXlZzj/9BDJAULJb5QUJ7o9Y8A/G+d8LkdQLPBE2Jaxe5XA==", "cpu": [ "x64" ], @@ -810,6 +1568,12 @@ "node": ">= 8" } }, + "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/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -820,9 +1584,66 @@ } }, "node_modules/@shikijs/core": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.6.0.tgz", - "integrity": "sha512-NIEAi5U5R7BLkbW1pG/ZKu3eb1lzc3/+jD0lFsuxMT7zjaf9bbNwdNyMr7zh/Zl8EXQtQ+MYBAt5G+JLu+5DlA==" + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.23.1.tgz", + "integrity": "sha512-NuOVgwcHgVC6jBVH5V7iblziw6iQbWWHrj5IlZI3Fqu2yx9awH7OIQkXIcsHsUmY19ckwSgUMgrqExEyP5A0TA==", + "dependencies": { + "@shikijs/engine-javascript": "1.23.1", + "@shikijs/engine-oniguruma": "1.23.1", + "@shikijs/types": "1.23.1", + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.3" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.23.1.tgz", + "integrity": "sha512-i/LdEwT5k3FVu07SiApRFwRcSJs5QM9+tod5vYCPig1Ywi8GR30zcujbxGQFJHwYD7A5BUqagi8o5KS+LEVgBg==", + "dependencies": { + "@shikijs/types": "1.23.1", + "@shikijs/vscode-textmate": "^9.3.0", + "oniguruma-to-es": "0.4.1" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.23.1.tgz", + "integrity": "sha512-KQ+lgeJJ5m2ISbUZudLR1qHeH3MnSs2mjFg7bnencgs5jDVPeJ2NVDJ3N5ZHbcTsOIh0qIueyAJnwg7lg7kwXQ==", + "dependencies": { + "@shikijs/types": "1.23.1", + "@shikijs/vscode-textmate": "^9.3.0" + } + }, + "node_modules/@shikijs/types": { + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.23.1.tgz", + "integrity": "sha512-98A5hGyEhzzAgQh2dAeHKrWW4HfCMeoFER2z16p5eJ+vmPeF6lZ/elEne6/UCU551F/WqkopqRsr1l2Yu6+A0g==", + "dependencies": { + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.3.0.tgz", + "integrity": "sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==" + }, + "node_modules/@shuding/opentype.js": { + "version": "1.4.0-beta.0", + "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", + "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==", + "license": "MIT", + "dependencies": { + "fflate": "^0.7.3", + "string.prototype.codepointat": "^0.2.1" + }, + "bin": { + "ot": "bin/ot" + }, + "engines": { + "node": ">= 8.0.0" + } }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", @@ -835,6 +1656,12 @@ "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/cli-spinner": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@types/cli-spinner/-/cli-spinner-0.2.3.tgz", @@ -844,11 +1671,16 @@ "@types/node": "*" } }, + "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": "*", @@ -885,14 +1717,12 @@ "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 + "integrity": "sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==" }, "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": "*" } @@ -901,7 +1731,6 @@ "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": "*" } @@ -909,20 +1738,17 @@ "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 + "integrity": "sha512-abT/iLHD3sGZwqMTX1TYCMEulr+wBd0SzyOQnjYNLp7sngdOHYtNkMRI5v3w5thoN+BWtlHVDx2Osvq6fxhZWw==" }, "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 + "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==" }, "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": "*" @@ -931,20 +1757,17 @@ "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 + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==" }, "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 + "integrity": "sha512-rxN6sHUXEZYCKV05MEh4z4WpPSqIw+aP7n9ZN6WYAAvZoEAghEK1WeVZMZcHRBwyaKflU43PCUAJNjFxCzPDjg==" }, "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": "*" } @@ -952,20 +1775,17 @@ "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 + "integrity": "sha512-76pBHCMTvPLt44wFOieouXcGXWOF0AJCceUvaFkxSZEu4VDUdv93JfpMa6VGNFs01FHfuP4a5Ou68eRG1KBfTw==" }, "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 + "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==" }, "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": "*" } @@ -973,20 +1793,17 @@ "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 + "integrity": "sha512-q7xbVLrWcXvSBBEoadowIUJ7sRpS1yvgMWnzHJggFy5cUZBq2HZL5k/pBSm0GdYWS1vs5/EDwMjSKF55PDY4Aw==" }, "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 + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==" }, "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": "*" } @@ -994,14 +1811,12 @@ "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 + "integrity": "sha512-9hjRTVoZjRFR6xo8igAJyNXQyPX6Aq++Nhb5ebrUF414dv4jr2MitM2fWiOY475wa3Za7TOS2Gh9fmqEhLTt0A==" }, "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": "*" } @@ -1009,32 +1824,27 @@ "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 + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==" }, "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 + "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==" }, "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 + "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==" }, "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 + "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==" }, "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": "*" } @@ -1042,20 +1852,17 @@ "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 + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==" }, "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 + "integrity": "sha512-xCB0z3Hi8eFIqyja3vW8iV01+OHGYR2di/+e+AiOcXIOrY82lcvWW8Ke1DYE/EUVMsBl4Db9RppSBS3X1U6J0w==" }, "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": "*" } @@ -1063,26 +1870,22 @@ "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 + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" }, "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 + "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==" }, "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 + "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==" }, "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": "*" } @@ -1091,7 +1894,6 @@ "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": "*" @@ -1105,6 +1907,21 @@ "@types/ms": "*" } }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, + "node_modules/@types/earcut": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.4.tgz", + "integrity": "sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -1121,8 +1938,7 @@ "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 + "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" }, "node_modules/@types/hast": { "version": "3.0.4", @@ -1162,20 +1978,20 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/nlcst": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-1.0.0.tgz", - "integrity": "sha512-3TGCfOcy8R8mMQ4CNSNOe3PG66HttvjcLzCoOpvXvDtfWOTi+uT/rxeOKm/qEwbM4SNe1O/PjdiBK2YcTjU4OQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", "dependencies": { "@types/unist": "*" } }, "node_modules/@types/node": { - "version": "20.12.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.5.tgz", - "integrity": "sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==", + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.8" } }, "node_modules/@types/pretty-time": { @@ -1193,24 +2009,30 @@ "source-map": "^0.6.0" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, "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==" }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -1227,6 +2049,33 @@ "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.44", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.44.tgz", + "integrity": "sha512-JDpYJN5E/asw84LTYhKyvPpxGnD+bAKPtpW9Ilurf7cZpxaTbxkQcGwOd7jgB9BPBrTYQ+32ufo4HiuomTjHNQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "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", @@ -1263,18 +2112,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1343,14 +2180,6 @@ "require-from-string": "^2.0.2" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "engines": { - "node": ">=8" - } - }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -1393,6 +2222,12 @@ "ieee754": "^1.1.13" } }, + "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==", + "peer": true + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1406,6 +2241,15 @@ "node": ">= 0.8" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -1462,27 +2306,44 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "license": "Apache-2.0", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dependencies": { + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" } }, "node_modules/citeproc": { @@ -1564,6 +2425,19 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1580,6 +2454,22 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "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==", + "peer": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1613,6 +2503,12 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "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==", + "license": "MIT" + }, "node_modules/content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -1621,6 +2517,15 @@ "node": ">= 0.6" } }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", @@ -1642,6 +2547,46 @@ "node": ">= 8" } }, + "node_modules/css-background-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz", + "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==", + "license": "MIT" + }, + "node_modules/css-box-shadow": { + "version": "1.0.0-3", + "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz", + "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==", + "license": "MIT" + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-gradient-parser": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/css-gradient-parser/-/css-gradient-parser-0.0.16.tgz", + "integrity": "sha512-3O5QdqgFRUbXvK1x5INf1YkBz1UKSWqrd63vWsum8MNHDBYD5urm3QtxZbKU259OrEXNM26lP/MPY3d1IGkBgA==", + "engines": { + "node": ">=16" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/css-tree": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", @@ -1665,6 +2610,54 @@ "node": ">=18" } }, + "node_modules/cytoscape": { + "version": "3.30.3", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.3.tgz", + "integrity": "sha512-HncJ9gGJbVtw7YXtIs3+6YAFSSiKsom0amWc33Z7QbylbY2JGMrA0yz4EwrdTScZxnwclXeEZHzO5pxoy0ZE4g==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" + }, "node_modules/d3": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", @@ -1926,6 +2919,46 @@ "node": ">=12" } }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, "node_modules/d3-scale": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", @@ -2035,6 +3068,16 @@ "node": ">=12" } }, + "node_modules/dagre-d3-es": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.11.tgz", + "integrity": "sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -2047,12 +3090,19 @@ "node": ">=18" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2127,6 +3177,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/dompurify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", + "license": "(MPL-2.0 OR Apache-2.0)" + }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", + "license": "ISC" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -2137,6 +3199,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "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==" + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -2149,52 +3216,70 @@ } }, "node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", + "integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" + "@esbuild/aix-ppc64": "0.24.0", + "@esbuild/android-arm": "0.24.0", + "@esbuild/android-arm64": "0.24.0", + "@esbuild/android-x64": "0.24.0", + "@esbuild/darwin-arm64": "0.24.0", + "@esbuild/darwin-x64": "0.24.0", + "@esbuild/freebsd-arm64": "0.24.0", + "@esbuild/freebsd-x64": "0.24.0", + "@esbuild/linux-arm": "0.24.0", + "@esbuild/linux-arm64": "0.24.0", + "@esbuild/linux-ia32": "0.24.0", + "@esbuild/linux-loong64": "0.24.0", + "@esbuild/linux-mips64el": "0.24.0", + "@esbuild/linux-ppc64": "0.24.0", + "@esbuild/linux-riscv64": "0.24.0", + "@esbuild/linux-s390x": "0.24.0", + "@esbuild/linux-x64": "0.24.0", + "@esbuild/netbsd-x64": "0.24.0", + "@esbuild/openbsd-arm64": "0.24.0", + "@esbuild/openbsd-x64": "0.24.0", + "@esbuild/sunos-x64": "0.24.0", + "@esbuild/win32-arm64": "0.24.0", + "@esbuild/win32-ia32": "0.24.0", + "@esbuild/win32-x64": "0.24.0" } }, "node_modules/esbuild-sass-plugin": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-2.16.1.tgz", - "integrity": "sha512-mBB2aEF0xk7yo+Q9pSUh8xYED/1O2wbAM6IauGkDrqy6pl9SbJNakLeLGXiNpNujWIudu8TJTZCv2L5AQYRXtA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-3.3.1.tgz", + "integrity": "sha512-SnO1ls+d52n6j8gRRpjexXI8MsHEaumS0IdDHaYM29Y6gakzZYMls6i9ql9+AWMSQk/eryndmUpXEgT34QrX1A==", "dependencies": { - "resolve": "^1.22.6", - "sass": "^1.7.3" + "resolve": "^1.22.8", + "safe-identifier": "^0.4.2", + "sass": "^1.71.1" }, "peerDependencies": { - "esbuild": "^0.19.4" + "esbuild": ">=0.20.1", + "sass-embedded": "^1.71.1" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz", + "integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/escalade": { @@ -2205,6 +3290,12 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", @@ -2245,6 +3336,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2276,14 +3373,6 @@ "node": ">=8.6.0" } }, - "node_modules/fast-url-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", - "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", - "dependencies": { - "punycode": "^1.3.2" - } - }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -2350,6 +3439,12 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/fflate": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", + "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2367,9 +3462,9 @@ "integrity": "sha512-c5o/+Um8aqCSOXGcZoqZOm+NqtVwNsvVpWv6lfmSclU954O3wvQKxxK8zj74fPaSJbXpSLTs4PRhh+wnoCXnKg==" }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -2406,6 +3501,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -2432,9 +3528,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.4.tgz", - "integrity": "sha512-ofbkKj+0pjXjhejr007J/fLf+sW+8H7K5GCm+msC8q3IpvgjobpyPqSRFemNyIMxklC0zeJpi7VDFna19FacvQ==", + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -2449,21 +3545,22 @@ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" }, "node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2481,9 +3578,9 @@ } }, "node_modules/globby": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", - "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.2", @@ -2533,6 +3630,21 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", @@ -2710,15 +3822,14 @@ "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, "node_modules/hast-util-to-html": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.1.tgz", - "integrity": "sha512-hZOofyZANbyWo+9RP75xIDV/gq+OUKx+T46IlwERnKmfpwp81XBFbT9mi26ws+SJchA4RVUQwIBJpqEOBhMzEQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz", + "integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", - "hast-util-raw": "^9.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", @@ -2738,9 +3849,9 @@ "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", - "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz", + "integrity": "sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==", "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", @@ -2812,9 +3923,9 @@ } }, "node_modules/hast-util-to-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", - "integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==", + "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==", "dependencies": { "@types/hast": "^3.0.0" }, @@ -2871,6 +3982,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hex-rgb": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz", + "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -2954,9 +4077,9 @@ } }, "node_modules/immutable": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.3.tgz", - "integrity": "sha512-808ZFYMsIRAjLAu5xkKo0TsbY9LBy9H5MazTKIEHerNkg0ymgilGfBPMR/3G7d/ihGmuK2Hw8S1izY2d3kd3wA==" + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==" }, "node_modules/inline-style-parser": { "version": "0.2.2", @@ -3004,38 +4127,11 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" }, "node_modules/is-core-module": { "version": "2.13.1", @@ -3130,15 +4226,21 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/ismobilejs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", + "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==", + "license": "MIT" + }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">=14" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3198,13 +4300,14 @@ } }, "node_modules/katex": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.8.tgz", - "integrity": "sha512-ftuDnJbcbOckGY11OO+zg3OofESlbR5DRl2cmN8HeWeeFIV7wTXvAOx8kEjZjobhA+9wh2fbKeO6cdcA9Mnovg==", + "version": "0.16.11", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", + "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" ], + "license": "MIT", "dependencies": { "commander": "^8.3.0" }, @@ -3220,6 +4323,11 @@ "node": ">= 12" } }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -3228,10 +4336,38 @@ "node": ">=0.10.0" } }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "license": "MIT" + }, + "node_modules/langium": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.0.0.tgz", + "integrity": "sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg==", + "license": "MIT", + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, "node_modules/lightningcss": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.24.1.tgz", - "integrity": "sha512-kUpHOLiH5GB0ERSv4pxqlL0RYKnOXtgGtVe7shDGfhS0AZ4D1ouKFYAcLcZhql8aMspDNzaUCumGHZ78tb2fTg==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.28.1.tgz", + "integrity": "sha512-KRDkHlLlNj3DWh79CDt93fPlRJh2W1AuHV0ZSZAMMuN7lqlsZTV5842idfS1urWG8q9tc17velp1gCXhY7sLnQ==", "dependencies": { "detect-libc": "^1.0.3" }, @@ -3243,21 +4379,22 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.24.1", - "lightningcss-darwin-x64": "1.24.1", - "lightningcss-freebsd-x64": "1.24.1", - "lightningcss-linux-arm-gnueabihf": "1.24.1", - "lightningcss-linux-arm64-gnu": "1.24.1", - "lightningcss-linux-arm64-musl": "1.24.1", - "lightningcss-linux-x64-gnu": "1.24.1", - "lightningcss-linux-x64-musl": "1.24.1", - "lightningcss-win32-x64-msvc": "1.24.1" + "lightningcss-darwin-arm64": "1.28.1", + "lightningcss-darwin-x64": "1.28.1", + "lightningcss-freebsd-x64": "1.28.1", + "lightningcss-linux-arm-gnueabihf": "1.28.1", + "lightningcss-linux-arm64-gnu": "1.28.1", + "lightningcss-linux-arm64-musl": "1.28.1", + "lightningcss-linux-x64-gnu": "1.28.1", + "lightningcss-linux-x64-musl": "1.28.1", + "lightningcss-win32-arm64-msvc": "1.28.1", + "lightningcss-win32-x64-msvc": "1.28.1" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.24.1.tgz", - "integrity": "sha512-1jQ12jBy+AE/73uGQWGSafK5GoWgmSiIQOGhSEXiFJSZxzV+OXIx+a9h2EYHxdJfX864M+2TAxWPWb0Vv+8y4w==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.28.1.tgz", + "integrity": "sha512-VG3vvzM0m/rguCdm76DdobNeNJnHK+jWcdkNLFWHLh9YCotRvbRIt45JxwcHlIF8TDqWStVLTdghq5NaigVCBQ==", "cpu": [ "arm64" ], @@ -3274,9 +4411,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.24.1.tgz", - "integrity": "sha512-R4R1d7VVdq2mG4igMU+Di8GPf0b64ZLnYVkubYnGG0Qxq1KaXQtAzcLI43EkpnoWvB/kUg8JKCWH4S13NfiLcQ==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.28.1.tgz", + "integrity": "sha512-O7ORdislvKfMohFl4Iq7fxKqdJOuuxArcglVI3amuFO5DJ0wfV3Gxgi1JRo49slfr7OVzJQEHLG4muTWYM5cTQ==", "cpu": [ "x64" ], @@ -3293,9 +4430,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.24.1.tgz", - "integrity": "sha512-z6NberUUw5ALES6Ixn2shmjRRrM1cmEn1ZQPiM5IrZ6xHHL5a1lPin9pRv+w6eWfcrEo+qGG6R9XfJrpuY3e4g==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.28.1.tgz", + "integrity": "sha512-b7sF89B31kYYijxVcFO7l5u6UNA862YstNu+3YbLl/IQKzveL4a5cwR5cdpG+OOhErg/c2u9WCmzZoX2I5GBvw==", "cpu": [ "x64" ], @@ -3312,9 +4449,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.24.1.tgz", - "integrity": "sha512-NLQLnBQW/0sSg74qLNI8F8QKQXkNg4/ukSTa+XhtkO7v3BnK19TS1MfCbDHt+TTdSgNEBv0tubRuapcKho2EWw==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.28.1.tgz", + "integrity": "sha512-p61kXwvhUDLLzkWHjzSFfUBW/F0iy3jr3CWi3k8SKULtJEsJXTI9DqRm9EixxMSe2AMBQBt4auTYiQL4B1N51A==", "cpu": [ "arm" ], @@ -3331,9 +4468,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.24.1.tgz", - "integrity": "sha512-AQxWU8c9E9JAjAi4Qw9CvX2tDIPjgzCTrZCSXKELfs4mCwzxRkHh2RCxX8sFK19RyJoJAjA/Kw8+LMNRHS5qEg==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.28.1.tgz", + "integrity": "sha512-iO+fN9hOMmzfwqcG2/BgUtMKD48H2JO/SXU44fyIwpY2veb65QF5xiRrQ9l1FwIxbGK3231KBYCtAqv+xf+NsQ==", "cpu": [ "arm64" ], @@ -3350,9 +4487,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.24.1.tgz", - "integrity": "sha512-JCgH/SrNrhqsguUA0uJUM1PvN5+dVuzPIlXcoWDHSv2OU/BWlj2dUYr3XNzEw748SmNZPfl2NjQrAdzaPOn1lA==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.28.1.tgz", + "integrity": "sha512-dnMHeXEmCUzHHZjaDpQBYuBKcN9nPC3nPFKl70bcj5Bkn5EmkcgEqm5p035LKOgvAwk1XwLpQCML6pXmCwz0NQ==", "cpu": [ "arm64" ], @@ -3369,9 +4506,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.24.1.tgz", - "integrity": "sha512-TYdEsC63bHV0h47aNRGN3RiK7aIeco3/keN4NkoSQ5T8xk09KHuBdySltWAvKLgT8JvR+ayzq8ZHnL1wKWY0rw==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.28.1.tgz", + "integrity": "sha512-7vWDISaMUn+oo2TwRdf2hl/BLdPxvywv9JKEqNZB/0K7bXwV4XE9wN/C2sAp1gGuh6QBA8lpjF4JIPt3HNlCHA==", "cpu": [ "x64" ], @@ -3388,9 +4525,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.24.1.tgz", - "integrity": "sha512-HLfzVik3RToot6pQ2Rgc3JhfZkGi01hFetHt40HrUMoeKitLoqUUT5owM6yTZPTytTUW9ukLBJ1pc3XNMSvlLw==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.28.1.tgz", + "integrity": "sha512-IHCu9tVGP+x5BCpA2rF3D04DBokcBza/a8AuHQU+1AiMKubuMegPwcL7RatBgK4ztFHeYnnD5NdhwhRfYMAtNA==", "cpu": [ "x64" ], @@ -3406,10 +4543,29 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.28.1.tgz", + "integrity": "sha512-Erm72kHmMg/3h350PTseskz+eEGBM17Fuu79WW2Qqt0BfWSF1jHHc12lkJCWMYl5jcBHPs5yZdgNHtJ7IJS3Uw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.24.1.tgz", - "integrity": "sha512-joEupPjYJ7PjZtDsS5lzALtlAudAbgIBMGJPNeFe5HfdmJXFd13ECmEM+5rXNxYVMRHua2w8132R6ab5Z6K9Ow==", + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.28.1.tgz", + "integrity": "sha512-ZPQtvx+uQBzrSdHH8p4H3M9Alue+x369TPZAA3b4K3d92FPhpZCuBG04+HQzspam9sVeID9mI6f3VRAs2ezaEA==", "cpu": [ "x64" ], @@ -3425,6 +4581,47 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linebreak": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", + "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", + "license": "MIT", + "dependencies": { + "base64-js": "0.0.8", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/linebreak/node_modules/base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "license": "MIT", + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -3435,11 +4632,11 @@ } }, "node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", "engines": { - "node": "14 || >=16.14" + "node": "20 || >=22" } }, "node_modules/markdown-table": { @@ -3451,6 +4648,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz", + "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/mathjax-full": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz", @@ -3477,36 +4686,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-find-and-replace/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-find-and-replace/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==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace/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==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "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", @@ -3791,27 +4970,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-phrasing/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-phrasing/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==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/mdast-util-to-hast": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz", - "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -3877,6 +5039,35 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.4.0.tgz", + "integrity": "sha512-mxCfEYvADJqOiHfGpJXLs4/fAjHz448rH0pfY5fAoxiz70rQiDSzUUy4dNET2T08i46IVpjohPd6WWbzmRHiPA==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.0.1", + "@iconify/utils": "^2.1.32", + "@mermaid-js/parser": "^0.3.0", + "@types/d3": "^7.4.3", + "@types/dompurify": "^3.0.5", + "cytoscape": "^3.29.2", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.11", + "dayjs": "^1.11.10", + "dompurify": "^3.0.11 <3.1.7", + "katex": "^0.16.9", + "khroma": "^2.1.0", + "lodash-es": "^4.17.21", + "marked": "^13.0.2", + "roughjs": "^4.6.6", + "stylis": "^4.3.1", + "ts-dedent": "^2.2.0", + "uuid": "^9.0.1" + } + }, "node_modules/mhchemparser": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz", @@ -4487,23 +5678,23 @@ } }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "engines": { "node": ">=16 || 14 >=14.17" } @@ -4513,22 +5704,35 @@ "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" }, + "node_modules/mlly": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.2.tgz", + "integrity": "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.12.1", + "pathe": "^1.1.2", + "pkg-types": "^1.2.0", + "ufo": "^1.5.4" + } + }, "node_modules/moo": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/nlcst-to-string": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.1.tgz", - "integrity": "sha512-63mVyqaqt0cmn2VcI2aH6kxe1rLAmSROqHMA0i4qqg1tidkfExgpb0FGMikMCn86mw5dFtBtEANfmSSK7TjNHw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", "dependencies": { - "@types/nlcst": "^1.0.0" + "@types/nlcst": "^2.0.0" }, "funding": { "type": "opencollective", @@ -4573,12 +5777,41 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" + "node_modules/oniguruma-to-es": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-0.4.1.tgz", + "integrity": "sha512-rNcEohFz095QKGRovP/yqPIKc+nP+Sjs4YTHMv33nMePGKrq/r2eu9Yh4646M5XluGJsUnmwoXuiXE69KDs+fQ==", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^5.0.0", + "regex-recursion": "^4.2.1" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, + "node_modules/package-manager-detector": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.2.tgz", + "integrity": "sha512-VgXbyrSNsml4eHWIvxxG/nTL4wgybMTXCV2Un/+yEc3aDKKU6nQBZjbeP3Pl3qm9Qg92X/1ng4ffvCeD/zwHgg==", + "license": "MIT" + }, + "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/parse-css-color": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/parse-css-color/-/parse-css-color-0.2.1.tgz", + "integrity": "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.1.4", + "hex-rgb": "^4.1.0" } }, "node_modules/parse-entities": { @@ -4601,24 +5834,38 @@ } }, "node_modules/parse-latin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-5.0.1.tgz", - "integrity": "sha512-b/K8ExXaWC9t34kKeDV8kGXBkXZ1HCSAZRYE7HR14eA1GlXX5L8iWhs8USJNhQU9q5ci413jCKF0gOyovvyRBg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", "dependencies": { - "nlcst-to-string": "^3.0.0", - "unist-util-modify-children": "^3.0.0", - "unist-util-visit-children": "^2.0.0" + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "github", "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" + }, "node_modules/parse5": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", @@ -4630,6 +5877,12 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, "node_modules/path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", @@ -4649,24 +5902,24 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-to-regexp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + "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==" }, "node_modules/path-type": { "version": "5.0.0", @@ -4679,10 +5932,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4695,30 +5954,76 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pixi.js": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.5.2.tgz", + "integrity": "sha512-TOt9g8ifOj4R9DN9ST1M8t2nvnuhr5oWL5YW9ywFLbnOVgFMDcEz+Xek5Mo8Xr64D+QU3qre3IFgreBlsHxTNw==", + "dependencies": { + "@pixi/colord": "^2.9.6", + "@types/css-font-loading-module": "^0.0.12", + "@types/earcut": "^2.1.4", + "@webgpu/types": "^0.1.40", + "@xmldom/xmldom": "^0.8.10", + "earcut": "^2.2.4", + "eventemitter3": "^5.0.1", + "ismobilejs": "^1.1.1", + "parse-svg-path": "^0.1.2" + } + }, + "node_modules/pkg-types": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz", + "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.2", + "pathe": "^1.1.2" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/preact": { - "version": "10.20.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.20.1.tgz", - "integrity": "sha512-JIFjgFg9B2qnOoGiYMVBtrcFxHqn+dNXbq76bVmcaHYJFYR4lW67AOcXgAYQQTDYXDOg/kTZrKPNCdRgJ2UJmw==", + "version": "10.24.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", + "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" } }, "node_modules/preact-render-to-string": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.4.2.tgz", - "integrity": "sha512-Sio5SvlyZSAXHuvnMgYzVQd67lNIuQe4uSjJ+2gfpJNC6L8zoHQR5xV7B/EjIqrAYWVyJ2eACkTCxVrIzZi6Vw==", - "dependencies": { - "pretty-format": "^3.8.0" - }, + "version": "6.5.11", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz", + "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==", "peerDependencies": { "preact": ">=10" } }, "node_modules/prettier": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz", - "integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -4741,11 +6046,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pretty-format": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", - "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" - }, "node_modules/pretty-time": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", @@ -4768,11 +6068,6 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -4806,14 +6101,15 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", "engines": { - "node": ">=8.10.0" + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/reading-time": { @@ -4821,6 +6117,27 @@ "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" }, + "node_modules/regex": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/regex/-/regex-5.0.2.tgz", + "integrity": "sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-4.2.1.tgz", + "integrity": "sha512-QHNZyZAeKdndD1G3bKAbBEKOSSK4KOHQrAJ01N1LJeb0SoH4DJIeFhp0uUpETgONifS4+P3sOgoA1dhzgrQvhA==", + "dependencies": { + "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==" + }, "node_modules/rehype-autolink-headings": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz", @@ -4839,16 +6156,16 @@ } }, "node_modules/rehype-citation": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/rehype-citation/-/rehype-citation-2.0.0.tgz", - "integrity": "sha512-rGawTBI8SJA1Y4IRyROvpYF6oXBVNFXlJYHIJ2jJH3HgeuCbAC9AO8wE/NMPLDOPQ8+Q8QkZm93fKsnUNbvwZA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/rehype-citation/-/rehype-citation-2.2.2.tgz", + "integrity": "sha512-a9+njSn4yJ3/bePz+T8AkCLXhSb3fK+HKlG9xEcLJraN3W92jGV91a10XEvSy6gJ5BvRdtDtu3aEd1uqvNDHRQ==", "dependencies": { - "@citation-js/core": "^0.7.1", + "@citation-js/core": "^0.7.14", "@citation-js/date": "^0.5.1", "@citation-js/name": "^0.4.2", - "@citation-js/plugin-bibjson": "^0.7.2", - "@citation-js/plugin-bibtex": "^0.7.2", - "@citation-js/plugin-csl": "^0.7.2", + "@citation-js/plugin-bibjson": "^0.7.14", + "@citation-js/plugin-bibtex": "^0.7.14", + "@citation-js/plugin-csl": "^0.7.14", "citeproc": "^2.4.63", "cross-fetch": "^4.0.0", "hast-util-from-dom": "^5.0.0", @@ -4860,9 +6177,9 @@ } }, "node_modules/rehype-katex": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.0.tgz", - "integrity": "sha512-h8FPkGE00r2XKU+/acgqwWUlyzve1IiOKwsEkg4pDL3k48PiE0Pt+/uLtVHDVkN1yA4iurZN6UES8ivHVEQV6Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", "dependencies": { "@types/hast": "^3.0.0", "@types/katex": "^0.16.0", @@ -4877,36 +6194,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-katex/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/rehype-katex/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==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-katex/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==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/rehype-mathjax": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/rehype-mathjax/-/rehype-mathjax-6.0.0.tgz", @@ -4926,36 +6213,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-mathjax/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/rehype-mathjax/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==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-mathjax/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==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.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", @@ -4971,22 +6228,22 @@ } }, "node_modules/rehype-pretty-code": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/rehype-pretty-code/-/rehype-pretty-code-0.13.0.tgz", - "integrity": "sha512-+22dz1StXlF7dlMyOySNaVxgcGhMI4BCxq0JxJJPWYGiKsI6cu5jyuIKGHXHvH18D8sv1rdKtvsY9UEfN3++SQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/rehype-pretty-code/-/rehype-pretty-code-0.14.0.tgz", + "integrity": "sha512-hBeKF/Wkkf3zyUS8lal9RCUuhypDWLQc+h9UrP9Pav25FUm/AQAVh4m5gdvJxh4Oz+U+xKvdsV01p1LdvsZTiQ==", "dependencies": { "@types/hast": "^3.0.4", "hast-util-to-string": "^3.0.0", "parse-numeric-range": "^1.3.0", "rehype-parse": "^9.0.0", - "unified": "^11.0.4", + "unified": "^11.0.5", "unist-util-visit": "^5.0.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "shiki": "^1.0.0" + "shiki": "^1.3.0" } }, "node_modules/rehype-raw": { @@ -5111,9 +6368,9 @@ } }, "node_modules/remark-rehype": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", - "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -5127,16 +6384,17 @@ } }, "node_modules/remark-smartypants": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-2.1.0.tgz", - "integrity": "sha512-qoF6Vz3BjU2tP6OfZqHOvCU0ACmu/6jhGaINSQRI9mM7wCxNQTKB3JUAN4SVoN2ybElEDTxBIABRep7e569iJw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", "dependencies": { - "retext": "^8.1.0", - "retext-smartypants": "^5.2.0", + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", "unist-util-visit": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=16.0.0" } }, "node_modules/remark-stringify": { @@ -5200,14 +6458,14 @@ } }, "node_modules/retext": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/retext/-/retext-8.1.0.tgz", - "integrity": "sha512-N9/Kq7YTn6ZpzfiGW45WfEGJqFf1IM1q8OsRa1CGzIebCJBNCANDRmOrholiDRGKo/We7ofKR4SEvcGAWEMD3Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", "dependencies": { - "@types/nlcst": "^1.0.0", - "retext-latin": "^3.0.0", - "retext-stringify": "^3.0.0", - "unified": "^10.0.0" + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" }, "funding": { "type": "opencollective", @@ -5215,47 +6473,13 @@ } }, "node_modules/retext-latin": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-3.1.0.tgz", - "integrity": "sha512-5MrD1tuebzO8ppsja5eEu+ZbBeUNCjoEarn70tkXOS7Bdsdf6tNahsv2bY0Z8VooFF6cw7/6S+d3yI/TMlMVVQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", "dependencies": { - "@types/nlcst": "^1.0.0", - "parse-latin": "^5.0.0", - "unherit": "^3.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-latin/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-latin/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" }, "funding": { "type": "opencollective", @@ -5263,61 +6487,13 @@ } }, "node_modules/retext-smartypants": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-5.2.0.tgz", - "integrity": "sha512-Do8oM+SsjrbzT2UNIKgheP0hgUQTDDQYyZaIY3kfq0pdFzoPk+ZClYJ+OERNXveog4xf1pZL4PfRxNoVL7a/jw==", + "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==", "dependencies": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/unist-util-visit": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", - "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" }, "funding": { "type": "opencollective", @@ -5325,79 +6501,13 @@ } }, "node_modules/retext-stringify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-3.1.0.tgz", - "integrity": "sha512-767TLOaoXFXyOnjx/EggXlb37ZD2u4P1n0GJqVdpipqACsQP+20W+BNpMYrlJkq7hxffnFk+jc6mAK9qrbuB8w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", "dependencies": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-stringify/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-stringify/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" }, "funding": { "type": "opencollective", @@ -5414,22 +6524,23 @@ } }, "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" }, "node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dependencies": { - "glob": "^10.3.7" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "bin": { "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14.18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5440,6 +6551,18 @@ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, "node_modules/rrweb-cssom": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", @@ -5472,17 +6595,31 @@ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==" + }, "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/sass": { - "version": "1.66.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz", - "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==", + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.4.tgz", + "integrity": "sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", + "chokidar": "^4.0.0", "immutable": "^4.0.0", "source-map-js": ">=0.6.2 <2.0.0" }, @@ -5493,6 +6630,396 @@ "node": ">=14.0.0" } }, + "node_modules/sass-embedded": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.79.4.tgz", + "integrity": "sha512-3AATrtStMgxYjkit02/Ix8vx/P7qderYG6DHjmehfk5jiw53OaWVScmcGJSwp/d77kAkxDQ+Y0r+79VynGmrkw==", + "peer": true, + "dependencies": { + "@bufbuild/protobuf": "^2.0.0", + "buffer-builder": "^0.2.0", + "colorjs.io": "^0.5.0", + "immutable": "^4.0.0", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "sass-embedded-android-arm": "1.79.4", + "sass-embedded-android-arm64": "1.79.4", + "sass-embedded-android-ia32": "1.79.4", + "sass-embedded-android-riscv64": "1.79.4", + "sass-embedded-android-x64": "1.79.4", + "sass-embedded-darwin-arm64": "1.79.4", + "sass-embedded-darwin-x64": "1.79.4", + "sass-embedded-linux-arm": "1.79.4", + "sass-embedded-linux-arm64": "1.79.4", + "sass-embedded-linux-ia32": "1.79.4", + "sass-embedded-linux-musl-arm": "1.79.4", + "sass-embedded-linux-musl-arm64": "1.79.4", + "sass-embedded-linux-musl-ia32": "1.79.4", + "sass-embedded-linux-musl-riscv64": "1.79.4", + "sass-embedded-linux-musl-x64": "1.79.4", + "sass-embedded-linux-riscv64": "1.79.4", + "sass-embedded-linux-x64": "1.79.4", + "sass-embedded-win32-arm64": "1.79.4", + "sass-embedded-win32-ia32": "1.79.4", + "sass-embedded-win32-x64": "1.79.4" + } + }, + "node_modules/sass-embedded-android-arm": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.79.4.tgz", + "integrity": "sha512-YOVpDGDcwWUQvktpJhYo4zOkknDpdX6ALpaeHDTX6GBUvnZfx+Widh76v+QFUhiJQ/I/hndXg1jv/PKilOHRrw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-arm64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.79.4.tgz", + "integrity": "sha512-0JAZ8TtXYv9yI3Yasaq03xvo7DLJOmD+Exb30oJKxXcWTAV9TB0ZWKoIRsFxbCyPxyn7ouxkaCEXQtaTRKrmfw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-ia32": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.79.4.tgz", + "integrity": "sha512-IjO3RoyvNN84ZyfAR5s/a8TIdNPfClb7CLGrswB3BN/NElYIJUJMVHD6+Y8W9QwBIZ8DrK1IdLFSTV8nn82xMA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-riscv64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.79.4.tgz", + "integrity": "sha512-uOT8nXmKxSwuIdcqvElVWBFcm/+YcIvmwfoKbpuuSOSxUe9eqFzxo+fk7ILhynzf6FBlvRUH5DcjGj+sXtCc3w==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-x64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.79.4.tgz", + "integrity": "sha512-W2FQoj3Z2J2DirNs3xSBVvrhMuqLnsqvOPulxOkhL/074+faKOZZnPx2tZ5zsHbY97SonciiU0SV0mm98xI42w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.79.4.tgz", + "integrity": "sha512-pcYtbN1VUAAcfgyHeX8ySndDWGjIvcq6rldduktPbGGuAlEWFDfnwjTbv0hS945ggdzZ6TFnaFlLEDr0SjKzBA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-x64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.79.4.tgz", + "integrity": "sha512-ir8CFTfc4JLx/qCP8LK1/3pWv35nRyAQkUK7lBIKM6hWzztt64gcno9rZIk4SpHr7Z/Bp1IYWWRS4ZT+4HmsbA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.79.4.tgz", + "integrity": "sha512-H/XEE3rY7c+tY0qDaELjPjC6VheAhBo1tPJQ6UHoBEf8xrbT/RT3dWiIS8grp9Vk54RCn05BEB/+POaljvvKGA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.79.4.tgz", + "integrity": "sha512-XIVn2mCuA422SR2kmKjF6jhjMs1Vrt1DbZ/ktSp+eR0sU4ugu2htg45GajiUFSKKRj7Sc+cBdThq1zPPsDLf1w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-ia32": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.79.4.tgz", + "integrity": "sha512-3nqZxV4nuUTb1ahLexVl4hsnx1KKwiGdHEf1xHWTZai6fYFMcwyNPrHySCQzFHqb5xiqSpPzzrKjuDhF6+guuQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.79.4.tgz", + "integrity": "sha512-HnbU1DEiQdUayioNzxh2WlbTEgQRBPTgIIvof8J63QLmVItUqE7EkWYkSUy4RhO+8NsuN9wzGmGTzFBvTImU7g==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.79.4.tgz", + "integrity": "sha512-C6qX06waPEfDgOHR8jXoYxl0EtIXOyBDyyonrLO3StRjWjGx7XMQj2hA/KXSsV+Hr71fBOsaViosqWXPzTbEiQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-ia32": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.79.4.tgz", + "integrity": "sha512-y5b0fdOPWyhj4c+mc88GvQiC5onRH1V0iNaWNjsiZ+L4hHje6T98nDLrCJn0fz5GQnXjyLCLZduMWbfV0QjHGg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.79.4.tgz", + "integrity": "sha512-G2M5ADMV9SqnkwpM0S+UzDz7xR2njCOhofku/sDMZABzAjQQWTsAykKoGmzlT98fTw2HbNhb6u74umf2WLhCfw==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.79.4.tgz", + "integrity": "sha512-kQm8dCU3DXf7DtUGWYPiPs03KJYKvFeiZJHhSx993DCM8D2b0wCXWky0S0Z46gf1sEur0SN4Lvnt1WczTqxIBw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.79.4.tgz", + "integrity": "sha512-GaTI/mXYWYSzG5wxtM4H2cozLpATyh+4l+rO9FFKOL8e1sUOLAzTeRdU2nSBYCuRqsxRuTZIwCXhSz9Q3NRuNA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-x64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.79.4.tgz", + "integrity": "sha512-f9laGkqHgC01h99Qt4LsOV+OLMffjvUcTu14hYWqMS9QVX5a4ihMwpf1NoAtTUytb7cVF3rYY/NVGuXt6G3ppQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-arm64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.79.4.tgz", + "integrity": "sha512-cidBvtaA2cJ6dNlwQEa8qak+ezypurzKs0h0QAHLH324+j/6Jum7LCnQhZRPYJBFjHl+WYd7KwzPnJ2X5USWnQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-ia32": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.79.4.tgz", + "integrity": "sha512-hexdmNTIZGTKNTzlMcdvEXzYuxOJcY89zqgsf45aQ2YMy4y2M8dTOxRI/Vz7p4iRxVp1Jow6LCtaLHrNI2Ordg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-x64": { + "version": "1.79.4", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.79.4.tgz", + "integrity": "sha512-73yrpiWIbti6DkxhWURklkgSLYKfU9itDmvHxB+oYSb4vQveIApqTwSyTOuIUb/6Da/EsgEpdJ4Lbj4sLaMZWA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/satori": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/satori/-/satori-0.11.3.tgz", + "integrity": "sha512-Wg7sls0iYAEETzi9YYcY16QVIqXjZT06XjkwondC5CGhw1mhmgKBCub8cCmkxdl/naXXQD+m29CFgn8pwtYCnA==", + "dependencies": { + "@shuding/opentype.js": "1.4.0-beta.0", + "css-background-parser": "^0.1.0", + "css-box-shadow": "1.0.0-3", + "css-gradient-parser": "^0.0.16", + "css-to-react-native": "^3.0.0", + "emoji-regex": "^10.2.1", + "escape-html": "^1.0.3", + "linebreak": "^1.1.0", + "parse-css-color": "^0.2.1", + "postcss-value-parser": "^4.2.0", + "yoga-wasm-web": "^0.3.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/satori/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==", + "license": "MIT" + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -5516,18 +7043,29 @@ "node": ">=4" } }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/serve-handler": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", - "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "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==", "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", - "fast-url-parser": "1.1.3", "mime-types": "2.1.18", "minimatch": "3.1.2", "path-is-inside": "1.0.2", - "path-to-regexp": "2.2.1", + "path-to-regexp": "3.3.0", "range-parser": "1.2.0" } }, @@ -5551,6 +7089,54 @@ "node": "*" } }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/sharp/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5571,11 +7157,16 @@ } }, "node_modules/shiki": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.6.0.tgz", - "integrity": "sha512-P31ROeXcVgW/k3Z+vUUErcxoTah7ZRaimctOpzGuqAntqnnSmx1HOsvnbAB8Z2qfXPRhw61yptAzCsuKOhTHwQ==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.23.1.tgz", + "integrity": "sha512-8kxV9TH4pXgdKGxNOkrSMydn1Xf6It8lsle0fiqxf7a1149K1WGtdOu3Zb91T5r1JpvRPxqxU3C2XdZZXQnrig==", "dependencies": { - "@shikijs/core": "1.6.0" + "@shikijs/core": "1.23.1", + "@shikijs/engine-javascript": "1.23.1", + "@shikijs/engine-oniguruma": "1.23.1", + "@shikijs/types": "1.23.1", + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4" } }, "node_modules/signal-exit": { @@ -5589,6 +7180,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -5719,6 +7319,12 @@ "node": ">=8" } }, + "node_modules/string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==", + "license": "MIT" + }, "node_modules/stringify-entities": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", @@ -5782,6 +7388,27 @@ "inline-style-parser": "0.2.2" } }, + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -5810,6 +7437,18 @@ "node": ">=14" } }, + "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/tinyexec": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", + "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5897,19 +7536,28 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tsx": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.9.3.tgz", - "integrity": "sha512-czVbetlILiyJZI5zGlj2kw9vFiSeyra9liPD4nG+Thh4pKTi0AmMEQ8zdV/L2xbIVKrIqif4sUNrsMAOksx9Zg==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", "dev": true, "dependencies": { - "esbuild": "~0.20.2", - "get-tsconfig": "^4.7.3" + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" }, "bin": { "tsx": "dist/cli.mjs" @@ -5922,9 +7570,9 @@ } }, "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", "cpu": [ "ppc64" ], @@ -5934,13 +7582,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", "cpu": [ "arm" ], @@ -5950,13 +7598,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", "cpu": [ "arm64" ], @@ -5966,13 +7614,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", "cpu": [ "x64" ], @@ -5982,13 +7630,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", "cpu": [ "arm64" ], @@ -5998,13 +7646,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", "cpu": [ "x64" ], @@ -6014,13 +7662,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", "cpu": [ "arm64" ], @@ -6030,13 +7678,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", "cpu": [ "x64" ], @@ -6046,13 +7694,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", "cpu": [ "arm" ], @@ -6062,13 +7710,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", "cpu": [ "arm64" ], @@ -6078,13 +7726,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", "cpu": [ "ia32" ], @@ -6094,13 +7742,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", "cpu": [ "loong64" ], @@ -6110,13 +7758,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", "cpu": [ "mips64el" ], @@ -6126,13 +7774,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", "cpu": [ "ppc64" ], @@ -6142,13 +7790,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", "cpu": [ "riscv64" ], @@ -6158,13 +7806,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", "cpu": [ "s390x" ], @@ -6174,13 +7822,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", "cpu": [ "x64" ], @@ -6190,13 +7838,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", "cpu": [ "x64" ], @@ -6206,13 +7854,13 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", "cpu": [ "x64" ], @@ -6222,13 +7870,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", "cpu": [ "x64" ], @@ -6238,13 +7886,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", "cpu": [ "arm64" ], @@ -6254,13 +7902,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", "cpu": [ "ia32" ], @@ -6270,13 +7918,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", "cpu": [ "x64" ], @@ -6286,51 +7934,52 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/tsx/node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -6340,19 +7989,26 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "license": "MIT" + }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true }, - "node_modules/unherit": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-3.0.1.tgz", - "integrity": "sha512-akOOQ/Yln8a2sgcLj4U0Jmx0R5jpIg2IUyRrWOzmEbjBtGzBdHtSeFKgoEcoH4KYIG/Pb8GQ/BwtYm0GCq1Sqg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" } }, "node_modules/unicorn-magic": { @@ -6367,9 +8023,9 @@ } }, "node_modules/unified": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", - "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -6407,10 +8063,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/unist-util-find-after/node_modules/unist-util-is": { + "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==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -6419,24 +8076,18 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-is": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "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": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-3.1.1.tgz", - "integrity": "sha512-yXi4Lm+TG5VG+qvokP6tpnk+r1EPwyYL04JWDxLvgvPV40jANh7nm3udk65OOWquvbMDe+PL9+LmkxDpTv/7BA==", + "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==", "dependencies": { - "@types/unist": "^2.0.0", + "@types/unist": "^3.0.0", "array-iterate": "^2.0.0" }, "funding": { @@ -6444,6 +8095,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", @@ -6479,18 +8135,6 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unist-util-visit": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", @@ -6506,39 +8150,9 @@ } }, "node_modules/unist-util-visit-children": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-2.0.2.tgz", - "integrity": "sha512-+LWpMFqyUwLGpsQxpumsQ9o9DG2VGLFrpz+rpVXYIEdPy57GSy5HioC0g3bg/8WP9oCLlapQtklOzQ8uLS496Q==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", - "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "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/unist-util-visit/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": "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==", "dependencies": { "@types/unist": "^3.0.0" }, @@ -6547,10 +8161,16 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-visit/node_modules/unist-util-visit-parents": { + "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==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -6560,6 +8180,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/universalify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", @@ -6577,13 +8208,31 @@ "requires-port": "^1.0.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", + "peer": true + }, "node_modules/vfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", - "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "dependencies": { "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" }, "funding": { @@ -6609,19 +8258,6 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/vfile-message": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/vfile/node_modules/@types/unist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", @@ -6652,6 +8288,55 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "license": "MIT" + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", @@ -6731,9 +8416,9 @@ "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==" }, "node_modules/workerpool": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.1.1.tgz", - "integrity": "sha512-EFoFTSEo9m4V4wNrwzVRjxnf/E/oBpOzcI/R5CIugJhl9RsCiq525rszo4AtqcjQQoqFdu2E3H82AnbtpaQHvg==" + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.2.0.tgz", + "integrity": "sha512-PKZqBOCo6CYkVOwAxWxQaSF2Fvb5Iv2fCeTP7buyWI2GiynWr46NcXSgK/idoV6e60dgCBfgYc+Un3HMvmqP8w==" }, "node_modules/wrap-ansi": { "version": "8.1.0", @@ -6817,9 +8502,9 @@ } }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, @@ -6927,6 +8612,12 @@ "node": ">=8" } }, + "node_modules/yoga-wasm-web": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", + "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==", + "license": "MIT" + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index 7b3f11ac6..11c1c91ea 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.2.3", + "version": "4.4.0", "type": "module", "author": "jackyzha0 ", "license": "MIT", @@ -21,7 +21,7 @@ }, "engines": { "npm": ">=9.3.1", - "node": ">=18.14" + "node": "20 || >=22" }, "keywords": [ "site generator", @@ -35,39 +35,43 @@ "quartz": "./quartz/bootstrap-cli.mjs" }, "dependencies": { - "@clack/prompts": "^0.7.0", - "@floating-ui/dom": "^1.6.3", - "@napi-rs/simple-git": "0.1.16", + "@clack/prompts": "^0.8.1", + "@floating-ui/dom": "^1.6.12", + "@myriaddreamin/rehype-typst": "^0.5.0-rc7", + "@napi-rs/simple-git": "0.1.19", + "@tweenjs/tween.js": "^25.0.0", "async-mutex": "^0.5.0", "chalk": "^5.3.0", - "chokidar": "^3.6.0", + "chokidar": "^4.0.1", "cli-spinner": "^0.2.10", "d3": "^7.9.0", - "esbuild-sass-plugin": "^2.16.1", + "esbuild-sass-plugin": "^3.3.1", "flexsearch": "0.7.43", "github-slugger": "^2.0.0", - "globby": "^14.0.1", + "globby": "^14.0.2", "gray-matter": "^4.0.3", - "hast-util-to-html": "^9.0.1", - "hast-util-to-jsx-runtime": "^2.3.0", - "hast-util-to-string": "^3.0.0", + "hast-util-to-html": "^9.0.3", + "hast-util-to-jsx-runtime": "^2.3.2", + "hast-util-to-string": "^3.0.1", "is-absolute-url": "^4.0.1", "js-yaml": "^4.1.0", - "lightningcss": "^1.24.1", + "lightningcss": "^1.28.1", "mdast-util-find-and-replace": "^3.0.1", - "mdast-util-to-hast": "^13.1.0", + "mdast-util-to-hast": "^13.2.0", "mdast-util-to-string": "^4.0.0", + "mermaid": "^11.4.0", "micromorph": "^0.4.5", - "preact": "^10.20.1", - "preact-render-to-string": "^6.4.2", + "pixi.js": "^8.5.2", + "preact": "^10.24.3", + "preact-render-to-string": "^6.5.11", "pretty-bytes": "^6.1.1", "pretty-time": "^1.1.0", "reading-time": "^1.5.0", "rehype-autolink-headings": "^7.1.0", - "rehype-citation": "^2.0.0", - "rehype-katex": "^7.0.0", + "rehype-citation": "^2.2.2", + "rehype-katex": "^7.0.1", "rehype-mathjax": "^6.0.0", - "rehype-pretty-code": "^0.13.0", + "rehype-pretty-code": "^0.14.0", "rehype-raw": "^7.0.0", "rehype-slug": "^6.0.0", "remark": "^15.0.1", @@ -76,20 +80,22 @@ "remark-gfm": "^4.0.0", "remark-math": "^6.0.0", "remark-parse": "^11.0.0", - "remark-rehype": "^11.1.0", - "remark-smartypants": "^2.1.0", - "rfdc": "^1.3.1", - "rimraf": "^5.0.7", - "serve-handler": "^6.1.5", - "shiki": "^1.6.0", + "remark-rehype": "^11.1.1", + "remark-smartypants": "^3.0.2", + "rfdc": "^1.4.1", + "rimraf": "^6.0.1", + "satori": "^0.11.3", + "serve-handler": "^6.1.6", + "sharp": "^0.33.5", + "shiki": "^1.23.1", "source-map-support": "^0.5.21", "to-vfile": "^8.0.0", "toml": "^3.0.0", - "unified": "^11.0.4", + "unified": "^11.0.5", "unist-util-visit": "^5.0.0", - "vfile": "^6.0.1", - "workerpool": "^9.1.1", - "ws": "^8.15.1", + "vfile": "^6.0.3", + "workerpool": "^9.2.0", + "ws": "^8.18.0", "yargs": "^17.7.2" }, "devDependencies": { @@ -97,14 +103,14 @@ "@types/d3": "^7.4.3", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", - "@types/node": "^20.12.5", + "@types/node": "^22.9.0", "@types/pretty-time": "^1.1.5", "@types/source-map-support": "^0.5.10", - "@types/ws": "^8.5.10", - "@types/yargs": "^17.0.32", - "esbuild": "^0.19.9", - "prettier": "^3.2.4", - "tsx": "^4.9.3", - "typescript": "^5.4.5" + "@types/ws": "^8.5.13", + "@types/yargs": "^17.0.33", + "esbuild": "^0.24.0", + "prettier": "^3.3.3", + "tsx": "^4.19.2", + "typescript": "^5.6.3" } } diff --git a/quartz.config.ts b/quartz.config.ts index 53b494859..436ade495 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -11,11 +11,14 @@ const config: QuartzConfig = { pageTitle: "🌱 oldwinterの数字花园", enableSPA: true, enablePopovers: true, - analytics: null, + analytics: { + provider: "plausible", + }, locale: "zh-CN", baseUrl: "garden.oldwinter.top", ignorePatterns: ["private", "templates", ".obsidian","Atlas","Calendar","Cards", "Extras","Sources", "Spaces"], defaultDateType: "published", + generateSocialImages: false, theme: { fontOrigin: "googleFonts", cdnCaching: false, @@ -34,6 +37,7 @@ const config: QuartzConfig = { secondary: "#284b63", tertiary: "#84a59d", highlight: "rgba(143, 159, 169, 0.15)", + textHighlight: "#fff23688", }, darkMode: { light: "#161618", @@ -44,6 +48,7 @@ const config: QuartzConfig = { secondary: "#7b97aa", tertiary: "#84a59d", highlight: "rgba(143, 159, 169, 0.15)", + textHighlight: "#b3aa0288", }, }, }, @@ -54,7 +59,6 @@ const config: QuartzConfig = { Plugin.CreatedModifiedDate({ priority: ["frontmatter"], }), - Plugin.Latex({ renderEngine: "katex" }), Plugin.SyntaxHighlighting({ theme: { light: "github-light", @@ -68,10 +72,7 @@ const config: QuartzConfig = { Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }), Plugin.Description(), ], - filters: [ - Plugin.RemoveDrafts(), - // Plugin.ExplicitPublish() - ], + filters: [Plugin.RemoveDrafts()], emitters: [ Plugin.AliasRedirects(), Plugin.ComponentResources(), diff --git a/quartz.layout.ts b/quartz.layout.ts index fba6a3e06..4749d7899 100644 --- a/quartz.layout.ts +++ b/quartz.layout.ts @@ -5,6 +5,7 @@ import * as Component from "./quartz/components" export const sharedPageComponents: SharedLayout = { head: Component.Head(), header: [], + afterBody: [], footer: Component.Footer({ links: { GitHub: "https://github.com/oldwinter/dg3", diff --git a/quartz/build.ts b/quartz/build.ts index 972a7e850..67ec0da4d 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -38,8 +38,13 @@ type BuildData = { type FileEvent = "add" | "change" | "delete" +function newBuildId() { + return Math.random().toString(36).substring(2, 8) +} + async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) { const ctx: BuildCtx = { + buildId: newBuildId(), argv, cfg, allSlugs: [], @@ -157,10 +162,13 @@ async function partialRebuildFromEntrypoint( return } - const buildStart = new Date().getTime() - buildData.lastBuildMs = buildStart + const buildId = newBuildId() + ctx.buildId = buildId + buildData.lastBuildMs = new Date().getTime() const release = await mut.acquire() - if (buildData.lastBuildMs > buildStart) { + + // if there's another build after us, release and let them do it + if (ctx.buildId !== buildId) { release() return } @@ -351,26 +359,22 @@ async function rebuildFromEntrypoint( toRemove.add(filePath) } - const buildStart = new Date().getTime() - buildData.lastBuildMs = buildStart + const buildId = newBuildId() + ctx.buildId = buildId + buildData.lastBuildMs = new Date().getTime() const release = await mut.acquire() // there's another build after us, release and let them do it - if (buildData.lastBuildMs > buildStart) { + if (ctx.buildId !== buildId) { release() return } const perf = new PerfTimer() console.log(chalk.yellow("Detected change, rebuilding...")) + try { const filesToRebuild = [...toRebuild].filter((fp) => !toRemove.has(fp)) - - const trackedSlugs = [...new Set([...contentMap.keys(), ...toRebuild, ...trackedAssets])] - .filter((fp) => !toRemove.has(fp)) - .map((fp) => slugifyFilePath(path.posix.relative(argv.directory, fp) as FilePath)) - - ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])] const parsedContent = await parseMarkdown(ctx, filesToRebuild) for (const content of parsedContent) { const [_tree, vfile] = content @@ -384,6 +388,13 @@ async function rebuildFromEntrypoint( const parsedFiles = [...contentMap.values()] const filteredContent = filterContent(ctx, parsedFiles) + // re-update slugs + const trackedSlugs = [...new Set([...contentMap.keys(), ...toRebuild, ...trackedAssets])] + .filter((fp) => !toRemove.has(fp)) + .map((fp) => slugifyFilePath(path.posix.relative(argv.directory, fp) as FilePath)) + + ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])] + // TODO: we can probably traverse the link graph to figure out what's safe to delete here // instead of just deleting everything await rimraf(path.join(argv.output, ".*"), { glob: true }) @@ -396,10 +407,10 @@ async function rebuildFromEntrypoint( } } - release() clientRefresh() toRebuild.clear() toRemove.clear() + release() } export default async (argv: Argv, mut: Mutex, clientRefresh: () => void) => { diff --git a/quartz/cfg.ts b/quartz/cfg.ts index 13fb51668..135f58499 100644 --- a/quartz/cfg.ts +++ b/quartz/cfg.ts @@ -2,6 +2,7 @@ import { ValidDateType } from "./components/Date" import { QuartzComponent } from "./components/types" import { ValidLocale } from "./i18n" import { PluginTypes } from "./plugins/types" +import { SocialImageOptions } from "./util/og" import { Theme } from "./util/theme" export type Analytics = @@ -34,9 +35,18 @@ export type Analytics = provider: "tinylytics" siteId: string } + | { + provider: "cabin" + host?: string + } + | { + provider: "clarity" + projectId?: string + } export interface GlobalConfiguration { pageTitle: string + pageTitleSuffix?: string /** Whether to enable single-page-app style rendering. this prevents flashes of unstyled content and improves smoothness of Quartz */ enableSPA: boolean /** Whether to display Wikipedia-style popovers when hovering over links */ @@ -51,11 +61,15 @@ export interface GlobalConfiguration { * Quartz will avoid using this as much as possible and use relative URLs most of the time */ baseUrl?: string + /** + * Whether to generate social images (Open Graph and Twitter standard) for link previews + */ + generateSocialImages: boolean | Partial theme: Theme /** * Allow to translate the date in the language of your choice. * Also used for UI translation (default: en-US) - * Need to be formated following BCP 47: https://en.wikipedia.org/wiki/IETF_language_tag + * Need to be formatted following BCP 47: https://en.wikipedia.org/wiki/IETF_language_tag * The first part is the language (en) and the second part is the script/region (US) * Language Codes: https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes * Region Codes: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 @@ -73,10 +87,11 @@ export interface FullPageLayout { header: QuartzComponent[] beforeBody: QuartzComponent[] pageBody: QuartzComponent + afterBody: QuartzComponent[] left: QuartzComponent[] right: QuartzComponent[] footer: QuartzComponent } export type PageLayout = Pick -export type SharedLayout = Pick +export type SharedLayout = Pick diff --git a/quartz/cli/handlers.js b/quartz/cli/handlers.js index 12e7e8ec9..6b23d8010 100644 --- a/quartz/cli/handlers.js +++ b/quartz/cli/handlers.js @@ -15,6 +15,7 @@ import { WebSocketServer } from "ws" import { randomUUID } from "crypto" import { Mutex } from "async-mutex" import { CreateArgv } from "./args.js" +import { globby } from "globby" import { exitIfCancel, escapePath, @@ -44,7 +45,7 @@ export async function handleCreate(argv) { let linkResolutionStrategy = argv.links?.toLowerCase() const sourceDirectory = argv.source - // If all cmd arguments were provided, check if theyre valid + // If all cmd arguments were provided, check if they're valid if (setupStrategy && linkResolutionStrategy) { // If setup isn't, "new", source argument is required if (setupStrategy !== "new") { @@ -236,6 +237,11 @@ export async function handleBuild(argv) { type: "css-text", cssImports: true, }), + sassPlugin({ + filter: /\.inline\.scss$/, + type: "css", + cssImports: true, + }), { name: "inline-script-loader", setup(build) { @@ -285,8 +291,8 @@ export async function handleBuild(argv) { } if (cleanupBuild) { - await cleanupBuild() console.log(chalk.yellow("Detected a source code change, doing a hard rebuild...")) + await cleanupBuild() } const result = await ctx.rebuild().catch((err) => { @@ -350,6 +356,15 @@ export async function handleBuild(argv) { source: "**/*.*", headers: [{ key: "Content-Disposition", value: "inline" }], }, + { + source: "**/*.webp", + headers: [{ key: "Content-Type", value: "image/webp" }], + }, + // fixes bug where avif images are displayed as text instead of images (future proof) + { + source: "**/*.avif", + headers: [{ key: "Content-Type", value: "image/avif" }], + }, ], }) const status = res.statusCode @@ -418,13 +433,12 @@ export async function handleBuild(argv) { ), ) console.log("hint: exit with ctrl+c") + const paths = await globby(["**/*.ts", "**/*.tsx", "**/*.scss", "package.json"]) chokidar - .watch(["**/*.ts", "**/*.tsx", "**/*.scss", "package.json"], { - ignoreInitial: true, - }) - .on("all", async () => { - build(clientRefresh) - }) + .watch(paths, { ignoreInitial: true }) + .on("add", () => build(clientRefresh)) + .on("change", () => build(clientRefresh)) + .on("unlink", () => build(clientRefresh)) } else { await build(() => {}) ctx.dispose() @@ -457,7 +471,25 @@ export async function handleUpdate(argv) { await popContentFolder(contentFolder) console.log("Ensuring dependencies are up to date") - const res = spawnSync("npm", ["i"], { stdio: "inherit" }) + + /* + On Windows, if the command `npm` is really `npm.cmd', this call fails + 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 + on Windows, without a manual `npm i` from the caller. + + However, by spawning a shell, we are able to call `npm.cmd`. + See: https://nodejs.org/api/child_process.html#spawning-bat-and-cmd-files-on-windows + */ + + const opts = { stdio: "inherit" } + if (process.platform === "win32") { + opts.shell = true + } + + const res = spawnSync("npm", ["i"], opts) if (res.status === 0) { console.log(chalk.green("Done!")) } else { diff --git a/quartz/components/Comments.tsx b/quartz/components/Comments.tsx new file mode 100644 index 000000000..5f29860c2 --- /dev/null +++ b/quartz/components/Comments.tsx @@ -0,0 +1,59 @@ +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" + } +} + +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 = + !fileData.frontmatter?.comments || fileData.frontmatter?.comments === "false" + if (disableComment) { + return <> + } + + return ( +
+ ) + } + + Comments.afterDOMLoaded = script + + return Comments +}) satisfies QuartzComponentConstructor diff --git a/quartz/components/Darkmode.tsx b/quartz/components/Darkmode.tsx index 8ed7c99b0..f64aad636 100644 --- a/quartz/components/Darkmode.tsx +++ b/quartz/components/Darkmode.tsx @@ -9,41 +9,38 @@ import { classNames } from "../util/lang" const Darkmode: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { return ( -
- - - -
+ ) } diff --git a/quartz/components/Explorer.tsx b/quartz/components/Explorer.tsx index cffc079ef..ec7c48ef7 100644 --- a/quartz/components/Explorer.tsx +++ b/quartz/components/Explorer.tsx @@ -44,12 +44,9 @@ export default ((userOpts?: Partial) => { // memoized let fileTree: FileNode let jsonTree: string + let lastBuildId: string = "" function constructFileTree(allFiles: QuartzPluginData[]) { - if (fileTree) { - return - } - // Construct tree from allFiles fileTree = new FileNode("") allFiles.forEach((file) => fileTree.add(file)) @@ -76,12 +73,17 @@ export default ((userOpts?: Partial) => { } const Explorer: QuartzComponent = ({ + ctx, cfg, allFiles, displayClass, fileData, }: QuartzComponentProps) => { - constructFileTree(allFiles) + if (ctx.buildId !== lastBuildId) { + lastBuildId = ctx.buildId + constructFileTree(allFiles) + } + return (
diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index 46ba5e002..f4c9d490e 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -1,14 +1,120 @@ import { i18n } from "../i18n" import { FullSlug, joinSegments, pathToRoot } from "../util/path" -import { JSResourceToScriptElement } from "../util/resources" +import { CSSResourceToStyleElement, JSResourceToScriptElement } from "../util/resources" import { googleFontHref } from "../util/theme" import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" +import satori, { SatoriOptions } from "satori" +import fs from "fs" +import sharp from "sharp" +import { ImageOptions, SocialImageOptions, getSatoriFont, defaultImage } from "../util/og" +import { unescapeHTML } from "../util/escape" + +/** + * Generates social image (OG/twitter standard) and saves it as `.webp` inside the public folder + * @param opts options for generating image + */ +async function generateSocialImage( + { cfg, description, fileName, fontsPromise, title, fileData }: ImageOptions, + userOpts: SocialImageOptions, + imageDir: string, +) { + const fonts = await fontsPromise + const { width, height } = userOpts + + // JSX that will be used to generate satori svg + const imageComponent = userOpts.imageStructure(cfg, userOpts, title, description, fonts, fileData) + + const svg = await satori(imageComponent, { width, height, fonts }) + + // Convert svg directly to webp (with additional compression) + const compressed = await sharp(Buffer.from(svg)).webp({ quality: 40 }).toBuffer() + + // Write to file system + const filePath = joinSegments(imageDir, `${fileName}.${extension}`) + fs.writeFileSync(filePath, compressed) +} + +const extension = "webp" + +const defaultOptions: SocialImageOptions = { + colorScheme: "lightMode", + width: 1200, + height: 630, + imageStructure: defaultImage, + excludeRoot: false, +} export default (() => { - const Head: QuartzComponent = ({ cfg, fileData, externalResources }: QuartzComponentProps) => { - const title = fileData.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title - const description = + let fontsPromise: Promise + + let fullOptions: SocialImageOptions + const Head: QuartzComponent = ({ + cfg, + fileData, + externalResources, + ctx, + }: QuartzComponentProps) => { + // Initialize options if not set + if (!fullOptions) { + if (typeof cfg.generateSocialImages !== "boolean") { + fullOptions = { ...defaultOptions, ...cfg.generateSocialImages } + } else { + fullOptions = defaultOptions + } + } + + // Memoize google fonts + if (!fontsPromise && cfg.generateSocialImages) { + fontsPromise = getSatoriFont(cfg.theme.typography.header, cfg.theme.typography.body) + } + + const slug = fileData.filePath + // since "/" is not a valid character in file names, replace with "-" + const fileName = slug?.replaceAll("/", "-") + + // Get file description (priority: frontmatter > fileData > default) + const fdDescription = fileData.description?.trim() ?? i18n(cfg.locale).propertyDefaults.description + const titleSuffix = cfg.pageTitleSuffix ?? "" + const title = + (fileData.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title) + titleSuffix + let description = "" + if (fdDescription) { + description = unescapeHTML(fdDescription) + } + + if (fileData.frontmatter?.socialDescription) { + description = fileData.frontmatter?.socialDescription as string + } else if (fileData.frontmatter?.description) { + description = fileData.frontmatter?.description + } + + const fileDir = joinSegments(ctx.argv.output, "static", "social-images") + if (cfg.generateSocialImages) { + // Generate folders for social images (if they dont exist yet) + if (!fs.existsSync(fileDir)) { + fs.mkdirSync(fileDir, { recursive: true }) + } + + if (fileName) { + // Generate social image (happens async) + generateSocialImage( + { + title, + description, + fileName, + fileDir, + fileExt: extension, + fontsPromise, + cfg, + fileData, + }, + fullOptions, + fileDir, + ) + } + } + const { css, js } = externalResources const url = new URL(`https://${cfg.baseUrl ?? "example.com"}`) @@ -16,7 +122,37 @@ export default (() => { const baseDir = fileData.slug === "404" ? path : pathToRoot(fileData.slug!) const iconPath = joinSegments(baseDir, "static/icon.png") - const ogImagePath = `https://${cfg.baseUrl}/static/og-image.png` + + const ogImageDefaultPath = `https://${cfg.baseUrl}/static/og-image.png` + // "static/social-images/slug-filename.md.webp" + const ogImageGeneratedPath = `https://${cfg.baseUrl}/${fileDir.replace( + `${ctx.argv.output}/`, + "", + )}/${fileName}.${extension}` + + // Use default og image if filePath doesnt exist (for autogenerated paths with no .md file) + const useDefaultOgImage = fileName === undefined || !cfg.generateSocialImages + + // Path to og/social image (priority: frontmatter > generated image (if enabled) > default image) + let ogImagePath = useDefaultOgImage ? ogImageDefaultPath : ogImageGeneratedPath + + // TODO: could be improved to support external images in the future + // Aliases for image and cover handled in `frontmatter.ts` + const frontmatterImgUrl = fileData.frontmatter?.socialImage + + // Override with default og image if config option is set + if (fileData.slug === "index") { + ogImagePath = ogImageDefaultPath + } + + // Override with frontmatter url if existing + if (frontmatterImgUrl) { + ogImagePath = `https://${cfg.baseUrl}/static/${frontmatterImgUrl}` + } + + // Url of current page + const socialUrl = + fileData.slug === "404" ? url.toString() : joinSegments(url.toString(), fileData.slug!) return ( @@ -30,17 +166,39 @@ export default (() => { )} + {/* OG/Twitter meta tags */} + + + + + - {cfg.baseUrl && } - - + + + {/* Dont set width and height if unknown (when using custom frontmatter image) */} + {!frontmatterImgUrl && ( + <> + + + + + + )} + + {cfg.baseUrl && ( + <> + + + + + + + )} - {css.map((href) => ( - - ))} + {css.map((resource) => CSSResourceToStyleElement(resource, true))} {js .filter((resource) => resource.loadTime === "beforeDOMReady") .map((res) => JSResourceToScriptElement(res, true))} diff --git a/quartz/components/PageList.tsx b/quartz/components/PageList.tsx index 1e5d232df..cc0124a8f 100644 --- a/quartz/components/PageList.tsx +++ b/quartz/components/PageList.tsx @@ -4,9 +4,9 @@ import { Date, getDate } from "./Date" import { QuartzComponent, QuartzComponentProps } from "./types" import { GlobalConfiguration } from "../cfg" -export function byDateAndAlphabetical( - cfg: GlobalConfiguration, -): (f1: QuartzPluginData, f2: QuartzPluginData) => number { +export type SortFn = (f1: QuartzPluginData, f2: QuartzPluginData) => number + +export function byDateAndAlphabetical(cfg: GlobalConfiguration): SortFn { return (f1, f2) => { if (f1.dates && f2.dates) { // sort descending @@ -27,10 +27,12 @@ export function byDateAndAlphabetical( type Props = { limit?: number + sort?: SortFn } & QuartzComponentProps -export const PageList: QuartzComponent = ({ cfg, fileData, allFiles, limit }: Props) => { - let list = allFiles.sort(byDateAndAlphabetical(cfg)) +export const PageList: QuartzComponent = ({ cfg, fileData, allFiles, limit, sort }: Props) => { + const sorter = sort ?? byDateAndAlphabetical(cfg) + let list = allFiles.sort(sorter) if (limit) { list = list.slice(0, limit) } @@ -44,11 +46,13 @@ export const PageList: QuartzComponent = ({ cfg, fileData, allFiles, limit }: Pr return (
  • - {page.dates && ( -

    - -

    - )} +
    + {page.dates && ( +

    + +

    + )} +

    diff --git a/quartz/components/PageTitle.tsx b/quartz/components/PageTitle.tsx index 2362f1027..046dc5276 100644 --- a/quartz/components/PageTitle.tsx +++ b/quartz/components/PageTitle.tsx @@ -7,14 +7,15 @@ const PageTitle: QuartzComponent = ({ fileData, cfg, displayClass }: QuartzCompo 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; } ` diff --git a/quartz/components/Search.tsx b/quartz/components/Search.tsx index 01e5a353d..8b9755518 100644 --- a/quartz/components/Search.tsx +++ b/quartz/components/Search.tsx @@ -19,24 +19,16 @@ export default ((userOpts?: Partial) => { const searchPlaceholder = i18n(cfg.locale).components.search.searchBarPlaceholder return (
    -
    +
    +
    - -
    +
      {fileData.toc.map((tocEntry) => (
    • diff --git a/quartz/components/TagList.tsx b/quartz/components/TagList.tsx index ba48098bd..4a89fbd67 100644 --- a/quartz/components/TagList.tsx +++ b/quartz/components/TagList.tsx @@ -33,7 +33,6 @@ TagList.css = ` gap: 0.4rem; margin: 1rem 0; flex-wrap: wrap; - justify-self: end; } .section-li > .section > .tags { diff --git a/quartz/components/index.ts b/quartz/components/index.ts index b3db76bed..5b197941c 100644 --- a/quartz/components/index.ts +++ b/quartz/components/index.ts @@ -19,6 +19,7 @@ import DesktopOnly from "./DesktopOnly" import MobileOnly from "./MobileOnly" import RecentNotes from "./RecentNotes" import Breadcrumbs from "./Breadcrumbs" +import Comments from "./Comments" export { ArticleTitle, @@ -42,4 +43,5 @@ export { RecentNotes, NotFound, Breadcrumbs, + Comments, } diff --git a/quartz/components/pages/FolderContent.tsx b/quartz/components/pages/FolderContent.tsx index a13f135f8..7a49d494f 100644 --- a/quartz/components/pages/FolderContent.tsx +++ b/quartz/components/pages/FolderContent.tsx @@ -2,21 +2,25 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro import path from "path" import style from "../styles/listPage.scss" -import { PageList } from "../PageList" -import { stripSlashes, simplifySlug } from "../../util/path" +import { byDateAndAlphabetical, PageList, SortFn } from "../PageList" +import { stripSlashes, simplifySlug, joinSegments, FullSlug } from "../../util/path" import { Root } from "hast" import { htmlToJsx } from "../../util/jsx" import { i18n } from "../../i18n" +import { QuartzPluginData } from "../../plugins/vfile" interface FolderContentOptions { /** * Whether to display number of folders */ showFolderCount: boolean + showSubfolders: boolean + sort?: SortFn } const defaultOptions: FolderContentOptions = { showFolderCount: true, + showSubfolders: true, } export default ((opts?: Partial) => { @@ -25,18 +29,52 @@ export default ((opts?: Partial) => { const FolderContent: QuartzComponent = (props: QuartzComponentProps) => { const { tree, fileData, allFiles, cfg } = props const folderSlug = stripSlashes(simplifySlug(fileData.slug!)) - const allPagesInFolder = allFiles.filter((file) => { + const folderParts = folderSlug.split(path.posix.sep) + + const allPagesInFolder: QuartzPluginData[] = [] + const allPagesInSubfolders: Map = new Map() + + allFiles.forEach((file) => { const fileSlug = stripSlashes(simplifySlug(file.slug!)) const prefixed = fileSlug.startsWith(folderSlug) && fileSlug !== folderSlug - const folderParts = folderSlug.split(path.posix.sep) const fileParts = fileSlug.split(path.posix.sep) const isDirectChild = fileParts.length === folderParts.length + 1 - return prefixed && isDirectChild + + if (!prefixed) { + return + } + + if (isDirectChild) { + allPagesInFolder.push(file) + } else if (options.showSubfolders) { + const subfolderSlug = joinSegments( + ...fileParts.slice(0, folderParts.length + 1), + ) as FullSlug + const pagesInFolder = allPagesInSubfolders.get(subfolderSlug) || [] + allPagesInSubfolders.set(subfolderSlug, [...pagesInFolder, file]) + } }) + + allPagesInSubfolders.forEach((files, subfolderSlug) => { + const hasIndex = allPagesInFolder.some( + (file) => subfolderSlug === stripSlashes(simplifySlug(file.slug!)), + ) + if (!hasIndex) { + const subfolderDates = files.sort(byDateAndAlphabetical(cfg))[0].dates + const subfolderTitle = subfolderSlug.split(path.posix.sep).at(-1)! + allPagesInFolder.push({ + slug: subfolderSlug, + dates: subfolderDates, + frontmatter: { title: subfolderTitle, tags: ["folder"] }, + }) + } + }) + const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? [] const classes = ["popover-hint", ...cssClasses].join(" ") const listProps = { ...props, + sort: options.sort, allFiles: allPagesInFolder, } diff --git a/quartz/components/pages/TagContent.tsx b/quartz/components/pages/TagContent.tsx index 9e04359c1..e41ab4644 100644 --- a/quartz/components/pages/TagContent.tsx +++ b/quartz/components/pages/TagContent.tsx @@ -1,113 +1,127 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "../types" import style from "../styles/listPage.scss" -import { PageList } from "../PageList" +import { PageList, SortFn } from "../PageList" import { FullSlug, getAllSegmentPrefixes, simplifySlug } from "../../util/path" import { QuartzPluginData } from "../../plugins/vfile" import { Root } from "hast" import { htmlToJsx } from "../../util/jsx" import { i18n } from "../../i18n" -const numPages = 10 -const TagContent: QuartzComponent = (props: QuartzComponentProps) => { - const { tree, fileData, allFiles, cfg } = props - const slug = fileData.slug - - if (!(slug?.startsWith("tags/") || slug === "tags")) { - throw new Error(`Component "TagContent" tried to render a non-tag page: ${slug}`) - } - - const tag = simplifySlug(slug.slice("tags/".length) as FullSlug) - const allPagesWithTag = (tag: string) => - allFiles.filter((file) => - (file.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes).includes(tag), - ) - - const content = - (tree as Root).children.length === 0 - ? fileData.description - : htmlToJsx(fileData.filePath!, tree) - const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? [] - const classes = ["popover-hint", ...cssClasses].join(" ") - if (tag === "/") { - const tags = [ - ...new Set( - allFiles.flatMap((data) => data.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes), - ), - ].sort((a, b) => a.localeCompare(b)) - const tagItemMap: Map = new Map() - for (const tag of tags) { - tagItemMap.set(tag, allPagesWithTag(tag)) - } - return ( -
      -
      -

      {content}

      -
      -

      {i18n(cfg.locale).pages.tagContent.totalTags({ count: tags.length })}

      -
      - {tags.map((tag) => { - const pages = tagItemMap.get(tag)! - const listProps = { - ...props, - allFiles: pages, - } - - const contentPage = allFiles.filter((file) => file.slug === `tags/${tag}`).at(0) - - const root = contentPage?.htmlAst - const content = - !root || root?.children.length === 0 - ? contentPage?.description - : htmlToJsx(contentPage.filePath!, root) - - return ( -
      -

      - - {tag} - -

      - {content &&

      {content}

      } -
      -

      - {i18n(cfg.locale).pages.tagContent.itemsUnderTag({ count: pages.length })} - {pages.length > numPages && ( - <> - {" "} - - {i18n(cfg.locale).pages.tagContent.showingFirst({ count: numPages })} - - - )} -

      - -
      -
      - ) - })} -
      -
      - ) - } else { - const pages = allPagesWithTag(tag) - const listProps = { - ...props, - allFiles: pages, - } - - return ( -
      -
      {content}
      -
      -

      {i18n(cfg.locale).pages.tagContent.itemsUnderTag({ count: pages.length })}

      -
      - -
      -
      -
      - ) - } +interface TagContentOptions { + sort?: SortFn + numPages: number } -TagContent.css = style + PageList.css -export default (() => TagContent) satisfies QuartzComponentConstructor +const defaultOptions: TagContentOptions = { + numPages: 10, +} + +export default ((opts?: Partial) => { + const options: TagContentOptions = { ...defaultOptions, ...opts } + + const TagContent: QuartzComponent = (props: QuartzComponentProps) => { + const { tree, fileData, allFiles, cfg } = props + const slug = fileData.slug + + if (!(slug?.startsWith("tags/") || slug === "tags")) { + throw new Error(`Component "TagContent" tried to render a non-tag page: ${slug}`) + } + + const tag = simplifySlug(slug.slice("tags/".length) as FullSlug) + const allPagesWithTag = (tag: string) => + allFiles.filter((file) => + (file.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes).includes(tag), + ) + + const content = + (tree as Root).children.length === 0 + ? fileData.description + : htmlToJsx(fileData.filePath!, tree) + const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? [] + const classes = ["popover-hint", ...cssClasses].join(" ") + if (tag === "/") { + const tags = [ + ...new Set( + allFiles.flatMap((data) => data.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes), + ), + ].sort((a, b) => a.localeCompare(b)) + const tagItemMap: Map = new Map() + for (const tag of tags) { + tagItemMap.set(tag, allPagesWithTag(tag)) + } + return ( +
      +
      +

      {content}

      +
      +

      {i18n(cfg.locale).pages.tagContent.totalTags({ count: tags.length })}

      +
      + {tags.map((tag) => { + const pages = tagItemMap.get(tag)! + const listProps = { + ...props, + allFiles: pages, + } + + const contentPage = allFiles.filter((file) => file.slug === `tags/${tag}`).at(0) + + const root = contentPage?.htmlAst + const content = + !root || root?.children.length === 0 + ? contentPage?.description + : htmlToJsx(contentPage.filePath!, root) + + return ( +
      +

      + + {tag} + +

      + {content &&

      {content}

      } +
      +

      + {i18n(cfg.locale).pages.tagContent.itemsUnderTag({ count: pages.length })} + {pages.length > options.numPages && ( + <> + {" "} + + {i18n(cfg.locale).pages.tagContent.showingFirst({ + count: options.numPages, + })} + + + )} +

      + +
      +
      + ) + })} +
      +
      + ) + } else { + const pages = allPagesWithTag(tag) + const listProps = { + ...props, + allFiles: pages, + } + + return ( +
      +
      {content}
      +
      +

      {i18n(cfg.locale).pages.tagContent.itemsUnderTag({ count: pages.length })}

      +
      + +
      +
      +
      + ) + } + } + + TagContent.css = style + PageList.css + return TagContent +}) satisfies QuartzComponentConstructor diff --git a/quartz/components/renderPage.tsx b/quartz/components/renderPage.tsx index 251a53f2e..9c530967b 100644 --- a/quartz/components/renderPage.tsx +++ b/quartz/components/renderPage.tsx @@ -14,6 +14,7 @@ interface RenderComponents { header: QuartzComponent[] beforeBody: QuartzComponent[] pageBody: QuartzComponent + afterBody: QuartzComponent[] left: QuartzComponent[] right: QuartzComponent[] footer: QuartzComponent @@ -28,7 +29,12 @@ export function pageResources( const contentIndexScript = `const fetchData = fetch("${contentIndexPath}").then(data => data.json())` return { - css: [joinSegments(baseDir, "index.css"), ...staticResources.css], + css: [ + { + content: joinSegments(baseDir, "index.css"), + }, + ...staticResources.css, + ], js: [ { src: joinSegments(baseDir, "prescript.js"), @@ -187,6 +193,7 @@ export function renderPage( header, beforeBody, pageBody: Content, + afterBody, left, right, footer: Footer, @@ -232,10 +239,16 @@ export function renderPage(
    +
    +
    {RightComponent} +
    -
    {pageResources.js diff --git a/quartz/components/scripts/clipboard.inline.ts b/quartz/components/scripts/clipboard.inline.ts index 87182a154..e16c11299 100644 --- a/quartz/components/scripts/clipboard.inline.ts +++ b/quartz/components/scripts/clipboard.inline.ts @@ -8,7 +8,9 @@ document.addEventListener("nav", () => { for (let i = 0; i < els.length; i++) { const codeBlock = els[i].getElementsByTagName("code")[0] if (codeBlock) { - const source = codeBlock.innerText.replace(/\n\n/g, "\n") + const source = ( + codeBlock.dataset.clipboard ? JSON.parse(codeBlock.dataset.clipboard) : codeBlock.innerText + ).replace(/\n\n/g, "\n") const button = document.createElement("button") button.className = "clipboard-button" button.type = "button" diff --git a/quartz/components/scripts/comments.inline.ts b/quartz/components/scripts/comments.inline.ts new file mode 100644 index 000000000..c54230fbe --- /dev/null +++ b/quartz/components/scripts/comments.inline.ts @@ -0,0 +1,91 @@ +const changeTheme = (e: CustomEventMap["themechange"]) => { + const theme = e.detail.theme + const iframe = document.querySelector("iframe.giscus-frame") as HTMLIFrameElement + if (!iframe) { + return + } + + if (!iframe.contentWindow) { + return + } + + iframe.contentWindow.postMessage( + { + giscus: { + setConfig: { + theme: getThemeUrl(getThemeName(theme)), + }, + }, + }, + "https://giscus.app", + ) +} + +const getThemeName = (theme: string) => { + if (theme !== "dark" && theme !== "light") { + return theme + } + const giscusContainer = document.querySelector(".giscus") as GiscusElement + if (!giscusContainer) { + return theme + } + const darkGiscus = giscusContainer.dataset.darkTheme ?? "dark" + const lightGiscus = giscusContainer.dataset.lightTheme ?? "light" + return theme === "dark" ? darkGiscus : lightGiscus +} + +const getThemeUrl = (theme: string) => { + const giscusContainer = document.querySelector(".giscus") as GiscusElement + if (!giscusContainer) { + return `https://giscus.app/themes/${theme}.css` + } + return `${giscusContainer.dataset.themeUrl ?? "https://giscus.app/themes"}/${theme}.css` +} + +type GiscusElement = Omit & { + dataset: DOMStringMap & { + repo: `${string}/${string}` + repoId: string + category: string + categoryId: string + themeUrl: string + lightTheme: string + darkTheme: string + mapping: "url" | "title" | "og:title" | "specific" | "number" | "pathname" + strict: string + reactionsEnabled: string + inputPosition: "top" | "bottom" + } +} + +document.addEventListener("nav", () => { + const giscusContainer = document.querySelector(".giscus") as GiscusElement + if (!giscusContainer) { + return + } + + const giscusScript = document.createElement("script") + giscusScript.src = "https://giscus.app/client.js" + giscusScript.async = true + giscusScript.crossOrigin = "anonymous" + giscusScript.setAttribute("data-loading", "lazy") + giscusScript.setAttribute("data-emit-metadata", "0") + giscusScript.setAttribute("data-repo", giscusContainer.dataset.repo) + giscusScript.setAttribute("data-repo-id", giscusContainer.dataset.repoId) + giscusScript.setAttribute("data-category", giscusContainer.dataset.category) + giscusScript.setAttribute("data-category-id", giscusContainer.dataset.categoryId) + giscusScript.setAttribute("data-mapping", giscusContainer.dataset.mapping) + giscusScript.setAttribute("data-strict", giscusContainer.dataset.strict) + giscusScript.setAttribute("data-reactions-enabled", giscusContainer.dataset.reactionsEnabled) + giscusScript.setAttribute("data-input-position", giscusContainer.dataset.inputPosition) + + const theme = document.documentElement.getAttribute("saved-theme") + if (theme) { + giscusScript.setAttribute("data-theme", getThemeUrl(getThemeName(theme))) + } + + giscusContainer.appendChild(giscusScript) + + document.addEventListener("themechange", changeTheme) + window.addCleanup(() => document.removeEventListener("themechange", changeTheme)) +}) diff --git a/quartz/components/scripts/darkmode.inline.ts b/quartz/components/scripts/darkmode.inline.ts index 48e0aa1f5..038ae0fe5 100644 --- a/quartz/components/scripts/darkmode.inline.ts +++ b/quartz/components/scripts/darkmode.inline.ts @@ -11,7 +11,8 @@ const emitThemeChangeEvent = (theme: "light" | "dark") => { document.addEventListener("nav", () => { const switchTheme = (e: Event) => { - const newTheme = (e.target as HTMLInputElement)?.checked ? "dark" : "light" + const newTheme = + document.documentElement.getAttribute("saved-theme") === "dark" ? "light" : "dark" document.documentElement.setAttribute("saved-theme", newTheme) localStorage.setItem("theme", newTheme) emitThemeChangeEvent(newTheme) @@ -21,17 +22,13 @@ document.addEventListener("nav", () => { const newTheme = e.matches ? "dark" : "light" document.documentElement.setAttribute("saved-theme", newTheme) localStorage.setItem("theme", newTheme) - toggleSwitch.checked = e.matches emitThemeChangeEvent(newTheme) } // Darkmode toggle - const toggleSwitch = document.querySelector("#darkmode-toggle") as HTMLInputElement - toggleSwitch.addEventListener("change", switchTheme) - window.addCleanup(() => toggleSwitch.removeEventListener("change", switchTheme)) - if (currentTheme === "dark") { - toggleSwitch.checked = true - } + const themeButton = document.querySelector("#darkmode") as HTMLButtonElement + themeButton.addEventListener("click", switchTheme) + window.addCleanup(() => themeButton.removeEventListener("click", switchTheme)) // Listen for changes in prefers-color-scheme const colorSchemeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)") diff --git a/quartz/components/scripts/explorer.inline.ts b/quartz/components/scripts/explorer.inline.ts index 3eb25ead4..33d328a6c 100644 --- a/quartz/components/scripts/explorer.inline.ts +++ b/quartz/components/scripts/explorer.inline.ts @@ -17,11 +17,14 @@ const observer = new IntersectionObserver((entries) => { function toggleExplorer(this: HTMLElement) { this.classList.toggle("collapsed") + this.setAttribute( + "aria-expanded", + this.getAttribute("aria-expanded") === "true" ? "false" : "true", + ) const content = this.nextElementSibling as MaybeHTMLElement if (!content) return content.classList.toggle("collapsed") - content.style.maxHeight = content.style.maxHeight === "0px" ? content.scrollHeight + "px" : "0px" } function toggleFolder(evt: MouseEvent) { diff --git a/quartz/components/scripts/graph.inline.ts b/quartz/components/scripts/graph.inline.ts index 1c9bb5d64..dbddae91f 100644 --- a/quartz/components/scripts/graph.inline.ts +++ b/quartz/components/scripts/graph.inline.ts @@ -1,19 +1,56 @@ -import type { ContentDetails, ContentIndex } from "../../plugins/emitters/contentIndex" -import * as d3 from "d3" +import type { ContentDetails } from "../../plugins/emitters/contentIndex" +import { + SimulationNodeDatum, + SimulationLinkDatum, + Simulation, + forceSimulation, + forceManyBody, + forceCenter, + forceLink, + forceCollide, + zoomIdentity, + select, + drag, + zoom, +} from "d3" +import { Text, Graphics, Application, Container, Circle } from "pixi.js" +import { Group as TweenGroup, Tween as Tweened } from "@tweenjs/tween.js" import { registerEscapeHandler, removeAllChildren } from "./util" import { FullSlug, SimpleSlug, getFullSlug, resolveRelative, simplifySlug } from "../../util/path" +import { D3Config } from "../Graph" + +type GraphicsInfo = { + color: string + gfx: Graphics + alpha: number + active: boolean +} type NodeData = { id: SimpleSlug text: string tags: string[] -} & d3.SimulationNodeDatum +} & SimulationNodeDatum -type LinkData = { +type SimpleLinkData = { source: SimpleSlug target: SimpleSlug } +type LinkData = { + source: NodeData + target: NodeData +} & SimulationLinkDatum + +type LinkRenderData = GraphicsInfo & { + simulationData: LinkData +} + +type NodeRenderData = GraphicsInfo & { + simulationData: NodeData + label: Text +} + const localStorageKey = "graph-visited" function getVisited(): Set { return new Set(JSON.parse(localStorage.getItem(localStorageKey) ?? "[]")) @@ -25,6 +62,11 @@ function addToVisited(slug: SimpleSlug) { localStorage.setItem(localStorageKey, JSON.stringify([...visited])) } +type TweenNode = { + update: (time: number) => void + stop: () => void +} + async function renderGraph(container: string, fullSlug: FullSlug) { const slug = simplifySlug(fullSlug) const visited = getVisited() @@ -45,7 +87,7 @@ async function renderGraph(container: string, fullSlug: FullSlug) { removeTags, showTags, focusOnHover, - } = JSON.parse(graph.dataset["cfg"]!) + } = JSON.parse(graph.dataset["cfg"]!) as D3Config const data: Map = new Map( Object.entries(await fetchData).map(([k, v]) => [ @@ -53,10 +95,11 @@ async function renderGraph(container: string, fullSlug: FullSlug) { v, ]), ) - const links: LinkData[] = [] + const links: SimpleLinkData[] = [] const tags: SimpleSlug[] = [] - const validLinks = new Set(data.keys()) + + const tweens = new Map() for (const [source, details] of data.entries()) { const outgoing = details.links ?? [] @@ -100,246 +143,459 @@ async function renderGraph(container: string, fullSlug: FullSlug) { if (showTags) tags.forEach((tag) => neighbourhood.add(tag)) } + const nodes = [...neighbourhood].map((url) => { + const text = url.startsWith("tags/") ? "#" + url.substring(5) : (data.get(url)?.title ?? url) + return { + id: url, + text, + tags: data.get(url)?.tags ?? [], + } + }) const graphData: { nodes: NodeData[]; links: LinkData[] } = { - nodes: [...neighbourhood].map((url) => { - const text = url.startsWith("tags/") ? "#" + url.substring(5) : data.get(url)?.title ?? url - return { - id: url, - text: text, - tags: data.get(url)?.tags ?? [], - } - }), - links: links.filter((l) => neighbourhood.has(l.source) && neighbourhood.has(l.target)), + nodes, + links: links + .filter((l) => neighbourhood.has(l.source) && neighbourhood.has(l.target)) + .map((l) => ({ + source: nodes.find((n) => n.id === l.source)!, + target: nodes.find((n) => n.id === l.target)!, + })), } - const simulation: d3.Simulation = d3 - .forceSimulation(graphData.nodes) - .force("charge", d3.forceManyBody().strength(-100 * repelForce)) - .force( - "link", - d3 - .forceLink(graphData.links) - .id((d: any) => d.id) - .distance(linkDistance), - ) - .force("center", d3.forceCenter().strength(centerForce)) + // we virtualize the simulation and use pixi to actually render it + const simulation: Simulation = forceSimulation(graphData.nodes) + .force("charge", forceManyBody().strength(-100 * repelForce)) + .force("center", forceCenter().strength(centerForce)) + .force("link", forceLink(graphData.links).distance(linkDistance)) + .force("collide", forceCollide((n) => nodeRadius(n)).iterations(3)) - const height = Math.max(graph.offsetHeight, 250) const width = graph.offsetWidth + const height = Math.max(graph.offsetHeight, 250) - const svg = d3 - .select("#" + container) - .append("svg") - .attr("width", width) - .attr("height", height) - .attr("viewBox", [-width / 2 / scale, -height / 2 / scale, width / scale, height / scale]) - - // draw links between nodes - const link = svg - .append("g") - .selectAll("line") - .data(graphData.links) - .join("line") - .attr("class", "link") - .attr("stroke", "var(--lightgray)") - .attr("stroke-width", 1) - - // svg groups - const graphNode = svg.append("g").selectAll("g").data(graphData.nodes).enter().append("g") + // precompute style prop strings as pixi doesn't support css variables + const cssVars = [ + "--secondary", + "--tertiary", + "--gray", + "--light", + "--lightgray", + "--dark", + "--darkgray", + "--bodyFont", + ] as const + const computedStyleMap = cssVars.reduce( + (acc, key) => { + acc[key] = getComputedStyle(document.documentElement).getPropertyValue(key) + return acc + }, + {} as Record<(typeof cssVars)[number], string>, + ) // calculate color const color = (d: NodeData) => { const isCurrent = d.id === slug if (isCurrent) { - return "var(--secondary)" + return computedStyleMap["--secondary"] } else if (visited.has(d.id) || d.id.startsWith("tags/")) { - return "var(--tertiary)" + return computedStyleMap["--tertiary"] } else { - return "var(--gray)" + return computedStyleMap["--gray"] } } - const drag = (simulation: d3.Simulation) => { - function dragstarted(event: any, d: NodeData) { - if (!event.active) simulation.alphaTarget(1).restart() - d.fx = d.x - d.fy = d.y - } - - function dragged(event: any, d: NodeData) { - d.fx = event.x - d.fy = event.y - } - - function dragended(event: any, d: NodeData) { - if (!event.active) simulation.alphaTarget(0) - d.fx = null - d.fy = null - } - - const noop = () => {} - return d3 - .drag() - .on("start", enableDrag ? dragstarted : noop) - .on("drag", enableDrag ? dragged : noop) - .on("end", enableDrag ? dragended : noop) - } - function nodeRadius(d: NodeData) { - const numLinks = links.filter((l: any) => l.source.id === d.id || l.target.id === d.id).length + const numLinks = graphData.links.filter( + (l) => l.source.id === d.id || l.target.id === d.id, + ).length return 2 + Math.sqrt(numLinks) } - let connectedNodes: SimpleSlug[] = [] + let hoveredNodeId: string | null = null + let hoveredNeighbours: Set = new Set() + const linkRenderData: LinkRenderData[] = [] + const nodeRenderData: NodeRenderData[] = [] + function updateHoverInfo(newHoveredId: string | null) { + hoveredNodeId = newHoveredId - // draw individual nodes - const node = graphNode - .append("circle") - .attr("class", "node") - .attr("id", (d) => d.id) - .attr("r", nodeRadius) - .attr("fill", color) - .style("cursor", "pointer") - .on("click", (_, d) => { - const targ = resolveRelative(fullSlug, d.id) - window.spaNavigate(new URL(targ, window.location.toString())) - }) - .on("mouseover", function (_, d) { - const currentId = d.id - const linkNodes = d3 - .selectAll(".link") - .filter((d: any) => d.source.id === currentId || d.target.id === currentId) - - if (focusOnHover) { - // fade out non-neighbour nodes - connectedNodes = linkNodes.data().flatMap((d: any) => [d.source.id, d.target.id]) - - d3.selectAll(".link") - .transition() - .duration(200) - .style("opacity", 0.2) - d3.selectAll(".node") - .filter((d) => !connectedNodes.includes(d.id)) - .transition() - .duration(200) - .style("opacity", 0.2) + if (newHoveredId === null) { + hoveredNeighbours = new Set() + for (const n of nodeRenderData) { + n.active = false } - // highlight links - linkNodes.transition().duration(200).attr("stroke", "var(--gray)").attr("stroke-width", 1) - - const bigFont = fontSize * 1.5 - - // show text for self - const parent = this.parentNode as HTMLElement - d3.select(parent) - .raise() - .select("text") - .transition() - .duration(200) - .attr("opacityOld", d3.select(parent).select("text").style("opacity")) - .style("opacity", 1) - .style("font-size", bigFont + "em") - }) - .on("mouseleave", function (_, d) { - if (focusOnHover) { - d3.selectAll(".link").transition().duration(200).style("opacity", 1) - d3.selectAll(".node").transition().duration(200).style("opacity", 1) + for (const l of linkRenderData) { + l.active = false } - const currentId = d.id - const linkNodes = d3 - .selectAll(".link") - .filter((d: any) => d.source.id === currentId || d.target.id === currentId) + } else { + hoveredNeighbours = new Set() + for (const l of linkRenderData) { + const linkData = l.simulationData + if (linkData.source.id === newHoveredId || linkData.target.id === newHoveredId) { + hoveredNeighbours.add(linkData.source.id) + hoveredNeighbours.add(linkData.target.id) + } - linkNodes.transition().duration(200).attr("stroke", "var(--lightgray)") + l.active = linkData.source.id === newHoveredId || linkData.target.id === newHoveredId + } - const parent = this.parentNode as HTMLElement - d3.select(parent) - .select("text") - .transition() - .duration(200) - .style("opacity", d3.select(parent).select("text").attr("opacityOld")) - .style("font-size", fontSize + "em") + for (const n of nodeRenderData) { + n.active = hoveredNeighbours.has(n.simulationData.id) + } + } + } + + let dragStartTime = 0 + let dragging = false + + function renderLinks() { + tweens.get("link")?.stop() + const tweenGroup = new TweenGroup() + + for (const l of linkRenderData) { + let alpha = 1 + + // if we are hovering over a node, we want to highlight the immediate neighbours + // with full alpha and the rest with default alpha + if (hoveredNodeId) { + alpha = l.active ? 1 : 0.2 + } + + l.color = l.active ? computedStyleMap["--gray"] : computedStyleMap["--lightgray"] + tweenGroup.add(new Tweened(l).to({ alpha }, 200)) + } + + tweenGroup.getAll().forEach((tw) => tw.start()) + tweens.set("link", { + update: tweenGroup.update.bind(tweenGroup), + stop() { + tweenGroup.getAll().forEach((tw) => tw.stop()) + }, }) - // @ts-ignore - .call(drag(simulation)) + } - // draw labels - const labels = graphNode - .append("text") - .attr("dx", 0) - .attr("dy", (d) => -nodeRadius(d) + "px") - .attr("text-anchor", "middle") - .text((d) => d.text) - .style("opacity", (opacityScale - 1) / 3.75) - .style("pointer-events", "none") - .style("font-size", fontSize + "em") - .raise() - // @ts-ignore - .call(drag(simulation)) + function renderLabels() { + tweens.get("label")?.stop() + const tweenGroup = new TweenGroup() + + const defaultScale = 1 / scale + const activeScale = defaultScale * 1.1 + for (const n of nodeRenderData) { + const nodeId = n.simulationData.id + + if (hoveredNodeId === nodeId) { + tweenGroup.add( + new Tweened(n.label).to( + { + alpha: 1, + scale: { x: activeScale, y: activeScale }, + }, + 100, + ), + ) + } else { + tweenGroup.add( + new Tweened(n.label).to( + { + alpha: n.label.alpha, + scale: { x: defaultScale, y: defaultScale }, + }, + 100, + ), + ) + } + } + + tweenGroup.getAll().forEach((tw) => tw.start()) + tweens.set("label", { + update: tweenGroup.update.bind(tweenGroup), + stop() { + tweenGroup.getAll().forEach((tw) => tw.stop()) + }, + }) + } + + function renderNodes() { + tweens.get("hover")?.stop() + + const tweenGroup = new TweenGroup() + for (const n of nodeRenderData) { + let alpha = 1 + + // if we are hovering over a node, we want to highlight the immediate neighbours + if (hoveredNodeId !== null && focusOnHover) { + alpha = n.active ? 1 : 0.2 + } + + tweenGroup.add(new Tweened(n.gfx, tweenGroup).to({ alpha }, 200)) + } + + tweenGroup.getAll().forEach((tw) => tw.start()) + tweens.set("hover", { + update: tweenGroup.update.bind(tweenGroup), + stop() { + tweenGroup.getAll().forEach((tw) => tw.stop()) + }, + }) + } + + function renderPixiFromD3() { + renderNodes() + renderLinks() + renderLabels() + } + + tweens.forEach((tween) => tween.stop()) + tweens.clear() + + const app = new Application() + await app.init({ + width, + height, + antialias: true, + autoStart: false, + autoDensity: true, + backgroundAlpha: 0, + preference: "webgpu", + resolution: window.devicePixelRatio, + eventMode: "static", + }) + graph.appendChild(app.canvas) + + const stage = app.stage + stage.interactive = false + + const labelsContainer = new Container({ zIndex: 3 }) + const nodesContainer = new Container({ zIndex: 2 }) + const linkContainer = new Container({ zIndex: 1 }) + stage.addChild(nodesContainer, labelsContainer, linkContainer) + + for (const n of graphData.nodes) { + const nodeId = n.id + + const label = new Text({ + interactive: false, + eventMode: "none", + text: n.text, + alpha: 0, + anchor: { x: 0.5, y: 1.2 }, + style: { + fontSize: fontSize * 15, + fill: computedStyleMap["--dark"], + fontFamily: computedStyleMap["--bodyFont"], + }, + resolution: window.devicePixelRatio * 4, + }) + label.scale.set(1 / scale) + + let oldLabelOpacity = 0 + const isTagNode = nodeId.startsWith("tags/") + const gfx = new Graphics({ + interactive: true, + label: nodeId, + eventMode: "static", + hitArea: new Circle(0, 0, nodeRadius(n)), + cursor: "pointer", + }) + .circle(0, 0, nodeRadius(n)) + .fill({ color: isTagNode ? computedStyleMap["--light"] : color(n) }) + .stroke({ width: isTagNode ? 2 : 0, color: color(n) }) + .on("pointerover", (e) => { + updateHoverInfo(e.target.label) + oldLabelOpacity = label.alpha + if (!dragging) { + renderPixiFromD3() + } + }) + .on("pointerleave", () => { + updateHoverInfo(null) + label.alpha = oldLabelOpacity + if (!dragging) { + renderPixiFromD3() + } + }) + + nodesContainer.addChild(gfx) + labelsContainer.addChild(label) + + const nodeRenderDatum: NodeRenderData = { + simulationData: n, + gfx, + label, + color: color(n), + alpha: 1, + active: false, + } + + nodeRenderData.push(nodeRenderDatum) + } + + for (const l of graphData.links) { + const gfx = new Graphics({ interactive: false, eventMode: "none" }) + linkContainer.addChild(gfx) + + const linkRenderDatum: LinkRenderData = { + simulationData: l, + gfx, + color: computedStyleMap["--lightgray"], + alpha: 1, + active: false, + } + + linkRenderData.push(linkRenderDatum) + } + + let currentTransform = zoomIdentity + if (enableDrag) { + select(app.canvas).call( + drag() + .container(() => app.canvas) + .subject(() => graphData.nodes.find((n) => n.id === hoveredNodeId)) + .on("start", function dragstarted(event) { + if (!event.active) simulation.alphaTarget(1).restart() + event.subject.fx = event.subject.x + event.subject.fy = event.subject.y + event.subject.__initialDragPos = { + x: event.subject.x, + y: event.subject.y, + fx: event.subject.fx, + fy: event.subject.fy, + } + dragStartTime = Date.now() + dragging = true + }) + .on("drag", function dragged(event) { + const initPos = event.subject.__initialDragPos + event.subject.fx = initPos.x + (event.x - initPos.x) / currentTransform.k + event.subject.fy = initPos.y + (event.y - initPos.y) / currentTransform.k + }) + .on("end", function dragended(event) { + if (!event.active) simulation.alphaTarget(0) + event.subject.fx = null + event.subject.fy = null + dragging = false + + // if the time between mousedown and mouseup is short, we consider it a click + if (Date.now() - dragStartTime < 500) { + const node = graphData.nodes.find((n) => n.id === event.subject.id) as NodeData + const targ = resolveRelative(fullSlug, node.id) + window.spaNavigate(new URL(targ, window.location.toString())) + } + }), + ) + } else { + for (const node of nodeRenderData) { + node.gfx.on("click", () => { + const targ = resolveRelative(fullSlug, node.simulationData.id) + window.spaNavigate(new URL(targ, window.location.toString())) + }) + } + } - // set panning if (enableZoom) { - svg.call( - d3 - .zoom() + select(app.canvas).call( + zoom() .extent([ [0, 0], [width, height], ]) .scaleExtent([0.25, 4]) .on("zoom", ({ transform }) => { - link.attr("transform", transform) - node.attr("transform", transform) + currentTransform = transform + stage.scale.set(transform.k, transform.k) + stage.position.set(transform.x, transform.y) + + // zoom adjusts opacity of labels too const scale = transform.k * opacityScale - const scaledOpacity = Math.max((scale - 1) / 3.75, 0) - labels.attr("transform", transform).style("opacity", scaledOpacity) + let scaleOpacity = Math.max((scale - 1) / 3.75, 0) + const activeNodes = nodeRenderData.filter((n) => n.active).flatMap((n) => n.label) + + for (const label of labelsContainer.children) { + if (!activeNodes.includes(label)) { + label.alpha = scaleOpacity + } + } }), ) } - // progress the simulation - simulation.on("tick", () => { - link - .attr("x1", (d: any) => d.source.x) - .attr("y1", (d: any) => d.source.y) - .attr("x2", (d: any) => d.target.x) - .attr("y2", (d: any) => d.target.y) - node.attr("cx", (d: any) => d.x).attr("cy", (d: any) => d.y) - labels.attr("x", (d: any) => d.x).attr("y", (d: any) => d.y) - }) -} - -function renderGlobalGraph() { - const slug = getFullSlug(window) - const container = document.getElementById("global-graph-outer") - const sidebar = container?.closest(".sidebar") as HTMLElement - container?.classList.add("active") - if (sidebar) { - sidebar.style.zIndex = "1" - } - - renderGraph("global-graph-container", slug) - - function hideGlobalGraph() { - container?.classList.remove("active") - const graph = document.getElementById("global-graph-container") - if (sidebar) { - sidebar.style.zIndex = "unset" + function animate(time: number) { + for (const n of nodeRenderData) { + const { x, y } = n.simulationData + if (!x || !y) continue + n.gfx.position.set(x + width / 2, y + height / 2) + if (n.label) { + n.label.position.set(x + width / 2, y + height / 2) + } } - if (!graph) return - removeAllChildren(graph) + + for (const l of linkRenderData) { + const linkData = l.simulationData + l.gfx.clear() + l.gfx.moveTo(linkData.source.x! + width / 2, linkData.source.y! + height / 2) + l.gfx + .lineTo(linkData.target.x! + width / 2, linkData.target.y! + height / 2) + .stroke({ alpha: l.alpha, width: 1, color: l.color }) + } + + tweens.forEach((t) => t.update(time)) + app.renderer.render(stage) + requestAnimationFrame(animate) } - registerEscapeHandler(container, hideGlobalGraph) + const graphAnimationFrameHandle = requestAnimationFrame(animate) + window.addCleanup(() => cancelAnimationFrame(graphAnimationFrameHandle)) } document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { const slug = e.detail.url - addToVisited(slug) + addToVisited(simplifySlug(slug)) await renderGraph("graph-container", slug) + // Function to re-render the graph when the theme changes + const handleThemeChange = () => { + renderGraph("graph-container", slug) + } + + // event listener for theme change + document.addEventListener("themechange", handleThemeChange) + + // cleanup for the event listener + window.addCleanup(() => { + document.removeEventListener("themechange", handleThemeChange) + }) + + const container = document.getElementById("global-graph-outer") + const sidebar = container?.closest(".sidebar") as HTMLElement + + function renderGlobalGraph() { + const slug = getFullSlug(window) + container?.classList.add("active") + if (sidebar) { + sidebar.style.zIndex = "1" + } + + renderGraph("global-graph-container", slug) + registerEscapeHandler(container, hideGlobalGraph) + } + + function hideGlobalGraph() { + container?.classList.remove("active") + if (sidebar) { + sidebar.style.zIndex = "" + } + } + + async function shortcutHandler(e: HTMLElementEventMap["keydown"]) { + if (e.key === "g" && (e.ctrlKey || e.metaKey) && !e.shiftKey) { + e.preventDefault() + const globalGraphOpen = container?.classList.contains("active") + globalGraphOpen ? hideGlobalGraph() : renderGlobalGraph() + } + } + const containerIcon = document.getElementById("global-graph-icon") containerIcon?.addEventListener("click", renderGlobalGraph) window.addCleanup(() => containerIcon?.removeEventListener("click", renderGlobalGraph)) + + document.addEventListener("keydown", shortcutHandler) + window.addCleanup(() => document.removeEventListener("keydown", shortcutHandler)) }) diff --git a/quartz/components/scripts/mermaid.inline.ts b/quartz/components/scripts/mermaid.inline.ts new file mode 100644 index 000000000..77a3ebe75 --- /dev/null +++ b/quartz/components/scripts/mermaid.inline.ts @@ -0,0 +1,242 @@ +import { removeAllChildren } from "./util" +import mermaid from "mermaid" + +interface Position { + x: number + y: number +} + +class DiagramPanZoom { + private isDragging = false + private startPan: Position = { x: 0, y: 0 } + private currentPan: Position = { x: 0, y: 0 } + private scale = 1 + private readonly MIN_SCALE = 0.5 + private readonly MAX_SCALE = 3 + private readonly ZOOM_SENSITIVITY = 0.001 + + constructor( + private container: HTMLElement, + private content: HTMLElement, + ) { + this.setupEventListeners() + this.setupNavigationControls() + } + + private setupEventListeners() { + // Mouse drag events + this.container.addEventListener("mousedown", this.onMouseDown.bind(this)) + document.addEventListener("mousemove", this.onMouseMove.bind(this)) + document.addEventListener("mouseup", this.onMouseUp.bind(this)) + + // Wheel zoom events + this.container.addEventListener("wheel", this.onWheel.bind(this), { passive: false }) + + // Reset on window resize + window.addEventListener("resize", this.resetTransform.bind(this)) + } + + private setupNavigationControls() { + const controls = document.createElement("div") + controls.className = "mermaid-controls" + + // Zoom controls + const zoomIn = this.createButton("+", () => this.zoom(0.1)) + const zoomOut = this.createButton("-", () => this.zoom(-0.1)) + const resetBtn = this.createButton("Reset", () => this.resetTransform()) + + controls.appendChild(zoomOut) + controls.appendChild(resetBtn) + controls.appendChild(zoomIn) + + this.container.appendChild(controls) + } + + private createButton(text: string, onClick: () => void): HTMLButtonElement { + const button = document.createElement("button") + button.textContent = text + button.className = "mermaid-control-button" + button.addEventListener("click", onClick) + window.addCleanup(() => button.removeEventListener("click", onClick)) + return button + } + + private onMouseDown(e: MouseEvent) { + if (e.button !== 0) return // Only handle left click + this.isDragging = true + this.startPan = { x: e.clientX - this.currentPan.x, y: e.clientY - this.currentPan.y } + this.container.style.cursor = "grabbing" + } + + private onMouseMove(e: MouseEvent) { + if (!this.isDragging) return + e.preventDefault() + + this.currentPan = { + x: e.clientX - this.startPan.x, + y: e.clientY - this.startPan.y, + } + + this.updateTransform() + } + + private onMouseUp() { + this.isDragging = false + this.container.style.cursor = "grab" + } + + private onWheel(e: WheelEvent) { + e.preventDefault() + + const delta = -e.deltaY * this.ZOOM_SENSITIVITY + const newScale = Math.min(Math.max(this.scale + delta, this.MIN_SCALE), this.MAX_SCALE) + + // Calculate mouse position relative to content + const rect = this.content.getBoundingClientRect() + const mouseX = e.clientX - rect.left + const mouseY = e.clientY - rect.top + + // Adjust pan to zoom around mouse position + const scaleDiff = newScale - this.scale + this.currentPan.x -= mouseX * scaleDiff + this.currentPan.y -= mouseY * scaleDiff + + this.scale = newScale + this.updateTransform() + } + + private zoom(delta: number) { + const newScale = Math.min(Math.max(this.scale + delta, this.MIN_SCALE), this.MAX_SCALE) + + // Zoom around center + const rect = this.content.getBoundingClientRect() + const centerX = rect.width / 2 + const centerY = rect.height / 2 + + const scaleDiff = newScale - this.scale + this.currentPan.x -= centerX * scaleDiff + this.currentPan.y -= centerY * scaleDiff + + this.scale = newScale + this.updateTransform() + } + + private updateTransform() { + this.content.style.transform = `translate(${this.currentPan.x}px, ${this.currentPan.y}px) scale(${this.scale})` + } + + private resetTransform() { + this.scale = 1 + this.currentPan = { x: 0, y: 0 } + this.updateTransform() + } +} + +const cssVars = [ + "--secondary", + "--tertiary", + "--gray", + "--light", + "--lightgray", + "--highlight", + "--dark", + "--darkgray", + "--codeFont", +] as const + +document.addEventListener("nav", async () => { + const center = document.querySelector(".center") as HTMLElement + const nodes = center.querySelectorAll("code.mermaid") as NodeListOf + if (nodes.length === 0) return + + const computedStyleMap = cssVars.reduce( + (acc, key) => { + acc[key] = getComputedStyle(document.documentElement).getPropertyValue(key) + return acc + }, + {} as Record<(typeof cssVars)[number], string>, + ) + + const darkMode = document.documentElement.getAttribute("saved-theme") === "dark" + mermaid.initialize({ + startOnLoad: false, + securityLevel: "loose", + theme: darkMode ? "dark" : "base", + themeVariables: { + fontFamily: computedStyleMap["--codeFont"], + primaryColor: computedStyleMap["--light"], + primaryTextColor: computedStyleMap["--darkgray"], + primaryBorderColor: computedStyleMap["--tertiary"], + lineColor: computedStyleMap["--darkgray"], + secondaryColor: computedStyleMap["--secondary"], + tertiaryColor: computedStyleMap["--tertiary"], + clusterBkg: computedStyleMap["--light"], + edgeLabelBackground: computedStyleMap["--highlight"], + }, + }) + await mermaid.run({ nodes }) + + for (let i = 0; i < nodes.length; i++) { + const codeBlock = nodes[i] as HTMLElement + const pre = codeBlock.parentElement as HTMLPreElement + const clipboardBtn = pre.querySelector(".clipboard-button") as HTMLButtonElement + const expandBtn = pre.querySelector(".expand-button") as HTMLButtonElement + + const clipboardStyle = window.getComputedStyle(clipboardBtn) + const clipboardWidth = + clipboardBtn.offsetWidth + + parseFloat(clipboardStyle.marginLeft || "0") + + parseFloat(clipboardStyle.marginRight || "0") + + // Set expand button position + expandBtn.style.right = `calc(${clipboardWidth}px + 0.3rem)` + pre.prepend(expandBtn) + + // query popup container + const popupContainer = pre.querySelector("#mermaid-container") as HTMLElement + if (!popupContainer) return + + let panZoom: DiagramPanZoom | null = null + + function showMermaid() { + const container = popupContainer.querySelector("#mermaid-space") as HTMLElement + const content = popupContainer.querySelector(".mermaid-content") as HTMLElement + if (!content) return + removeAllChildren(content) + + // Clone the mermaid content + const mermaidContent = codeBlock.querySelector("svg")!.cloneNode(true) as SVGElement + content.appendChild(mermaidContent) + + // Show container + popupContainer.classList.add("active") + container.style.cursor = "grab" + + // Initialize pan-zoom after showing the popup + panZoom = new DiagramPanZoom(container, content) + } + + function hideMermaid() { + popupContainer.classList.remove("active") + panZoom = null + } + + function handleEscape(e: any) { + if (e.key === "Escape") { + hideMermaid() + } + } + + const closeBtn = popupContainer.querySelector(".close-button") as HTMLButtonElement + + closeBtn.addEventListener("click", hideMermaid) + expandBtn.addEventListener("click", showMermaid) + document.addEventListener("keydown", handleEscape) + + window.addCleanup(() => { + closeBtn.removeEventListener("click", hideMermaid) + expandBtn.removeEventListener("click", showMermaid) + document.removeEventListener("keydown", handleEscape) + }) + } +}) diff --git a/quartz/components/scripts/popover.inline.ts b/quartz/components/scripts/popover.inline.ts index 972d3c638..49f438205 100644 --- a/quartz/components/scripts/popover.inline.ts +++ b/quartz/components/scripts/popover.inline.ts @@ -3,7 +3,7 @@ import { normalizeRelativeURLs } from "../../util/path" const p = new DOMParser() async function mouseEnterHandler( - this: HTMLLinkElement, + this: HTMLAnchorElement, { clientX, clientY }: { clientX: number; clientY: number }, ) { const link = this @@ -33,7 +33,7 @@ async function mouseEnterHandler( thisUrl.hash = "" thisUrl.search = "" const targetUrl = new URL(link.href) - const hash = targetUrl.hash + const hash = decodeURIComponent(targetUrl.hash) targetUrl.hash = "" targetUrl.search = "" @@ -100,7 +100,7 @@ async function mouseEnterHandler( } document.addEventListener("nav", () => { - const links = [...document.getElementsByClassName("internal")] as HTMLLinkElement[] + const links = [...document.getElementsByClassName("internal")] as HTMLAnchorElement[] for (const link of links) { link.addEventListener("mouseenter", mouseEnterHandler) window.addCleanup(() => link.removeEventListener("mouseenter", mouseEnterHandler)) diff --git a/quartz/components/scripts/search.inline.ts b/quartz/components/scripts/search.inline.ts index 72be6b8dd..f422d4988 100644 --- a/quartz/components/scripts/search.inline.ts +++ b/quartz/components/scripts/search.inline.ts @@ -148,7 +148,7 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { const data = await fetchData const container = document.getElementById("search-container") const sidebar = container?.closest(".sidebar") as HTMLElement - const searchIcon = document.getElementById("search-icon") + const searchButton = document.getElementById("search-button") const searchBar = document.getElementById("search-bar") as HTMLInputElement | null const searchLayout = document.getElementById("search-layout") const idDataMap = Object.keys(data) as FullSlug[] @@ -178,7 +178,7 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { searchBar.value = "" // clear the input when we dismiss the search } if (sidebar) { - sidebar.style.zIndex = "unset" + sidebar.style.zIndex = "" } if (results) { removeAllChildren(results) @@ -191,6 +191,8 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { } searchType = "basic" // reset search type after closing + + searchButton?.focus() } function showSearch(searchTypeNew: SearchType) { @@ -458,8 +460,8 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { document.addEventListener("keydown", shortcutHandler) window.addCleanup(() => document.removeEventListener("keydown", shortcutHandler)) - searchIcon?.addEventListener("click", () => showSearch("basic")) - window.addCleanup(() => searchIcon?.removeEventListener("click", () => showSearch("basic"))) + searchButton?.addEventListener("click", () => showSearch("basic")) + window.addCleanup(() => searchButton?.removeEventListener("click", () => showSearch("basic"))) searchBar?.addEventListener("input", onType) window.addCleanup(() => searchBar?.removeEventListener("input", onType)) diff --git a/quartz/components/scripts/toc.inline.ts b/quartz/components/scripts/toc.inline.ts index 546859ed3..2cfb3f921 100644 --- a/quartz/components/scripts/toc.inline.ts +++ b/quartz/components/scripts/toc.inline.ts @@ -16,10 +16,13 @@ const observer = new IntersectionObserver((entries) => { function toggleToc(this: HTMLElement) { this.classList.toggle("collapsed") + this.setAttribute( + "aria-expanded", + this.getAttribute("aria-expanded") === "true" ? "false" : "true", + ) const content = this.nextElementSibling as HTMLElement | undefined if (!content) return content.classList.toggle("collapsed") - content.style.maxHeight = content.style.maxHeight === "0px" ? content.scrollHeight + "px" : "0px" } function setupToc() { @@ -28,7 +31,6 @@ function setupToc() { const collapsed = toc.classList.contains("collapsed") const content = toc.nextElementSibling as HTMLElement | undefined if (!content) return - content.style.maxHeight = collapsed ? "0px" : content.scrollHeight + "px" toc.addEventListener("click", toggleToc) window.addCleanup(() => toc.removeEventListener("click", toggleToc)) } diff --git a/quartz/components/scripts/util.ts b/quartz/components/scripts/util.ts index 4ffff29e2..d0a16c651 100644 --- a/quartz/components/scripts/util.ts +++ b/quartz/components/scripts/util.ts @@ -3,6 +3,7 @@ export function registerEscapeHandler(outsideContainer: HTMLElement | null, cb: function click(this: HTMLElement, e: HTMLElementEventMap["click"]) { if (e.target !== this) return e.preventDefault() + e.stopPropagation() cb() } diff --git a/quartz/components/styles/backlinks.scss b/quartz/components/styles/backlinks.scss index 04302f22e..7b3237b8a 100644 --- a/quartz/components/styles/backlinks.scss +++ b/quartz/components/styles/backlinks.scss @@ -1,5 +1,19 @@ +@use "../../styles/variables.scss" as *; + .backlinks { - position: relative; + flex-direction: column; + /*&:after { + pointer-events: none; + content: ""; + width: 100%; + height: 50px; + position: absolute; + left: 0; + bottom: 0; + opacity: 1; + transition: opacity 0.3s ease; + background: linear-gradient(transparent 0px, var(--light)); + }*/ & > h3 { font-size: 1rem; @@ -17,4 +31,14 @@ } } } + + & > .overflow { + &:after { + display: none; + } + height: auto; + @media all and not ($desktop) { + height: 250px; + } + } } diff --git a/quartz/components/styles/darkmode.scss b/quartz/components/styles/darkmode.scss index 348c6f793..edf4e61cf 100644 --- a/quartz/components/styles/darkmode.scss +++ b/quartz/components/styles/darkmode.scss @@ -1,17 +1,15 @@ .darkmode { + cursor: pointer; + padding: 0; position: relative; + background: none; + border: none; width: 20px; height: 20px; margin: 0 10px; - - & > .toggle { - display: none; - box-sizing: border-box; - } + text-align: inherit; & svg { - cursor: pointer; - opacity: 0; position: absolute; width: 20px; height: 20px; @@ -29,20 +27,20 @@ color-scheme: light; } -:root[saved-theme="dark"] .toggle ~ label { +:root[saved-theme="dark"] .darkmode { & > #dayIcon { - opacity: 0; + display: none; } & > #nightIcon { - opacity: 1; + display: inline; } } -:root .toggle ~ label { +:root .darkmode { & > #dayIcon { - opacity: 1; + display: inline; } & > #nightIcon { - opacity: 0; + display: none; } } diff --git a/quartz/components/styles/explorer.scss b/quartz/components/styles/explorer.scss index 55ea8aa88..397fd0241 100644 --- a/quartz/components/styles/explorer.scss +++ b/quartz/components/styles/explorer.scss @@ -1,7 +1,29 @@ @use "../../styles/variables.scss" as *; +.explorer { + display: flex; + flex-direction: column; + overflow-y: hidden; + &.desktop-only { + @media all and not ($mobile) { + display: flex; + } + } + /*&:after { + pointer-events: none; + content: ""; + width: 100%; + height: 50px; + position: absolute; + left: 0; + bottom: 0; + opacity: 1; + transition: opacity 0.3s ease; + background: linear-gradient(transparent 0px, var(--light)); + }*/ +} + button#explorer { - all: unset; background-color: transparent; border: none; text-align: left; @@ -11,7 +33,7 @@ button#explorer { display: flex; align-items: center; - & h1 { + & h2 { font-size: 1rem; display: inline-block; margin: 0; @@ -45,12 +67,20 @@ button#explorer { #explorer-content { list-style: none; overflow: hidden; - max-height: none; - transition: max-height 0.35s ease; + overflow-y: auto; + max-height: 100%; + transition: + max-height 0.35s ease, + visibility 0s linear 0s; margin-top: 0.5rem; + visibility: visible; - &.collapsed > .overflow::after { - opacity: 0; + &.collapsed { + max-height: 0; + transition: + max-height 0.35s ease, + visibility 0s linear 0.35s; + visibility: hidden; } & ul { @@ -67,6 +97,9 @@ button#explorer { pointer-events: all; } } + > #explorer-ul { + max-height: none; + } } svg { diff --git a/quartz/components/styles/graph.scss b/quartz/components/styles/graph.scss index 3deaa1feb..1b19f132c 100644 --- a/quartz/components/styles/graph.scss +++ b/quartz/components/styles/graph.scss @@ -16,10 +16,13 @@ overflow: hidden; & > #global-graph-icon { + cursor: pointer; + background: none; + border: none; color: var(--dark); opacity: 0.5; - width: 18px; - height: 18px; + width: 24px; + height: 24px; position: absolute; padding: 0.2rem; margin: 0.3rem; @@ -59,10 +62,10 @@ top: 50%; left: 50%; transform: translate(-50%, -50%); - height: 60vh; - width: 50vw; + height: 80vh; + width: 80vw; - @media all and (max-width: $fullPageWidth) { + @media all and not ($desktop) { width: 90%; } } diff --git a/quartz/components/styles/listPage.scss b/quartz/components/styles/listPage.scss index c8fc9e957..e86c39dcb 100644 --- a/quartz/components/styles/listPage.scss +++ b/quartz/components/styles/listPage.scss @@ -11,9 +11,9 @@ li.section-li { & > .section { display: grid; - grid-template-columns: 6em 3fr 1fr; + grid-template-columns: fit-content(8em) 3fr 1fr; - @media all and (max-width: $mobileBreakpoint) { + @media all and ($mobile) { & > .tags { display: none; } @@ -23,9 +23,8 @@ li.section-li { background-color: transparent; } - & > .meta { - margin: 0; - flex-basis: 6em; + & .meta { + margin: 0 1em 0 0; opacity: 0.6; } } @@ -33,7 +32,8 @@ li.section-li { // modifications in popover context .popover .section { - grid-template-columns: 6em 1fr !important; + grid-template-columns: fit-content(8em) 1fr !important; + & > .tags { display: none; } diff --git a/quartz/components/styles/mermaid.inline.scss b/quartz/components/styles/mermaid.inline.scss new file mode 100644 index 000000000..79a1c8495 --- /dev/null +++ b/quartz/components/styles/mermaid.inline.scss @@ -0,0 +1,163 @@ +.expand-button { + position: absolute; + display: flex; + float: right; + padding: 0.4rem; + margin: 0.3rem; + right: 0; // NOTE: right will be set in mermaid.inline.ts + color: var(--gray); + border-color: var(--dark); + background-color: var(--light); + border: 1px solid; + border-radius: 5px; + opacity: 0; + transition: 0.2s; + + & > svg { + fill: var(--light); + filter: contrast(0.3); + } + + &:hover { + cursor: pointer; + border-color: var(--secondary); + } + + &:focus { + outline: 0; + } +} + +pre { + &:hover > .expand-button { + opacity: 1; + transition: 0.2s; + } +} + +#mermaid-container { + position: fixed; + contain: layout; + z-index: 999; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + overflow: hidden; + display: none; + backdrop-filter: blur(4px); + background: rgba(0, 0, 0, 0.5); + + &.active { + display: inline-block; + } + + & > #mermaid-space { + display: grid; + width: 90%; + height: 90vh; + margin: 5vh auto; + background: var(--light); + box-shadow: + 0 14px 50px rgba(27, 33, 48, 0.12), + 0 10px 30px rgba(27, 33, 48, 0.16); + overflow: hidden; + position: relative; + + & > .mermaid-header { + display: flex; + justify-content: flex-end; + padding: 1rem; + border-bottom: 1px solid var(--lightgray); + background: var(--light); + z-index: 2; + max-height: fit-content; + + & > .close-button { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 0; + background: transparent; + border: none; + border-radius: 4px; + color: var(--darkgray); + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + background: var(--lightgray); + color: var(--dark); + } + } + } + + & > .mermaid-content { + padding: 2rem; + position: relative; + transform-origin: 0 0; + transition: transform 0.1s ease; + overflow: visible; + min-height: 200px; + min-width: 200px; + + pre { + margin: 0; + border: none; + } + + svg { + max-width: none; + height: auto; + } + } + + & > .mermaid-controls { + position: absolute; + bottom: 20px; + right: 20px; + display: flex; + gap: 8px; + padding: 8px; + background: var(--light); + border: 1px solid var(--lightgray); + border-radius: 6px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + z-index: 2; + + .mermaid-control-button { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 0; + border: 1px solid var(--lightgray); + background: var(--light); + color: var(--dark); + border-radius: 4px; + cursor: pointer; + font-size: 16px; + font-family: var(--bodyFont); + transition: all 0.2s ease; + + &:hover { + background: var(--lightgray); + } + + &:active { + transform: translateY(1px); + } + + // Style the reset button differently + &:nth-child(2) { + width: auto; + padding: 0 12px; + font-size: 14px; + } + } + } + } +} diff --git a/quartz/components/styles/popover.scss b/quartz/components/styles/popover.scss index b1694f97c..38d612697 100644 --- a/quartz/components/styles/popover.scss +++ b/quartz/components/styles/popover.scss @@ -70,7 +70,7 @@ opacity 0.3s ease, visibility 0.3s ease; - @media all and (max-width: $mobileBreakpoint) { + @media all and ($mobile) { display: none !important; } } diff --git a/quartz/components/styles/search.scss b/quartz/components/styles/search.scss index 8a9ec6714..080178fbe 100644 --- a/quartz/components/styles/search.scss +++ b/quartz/components/styles/search.scss @@ -3,20 +3,25 @@ .search { min-width: fit-content; max-width: 14rem; - flex-grow: 0.3; + @media all and ($mobile) { + flex-grow: 0.3; + } - & > #search-icon { + & > .search-button { background-color: var(--lightgray); + border: none; border-radius: 4px; + font-family: inherit; + font-size: inherit; height: 2rem; + padding: 0; display: flex; align-items: center; + text-align: inherit; cursor: pointer; white-space: nowrap; - - & > div { - flex-grow: 1; - } + width: 100%; + justify-content: space-between; & > p { display: inline; @@ -59,7 +64,7 @@ margin-left: auto; margin-right: auto; - @media all and (max-width: $fullPageWidth) { + @media all and not ($desktop) { width: 90%; } @@ -101,7 +106,7 @@ flex: 0 0 min(30%, 450px); } - @media all and (min-width: $tabletBreakpoint) { + @media all and not ($tablet) { &[data-preview] { & .result-card > p.preview { display: none; @@ -127,7 +132,7 @@ border-radius: 5px; } - @media all and (max-width: $tabletBreakpoint) { + @media all and ($tablet) { & > #preview-container { display: none !important; } diff --git a/quartz/components/styles/toc.scss b/quartz/components/styles/toc.scss index 27ff62a40..4988cd836 100644 --- a/quartz/components/styles/toc.scss +++ b/quartz/components/styles/toc.scss @@ -1,3 +1,20 @@ +@use "../../styles/variables.scss" as *; + +.toc { + display: flex; + flex-direction: column; + + &.desktop-only { + max-height: 40%; + } +} + +@media all and not ($mobile) { + .toc { + display: flex; + } +} + button#toc { background-color: transparent; border: none; @@ -28,9 +45,21 @@ button#toc { #toc-content { list-style: none; overflow: hidden; - max-height: none; - transition: max-height 0.5s ease; + overflow-y: auto; + max-height: 100%; + transition: + max-height 0.35s ease, + visibility 0s linear 0s; position: relative; + visibility: visible; + + &.collapsed { + max-height: 0; + transition: + max-height 0.35s ease, + visibility 0s linear 0.35s; + visibility: hidden; + } &.collapsed > .overflow::after { opacity: 0; @@ -51,6 +80,10 @@ button#toc { } } } + > ul.overflow { + max-height: none; + width: 100%; + } @for $i from 0 through 6 { & .depth-#{$i} { diff --git a/quartz/i18n/index.ts b/quartz/i18n/index.ts index eab1f1a78..f328ada8d 100644 --- a/quartz/i18n/index.ts +++ b/quartz/i18n/index.ts @@ -1,11 +1,13 @@ import { Translation, CalloutTranslation } from "./locales/definition" -import en from "./locales/en-US" +import enUs from "./locales/en-US" +import enGb from "./locales/en-GB" import fr from "./locales/fr-FR" import it from "./locales/it-IT" import ja from "./locales/ja-JP" import de from "./locales/de-DE" import nl from "./locales/nl-NL" import ro from "./locales/ro-RO" +import ca from "./locales/ca-ES" import es from "./locales/es-ES" import ar from "./locales/ar-SA" import uk from "./locales/uk-UA" @@ -17,9 +19,12 @@ import pt from "./locales/pt-BR" import hu from "./locales/hu-HU" import fa from "./locales/fa-IR" import pl from "./locales/pl-PL" +import cs from "./locales/cs-CZ" +import tr from "./locales/tr-TR" export const TRANSLATIONS = { - "en-US": en, + "en-US": enUs, + "en-GB": enGb, "fr-FR": fr, "it-IT": it, "ja-JP": ja, @@ -28,6 +33,7 @@ export const TRANSLATIONS = { "nl-BE": nl, "ro-RO": ro, "ro-MD": ro, + "ca-ES": ca, "es-ES": es, "ar-SA": ar, "ar-AE": ar, @@ -58,6 +64,8 @@ export const TRANSLATIONS = { "hu-HU": hu, "fa-IR": fa, "pl-PL": pl, + "cs-CZ": cs, + "tr-TR": tr, } as const export const defaultTranslation = "en-US" diff --git a/quartz/i18n/locales/ca-ES.ts b/quartz/i18n/locales/ca-ES.ts new file mode 100644 index 000000000..aadbd4157 --- /dev/null +++ b/quartz/i18n/locales/ca-ES.ts @@ -0,0 +1,84 @@ +import { Translation } from "./definition" + +export default { + propertyDefaults: { + title: "Sense títol", + description: "Sense descripció", + }, + components: { + callout: { + note: "Nota", + abstract: "Resum", + info: "Informació", + todo: "Per fer", + tip: "Consell", + success: "Èxit", + question: "Pregunta", + warning: "Advertència", + failure: "Fall", + danger: "Perill", + bug: "Error", + example: "Exemple", + quote: "Cita", + }, + backlinks: { + title: "Retroenllaç", + noBacklinksFound: "No s'han trobat retroenllaços", + }, + themeToggle: { + lightMode: "Mode clar", + darkMode: "Mode fosc", + }, + explorer: { + title: "Explorador", + }, + footer: { + createdWith: "Creat amb", + }, + graph: { + title: "Vista Gràfica", + }, + recentNotes: { + title: "Notes Recents", + seeRemainingMore: ({ remaining }) => `Vegi ${remaining} més →`, + }, + transcludes: { + transcludeOf: ({ targetSlug }) => `Transcluit de ${targetSlug}`, + linkToOriginal: "Enllaç a l'original", + }, + search: { + title: "Cercar", + searchBarPlaceholder: "Cerca alguna cosa", + }, + tableOfContents: { + title: "Taula de Continguts", + }, + contentMeta: { + readingTime: ({ minutes }) => `Es llegeix en ${minutes} min`, + }, + }, + pages: { + rss: { + recentNotes: "Notes recents", + lastFewNotes: ({ count }) => `Últimes ${count} notes`, + }, + error: { + title: "No s'ha trobat.", + notFound: "Aquesta pàgina és privada o no existeix.", + home: "Torna a la pàgina principal", + }, + folderContent: { + folder: "Carpeta", + itemsUnderFolder: ({ count }) => + count === 1 ? "1 article en aquesta carpeta." : `${count} articles en esta carpeta.`, + }, + tagContent: { + tag: "Etiqueta", + tagIndex: "índex d'Etiquetes", + itemsUnderTag: ({ count }) => + count === 1 ? "1 article amb aquesta etiqueta." : `${count} article amb aquesta etiqueta.`, + showingFirst: ({ count }) => `Mostrant les primeres ${count} etiquetes.`, + totalTags: ({ count }) => `S'han trobat ${count} etiquetes en total.`, + }, + }, +} as const satisfies Translation diff --git a/quartz/i18n/locales/cs-CZ.ts b/quartz/i18n/locales/cs-CZ.ts new file mode 100644 index 000000000..bf089d137 --- /dev/null +++ b/quartz/i18n/locales/cs-CZ.ts @@ -0,0 +1,84 @@ +import { Translation } from "./definition" + +export default { + propertyDefaults: { + title: "Bez názvu", + description: "Nebyl uveden žádný popis", + }, + components: { + callout: { + note: "Poznámka", + abstract: "Abstract", + info: "Info", + todo: "Todo", + tip: "Tip", + success: "Úspěch", + question: "Otázka", + warning: "Upozornění", + failure: "Chyba", + danger: "Nebezpečí", + bug: "Bug", + example: "Příklad", + quote: "Citace", + }, + backlinks: { + title: "Příchozí odkazy", + noBacklinksFound: "Nenalezeny žádné příchozí odkazy", + }, + themeToggle: { + lightMode: "Světlý režim", + darkMode: "Tmavý režim", + }, + explorer: { + title: "Procházet", + }, + footer: { + createdWith: "Vytvořeno pomocí", + }, + graph: { + title: "Graf", + }, + recentNotes: { + title: "Nejnovější poznámky", + seeRemainingMore: ({ remaining }) => `Zobraz ${remaining} dalších →`, + }, + transcludes: { + transcludeOf: ({ targetSlug }) => `Zobrazení ${targetSlug}`, + linkToOriginal: "Odkaz na původní dokument", + }, + search: { + title: "Hledat", + searchBarPlaceholder: "Hledejte něco", + }, + tableOfContents: { + title: "Obsah", + }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min čtení`, + }, + }, + pages: { + rss: { + recentNotes: "Nejnovější poznámky", + lastFewNotes: ({ count }) => `Posledních ${count} poznámek`, + }, + error: { + title: "Nenalezeno", + notFound: "Tato stránka je buď soukromá, nebo neexistuje.", + home: "Návrat na domovskou stránku", + }, + folderContent: { + folder: "Složka", + itemsUnderFolder: ({ count }) => + count === 1 ? "1 položka v této složce." : `${count} položek v této složce.`, + }, + tagContent: { + tag: "Tag", + tagIndex: "Rejstřík tagů", + itemsUnderTag: ({ count }) => + count === 1 ? "1 položka s tímto tagem." : `${count} položek s tímto tagem.`, + showingFirst: ({ count }) => `Zobrazují se první ${count} tagy.`, + totalTags: ({ count }) => `Nalezeno celkem ${count} tagů.`, + }, + }, +} as const satisfies Translation diff --git a/quartz/i18n/locales/en-GB.ts b/quartz/i18n/locales/en-GB.ts new file mode 100644 index 000000000..5388b032c --- /dev/null +++ b/quartz/i18n/locales/en-GB.ts @@ -0,0 +1,84 @@ +import { Translation } from "./definition" + +export default { + propertyDefaults: { + title: "Untitled", + description: "No description provided", + }, + components: { + callout: { + note: "Note", + abstract: "Abstract", + info: "Info", + todo: "To-Do", + tip: "Tip", + success: "Success", + question: "Question", + warning: "Warning", + failure: "Failure", + danger: "Danger", + bug: "Bug", + example: "Example", + quote: "Quote", + }, + backlinks: { + title: "Backlinks", + noBacklinksFound: "No backlinks found", + }, + themeToggle: { + lightMode: "Light mode", + darkMode: "Dark mode", + }, + explorer: { + title: "Explorer", + }, + footer: { + createdWith: "Created with", + }, + graph: { + title: "Graph View", + }, + recentNotes: { + title: "Recent Notes", + seeRemainingMore: ({ remaining }) => `See ${remaining} more →`, + }, + transcludes: { + transcludeOf: ({ targetSlug }) => `Transclude of ${targetSlug}`, + linkToOriginal: "Link to original", + }, + search: { + title: "Search", + searchBarPlaceholder: "Search for something", + }, + tableOfContents: { + title: "Table of Contents", + }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, + }, + pages: { + rss: { + recentNotes: "Recent notes", + lastFewNotes: ({ count }) => `Last ${count} notes`, + }, + error: { + title: "Not Found", + notFound: "Either this page is private or doesn't exist.", + home: "Return to Homepage", + }, + folderContent: { + folder: "Folder", + itemsUnderFolder: ({ count }) => + count === 1 ? "1 item under this folder." : `${count} items under this folder.`, + }, + tagContent: { + tag: "Tag", + tagIndex: "Tag Index", + itemsUnderTag: ({ count }) => + count === 1 ? "1 item with this tag." : `${count} items with this tag.`, + showingFirst: ({ count }) => `Showing first ${count} tags.`, + totalTags: ({ count }) => `Found ${count} total tags.`, + }, + }, +} as const satisfies Translation diff --git a/quartz/i18n/locales/es-ES.ts b/quartz/i18n/locales/es-ES.ts index 8b0adcc37..c4a57aa12 100644 --- a/quartz/i18n/locales/es-ES.ts +++ b/quartz/i18n/locales/es-ES.ts @@ -22,8 +22,8 @@ export default { quote: "Cita", }, backlinks: { - title: "Enlaces de Retroceso", - noBacklinksFound: "No se han encontrado enlaces traseros", + title: "Retroenlaces", + noBacklinksFound: "No se han encontrado retroenlaces", }, themeToggle: { lightMode: "Modo claro", @@ -54,18 +54,18 @@ export default { title: "Tabla de Contenidos", }, contentMeta: { - readingTime: ({ minutes }) => `${minutes} min read`, + readingTime: ({ minutes }) => `Se lee en ${minutes} min`, }, }, pages: { rss: { recentNotes: "Notas recientes", - lastFewNotes: ({ count }) => `Últimás ${count} notas`, + lastFewNotes: ({ count }) => `Últimas ${count} notas`, }, error: { - title: "No se encontró.", + title: "No se ha encontrado.", notFound: "Esta página es privada o no existe.", - home: "Regresar a la página principal", + home: "Regresa a la página principal", }, folderContent: { folder: "Carpeta", @@ -78,7 +78,7 @@ export default { itemsUnderTag: ({ count }) => count === 1 ? "1 artículo con esta etiqueta." : `${count} artículos con esta etiqueta.`, showingFirst: ({ count }) => `Mostrando las primeras ${count} etiquetas.`, - totalTags: ({ count }) => `Se encontraron ${count} etiquetas en total.`, + totalTags: ({ count }) => `Se han encontrado ${count} etiquetas en total.`, }, }, } as const satisfies Translation diff --git a/quartz/i18n/locales/tr-TR.ts b/quartz/i18n/locales/tr-TR.ts new file mode 100644 index 000000000..a3805d1a9 --- /dev/null +++ b/quartz/i18n/locales/tr-TR.ts @@ -0,0 +1,84 @@ +import { Translation } from "./definition" + +export default { + propertyDefaults: { + title: "İsimsiz", + description: "Herhangi bir açıklama eklenmedi", + }, + components: { + callout: { + note: "Not", + abstract: "Özet", + info: "Bilgi", + todo: "Yapılacaklar", + tip: "İpucu", + success: "Başarılı", + question: "Soru", + warning: "Uyarı", + failure: "Başarısız", + danger: "Tehlike", + bug: "Hata", + example: "Örnek", + quote: "Alıntı", + }, + backlinks: { + title: "Backlinkler", + noBacklinksFound: "Backlink bulunamadı", + }, + themeToggle: { + lightMode: "Açık mod", + darkMode: "Koyu mod", + }, + explorer: { + title: "Gezgin", + }, + footer: { + createdWith: "Şununla oluşturuldu", + }, + graph: { + title: "Grafik Görünümü", + }, + recentNotes: { + title: "Son Notlar", + seeRemainingMore: ({ remaining }) => `${remaining} tane daha gör →`, + }, + transcludes: { + transcludeOf: ({ targetSlug }) => `${targetSlug} sayfasından alıntı`, + linkToOriginal: "Orijinal bağlantı", + }, + search: { + title: "Arama", + searchBarPlaceholder: "Bir şey arayın", + }, + tableOfContents: { + title: "İçindekiler", + }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} dakika okuma süresi`, + }, + }, + pages: { + rss: { + recentNotes: "Son notlar", + lastFewNotes: ({ count }) => `Son ${count} not`, + }, + error: { + title: "Bulunamadı", + notFound: "Bu sayfa ya özel ya da mevcut değil.", + home: "Anasayfaya geri dön", + }, + folderContent: { + folder: "Klasör", + itemsUnderFolder: ({ count }) => + count === 1 ? "Bu klasör altında 1 öğe." : `Bu klasör altındaki ${count} öğe.`, + }, + tagContent: { + tag: "Etiket", + tagIndex: "Etiket Sırası", + itemsUnderTag: ({ count }) => + count === 1 ? "Bu etikete sahip 1 öğe." : `Bu etiket altındaki ${count} öğe.`, + showingFirst: ({ count }) => `İlk ${count} etiket gösteriliyor.`, + totalTags: ({ count }) => `Toplam ${count} adet etiket bulundu.`, + }, + }, +} as const satisfies Translation diff --git a/quartz/i18n/locales/uk-UA.ts b/quartz/i18n/locales/uk-UA.ts index d39febb75..469de4f80 100644 --- a/quartz/i18n/locales/uk-UA.ts +++ b/quartz/i18n/locales/uk-UA.ts @@ -54,7 +54,7 @@ export default { title: "Зміст", }, contentMeta: { - readingTime: ({ minutes }) => `${minutes} min read`, + readingTime: ({ minutes }) => `${minutes} хв читання`, }, }, pages: { @@ -68,17 +68,17 @@ export default { home: "Повернутися на головну сторінку", }, folderContent: { - folder: "Папка", + folder: "Тека", itemsUnderFolder: ({ count }) => - count === 1 ? "У цій папці 1 елемент." : `Елементів у цій папці: ${count}.`, + count === 1 ? "У цій теці 1 елемент." : `Елементів у цій теці: ${count}.`, }, tagContent: { - tag: "Тег", - tagIndex: "Індекс тегу", + tag: "Мітка", + tagIndex: "Індекс мітки", itemsUnderTag: ({ count }) => - count === 1 ? "1 елемент з цим тегом." : `Елементів з цим тегом: ${count}.`, - showingFirst: ({ count }) => `Показ перших ${count} тегів.`, - totalTags: ({ count }) => `Всього знайдено тегів: ${count}.`, + count === 1 ? "1 елемент з цією міткою." : `Елементів з цією міткою: ${count}.`, + showingFirst: ({ count }) => `Показ перших ${count} міток.`, + totalTags: ({ count }) => `Всього знайдено міток: ${count}.`, }, }, } as const satisfies Translation diff --git a/quartz/plugins/emitters/componentResources.ts b/quartz/plugins/emitters/componentResources.ts index e6725d99d..08278305e 100644 --- a/quartz/plugins/emitters/componentResources.ts +++ b/quartz/plugins/emitters/componentResources.ts @@ -144,6 +144,23 @@ function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentReso tinylyticsScript.defer = true document.head.appendChild(tinylyticsScript) `) + } else if (cfg.analytics?.provider === "cabin") { + componentResources.afterDOMLoaded.push(` + const cabinScript = document.createElement("script") + cabinScript.src = "${cfg.analytics.host ?? "https://scripts.withcabin.com"}/hello.js" + cabinScript.defer = true + cabinScript.async = true + document.head.appendChild(cabinScript) + `) + } else if (cfg.analytics?.provider === "clarity") { + componentResources.afterDOMLoaded.push(` + const clarityScript = document.createElement("script") + clarityScript.innerHTML= \`(function(c,l,a,r,i,t,y){c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; + t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; + y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); + })(window, document, "clarity", "script", "${cfg.analytics.projectId}");\` + document.head.appendChild(clarityScript) + `) } if (cfg.enableSPA) { diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx index f4938026e..2ac132147 100644 --- a/quartz/plugins/emitters/contentPage.tsx +++ b/quartz/plugins/emitters/contentPage.tsx @@ -59,14 +59,25 @@ export const ContentPage: QuartzEmitterPlugin> = (userOp ...userOpts, } - const { head: Head, header, beforeBody, pageBody, left, right, footer: Footer } = opts + const { head: Head, header, beforeBody, pageBody, afterBody, left, right, footer: Footer } = opts const Header = HeaderConstructor() const Body = BodyConstructor() return { name: "ContentPage", getQuartzComponents() { - return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] + return [ + Head, + Header, + Body, + ...header, + ...beforeBody, + pageBody, + ...afterBody, + ...left, + ...right, + Footer, + ] }, async getDependencyGraph(ctx, content, _resources) { const graph = new DepGraph() diff --git a/quartz/plugins/emitters/folderPage.tsx b/quartz/plugins/emitters/folderPage.tsx index d892b282a..b6d860272 100644 --- a/quartz/plugins/emitters/folderPage.tsx +++ b/quartz/plugins/emitters/folderPage.tsx @@ -3,7 +3,7 @@ import { QuartzComponentProps } from "../../components/types" import HeaderConstructor from "../../components/Header" import BodyConstructor from "../../components/Body" import { pageResources, renderPage } from "../../components/renderPage" -import { ProcessedContent, defaultProcessedContent } from "../vfile" +import { ProcessedContent, QuartzPluginData, defaultProcessedContent } from "../vfile" import { FullPageLayout } from "../../cfg" import path from "path" import { @@ -21,22 +21,37 @@ import { write } from "./helpers" import { i18n } from "../../i18n" import DepGraph from "../../depgraph" -export const FolderPage: QuartzEmitterPlugin> = (userOpts) => { +interface FolderPageOptions extends FullPageLayout { + sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number +} + +export const FolderPage: QuartzEmitterPlugin> = (userOpts) => { const opts: FullPageLayout = { ...sharedPageComponents, ...defaultListPageLayout, - pageBody: FolderContent(), + pageBody: FolderContent({ sort: userOpts?.sort }), ...userOpts, } - const { head: Head, header, beforeBody, pageBody, left, right, footer: Footer } = opts + const { head: Head, header, beforeBody, pageBody, afterBody, left, right, footer: Footer } = opts const Header = HeaderConstructor() const Body = BodyConstructor() return { name: "FolderPage", getQuartzComponents() { - return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] + return [ + Head, + Header, + Body, + ...header, + ...beforeBody, + pageBody, + ...afterBody, + ...left, + ...right, + Footer, + ] }, async getDependencyGraph(_ctx, content, _resources) { // Example graph: @@ -61,12 +76,11 @@ export const FolderPage: QuartzEmitterPlugin> = (userOpt const folders: Set = new Set( allFiles.flatMap((data) => { - const slug = data.slug - const folderName = path.dirname(slug ?? "") as SimpleSlug - if (slug && folderName !== "." && folderName !== "tags") { - return [folderName] - } - return [] + return data.slug + ? _getFolders(data.slug).filter( + (folderName) => folderName !== "." && folderName !== "tags", + ) + : [] }), ) @@ -118,3 +132,14 @@ export const FolderPage: QuartzEmitterPlugin> = (userOpt }, } } + +function _getFolders(slug: FullSlug): SimpleSlug[] { + var folderName = path.dirname(slug ?? "") as SimpleSlug + const parentFolderNames = [folderName] + + while (folderName !== ".") { + folderName = path.dirname(folderName ?? "") as SimpleSlug + parentFolderNames.push(folderName) + } + return parentFolderNames +} diff --git a/quartz/plugins/emitters/tagPage.tsx b/quartz/plugins/emitters/tagPage.tsx index d88d0722a..066d4ec26 100644 --- a/quartz/plugins/emitters/tagPage.tsx +++ b/quartz/plugins/emitters/tagPage.tsx @@ -3,7 +3,7 @@ import { QuartzComponentProps } from "../../components/types" import HeaderConstructor from "../../components/Header" import BodyConstructor from "../../components/Body" import { pageResources, renderPage } from "../../components/renderPage" -import { ProcessedContent, defaultProcessedContent } from "../vfile" +import { ProcessedContent, QuartzPluginData, defaultProcessedContent } from "../vfile" import { FullPageLayout } from "../../cfg" import { FilePath, @@ -18,22 +18,37 @@ import { write } from "./helpers" import { i18n } from "../../i18n" import DepGraph from "../../depgraph" -export const TagPage: QuartzEmitterPlugin> = (userOpts) => { +interface TagPageOptions extends FullPageLayout { + sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number +} + +export const TagPage: QuartzEmitterPlugin> = (userOpts) => { const opts: FullPageLayout = { ...sharedPageComponents, ...defaultListPageLayout, - pageBody: TagContent(), + pageBody: TagContent({ sort: userOpts?.sort }), ...userOpts, } - const { head: Head, header, beforeBody, pageBody, left, right, footer: Footer } = opts + const { head: Head, header, beforeBody, pageBody, afterBody, left, right, footer: Footer } = opts const Header = HeaderConstructor() const Body = BodyConstructor() return { name: "TagPage", getQuartzComponents() { - return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] + return [ + Head, + Header, + Body, + ...header, + ...beforeBody, + pageBody, + ...afterBody, + ...left, + ...right, + Footer, + ] }, async getDependencyGraph(ctx, content, _resources) { const graph = new DepGraph() diff --git a/quartz/plugins/filters/draft.ts b/quartz/plugins/filters/draft.ts index 65e2d6b61..e8f1d4eea 100644 --- a/quartz/plugins/filters/draft.ts +++ b/quartz/plugins/filters/draft.ts @@ -3,7 +3,8 @@ import { QuartzFilterPlugin } from "../types" export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({ name: "RemoveDrafts", shouldPublish(_ctx, [_tree, vfile]) { - const draftFlag: boolean = vfile.data?.frontmatter?.draft ?? false + const draftFlag: boolean = + vfile.data?.frontmatter?.draft === true || vfile.data?.frontmatter?.draft === "true" return !draftFlag }, }) diff --git a/quartz/plugins/filters/explicit.ts b/quartz/plugins/filters/explicit.ts index 79a46a81c..e2558e827 100644 --- a/quartz/plugins/filters/explicit.ts +++ b/quartz/plugins/filters/explicit.ts @@ -3,6 +3,6 @@ import { QuartzFilterPlugin } from "../types" export const ExplicitPublish: QuartzFilterPlugin = () => ({ name: "ExplicitPublish", shouldPublish(_ctx, [_tree, vfile]) { - return vfile.data?.frontmatter?.publish ?? false + return vfile.data?.frontmatter?.publish === true || vfile.data?.frontmatter?.publish === "true" }, }) diff --git a/quartz/plugins/index.ts b/quartz/plugins/index.ts index 554b1170b..df9fd1d24 100644 --- a/quartz/plugins/index.ts +++ b/quartz/plugins/index.ts @@ -28,10 +28,10 @@ export function getStaticResourcesFromPlugins(ctx: BuildCtx) { loadTime: "afterDOMReady", contentType: "inline", script: ` - const socket = new WebSocket('${wsUrl}') - // reload(true) ensures resources like images and scripts are fetched again in firefox - socket.addEventListener('message', () => document.location.reload(true)) - `, + const socket = new WebSocket('${wsUrl}') + // reload(true) ensures resources like images and scripts are fetched again in firefox + socket.addEventListener('message', () => document.location.reload(true)) + `, }) } diff --git a/quartz/plugins/transformers/citations.ts b/quartz/plugins/transformers/citations.ts index bb302e437..dcac41b2e 100644 --- a/quartz/plugins/transformers/citations.ts +++ b/quartz/plugins/transformers/citations.ts @@ -17,11 +17,11 @@ const defaultOptions: Options = { csl: "apa", } -export const Citations: QuartzTransformerPlugin | undefined> = (userOpts) => { +export const Citations: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "Citations", - htmlPlugins() { + htmlPlugins(ctx) { const plugins: PluggableList = [] // Add rehype-citation to the list of plugins @@ -31,6 +31,8 @@ export const Citations: QuartzTransformerPlugin | undefined> = bibliography: opts.bibliographyFile, suppressBibliography: opts.suppressBibliography, linkCitations: opts.linkCitations, + csl: opts.csl, + lang: ctx.cfg.configuration.locale ?? "en-US", }, ]) @@ -38,7 +40,7 @@ export const Citations: QuartzTransformerPlugin | undefined> = // using https://github.com/syntax-tree/unist-util-visit as they're just anochor links plugins.push(() => { return (tree, _file) => { - visit(tree, "element", (node, index, parent) => { + visit(tree, "element", (node, _index, _parent) => { if (node.tagName === "a" && node.properties?.href?.startsWith("#bib")) { node.properties["data-no-popover"] = true } diff --git a/quartz/plugins/transformers/description.ts b/quartz/plugins/transformers/description.ts index 5900745c4..c7e592ee9 100644 --- a/quartz/plugins/transformers/description.ts +++ b/quartz/plugins/transformers/description.ts @@ -18,7 +18,7 @@ const urlRegex = new RegExp( "g", ) -export const Description: QuartzTransformerPlugin | undefined> = (userOpts) => { +export const Description: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "Description", diff --git a/quartz/plugins/transformers/frontmatter.ts b/quartz/plugins/transformers/frontmatter.ts index 5ab239a31..417b21853 100644 --- a/quartz/plugins/transformers/frontmatter.ts +++ b/quartz/plugins/transformers/frontmatter.ts @@ -40,7 +40,7 @@ function coerceToArray(input: string | string[]): string[] | undefined { .map((tag: string | number) => tag.toString()) } -export const FrontMatter: QuartzTransformerPlugin | undefined> = (userOpts) => { +export const FrontMatter: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "FrontMatter", @@ -71,6 +71,10 @@ export const FrontMatter: QuartzTransformerPlugin | undefined> const cssclasses = coerceToArray(coalesceAliases(data, ["cssclasses", "cssclass"])) if (cssclasses) data.cssclasses = cssclasses + const socialImage = coalesceAliases(data, ["socialImage", "image", "cover"]) + + if (socialImage) data.socialImage = socialImage + // fill in frontmatter file.data.frontmatter = data as QuartzPluginData["frontmatter"] } @@ -88,11 +92,13 @@ declare module "vfile" { tags: string[] aliases: string[] description: string - publish: boolean - draft: boolean + publish: boolean | string + draft: boolean | string lang: string enableToc: string cssclasses: string[] + socialImage: string + comments: boolean | string }> } } diff --git a/quartz/plugins/transformers/gfm.ts b/quartz/plugins/transformers/gfm.ts index 48681ff77..eec26f7b9 100644 --- a/quartz/plugins/transformers/gfm.ts +++ b/quartz/plugins/transformers/gfm.ts @@ -14,9 +14,7 @@ const defaultOptions: Options = { linkHeadings: true, } -export const GitHubFlavoredMarkdown: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const GitHubFlavoredMarkdown: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "GitHubFlavoredMarkdown", diff --git a/quartz/plugins/transformers/index.ts b/quartz/plugins/transformers/index.ts index 7908c865e..8e2cd844f 100644 --- a/quartz/plugins/transformers/index.ts +++ b/quartz/plugins/transformers/index.ts @@ -10,3 +10,4 @@ export { OxHugoFlavouredMarkdown } from "./oxhugofm" export { SyntaxHighlighting } from "./syntax" export { TableOfContents } from "./toc" export { HardLineBreaks } from "./linebreaks" +export { RoamFlavoredMarkdown } from "./roam" diff --git a/quartz/plugins/transformers/lastmod.ts b/quartz/plugins/transformers/lastmod.ts index 2c7b9ce47..fe8c01bcf 100644 --- a/quartz/plugins/transformers/lastmod.ts +++ b/quartz/plugins/transformers/lastmod.ts @@ -27,9 +27,7 @@ function coerceDate(fp: string, d: any): Date { } type MaybeDate = undefined | string | number -export const CreatedModifiedDate: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const CreatedModifiedDate: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "CreatedModifiedDate", diff --git a/quartz/plugins/transformers/latex.ts b/quartz/plugins/transformers/latex.ts index c9f6bff0d..26913bac3 100644 --- a/quartz/plugins/transformers/latex.ts +++ b/quartz/plugins/transformers/latex.ts @@ -1,44 +1,66 @@ import remarkMath from "remark-math" import rehypeKatex from "rehype-katex" import rehypeMathjax from "rehype-mathjax/svg" +//@ts-ignore +import rehypeTypst from "@myriaddreamin/rehype-typst" import { QuartzTransformerPlugin } from "../types" +import { KatexOptions } from "katex" +import { Options as MathjaxOptions } from "rehype-mathjax/svg" +//@ts-ignore +import { Options as TypstOptions } from "@myriaddreamin/rehype-typst" interface Options { - renderEngine: "katex" | "mathjax" + renderEngine: "katex" | "mathjax" | "typst" + customMacros: MacroType + katexOptions: Omit + mathJaxOptions: Omit + typstOptions: TypstOptions } -export const Latex: QuartzTransformerPlugin = (opts?: Options) => { +interface MacroType { + [key: string]: string +} + +export const Latex: QuartzTransformerPlugin> = (opts) => { const engine = opts?.renderEngine ?? "katex" + const macros = opts?.customMacros ?? {} return { name: "Latex", markdownPlugins() { return [remarkMath] }, htmlPlugins() { - if (engine === "katex") { - return [[rehypeKatex, { output: "html" }]] - } else { - return [rehypeMathjax] + switch (engine) { + case "katex": { + return [[rehypeKatex, { output: "html", macros, ...(opts?.katexOptions ?? {}) }]] + } + case "typst": { + return [[rehypeTypst, opts?.typstOptions ?? {}]] + } + case "mathjax": { + return [[rehypeMathjax, { macros, ...(opts?.mathJaxOptions ?? {}) }]] + } + default: { + return [[rehypeMathjax, { macros, ...(opts?.mathJaxOptions ?? {}) }]] + } } }, externalResources() { - if (engine === "katex") { - return { - css: [ - // base css - "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css", - ], - js: [ - { - // fix copy behaviour: https://github.com/KaTeX/KaTeX/blob/main/contrib/copy-tex/README.md - src: "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/copy-tex.min.js", - loadTime: "afterDOMReady", - contentType: "external", - }, - ], - } - } else { - return {} + switch (engine) { + case "katex": + return { + css: [{ content: "https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css" }], + js: [ + { + // fix copy behaviour: https://github.com/KaTeX/KaTeX/blob/main/contrib/copy-tex/README.md + src: "https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/copy-tex.min.js", + loadTime: "afterDOMReady", + contentType: "external", + }, + ], + } + default: + return { css: [], js: [] } } }, } diff --git a/quartz/plugins/transformers/links.ts b/quartz/plugins/transformers/links.ts index f89d367d7..3e8dbdede 100644 --- a/quartz/plugins/transformers/links.ts +++ b/quartz/plugins/transformers/links.ts @@ -8,7 +8,6 @@ import { simplifySlug, splitAnchor, transformLink, - joinSegments, } from "../../util/path" import path from "path" import { visit } from "unist-util-visit" @@ -33,7 +32,7 @@ const defaultOptions: Options = { externalLinkIcon: true, } -export const CrawlLinks: QuartzTransformerPlugin | undefined> = (userOpts) => { +export const CrawlLinks: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "LinkProcessing", @@ -66,7 +65,9 @@ export const CrawlLinks: QuartzTransformerPlugin | undefined> = type: "element", tagName: "svg", properties: { + "aria-hidden": "true", class: "external-icon", + style: "max-width:0.8em;max-height:0.8em", viewBox: "0 0 512 512", }, children: [ @@ -93,7 +94,7 @@ export const CrawlLinks: QuartzTransformerPlugin | undefined> = } node.properties.className = classes - if (opts.openLinksInNewTab) { + if (isExternal && opts.openLinksInNewTab) { node.properties.target = "_blank" } diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts index 108f7f779..624308ca4 100644 --- a/quartz/plugins/transformers/ofm.ts +++ b/quartz/plugins/transformers/ofm.ts @@ -2,15 +2,18 @@ import { QuartzTransformerPlugin } from "../types" import { Root, Html, BlockContent, DefinitionContent, Paragraph, Code } from "mdast" import { Element, Literal, Root as HtmlRoot } from "hast" import { ReplaceFunction, findAndReplace as mdastFindReplace } from "mdast-util-find-and-replace" -import { slug as slugAnchor } from "github-slugger" import rehypeRaw from "rehype-raw" import { SKIP, visit } from "unist-util-visit" import path from "path" -import { JSResource } from "../../util/resources" +import { splitAnchor } from "../../util/path" +import { JSResource, CSSResource } from "../../util/resources" // @ts-ignore import calloutScript from "../../components/scripts/callout.inline.ts" // @ts-ignore import checkboxScript from "../../components/scripts/checkbox.inline.ts" +// @ts-ignore +import mermaidExtensionScript from "../../components/scripts/mermaid.inline.ts" +import mermaidStyle from "../../components/styles/mermaid.inline.scss" import { FilePath, pathToRoot, slugTag, slugifyFilePath } from "../../util/path" import { toHast } from "mdast-util-to-hast" import { toHtml } from "hast-util-to-html" @@ -97,7 +100,7 @@ function canonicalizeCallout(calloutName: string): keyof typeof calloutMapping { export const externalLinkRegex = /^https?:\/\//i -export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/, "g") +export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/g) // !? -> optional embedding // \[\[ -> open brace @@ -105,35 +108,30 @@ export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/, "g") // (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link) // (\\?\|[^\[\]\#]+)? -> optional escape \ then | then one or more non-special characters (alias) export const wikilinkRegex = new RegExp( - /!?\[\[([^\[\]\|\#\\]+)?(#+[^\[\]\|\#\\]+)?(\\?\|[^\[\]\#]+)?\]\]/, - "g", + /!?\[\[([^\[\]\|\#\\]+)?(#+[^\[\]\|\#\\]+)?(\\?\|[^\[\]\#]+)?\]\]/g, ) // ^\|([^\n])+\|\n(\|) -> matches the header row // ( ?:?-{3,}:? ?\|)+ -> matches the header row separator // (\|([^\n])+\|\n)+ -> matches the body rows -export const tableRegex = new RegExp( - /^\|([^\n])+\|\n(\|)( ?:?-{3,}:? ?\|)+\n(\|([^\n])+\|\n?)+/, - "gm", -) +export const tableRegex = new RegExp(/^\|([^\n])+\|\n(\|)( ?:?-{3,}:? ?\|)+\n(\|([^\n])+\|\n?)+/gm) // matches any wikilink, only used for escaping wikilinks inside tables -export const tableWikilinkRegex = new RegExp(/(!?\[\[[^\]]*?\]\])/, "g") +export const tableWikilinkRegex = new RegExp(/(!?\[\[[^\]]*?\]\]|\[\^[^\]]*?\])/g) -const highlightRegex = new RegExp(/==([^=]+)==/, "g") -const commentRegex = new RegExp(/%%[\s\S]*?%%/, "g") +const highlightRegex = new RegExp(/==([^=]+)==/g) +const commentRegex = new RegExp(/%%[\s\S]*?%%/g) // from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts -const calloutRegex = new RegExp(/^\[\!(\w+)\]([+-]?)/) -const calloutLineRegex = new RegExp(/^> *\[\!\w+\][+-]?.*$/, "gm") +const calloutRegex = new RegExp(/^\[\!([\w-]+)\|?(.+?)?\]([+-]?)/) +const calloutLineRegex = new RegExp(/^> *\[\!\w+\|?.*?\][+-]?.*$/gm) // (?:^| ) -> non-capturing group, tag should start be separated by a space or be the start of the line // #(...) -> capturing group, tag itself must start with # // (?:[-_\p{L}\d\p{Z}])+ -> non-capturing group, non-empty string of (Unicode-aware) alpha-numeric characters and symbols, hyphens and/or underscores // (?:\/[-_\p{L}\d\p{Z}]+)*) -> non-capturing group, matches an arbitrary number of tag strings separated by "/" const tagRegex = new RegExp( - /(?:^| )#((?:[-_\p{L}\p{Emoji}\p{M}\d])+(?:\/[-_\p{L}\p{Emoji}\p{M}\d]+)*)/, - "gu", + /(?:^| )#((?:[-_\p{L}\p{Emoji}\p{M}\d])+(?:\/[-_\p{L}\p{Emoji}\p{M}\d]+)*)/gu, ) -const blockReferenceRegex = new RegExp(/\^([-_A-Za-z0-9]+)$/, "g") +const blockReferenceRegex = new RegExp(/\^([-_A-Za-z0-9]+)$/g) const ytLinkRegex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/ const ytPlaylistLinkRegex = /[?&]list=([^#?&]*)/ const videoExtensionRegex = new RegExp(/\.(mp4|webm|ogg|avi|mov|flv|wmv|mkv|mpg|mpeg|3gp|m4v)$/) @@ -141,9 +139,7 @@ const wikilinkImageEmbedRegex = new RegExp( /^(?(?!^\d*x?\d*$).*?)?(\|?\s*?(?\d+)(x(?\d+))?)?$/, ) -export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } const mdastToHtml = (ast: PhrasingContent | Paragraph) => { @@ -184,8 +180,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin // replace all wikilinks inside a table first src = src.replace(tableRegex, (value) => { // escape all aliases and headers in wikilinks inside a table - return value.replace(tableWikilinkRegex, (value, ...capture) => { - const [raw]: (string | undefined)[] = capture + return value.replace(tableWikilinkRegex, (_value, raw) => { + // const [raw]: (string | undefined)[] = capture let escaped = raw ?? "" escaped = escaped.replace("#", "\\#") // escape pipe characters if they are not already escaped @@ -199,10 +195,9 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin src = src.replace(wikilinkRegex, (value, ...capture) => { const [rawFp, rawHeader, rawAlias]: (string | undefined)[] = capture - const fp = rawFp ?? "" - const anchor = rawHeader?.trim().replace(/^#+/, "") - const blockRef = Boolean(anchor?.startsWith("^")) ? "^" : "" - const displayAnchor = anchor ? `#${blockRef}${slugAnchor(anchor)}` : "" + const [fp, anchor] = splitAnchor(`${rawFp ?? ""}${rawHeader ?? ""}`) + const blockRef = Boolean(rawHeader?.match(/^#?\^/)) ? "^" : "" + const displayAnchor = anchor ? `#${blockRef}${anchor.trim().replace(/^#+/, "")}` : "" const displayAlias = rawAlias ?? rawHeader?.replace("#", "|") ?? "" const embedDisplay = value.startsWith("!") ? "!" : "" @@ -269,14 +264,14 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin } else if ([".pdf"].includes(ext)) { return { type: "html", - value: ``, + value: ``, } } else { const block = anchor return { type: "html", data: { hProperties: { transclude: true } }, - value: `
    Transclude of ${url}${block}
    `, } @@ -287,6 +282,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin // internal link const url = fp + anchor + return { type: "link", url, @@ -332,8 +328,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin replacements.push([ tagRegex, (_value: string, tag: string) => { - // Check if the tag only includes numbers - if (/^\d+$/.test(tag)) { + // Check if the tag only includes numbers and slashes + if (/^[\/\d]+$/.test(tag)) { return false } @@ -414,8 +410,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin return } - // find first line - const firstChild = node.children[0] + // find first line and callout content + const [firstChild, ...calloutContent] = node.children if (firstChild.type !== "paragraph" || firstChild.children[0]?.type !== "text") { return } @@ -427,7 +423,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin const match = firstLine.match(calloutRegex) if (match && match.input) { - const [calloutDirective, typeString, collapseChar] = match + const [calloutDirective, typeString, calloutMetaData, collapseChar] = match const calloutType = canonicalizeCallout(typeString.toLowerCase()) const collapse = collapseChar === "+" || collapseChar === "-" const defaultState = collapseChar === "-" ? "collapsed" : "expanded" @@ -438,7 +434,9 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin children: [ { type: "text", - value: useDefaultTitle ? capitalize(typeString) : titleContent + " ", + value: useDefaultTitle + ? capitalize(typeString).replace(/-/g, " ") + : titleContent + " ", }, ...restOfTitle, ], @@ -489,8 +487,24 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin className: classNames.join(" "), "data-callout": calloutType, "data-callout-fold": collapse, + "data-callout-metadata": calloutMetaData, }, } + + // Add callout-content class to callout body if it has one. + if (calloutContent.length > 0) { + const contentData: BlockContent | DefinitionContent = { + data: { + hProperties: { + className: "callout-content", + }, + hName: "div", + }, + type: "blockquote", + children: [...calloutContent], + } + node.children = [node.children[0], contentData] + } } }) } @@ -505,6 +519,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin node.data = { hProperties: { className: ["mermaid"], + "data-clipboard": JSON.stringify(node.value), }, } } @@ -606,11 +621,10 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin // YouTube video (with optional playlist) node.tagName = "iframe" node.properties = { - class: "external-embed", + class: "external-embed youtube", allow: "fullscreen", frameborder: 0, width: "600px", - height: "350px", src: playlistId ? `https://www.youtube.com/embed/${videoId}?list=${playlistId}` : `https://www.youtube.com/embed/${videoId}`, @@ -619,11 +633,10 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin // YouTube playlist only. node.tagName = "iframe" node.properties = { - class: "external-embed", + class: "external-embed youtube", allow: "fullscreen", frameborder: 0, width: "600px", - height: "350px", src: `https://www.youtube.com/embed/videoseries?list=${playlistId}`, } } @@ -651,10 +664,138 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin }) } + if (opts.mermaid) { + plugins.push(() => { + return (tree: HtmlRoot, _file) => { + visit(tree, "element", (node: Element, _idx, parent) => { + if ( + node.tagName === "code" && + ((node.properties?.className ?? []) as string[])?.includes("mermaid") + ) { + parent!.children = [ + { + type: "element", + tagName: "button", + properties: { + className: ["expand-button"], + "aria-label": "Expand mermaid diagram", + "aria-hidden": "true", + "data-view-component": true, + }, + children: [ + { + type: "element", + tagName: "svg", + properties: { + width: 16, + height: 16, + viewBox: "0 0 16 16", + fill: "currentColor", + }, + children: [ + { + type: "element", + tagName: "path", + properties: { + fillRule: "evenodd", + d: "M3.72 3.72a.75.75 0 011.06 1.06L2.56 7h10.88l-2.22-2.22a.75.75 0 011.06-1.06l3.5 3.5a.75.75 0 010 1.06l-3.5 3.5a.75.75 0 11-1.06-1.06l2.22-2.22H2.56l2.22 2.22a.75.75 0 11-1.06 1.06l-3.5-3.5a.75.75 0 010-1.06l3.5-3.5z", + }, + children: [], + }, + ], + }, + ], + }, + node, + { + type: "element", + tagName: "div", + properties: { id: "mermaid-container" }, + children: [ + { + type: "element", + tagName: "div", + properties: { id: "mermaid-space" }, + children: [ + { + type: "element", + tagName: "div", + properties: { className: ["mermaid-header"] }, + children: [ + { + type: "element", + tagName: "button", + properties: { + className: ["close-button"], + "aria-label": "close button", + }, + children: [ + { + type: "element", + tagName: "svg", + properties: { + "aria-hidden": "true", + xmlns: "http://www.w3.org/2000/svg", + width: 24, + height: 24, + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + "stroke-width": "2", + "stroke-linecap": "round", + "stroke-linejoin": "round", + }, + children: [ + { + type: "element", + tagName: "line", + properties: { + x1: 18, + y1: 6, + x2: 6, + y2: 18, + }, + children: [], + }, + { + type: "element", + tagName: "line", + properties: { + x1: 6, + y1: 6, + x2: 18, + y2: 18, + }, + children: [], + }, + ], + }, + ], + }, + ], + }, + { + type: "element", + tagName: "div", + properties: { className: ["mermaid-content"] }, + children: [], + }, + ], + }, + ], + }, + ] + } + }) + } + }) + } + return plugins }, externalResources() { const js: JSResource[] = [] + const css: CSSResource[] = [] if (opts.enableCheckbox) { js.push({ @@ -674,32 +815,18 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin if (opts.mermaid) { js.push({ - script: ` - let mermaidImport = undefined - document.addEventListener('nav', async () => { - if (document.querySelector("code.mermaid")) { - mermaidImport ||= await import('https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.7.0/mermaid.esm.min.mjs') - const mermaid = mermaidImport.default - const darkMode = document.documentElement.getAttribute('saved-theme') === 'dark' - mermaid.initialize({ - startOnLoad: false, - securityLevel: 'loose', - theme: darkMode ? 'dark' : 'default' - }) - - await mermaid.run({ - querySelector: '.mermaid' - }) - } - }); - `, + script: mermaidExtensionScript, loadTime: "afterDOMReady", moduleType: "module", contentType: "inline", }) + css.push({ + content: mermaidStyle, + inline: true, + }) } - return { js } + return { js, css } }, } } diff --git a/quartz/plugins/transformers/oxhugofm.ts b/quartz/plugins/transformers/oxhugofm.ts index 6e70bb190..cdbffcffd 100644 --- a/quartz/plugins/transformers/oxhugofm.ts +++ b/quartz/plugins/transformers/oxhugofm.ts @@ -47,9 +47,7 @@ const quartzLatexRegex = new RegExp(/\$\$[\s\S]*?\$\$|\$.*?\$/, "g") * markdown to make it compatible with quartz but the list of changes applied it * is not exhaustive. * */ -export const OxHugoFlavouredMarkdown: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const OxHugoFlavouredMarkdown: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "OxHugoFlavouredMarkdown", diff --git a/quartz/plugins/transformers/roam.ts b/quartz/plugins/transformers/roam.ts new file mode 100644 index 000000000..b3be8f542 --- /dev/null +++ b/quartz/plugins/transformers/roam.ts @@ -0,0 +1,224 @@ +import { QuartzTransformerPlugin } from "../types" +import { PluggableList } from "unified" +import { SKIP, visit } from "unist-util-visit" +import { ReplaceFunction, findAndReplace as mdastFindReplace } from "mdast-util-find-and-replace" +import { Root, Html, Paragraph, Text, Link, Parent } from "mdast" +import { Node } from "unist" +import { VFile } from "vfile" +import { BuildVisitor } from "unist-util-visit" + +export interface Options { + orComponent: boolean + TODOComponent: boolean + DONEComponent: boolean + videoComponent: boolean + audioComponent: boolean + pdfComponent: boolean + blockquoteComponent: boolean + tableComponent: boolean + attributeComponent: boolean +} + +const defaultOptions: Options = { + orComponent: true, + TODOComponent: true, + DONEComponent: true, + videoComponent: true, + audioComponent: true, + pdfComponent: true, + blockquoteComponent: true, + tableComponent: true, + attributeComponent: true, +} + +const orRegex = new RegExp(/{{or:(.*?)}}/, "g") +const TODORegex = new RegExp(/{{.*?\bTODO\b.*?}}/, "g") +const DONERegex = new RegExp(/{{.*?\bDONE\b.*?}}/, "g") +const videoRegex = new RegExp(/{{.*?\[\[video\]\].*?\:(.*?)}}/, "g") +const youtubeRegex = new RegExp( + /{{.*?\[\[video\]\].*?(https?:\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?)}}/, + "g", +) + +// const multimediaRegex = new RegExp(/{{.*?\b(video|audio)\b.*?\:(.*?)}}/, "g") + +const audioRegex = new RegExp(/{{.*?\[\[audio\]\].*?\:(.*?)}}/, "g") +const pdfRegex = new RegExp(/{{.*?\[\[pdf\]\].*?\:(.*?)}}/, "g") +const blockquoteRegex = new RegExp(/(\[\[>\]\])\s*(.*)/, "g") +const roamHighlightRegex = new RegExp(/\^\^(.+)\^\^/, "g") +const roamItalicRegex = new RegExp(/__(.+)__/, "g") +const tableRegex = new RegExp(/- {{.*?\btable\b.*?}}/, "g") /* TODO */ +const attributeRegex = new RegExp(/\b\w+(?:\s+\w+)*::/, "g") /* TODO */ + +function isSpecialEmbed(node: Paragraph): boolean { + if (node.children.length !== 2) return false + + const [textNode, linkNode] = node.children + return ( + textNode.type === "text" && + textNode.value.startsWith("{{[[") && + linkNode.type === "link" && + linkNode.children[0].type === "text" && + linkNode.children[0].value.endsWith("}}") + ) +} + +function transformSpecialEmbed(node: Paragraph, opts: Options): Html | null { + const [textNode, linkNode] = node.children as [Text, Link] + const embedType = textNode.value.match(/\{\{\[\[(.*?)\]\]:/)?.[1]?.toLowerCase() + const url = linkNode.url.slice(0, -2) // Remove the trailing '}}' + + switch (embedType) { + case "audio": + return opts.audioComponent + ? { + type: "html", + value: ``, + } + : null + case "video": + if (!opts.videoComponent) return null + // Check if it's a YouTube video + const youtubeMatch = url.match( + /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?(.+)/, + ) + if (youtubeMatch) { + const videoId = youtubeMatch[1].split("&")[0] // Remove additional parameters + const playlistMatch = url.match(/[?&]list=([^#\&\?]*)/) + const playlistId = playlistMatch ? playlistMatch[1] : null + + return { + type: "html", + value: ``, + } + } else { + return { + type: "html", + value: ``, + } + } + case "pdf": + return opts.pdfComponent + ? { + type: "html", + value: ``, + } + : null + default: + return null + } +} + +export const RoamFlavoredMarkdown: QuartzTransformerPlugin | undefined> = ( + userOpts, +) => { + const opts = { ...defaultOptions, ...userOpts } + + return { + name: "RoamFlavoredMarkdown", + markdownPlugins() { + const plugins: PluggableList = [] + + plugins.push(() => { + return (tree: Root, file: VFile) => { + const replacements: [RegExp, ReplaceFunction][] = [] + + // Handle special embeds (audio, video, PDF) + if (opts.audioComponent || opts.videoComponent || opts.pdfComponent) { + visit(tree, "paragraph", ((node: Paragraph, index: number, parent: Parent | null) => { + if (isSpecialEmbed(node)) { + const transformedNode = transformSpecialEmbed(node, opts) + if (transformedNode && parent) { + parent.children[index] = transformedNode + } + } + }) as BuildVisitor) + } + + // Roam italic syntax + replacements.push([ + roamItalicRegex, + (_value: string, match: string) => ({ + type: "emphasis", + children: [{ type: "text", value: match }], + }), + ]) + + // Roam highlight syntax + replacements.push([ + roamHighlightRegex, + (_value: string, inner: string) => ({ + type: "html", + value: `${inner}`, + }), + ]) + + if (opts.orComponent) { + replacements.push([ + orRegex, + (match: string) => { + const matchResult = match.match(/{{or:(.*?)}}/) + if (matchResult === null) { + return { type: "html", value: "" } + } + const optionsString: string = matchResult[1] + const options: string[] = optionsString.split("|") + const selectHtml: string = `` + return { type: "html", value: selectHtml } + }, + ]) + } + + if (opts.TODOComponent) { + replacements.push([ + TODORegex, + () => ({ + type: "html", + value: ``, + }), + ]) + } + + if (opts.DONEComponent) { + replacements.push([ + DONERegex, + () => ({ + type: "html", + value: ``, + }), + ]) + } + + if (opts.blockquoteComponent) { + replacements.push([ + blockquoteRegex, + (_match: string, _marker: string, content: string) => ({ + type: "html", + value: `
    ${content.trim()}
    `, + }), + ]) + } + + mdastFindReplace(tree, replacements) + } + }) + + return plugins + }, + } +} diff --git a/quartz/plugins/transformers/syntax.ts b/quartz/plugins/transformers/syntax.ts index f11734e5f..5d3aae0d8 100644 --- a/quartz/plugins/transformers/syntax.ts +++ b/quartz/plugins/transformers/syntax.ts @@ -19,10 +19,8 @@ const defaultOptions: Options = { keepBackground: false, } -export const SyntaxHighlighting: QuartzTransformerPlugin = ( - userOpts?: Partial, -) => { - const opts: Partial = { ...defaultOptions, ...userOpts } +export const SyntaxHighlighting: QuartzTransformerPlugin> = (userOpts) => { + const opts: CodeOptions = { ...defaultOptions, ...userOpts } return { name: "SyntaxHighlighting", diff --git a/quartz/plugins/transformers/toc.ts b/quartz/plugins/transformers/toc.ts index bfc2f9877..791547b6a 100644 --- a/quartz/plugins/transformers/toc.ts +++ b/quartz/plugins/transformers/toc.ts @@ -25,9 +25,7 @@ interface TocEntry { } const slugAnchor = new Slugger() -export const TableOfContents: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const TableOfContents: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "TableOfContents", diff --git a/quartz/processors/parse.ts b/quartz/processors/parse.ts index 3950fee09..2bd530c64 100644 --- a/quartz/processors/parse.ts +++ b/quartz/processors/parse.ts @@ -143,7 +143,7 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise[] = [] for (const chunk of chunks(fps, CHUNK_SIZE)) { - childPromises.push(pool.exec("parseFiles", [argv, chunk, ctx.allSlugs])) + childPromises.push(pool.exec("parseFiles", [ctx.buildId, argv, chunk, ctx.allSlugs])) } const results: ProcessedContent[][] = await WorkerPromise.all(childPromises).catch((err) => { diff --git a/quartz/static/giscus/dark.css b/quartz/static/giscus/dark.css new file mode 100644 index 000000000..e98088f4d --- /dev/null +++ b/quartz/static/giscus/dark.css @@ -0,0 +1,99 @@ +/*! MIT License + * Copyright (c) 2018 GitHub Inc. + * https://github.com/primer/primitives/blob/main/LICENSE + */ + +main { + --color-prettylights-syntax-comment: #8b949e; + --color-prettylights-syntax-constant: #79c0ff; + --color-prettylights-syntax-entity: #d2a8ff; + --color-prettylights-syntax-storage-modifier-import: #c9d1d9; + --color-prettylights-syntax-entity-tag: #7ee787; + --color-prettylights-syntax-keyword: #ff7b72; + --color-prettylights-syntax-string: #a5d6ff; + --color-prettylights-syntax-variable: #ffa657; + --color-prettylights-syntax-brackethighlighter-unmatched: #f85149; + --color-prettylights-syntax-invalid-illegal-text: #f0f6fc; + --color-prettylights-syntax-invalid-illegal-bg: #8e1519; + --color-prettylights-syntax-carriage-return-text: #f0f6fc; + --color-prettylights-syntax-carriage-return-bg: #b62324; + --color-prettylights-syntax-string-regexp: #7ee787; + --color-prettylights-syntax-markup-list: #f2cc60; + --color-prettylights-syntax-markup-heading: #1f6feb; + --color-prettylights-syntax-markup-italic: #c9d1d9; + --color-prettylights-syntax-markup-bold: #c9d1d9; + --color-prettylights-syntax-markup-deleted-text: #ffdcd7; + --color-prettylights-syntax-markup-deleted-bg: #67060c; + --color-prettylights-syntax-markup-inserted-text: #aff5b4; + --color-prettylights-syntax-markup-inserted-bg: #033a16; + --color-prettylights-syntax-markup-changed-text: #ffdfb6; + --color-prettylights-syntax-markup-changed-bg: #5a1e02; + --color-prettylights-syntax-markup-ignored-text: #c9d1d9; + --color-prettylights-syntax-markup-ignored-bg: #1158c7; + --color-prettylights-syntax-meta-diff-range: #d2a8ff; + --color-prettylights-syntax-brackethighlighter-angle: #8b949e; + --color-prettylights-syntax-sublimelinter-gutter-mark: #484f58; + --color-prettylights-syntax-constant-other-reference-link: #a5d6ff; + --color-btn-text: #d4d4d4; /* --darkgray */ + --color-btn-bg: #161618; /* --light */ + --color-btn-border: rgb(240, 246, 252 / 10%); /* --dark */ + --color-btn-shadow: 0 0 transparent; + --color-btn-inset-shadow: 0 0 transparent; + --color-btn-hover-bg: #30363d; + --color-btn-hover-border: #8b949e; + --color-btn-active-bg: hsl(212deg 12% 18% / 100%); + --color-btn-active-border: #6e7681; + --color-btn-selected-bg: #161b22; + --color-btn-primary-text: #fff; + --color-btn-primary-bg: #84a59d; /* --tertiary */ + --color-btn-primary-border: rgb(240, 246, 252 / 10%); /* --dark */ + --color-btn-primary-shadow: 0 0 transparent; + --color-btn-primary-inset-shadow: 0 0 transparent; + --color-btn-primary-hover-bg: #7b97aa; /* --secondary */ + --color-btn-primary-hover-border: rgb(240, 246, 252 / 10%); /* --dark */ + --color-btn-primary-selected-bg: #7b97aa; /* --secondary */ + --color-btn-primary-selected-shadow: 0 0 transparent; + --color-btn-primary-disabled-text: rgba(33, 32, 32, 0.5); + --color-btn-primary-disabled-bg: rgb(35 134 54 / 60%); + --color-btn-primary-disabled-border: rgb(240 246 252 / 10%); + --color-action-list-item-default-hover-bg: rgb(177 186 196 / 12%); + --color-segmented-control-bg: rgb(110 118 129 / 10%); + --color-segmented-control-button-bg: #0d1117; + --color-segmented-control-button-selected-border: #6e7681; + --color-fg-default: #ebebec; /* --dark */ + --color-fg-muted: #d4d4d4; /* --darkgray */ + --color-fg-subtle: #d4d4d4; /* --darkgray */ + --color-canvas-default: #0d1117; + --color-canvas-overlay: #161b22; + --color-canvas-inset: #010409; + --color-canvas-subtle: #161b22; + --color-border-default: #30363d; + --color-border-muted: #21262d; + --color-neutral-muted: rgb(110 118 129 / 40%); + --color-accent-fg: #2f81f7; + --color-accent-emphasis: #1f6feb; + --color-accent-muted: rgb(56 139 253 / 40%); + --color-accent-subtle: rgb(56 139 253 / 10%); + --color-success-fg: #3fb950; + --color-attention-fg: #d29922; + --color-attention-muted: rgb(187 128 9 / 40%); + --color-attention-subtle: rgb(187 128 9 / 15%); + --color-danger-fg: #f85149; + --color-danger-muted: rgb(248 81 73 / 40%); + --color-danger-subtle: rgb(248 81 73 / 10%); + --color-primer-shadow-inset: 0 0 transparent; + --color-scale-gray-7: #21262d; + --color-scale-blue-8: #0c2d6b; + + /*! Extensions from @primer/css/alerts/flash.scss */ + --color-social-reaction-bg-hover: var(--color-scale-gray-7); + --color-social-reaction-bg-reacted-hover: var(--color-scale-blue-8); +} + +main .pagination-loader-container { + background-image: url("https://github.com/images/modules/pulls/progressive-disclosure-line-dark.svg"); +} + +main .gsc-loading-image { + background-image: url("https://github.githubassets.com/images/mona-loading-dark.gif"); +} diff --git a/quartz/static/giscus/light.css b/quartz/static/giscus/light.css new file mode 100644 index 000000000..84b58c0a7 --- /dev/null +++ b/quartz/static/giscus/light.css @@ -0,0 +1,99 @@ +/*! MIT License + * Copyright (c) 2018 GitHub Inc. + * https://github.com/primer/primitives/blob/main/LICENSE + */ + +main { + --color-prettylights-syntax-comment: #6e7781; + --color-prettylights-syntax-constant: #0550ae; + --color-prettylights-syntax-entity: #8250df; + --color-prettylights-syntax-storage-modifier-import: #24292f; + --color-prettylights-syntax-entity-tag: #116329; + --color-prettylights-syntax-keyword: #cf222e; + --color-prettylights-syntax-string: #0a3069; + --color-prettylights-syntax-variable: #953800; + --color-prettylights-syntax-brackethighlighter-unmatched: #82071e; + --color-prettylights-syntax-invalid-illegal-text: #f6f8fa; + --color-prettylights-syntax-invalid-illegal-bg: #82071e; + --color-prettylights-syntax-carriage-return-text: #f6f8fa; + --color-prettylights-syntax-carriage-return-bg: #cf222e; + --color-prettylights-syntax-string-regexp: #116329; + --color-prettylights-syntax-markup-list: #3b2300; + --color-prettylights-syntax-markup-heading: #0550ae; + --color-prettylights-syntax-markup-italic: #24292f; + --color-prettylights-syntax-markup-bold: #24292f; + --color-prettylights-syntax-markup-deleted-text: #82071e; + --color-prettylights-syntax-markup-deleted-bg: #ffebe9; + --color-prettylights-syntax-markup-inserted-text: #116329; + --color-prettylights-syntax-markup-inserted-bg: #dafbe1; + --color-prettylights-syntax-markup-changed-text: #953800; + --color-prettylights-syntax-markup-changed-bg: #ffd8b5; + --color-prettylights-syntax-markup-ignored-text: #eaeef2; + --color-prettylights-syntax-markup-ignored-bg: #0550ae; + --color-prettylights-syntax-meta-diff-range: #8250df; + --color-prettylights-syntax-brackethighlighter-angle: #57606a; + --color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f; + --color-prettylights-syntax-constant-other-reference-link: #0a3069; + --color-btn-text: #4e4e4e; /* --darkgray */ + --color-btn-bg: #faf8f8; /* --light */ + --color-btn-border: rgb(43, 43, 43 / 15%); /* --dark */ + --color-btn-shadow: 0 1px 0 rgb(31 35 40 / 4%); + --color-btn-inset-shadow: inset 0 1px 0 rgb(255 255 255 / 25%); + --color-btn-hover-bg: #f3f4f6; + --color-btn-hover-border: rgb(43, 43, 43 / 15%); /* --dark */ + --color-btn-active-bg: hsl(220deg 14% 93% / 100%); + --color-btn-active-border: rgb(31 35 40 / 15%); + --color-btn-selected-bg: hsl(220deg 14% 94% / 100%); + --color-btn-primary-text: #fff; + --color-btn-primary-bg: #84a59d; /* --tertiary */ + --color-btn-primary-border: rgb(43, 43, 43 / 15%); /* --dark */ + --color-btn-primary-shadow: 0 1px 0 rgb(31 35 40 / 10%); + --color-btn-primary-inset-shadow: inset 0 1px 0 rgb(255 255 255 / 3%); + --color-btn-primary-hover-bg: #284b63; /* --secondary */ + --color-btn-primary-hover-border: rgb(43, 43, 43 / 15%); /* --dark */ + --color-btn-primary-selected-bg: #284b63; /* --secondary */ + --color-btn-primary-selected-shadow: inset 0 1px 0 rgb(0 45 17 / 20%); + --color-btn-primary-disabled-text: rgb(255 255 255 / 80%); + --color-btn-primary-disabled-bg: #94d3a2; + --color-btn-primary-disabled-border: rgb(31 35 40 / 15%); + --color-action-list-item-default-hover-bg: rgb(208 215 222 / 32%); + --color-segmented-control-bg: #eaeef2; + --color-segmented-control-button-bg: #fff; + --color-segmented-control-button-selected-border: #8c959f; + --color-fg-default: #2b2b2b; /* --dark */ + --color-fg-muted: #4e4e4e; /* --darkgray */ + --color-fg-subtle: #4e4e4e; /* --darkgray */ + --color-canvas-default: #fff; + --color-canvas-overlay: #fff; + --color-canvas-inset: #f6f8fa; + --color-canvas-subtle: #f6f8fa; + --color-border-default: #d0d7de; + --color-border-muted: hsl(210deg 18% 87% / 100%); + --color-neutral-muted: rgb(175 184 193 / 20%); + --color-accent-fg: #0969da; + --color-accent-emphasis: #0969da; + --color-accent-muted: rgb(84 174 255 / 40%); + --color-accent-subtle: #ddf4ff; + --color-success-fg: #1a7f37; + --color-attention-fg: #9a6700; + --color-attention-muted: rgb(212 167 44 / 40%); + --color-attention-subtle: #fff8c5; + --color-danger-fg: #d1242f; + --color-danger-muted: rgb(255 129 130 / 40%); + --color-danger-subtle: #ffebe9; + --color-primer-shadow-inset: inset 0 1px 0 rgb(208 215 222 / 20%); + --color-scale-gray-1: #eaeef2; + --color-scale-blue-1: #b6e3ff; + + /*! Extensions from @primer/css/alerts/flash.scss */ + --color-social-reaction-bg-hover: var(--color-scale-gray-1); + --color-social-reaction-bg-reacted-hover: var(--color-scale-blue-1); +} + +main .pagination-loader-container { + background-image: url("https://github.com/images/modules/pulls/progressive-disclosure-line.svg"); +} + +main .gsc-loading-image { + background-image: url("https://github.githubassets.com/images/mona-loading-default.gif"); +} diff --git a/quartz/styles/base.scss b/quartz/styles/base.scss index 859bb433e..34d7e40fa 100644 --- a/quartz/styles/base.scss +++ b/quartz/styles/base.scss @@ -12,7 +12,6 @@ html { body, section { margin: 0; - max-width: 100%; box-sizing: border-box; background-color: var(--light); font-family: var(--bodyFont); @@ -20,11 +19,10 @@ section { } .text-highlight { - background-color: #fff23688; + background-color: var(--textHighlight); padding: 0 0.1rem; border-radius: 5px; } - ::selection { background: color-mix(in srgb, var(--tertiary) 60%, rgba(255, 255, 255, 0)); color: var(--darkgray); @@ -43,10 +41,22 @@ ul, .math { color: var(--darkgray); fill: var(--darkgray); - overflow-wrap: anywhere; hyphens: auto; } +p, +ul, +text, +a, +li, +ol, +ul, +.katex, +.math { + overflow-wrap: anywhere; + /* tr and td removed from list of selectors for overflow-wrap, allowing them to use default 'normal' property value */ +} + .math { &.math-display { text-align: center; @@ -98,25 +108,21 @@ a { .desktop-only { display: initial; - @media all and (max-width: $fullPageWidth) { + @media all and ($mobile) { display: none; } } .mobile-only { display: none; - @media all and (max-width: $fullPageWidth) { + @media all and ($mobile) { display: initial; } } .page { - @media all and (max-width: $fullPageWidth) { - margin: 0 auto; - padding: 0 1rem; - max-width: $pageWidth; - } - + max-width: calc(#{map-get($breakpoints, desktop)} + 300px); + margin: 0 auto; & article { & > h1 { font-size: 2rem; @@ -144,70 +150,120 @@ a { } & > #quartz-body { - width: 100%; - display: flex; - @media all and (max-width: $fullPageWidth) { - flex-direction: column; + display: grid; + grid-template-columns: #{map-get($desktopGrid, templateColumns)}; + grid-template-rows: #{map-get($desktopGrid, templateRows)}; + column-gap: #{map-get($desktopGrid, columnGap)}; + row-gap: #{map-get($desktopGrid, rowGap)}; + grid-template-areas: #{map-get($desktopGrid, templateAreas)}; + @media all and ($tablet) { + grid-template-columns: #{map-get($tabletGrid, templateColumns)}; + grid-template-rows: #{map-get($tabletGrid, templateRows)}; + column-gap: #{map-get($tabletGrid, columnGap)}; + row-gap: #{map-get($tabletGrid, rowGap)}; + grid-template-areas: #{map-get($tabletGrid, templateAreas)}; + } + @media all and ($mobile) { + grid-template-columns: #{map-get($mobileGrid, templateColumns)}; + grid-template-rows: #{map-get($mobileGrid, templateRows)}; + column-gap: #{map-get($mobileGrid, columnGap)}; + row-gap: #{map-get($mobileGrid, rowGap)}; + grid-template-areas: #{map-get($mobileGrid, templateAreas)}; + } + + @media all and not ($desktop) { + padding: 0 1rem; + } + @media all and ($mobile) { + margin: 0 auto; } & .sidebar { - flex: 1; - display: flex; - flex-direction: column; gap: 2rem; top: 0; - width: $sidePanelWidth; - margin-top: $topSpacing; box-sizing: border-box; - padding: 0 4rem; - position: fixed; - @media all and (max-width: $fullPageWidth) { - position: initial; - flex-direction: row; - padding: 0; - width: initial; - margin-top: 2rem; - } + padding: $topSpacing 2rem 2rem 2rem; + display: flex; + height: 100vh; + position: sticky; } & .sidebar.left { - left: calc(calc(100vw - $pageWidth) / 2 - $sidePanelWidth); - @media all and (max-width: $fullPageWidth) { + z-index: 1; + grid-area: grid-sidebar-left; + flex-direction: column; + @media all and ($mobile) { gap: 0; align-items: center; + position: initial; + display: flex; + height: unset; + flex-direction: row; + padding: 0; + padding-top: 2rem; } } & .sidebar.right { - right: calc(calc(100vw - $pageWidth) / 2 - $sidePanelWidth); - flex-wrap: wrap; - & > * { - @media all and (max-width: $fullPageWidth) { + grid-area: grid-sidebar-right; + margin-right: 0; + flex-direction: column; + @media all and ($mobile) { + margin-left: inherit; + margin-right: inherit; + } + @media all and not ($desktop) { + position: initial; + height: unset; + width: 100%; + flex-direction: row; + padding: 0; + & > * { flex: 1; - min-width: 140px; + } + & > .toc { + display: none; } } } - } - - & .page-header { - width: $pageWidth; - margin: $topSpacing auto 0 auto; - @media all and (max-width: $fullPageWidth) { - width: initial; - margin-top: 2rem; + & .page-header, + & .page-footer { + margin-top: 1rem; } - } - & .center, - & footer { - margin-left: auto; - margin-right: auto; - width: $pageWidth; - @media all and (max-width: $fullPageWidth) { - width: initial; + & .page-header { + grid-area: grid-header; + margin: $topSpacing 0 0 0; + @media all and ($mobile) { + margin-top: 0; + padding: 0; + } + } + + & .center > article { + grid-area: grid-center; + } + + & footer { + grid-area: grid-footer; + } + + & .center, + & footer { + max-width: 100%; + min-width: 100%; + margin-left: auto; + margin-right: auto; + @media all and ($tablet) { + margin-right: 0; + } + @media all and ($mobile) { + margin-right: 0; + margin-left: 0; + } + } + & footer { margin-left: 0; - margin-right: 0; } } } @@ -363,7 +419,7 @@ pre { counter-increment: line 0; display: grid; padding: 0.5rem 0; - overflow-x: scroll; + overflow-x: auto; & [data-highlighted-chars] { background-color: var(--highlight); @@ -481,9 +537,15 @@ video { flex: 1 1 auto; } +div:has(> .overflow) { + display: flex; + overflow-y: auto; + max-height: 100%; +} + ul.overflow, ol.overflow { - max-height: 400; + max-height: 100%; overflow-y: auto; // clearfix @@ -493,8 +555,7 @@ ol.overflow { & > li:last-of-type { margin-bottom: 30px; } - - &:after { + /*&:after { pointer-events: none; content: ""; width: 100%; @@ -505,7 +566,7 @@ ol.overflow { opacity: 1; transition: opacity 0.3s ease; background: linear-gradient(transparent 0px, var(--light)); - } + }*/ } .transclude { @@ -518,3 +579,11 @@ ol.overflow { overflow-x: auto; overflow-y: hidden; } + +.external-embed.youtube, +iframe.pdf { + aspect-ratio: 16 / 9; + height: 100%; + width: 100%; + border-radius: 5px; +} diff --git a/quartz/styles/callouts.scss b/quartz/styles/callouts.scss index b1fd180ce..d6f65aadc 100644 --- a/quartz/styles/callouts.scss +++ b/quartz/styles/callouts.scss @@ -10,7 +10,7 @@ transition: max-height 0.3s ease; box-sizing: border-box; - & > *:nth-child(2) { + & > .callout-content > :first-child { margin-top: 0; } diff --git a/quartz/styles/variables.scss b/quartz/styles/variables.scss index e45cc9158..4a5cea583 100644 --- a/quartz/styles/variables.scss +++ b/quartz/styles/variables.scss @@ -1,9 +1,56 @@ -$pageWidth: 750px; -$mobileBreakpoint: 600px; -$tabletBreakpoint: 1000px; -$sidePanelWidth: 380px; +/** + * Layout breakpoints + * $mobile: screen width below this value will use mobile styles + * $desktop: screen width above this value will use desktop styles + * Screen width between $mobile and $desktop width will use the tablet layout. + * assuming mobile < desktop + */ +$breakpoints: ( + mobile: 800px, + desktop: 1200px, +); + +$mobile: "(max-width: #{map-get($breakpoints, mobile)})"; +$tablet: "(min-width: #{map-get($breakpoints, mobile)}) and (max-width: #{map-get($breakpoints, desktop)})"; +$desktop: "(min-width: #{map-get($breakpoints, desktop)})"; + +$pageWidth: #{map-get($breakpoints, mobile)}; +$sidePanelWidth: 320px; //380px; $topSpacing: 6rem; -$fullPageWidth: $pageWidth + 2 * $sidePanelWidth; $boldWeight: 700; $semiBoldWeight: 600; $normalWeight: 400; + +$mobileGrid: ( + templateRows: "auto auto auto auto auto", + templateColumns: "auto", + rowGap: "5px", + columnGap: "5px", + templateAreas: + '"grid-sidebar-left"\ + "grid-header"\ + "grid-center"\ + "grid-sidebar-right"\ + "grid-footer"', +); +$tabletGrid: ( + templateRows: "auto auto auto auto", + templateColumns: "#{$sidePanelWidth} auto", + rowGap: "5px", + columnGap: "5px", + templateAreas: + '"grid-sidebar-left grid-header"\ + "grid-sidebar-left grid-center"\ + "grid-sidebar-left grid-sidebar-right"\ + "grid-sidebar-left grid-footer"', +); +$desktopGrid: ( + templateRows: "auto auto auto", + templateColumns: "#{$sidePanelWidth} auto #{$sidePanelWidth}", + rowGap: "5px", + columnGap: "5px", + templateAreas: + '"grid-sidebar-left grid-header grid-sidebar-right"\ + "grid-sidebar-left grid-center grid-sidebar-right"\ + "grid-sidebar-left grid-footer grid-sidebar-right"', +); diff --git a/quartz/util/ctx.ts b/quartz/util/ctx.ts index e05611418..044d21f68 100644 --- a/quartz/util/ctx.ts +++ b/quartz/util/ctx.ts @@ -14,6 +14,7 @@ export interface Argv { } export interface BuildCtx { + buildId: string argv: Argv cfg: QuartzConfig allSlugs: FullSlug[] diff --git a/quartz/util/escape.ts b/quartz/util/escape.ts index 197558c7d..ac59cc74d 100644 --- a/quartz/util/escape.ts +++ b/quartz/util/escape.ts @@ -6,3 +6,12 @@ export const escapeHTML = (unsafe: string) => { .replaceAll('"', """) .replaceAll("'", "'") } + +export const unescapeHTML = (html: string) => { + return html + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll(""", '"') + .replaceAll("'", "'") +} diff --git a/quartz/util/og.tsx b/quartz/util/og.tsx new file mode 100644 index 000000000..0430a265d --- /dev/null +++ b/quartz/util/og.tsx @@ -0,0 +1,200 @@ +import { FontWeight, SatoriOptions } from "satori/wasm" +import { GlobalConfiguration } from "../cfg" +import { QuartzPluginData } from "../plugins/vfile" +import { JSXInternal } from "preact/src/jsx" +import { ThemeKey } from "./theme" + +/** + * Get an array of `FontOptions` (for satori) given google font names + * @param headerFontName name of google font used for header + * @param bodyFontName name of google font used for body + * @returns FontOptions for header and body + */ +export async function getSatoriFont(headerFontName: string, bodyFontName: string) { + const headerWeight = 700 as FontWeight + const bodyWeight = 400 as FontWeight + + // Fetch fonts + const headerFont = await fetchTtf(headerFontName, headerWeight) + const bodyFont = await fetchTtf(bodyFontName, bodyWeight) + + // Convert fonts to satori font format and return + const fonts: SatoriOptions["fonts"] = [ + { name: headerFontName, data: headerFont, weight: headerWeight, style: "normal" }, + { name: bodyFontName, data: bodyFont, weight: bodyWeight, style: "normal" }, + ] + return fonts +} + +/** + * Get the `.ttf` file of a google font + * @param fontName name of google font + * @param weight what font weight to fetch font + * @returns `.ttf` file of google font + */ +async function fetchTtf(fontName: string, weight: FontWeight): Promise { + try { + // Get css file from google fonts + const cssResponse = await fetch(`https://fonts.googleapis.com/css?family=${fontName}:${weight}`) + const css = await cssResponse.text() + + // Extract .ttf url from css file + const urlRegex = /url\((https:\/\/fonts.gstatic.com\/s\/.*?.ttf)\)/g + const match = urlRegex.exec(css) + + if (!match) { + throw new Error("Could not fetch font") + } + + // Retrieve font data as ArrayBuffer + const fontResponse = await fetch(match[1]) + + // fontData is an ArrayBuffer containing the .ttf file data (get match[1] due to google fonts response format, always contains link twice, but second entry is the "raw" link) + const fontData = await fontResponse.arrayBuffer() + + return fontData + } catch (error) { + throw new Error(`Error fetching font: ${error}`) + } +} + +export type SocialImageOptions = { + /** + * What color scheme to use for image generation (uses colors from config theme) + */ + colorScheme: ThemeKey + /** + * Height to generate image with in pixels (should be around 630px) + */ + height: number + /** + * Width to generate image with in pixels (should be around 1200px) + */ + width: number + /** + * Whether to use the auto generated image for the root path ("/", when set to false) or the default og image (when set to true). + */ + excludeRoot: boolean + /** + * JSX to use for generating image. See satori docs for more info (https://github.com/vercel/satori) + * @param cfg global quartz config + * @param userOpts options that can be set by user + * @param title title of current page + * @param description description of current page + * @param fonts global font that can be used for styling + * @param fileData full fileData of current page + * @returns prepared jsx to be used for generating image + */ + imageStructure: ( + cfg: GlobalConfiguration, + userOpts: UserOpts, + title: string, + description: string, + fonts: SatoriOptions["fonts"], + fileData: QuartzPluginData, + ) => JSXInternal.Element +} + +export type UserOpts = Omit + +export type ImageOptions = { + /** + * what title to use as header in image + */ + title: string + /** + * what description to use as body in image + */ + description: string + /** + * what fileName to use when writing to disk + */ + fileName: string + /** + * what directory to store image in + */ + fileDir: string + /** + * what file extension to use (should be `webp` unless you also change sharp conversion) + */ + fileExt: string + /** + * header + body font to be used when generating satori image (as promise to work around sync in component) + */ + fontsPromise: Promise + /** + * `GlobalConfiguration` of quartz (used for theme/typography) + */ + cfg: GlobalConfiguration + /** + * full file data of current page + */ + fileData: QuartzPluginData +} + +// This is the default template for generated social image. +export const defaultImage: SocialImageOptions["imageStructure"] = ( + cfg: GlobalConfiguration, + { colorScheme }: UserOpts, + title: string, + description: string, + fonts: SatoriOptions["fonts"], + _fileData: QuartzPluginData, +) => { + // How many characters are allowed before switching to smaller font + const fontBreakPoint = 22 + const useSmallerFont = title.length > fontBreakPoint + + // Setup to access image + const iconPath = `https://${cfg.baseUrl}/static/icon.png` + return ( +
    +
    + +

    + {title} +

    +
    +

    + {description} +

    +
    + ) +} diff --git a/quartz/util/resources.tsx b/quartz/util/resources.tsx index a572d891f..72ae9e63e 100644 --- a/quartz/util/resources.tsx +++ b/quartz/util/resources.tsx @@ -16,6 +16,12 @@ export type JSResource = { } ) +export type CSSResource = { + content: string + inline?: boolean + spaPreserve?: boolean +} + export function JSResourceToScriptElement(resource: JSResource, preserve?: boolean): JSX.Element { const scriptType = resource.moduleType ?? "application/javascript" const spaPreserve = preserve ?? resource.spaPreserve @@ -36,7 +42,24 @@ export function JSResourceToScriptElement(resource: JSResource, preserve?: boole } } +export function CSSResourceToStyleElement(resource: CSSResource, preserve?: boolean): JSX.Element { + const spaPreserve = preserve ?? resource.spaPreserve + if (resource.inline ?? false) { + return + } else { + return ( + + ) + } +} + export interface StaticResources { - css: string[] + css: CSSResource[] js: JSResource[] } diff --git a/quartz/util/theme.ts b/quartz/util/theme.ts index d3bfb9a0d..9046cec66 100644 --- a/quartz/util/theme.ts +++ b/quartz/util/theme.ts @@ -7,6 +7,7 @@ export interface ColorScheme { secondary: string tertiary: string highlight: string + textHighlight: string } interface Colors { @@ -49,6 +50,7 @@ ${stylesheet.join("\n\n")} --secondary: ${theme.colors.lightMode.secondary}; --tertiary: ${theme.colors.lightMode.tertiary}; --highlight: ${theme.colors.lightMode.highlight}; + --textHighlight: ${theme.colors.lightMode.textHighlight}; --headerFont: "${theme.typography.header}", ${DEFAULT_SANS_SERIF}; --bodyFont: "${theme.typography.body}", ${DEFAULT_SANS_SERIF}; @@ -64,6 +66,7 @@ ${stylesheet.join("\n\n")} --secondary: ${theme.colors.darkMode.secondary}; --tertiary: ${theme.colors.darkMode.tertiary}; --highlight: ${theme.colors.darkMode.highlight}; + --textHighlight: ${theme.colors.darkMode.textHighlight}; } ` } diff --git a/quartz/worker.ts b/quartz/worker.ts index b92bdac94..a209df9a0 100644 --- a/quartz/worker.ts +++ b/quartz/worker.ts @@ -7,8 +7,14 @@ import { createFileParser, createProcessor } from "./processors/parse" import { options } from "./util/sourcemap" // only called from worker thread -export async function parseFiles(argv: Argv, fps: FilePath[], allSlugs: FullSlug[]) { +export async function parseFiles( + buildId: string, + argv: Argv, + fps: FilePath[], + allSlugs: FullSlug[], +) { const ctx: BuildCtx = { + buildId, cfg, argv, allSlugs, diff --git a/tsconfig.json b/tsconfig.json index 306204b5d..784ab231b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,8 +13,8 @@ "forceConsistentCasingInFileNames": true, "esModuleInterop": true, "jsx": "react-jsx", - "jsxImportSource": "preact", + "jsxImportSource": "preact" }, "include": ["**/*.ts", "**/*.tsx", "./package.json"], - "exclude": ["build/**/*.d.ts"], + "exclude": ["build/**/*.d.ts"] }