diff --git a/.changeset/brave-nimbus-docs.md b/.changeset/brave-nimbus-docs.md new file mode 100644 index 0000000..6b3632c --- /dev/null +++ b/.changeset/brave-nimbus-docs.md @@ -0,0 +1,5 @@ +--- +"@cloudflare/polystella": patch +--- + +Document the requirement to add a Changesets entry for package-affecting changes and record the docs migration to Nimbus. diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a14f3b4..c027d4c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,7 +27,7 @@ concurrency: jobs: build: - name: Build Starlight site + name: Build Nimbus docs site runs-on: ubuntu-latest timeout-minutes: 15 steps: diff --git a/AGENTS.md b/AGENTS.md index 47ebd37..d8f695b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,6 +29,7 @@ section numbers. Inserting new sections never breaks links. | `pnpm test:watch` | Vitest in watch mode. | | `pnpm build` | Compile `src/` → `dist/` via `tsc -p tsconfig.build.json` (mirrored layout, `.js` + `.d.ts` + sourcemaps + declaration maps). Produces the standalone `polystella` CLI at `dist/cli.js` and library entries. | | `pnpm exec tsc --noEmit` | Typecheck against the root `tsconfig.json` (which includes tests). The build config (`tsconfig.build.json`) sets `noEmit: false` and narrows `include` to `src/**`. | +| `pnpm changeset` | Add a Changesets entry for package-affecting work. Use `pnpm changeset add --empty` only for changes that intentionally do not need a package release. | No lint step yet. @@ -85,6 +86,12 @@ to the explanatory section when adding code that touches one. ### Always - Run `pnpm test` before pushing. Tests must stay green. +- Add a Changesets entry for every change that affects the published + package, its documented behaviour, or release-facing contributor + guidance. Use `pnpm changeset` for release notes; use + `pnpm changeset add --empty` only when the change deliberately does + not require a package release (for example, docs-site-only or CI-only + maintenance). - Bump the package version in `package.json` only — `POLYSTELLA_VERSION` (in `src/version.ts`) reads it at module-load time via a JSON import attribute, so the constant flows automatically through to diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 583b476..f3b463e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,7 +43,7 @@ Required: | `pnpm exec tsc --noEmit` | Typecheck the package. | | `pnpm build` | Compile `src/` → `dist/` (library + CLI, JS + `.d.ts`). | | `pnpm build:llms` | Regenerate `llms-full.txt` from canonical agent docs. | -| `pnpm --filter polystella-docs dev` | Run the Starlight docs site locally. | +| `pnpm --filter polystella-docs dev` | Run the Nimbus docs site locally. | | `pnpm --filter polystella-docs build` | Build the docs site (includes auto-generated config reference). | | `pnpm --filter polystella-docs check` | Astro check over docs content. | diff --git a/README.md b/README.md index 7330f69..f2c5870 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ collection APIs. ## Documentation -Full documentation lives at the Starlight docs site (under `docs/` in this repo): +Full documentation lives at the Nimbus docs site (under `docs/` in this repo): - [Getting started](https://polystella-docs.pcx-team.workers.dev/getting-started/install/) — install, quick start, mental model - [Concepts](https://polystella-docs.pcx-team.workers.dev/concepts/how-it-works/) — pipeline, cache, overrides, runtime bridge diff --git a/docs/.nimbus/lint.json b/docs/.nimbus/lint.json new file mode 100644 index 0000000..e1f00b6 --- /dev/null +++ b/docs/.nimbus/lint.json @@ -0,0 +1,9 @@ +{ + "version": 1, + "rules": { + "nimbus/frontmatter-shape": "error", + "nimbus/internal-link": "error" + }, + "collections": {}, + "site": "https://polystella-docs.pcx-team.workers.dev" +} diff --git a/docs/.nimbus/routes.json b/docs/.nimbus/routes.json new file mode 100644 index 0000000..8471902 --- /dev/null +++ b/docs/.nimbus/routes.json @@ -0,0 +1,50 @@ +{ + "version": 1, + "base": "/", + "knownRoutes": [ + "/", + "/404", + "/adapters/custom-loader", + "/adapters/markdown", + "/adapters/mdx", + "/adapters/toml", + "/cli", + "/cli/audit-mdx", + "/cli/check-ui", + "/cli/sync-ui", + "/cli/translate", + "/cli/translate-ui", + "/concepts/ai-marker", + "/concepts/glossaries", + "/concepts/how-it-works", + "/concepts/mode-boundary", + "/concepts/overrides", + "/concepts/r2-cache", + "/concepts/runtime-bridge", + "/configuration", + "/configuration/reference", + "/cookbook/locale-picker", + "/getting-started/install", + "/getting-started/mental-model", + "/getting-started/quick-start", + "/operations/branch-dispatch", + "/operations/ci", + "/operations/preview-isolation", + "/providers/anthropic", + "/providers/batching", + "/providers/model-selection", + "/providers/permanent-errors", + "/providers/workers-ai", + "/reference/breaking-changes", + "/reference/exports", + "/roadmap", + "/routing/configuration", + "/routing/shims", + "/runtime-api/explicit-imports", + "/runtime-api/locals", + "/runtime-api/middleware", + "/runtime-api/react-hooks", + "/troubleshooting/missing-translations" + ], + "opaqueNamespaces": [] +} diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs deleted file mode 100644 index bca382b..0000000 --- a/docs/astro.config.mjs +++ /dev/null @@ -1,136 +0,0 @@ -// @ts-check -import { defineConfig } from "astro/config"; -import starlight from "@astrojs/starlight"; - -/** - * Starlight configuration for the PolyStella docs site. - * - * Single-language (en-US) for v0.x. Dogfooding polystella's own - * translation pipeline on the docs is queued for a later release. - */ -export default defineConfig({ - site: "https://polystella-docs.pcx-team.workers.dev", - integrations: [ - starlight({ - title: "PolyStella", - description: "AI-driven content localization for Astro", - logo: { - src: "./src/assets/wordmark.svg", - replacesTitle: true, - }, - social: [ - { - icon: "github", - label: "GitHub", - href: "https://github.com/cloudflare/polystella", - }, - ], - editLink: { - baseUrl: "https://github.com/cloudflare/polystella/edit/main/docs/", - }, - sidebar: [ - { - label: "Getting started", - items: [ - { label: "Install", slug: "getting-started/install" }, - { label: "Quick start", slug: "getting-started/quick-start" }, - { label: "Mental model", slug: "getting-started/mental-model" }, - ], - }, - { - label: "Concepts", - items: [ - { label: "How it works", slug: "concepts/how-it-works" }, - { label: "R2 cache", slug: "concepts/r2-cache" }, - { label: "Glossaries", slug: "concepts/glossaries" }, - { label: "Overrides", slug: "concepts/overrides" }, - { label: "Mode boundary", slug: "concepts/mode-boundary" }, - { label: "Runtime bridge", slug: "concepts/runtime-bridge" }, - { label: "AI marker", slug: "concepts/ai-marker" }, - ], - }, - { - label: "Configuration", - items: [ - { label: "Overview", slug: "configuration" }, - { label: "Full reference", slug: "configuration/reference" }, - ], - }, - { - label: "Adapters", - items: [ - { label: "Markdown", slug: "adapters/markdown" }, - { label: "MDX", slug: "adapters/mdx" }, - { label: "TOML", slug: "adapters/toml" }, - { label: "Custom loader", slug: "adapters/custom-loader" }, - ], - }, - { - label: "Providers", - items: [ - { label: "Workers AI", slug: "providers/workers-ai" }, - { label: "Anthropic", slug: "providers/anthropic" }, - { label: "Model selection", slug: "providers/model-selection" }, - { label: "Batching", slug: "providers/batching" }, - { label: "Permanent errors", slug: "providers/permanent-errors" }, - ], - }, - { - label: "Routing", - items: [ - { label: "Standalone shims", slug: "routing/shims" }, - { label: "Route configuration", slug: "routing/configuration" }, - ], - }, - { - label: "Runtime API", - items: [ - { label: "Astro.locals", slug: "runtime-api/locals" }, - { label: "Middleware", slug: "runtime-api/middleware" }, - { label: "Explicit imports", slug: "runtime-api/explicit-imports" }, - { label: "React hooks", slug: "runtime-api/react-hooks" }, - ], - }, - { - label: "CLI", - items: [ - { label: "Overview", slug: "cli" }, - { label: "translate", slug: "cli/translate" }, - { label: "check-ui", slug: "cli/check-ui" }, - { label: "sync-ui", slug: "cli/sync-ui" }, - { label: "translate-ui", slug: "cli/translate-ui" }, - { label: "audit-mdx", slug: "cli/audit-mdx" }, - ], - }, - { - label: "Operations", - items: [ - { label: "CI / Workers Builds", slug: "operations/ci" }, - { label: "Branch dispatch", slug: "operations/branch-dispatch" }, - { label: "Preview isolation", slug: "operations/preview-isolation" }, - ], - }, - { - label: "Cookbook", - items: [{ autogenerate: { directory: "cookbook" } }], - }, - { - label: "Troubleshooting", - items: [{ autogenerate: { directory: "troubleshooting" } }], - }, - { - label: "Reference", - items: [ - { label: "Public exports", slug: "reference/exports" }, - { label: "Breaking changes", slug: "reference/breaking-changes" }, - ], - }, - { - label: "Roadmap", - slug: "roadmap", - }, - ], - customCss: ["./src/styles/custom.css"], - }), - ], -}); diff --git a/docs/astro.config.ts b/docs/astro.config.ts new file mode 100644 index 0000000..f6696c8 --- /dev/null +++ b/docs/astro.config.ts @@ -0,0 +1,94 @@ +import { defineConfig } from "astro/config"; +import icon from "astro-icon"; +import nimbus, { defineConfig as defineNimbusConfig } from "nimbus-docs"; + +const nimbusConfig = defineNimbusConfig({ + site: "https://polystella-docs.pcx-team.workers.dev", + title: "PolyStella", + description: "AI-driven content localization for Astro", + locale: "en", + github: "https://github.com/cloudflare/polystella", + editPattern: "https://github.com/cloudflare/polystella/edit/main/docs/{path}", + socialImageAlt: "PolyStella documentation preview", + sidebar: { + items: [ + { + label: "Getting started", + items: ["getting-started/install", "getting-started/quick-start", "getting-started/mental-model"], + }, + { + label: "Concepts", + items: [ + "concepts/how-it-works", + "concepts/r2-cache", + "concepts/glossaries", + "concepts/overrides", + "concepts/mode-boundary", + "concepts/runtime-bridge", + "concepts/ai-marker", + ], + }, + { + label: "Configuration", + items: ["configuration", "configuration/reference"], + }, + { + label: "Adapters", + items: ["adapters/markdown", "adapters/mdx", "adapters/toml", "adapters/custom-loader"], + }, + { + label: "Providers", + items: [ + "providers/workers-ai", + "providers/anthropic", + "providers/model-selection", + "providers/batching", + "providers/permanent-errors", + ], + }, + { + label: "Routing", + items: ["routing/shims", "routing/configuration"], + }, + { + label: "Runtime API", + items: ["runtime-api/locals", "runtime-api/middleware", "runtime-api/explicit-imports", "runtime-api/react-hooks"], + }, + { + label: "CLI", + items: ["cli", "cli/translate", "cli/check-ui", "cli/sync-ui", "cli/translate-ui", "cli/audit-mdx"], + }, + { + label: "Operations", + items: ["operations/ci", "operations/branch-dispatch", "operations/preview-isolation"], + }, + { label: "Cookbook", autogenerate: { directory: "cookbook" } }, + { + label: "Troubleshooting", + autogenerate: { directory: "troubleshooting" }, + }, + { + label: "Reference", + items: ["reference/exports", "reference/breaking-changes"], + }, + "roadmap", + ], + }, +}); + +export default defineConfig({ + output: "static", + prefetch: { + prefetchAll: true, + defaultStrategy: "hover", + }, + integrations: [ + icon(), + nimbus(nimbusConfig, { + rules: { + "nimbus/frontmatter-shape": "error", + "nimbus/internal-link": "error", + }, + }), + ], +}); diff --git a/docs/package.json b/docs/package.json index 73031e1..bb19bb2 100644 --- a/docs/package.json +++ b/docs/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "type": "module", - "description": "Starlight-based documentation site for PolyStella.", + "description": "Nimbus-based documentation site for PolyStella.", "scripts": { "dev": "pnpm prebuild && astro dev", "start": "pnpm prebuild && astro dev", @@ -17,12 +17,24 @@ "deploy": "wrangler deploy" }, "dependencies": { - "@astrojs/starlight": "^0.41.3", + "@fontsource-variable/inter": "^5.2.8", + "@fontsource-variable/jetbrains-mono": "^5.2.8", + "@iconify-json/ph": "^1.2.0", "astro": "^7.0.0", + "astro-icon": "^1.1.0", + "astro-og-canvas": "^0.13.0", + "canvaskit-wasm": "^0.41.1", + "clsx": "^2.1.1", + "nimbus-docs": "^0.1.22", + "shiki": "^4.2.0", + "tailwind-merge": "^3.5.0", "sharp": "^0.35.3" }, "devDependencies": { "@astrojs/check": "^0.9.9", + "@tailwindcss/postcss": "^4.1.4", + "pagefind": "^1.5.2", + "tailwindcss": "^4.1.4", "@types/node": "^26.1.0", "tsx": "^4.19.0", "typescript": "^6.0.3", diff --git a/docs/postcss.config.mjs b/docs/postcss.config.mjs new file mode 100644 index 0000000..c2ddf74 --- /dev/null +++ b/docs/postcss.config.mjs @@ -0,0 +1,5 @@ +export default { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; diff --git a/docs/public/_headers b/docs/public/_headers index a2fbdbb..ede26c5 100644 --- a/docs/public/_headers +++ b/docs/public/_headers @@ -4,8 +4,8 @@ # # Syntax: https://developers.cloudflare.com/workers/static-assets/headers/ # -# CSP is intentionally omitted: Starlight ships inline -# ` + + diff --git a/docs/src/components/ui/banner/banner.client.ts b/docs/src/components/ui/banner/banner.client.ts new file mode 100644 index 0000000..4ee2fda --- /dev/null +++ b/docs/src/components/ui/banner/banner.client.ts @@ -0,0 +1,49 @@ +/** + * Storage key: `nb-banner-dismissed-{id}`. Value is "0" for permanent, + * or a future timestamp (ms) for time-limited dismissal. + */ + +import { mount } from "nimbus-docs/client"; + +const KEY_PREFIX = "nb-banner-dismissed-"; + +function initBanner(banner: HTMLElement): () => void { + const id = banner.dataset.nbBannerDismiss; + if (!id) return () => {}; + + const key = `${KEY_PREFIX}${id}`; + + try { + const stored = localStorage.getItem(key); + if (stored) { + const expiry = Number(stored); + if (expiry === 0 || expiry > Date.now()) { + banner.remove(); + return () => {}; + } + localStorage.removeItem(key); + } + } catch { + // localStorage unavailable; show without persistence. + } + + const btn = banner.querySelector("[data-nb-banner-close]"); + if (!btn) return () => {}; + + function handleClick() { + const days = Number(banner.dataset.nbBannerDays) || 0; + const value = days > 0 ? String(Date.now() + days * 86400000) : "0"; + try { + localStorage.setItem(key, value); + } catch { + // localStorage unavailable; dismissal is session-only. + } + banner.remove(); + } + + btn.addEventListener("click", handleClick); + + return () => btn.removeEventListener("click", handleClick); +} + +mount("[data-nb-banner-dismiss]", initBanner); diff --git a/docs/src/components/ui/banner/index.ts b/docs/src/components/ui/banner/index.ts new file mode 100644 index 0000000..9b90dcf --- /dev/null +++ b/docs/src/components/ui/banner/index.ts @@ -0,0 +1 @@ +export { default as Banner } from "./Banner.astro"; diff --git a/docs/src/components/ui/breadcrumbs/Breadcrumbs.astro b/docs/src/components/ui/breadcrumbs/Breadcrumbs.astro new file mode 100644 index 0000000..53da5f3 --- /dev/null +++ b/docs/src/components/ui/breadcrumbs/Breadcrumbs.astro @@ -0,0 +1,84 @@ +--- +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; +import type { Breadcrumb } from "nimbus-docs/types"; + +interface Props extends HTMLAttributes<"nav"> { + items: Breadcrumb[]; + /** Max visible crumbs before collapsing middle items (default: 4) */ + maxVisible?: number; +} + +const { items, maxVisible = 4, class: className, ...attrs } = Astro.props; + +// Determine if we need to collapse the middle +const shouldCollapse = items.length > maxVisible; +// When collapsed: Home + first segment + ... + last 2 (parent + current) +const headCount = 2; // Home + first segment +const tailCount = 2; // parent + current page +const headItems = shouldCollapse ? items.slice(0, headCount) : items; +const collapsedItems = shouldCollapse ? items.slice(headCount, items.length - tailCount) : []; +const tailItems = shouldCollapse ? items.slice(items.length - tailCount) : []; +--- + +{items.length > 1 && ( + +)} diff --git a/docs/src/components/ui/breadcrumbs/index.ts b/docs/src/components/ui/breadcrumbs/index.ts new file mode 100644 index 0000000..734e208 --- /dev/null +++ b/docs/src/components/ui/breadcrumbs/index.ts @@ -0,0 +1 @@ +export { default as Breadcrumbs } from "./Breadcrumbs.astro"; diff --git a/docs/src/components/ui/button/Button.astro b/docs/src/components/ui/button/Button.astro new file mode 100644 index 0000000..4503785 --- /dev/null +++ b/docs/src/components/ui/button/Button.astro @@ -0,0 +1,69 @@ +--- +/** + * Button — primary action trigger. + * + * + * + * + * diff --git a/docs/src/components/ui/button/index.ts b/docs/src/components/ui/button/index.ts new file mode 100644 index 0000000..32440d6 --- /dev/null +++ b/docs/src/components/ui/button/index.ts @@ -0,0 +1,13 @@ +export { default as Button } from "./Button.astro"; +export { + buttonVariants, + buttonBase, + buttonVariantClasses, + buttonSizeText, + buttonSizeCompact, + buttonIconSize, + type ButtonVariant, + type ButtonSize, + type ButtonShape, + type ButtonVariantsOptions, +} from "./variants"; diff --git a/docs/src/components/ui/button/variants.ts b/docs/src/components/ui/button/variants.ts new file mode 100644 index 0000000..f98c1c6 --- /dev/null +++ b/docs/src/components/ui/button/variants.ts @@ -0,0 +1,65 @@ +/** + * Shared button styling — the single source of truth for both diff --git a/docs/src/components/ui/collapsible/collapsible.client.ts b/docs/src/components/ui/collapsible/collapsible.client.ts new file mode 100644 index 0000000..9e93213 --- /dev/null +++ b/docs/src/components/ui/collapsible/collapsible.client.ts @@ -0,0 +1,22 @@ +/** Wires Collapsible via the disclosure module. */ + +import { mount, makeDisclosure } from "nimbus-docs/client"; + +function initCollapsible(root: HTMLElement): () => void { + const trigger = root.querySelector("[data-nb-collapsible-trigger]"); + const content = root.querySelector("[data-nb-collapsible-content]"); + + if (!trigger || !content) return () => {}; + + const defaultOpen = root.dataset.nbDefaultOpen === "true"; + + const disclosure = makeDisclosure({ + trigger, + content, + defaultOpen, + }); + + return () => disclosure.destroy(); +} + +mount("[data-nb-collapsible]", initCollapsible); diff --git a/docs/src/components/ui/collapsible/index.ts b/docs/src/components/ui/collapsible/index.ts new file mode 100644 index 0000000..a4c4221 --- /dev/null +++ b/docs/src/components/ui/collapsible/index.ts @@ -0,0 +1,3 @@ +export { default as Collapsible } from "./Collapsible.astro"; +export { default as CollapsibleTrigger } from "./CollapsibleTrigger.astro"; +export { default as CollapsibleContent } from "./CollapsibleContent.astro"; diff --git a/docs/src/components/ui/dialog/Dialog.astro b/docs/src/components/ui/dialog/Dialog.astro new file mode 100644 index 0000000..24e3309 --- /dev/null +++ b/docs/src/components/ui/dialog/Dialog.astro @@ -0,0 +1,53 @@ +--- +/** + * Dialog — modal overlay built on the native . + * + * Open with `el.showModal()`, close with `el.close()` or Escape. + * Scroll-lock and backdrop-click-to-close are handled automatically. + * + * + * + *
Are you sure?
+ * Cancel + *
+ *
+ */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"dialog"> {} + +const { class: className, ...attrs } = Astro.props; +--- + + + + + + diff --git a/docs/src/components/ui/dialog/DialogClose.astro b/docs/src/components/ui/dialog/DialogClose.astro new file mode 100644 index 0000000..bc6e81f --- /dev/null +++ b/docs/src/components/ui/dialog/DialogClose.astro @@ -0,0 +1,35 @@ +--- +/** + * DialogClose — button that closes the nearest ancestor . + * Consumer provides the visual (icon, text, kbd hint) via default slot. + */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"button"> {} + +const { class: className, ...attrs } = Astro.props; +--- + + + + diff --git a/docs/src/components/ui/dialog/DialogContent.astro b/docs/src/components/ui/dialog/DialogContent.astro new file mode 100644 index 0000000..462448a --- /dev/null +++ b/docs/src/components/ui/dialog/DialogContent.astro @@ -0,0 +1,21 @@ +--- +/** + * DialogContent — inner frame of a Dialog. Centered, constrained, styled. + * Consumer controls max-width/height via class override. + */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"div"> {} + +const { class: className, ...attrs } = Astro.props; +--- + +
+
+ +
+
diff --git a/docs/src/components/ui/dialog/index.ts b/docs/src/components/ui/dialog/index.ts new file mode 100644 index 0000000..fe7fb64 --- /dev/null +++ b/docs/src/components/ui/dialog/index.ts @@ -0,0 +1,3 @@ +export { default as Dialog } from "./Dialog.astro"; +export { default as DialogContent } from "./DialogContent.astro"; +export { default as DialogClose } from "./DialogClose.astro"; diff --git a/docs/src/components/ui/layer-card/LayerCard.astro b/docs/src/components/ui/layer-card/LayerCard.astro new file mode 100644 index 0000000..8473c7b --- /dev/null +++ b/docs/src/components/ui/layer-card/LayerCard.astro @@ -0,0 +1,23 @@ +--- +/** + * LayerCard — two-layer card (recessed header + raised content). + * + * + * Title or tabs + * Main content + * + */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"div"> {} + +const { class: className, ...attrs } = Astro.props; +--- + +
+ +
diff --git a/docs/src/components/ui/layer-card/LayerCardContent.astro b/docs/src/components/ui/layer-card/LayerCardContent.astro new file mode 100644 index 0000000..12bdaea --- /dev/null +++ b/docs/src/components/ui/layer-card/LayerCardContent.astro @@ -0,0 +1,16 @@ +--- +/** LayerCardContent — raised content layer of a LayerCard. */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"div"> {} + +const { class: className, ...attrs } = Astro.props; +--- + +
+ +
diff --git a/docs/src/components/ui/layer-card/LayerCardHeader.astro b/docs/src/components/ui/layer-card/LayerCardHeader.astro new file mode 100644 index 0000000..b9be404 --- /dev/null +++ b/docs/src/components/ui/layer-card/LayerCardHeader.astro @@ -0,0 +1,16 @@ +--- +/** LayerCardHeader — recessed header layer of a LayerCard. */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"div"> {} + +const { class: className, ...attrs } = Astro.props; +--- + +
+ +
diff --git a/docs/src/components/ui/layer-card/index.ts b/docs/src/components/ui/layer-card/index.ts new file mode 100644 index 0000000..dd347fe --- /dev/null +++ b/docs/src/components/ui/layer-card/index.ts @@ -0,0 +1,3 @@ +export { default as LayerCard } from "./LayerCard.astro"; +export { default as LayerCardHeader } from "./LayerCardHeader.astro"; +export { default as LayerCardContent } from "./LayerCardContent.astro"; diff --git a/docs/src/components/ui/link-button/LinkButton.astro b/docs/src/components/ui/link-button/LinkButton.astro new file mode 100644 index 0000000..e1eb918 --- /dev/null +++ b/docs/src/components/ui/link-button/LinkButton.astro @@ -0,0 +1,75 @@ +--- +/** + * LinkButton — an anchor styled as a button. + * + * Get started + * Read the docs + * Learn more + * + * + * The `icon` prop appends a right-caret that nudges on hover. + * + * Styling is delegated to the shared `ui/button/variants`, so LinkButton and + * Button stay visually identical. The original props are preserved (used by + * MDX): the LinkButton-only aliases map onto the shared vocabulary — + * `minimal → ghost`, `md → base`. + */ +import { cn } from "@/lib/cn"; +import { Icon } from "astro-icon/components"; +import type { HTMLAttributes } from "astro/types"; +import { + buttonVariants, + buttonIconSize, + type ButtonVariant, + type ButtonSize, + type ButtonShape, +} from "../button/variants"; + +interface Props extends HTMLAttributes<"a"> { + href: string; + /** Original `primary | secondary | minimal`, plus Button's variants. */ + variant?: ButtonVariant | "minimal"; + /** Original `sm | md | lg`, plus Button's `xs | base`. */ + size?: ButtonSize | "md"; + /** `base` (default) · `square` · `circle` (icon-only — pass `aria-label`). */ + shape?: ButtonShape; + /** Append a caret-right that nudges on hover. */ + icon?: boolean; +} + +const { + href, + variant = "primary", + size = "md", + shape = "base", + icon = false, + class: className, + ...attrs +} = Astro.props; + +// Map the LinkButton-only aliases onto the shared Button vocabulary. +const resolvedVariant: ButtonVariant = variant === "minimal" ? "ghost" : variant; +const resolvedSize: ButtonSize = size === "md" ? "base" : size; +--- + + + + { + icon && ( + + ) + } + diff --git a/docs/src/components/ui/link-button/index.ts b/docs/src/components/ui/link-button/index.ts new file mode 100644 index 0000000..71411b5 --- /dev/null +++ b/docs/src/components/ui/link-button/index.ts @@ -0,0 +1 @@ +export { default as LinkButton } from "./LinkButton.astro"; diff --git a/docs/src/components/ui/package-managers/PackageManagers.astro b/docs/src/components/ui/package-managers/PackageManagers.astro new file mode 100644 index 0000000..4e203af --- /dev/null +++ b/docs/src/components/ui/package-managers/PackageManagers.astro @@ -0,0 +1,123 @@ +--- +/** + * PackageManagers — code block with a tab per package manager (npm, + * pnpm, yarn, bun). Selection syncs across instances via sessionStorage; + * an inline custom element restores the saved tab before paint. + */ +import { createHash } from "node:crypto"; +import { Icon } from "astro-icon/components"; +import { getTabs } from "nimbus-docs/lib/pkgm"; +import type { CommandType, CommandOptions } from "nimbus-docs/lib/pkgm"; +import { LayerCard, LayerCardHeader } from "@/components/ui/layer-card"; + +interface Props extends CommandOptions { + pkg?: string; + type?: CommandType; +} + +const { pkg, type = "add", args, dev, comment } = Astro.props; +const tabs = getTabs(type, pkg, { args, dev, comment }); +// Deterministic ID — hash the props so two builds with identical content +// produce identical IDs. Required for incremental builds: a per-render +// `crypto.randomUUID()` would make warm output differ from cold. +// Two instances with identical props on the same page would collide; in +// practice this is a rare authoring pattern (same package + type + args). +const uid = + "pm-" + + createHash("sha256") + .update(JSON.stringify({ pkg, type, args, dev, comment })) + .digest("hex") + .slice(0, 12); +--- + + + +
+ + + {tabs.map((tab, i) => ( + + ))} + + + {tabs.map((tab, i) => { + const cmdLines = tab.cmd.split("\n"); + const commentPrefix = cmdLines.length > 1 ? cmdLines.slice(0, -1).join("\n") + "\n" : ""; + const codeLine = cmdLines[cmdLines.length - 1]; + const spaceIdx = codeLine.indexOf(" "); + const codeFirst = spaceIdx === -1 ? codeLine : codeLine.slice(0, spaceIdx); + const codeRest = spaceIdx === -1 ? "" : codeLine.slice(spaceIdx); + return ( + + ); + })} + + + + +
+ + diff --git a/docs/src/components/ui/package-managers/index.ts b/docs/src/components/ui/package-managers/index.ts new file mode 100644 index 0000000..248021d --- /dev/null +++ b/docs/src/components/ui/package-managers/index.ts @@ -0,0 +1 @@ +export { default as PackageManagers } from "./PackageManagers.astro"; diff --git a/docs/src/components/ui/package-managers/package-managers.client.ts b/docs/src/components/ui/package-managers/package-managers.client.ts new file mode 100644 index 0000000..a7c1152 --- /dev/null +++ b/docs/src/components/ui/package-managers/package-managers.client.ts @@ -0,0 +1,55 @@ +/** + * Sync key `ui-pm-tab` (sessionStorage) is shared with the + * `` early-paint element to avoid flash across navigations. + */ + +import { mount, initTabs } from "nimbus-docs/client"; + +function cloneIcon(tpl: HTMLTemplateElement | null): Node { + return tpl ? tpl.content.cloneNode(true) : document.createTextNode(""); +} + +function initPackageManager(container: HTMLElement): () => void { + const copyTpl = container.querySelector("[data-nb-pm-icon-copy]"); + const checkTpl = container.querySelector("[data-nb-pm-icon-check]"); + + const tabs = initTabs({ + container, + tabSelector: "[data-nb-pm-tab]", + panelSelector: "[data-nb-pm-panel]", + rovingTabindex: true, + sync: { key: "ui-pm-tab", storage: "session" }, + }); + + const copyHandlers: Array<{ btn: HTMLButtonElement; handler: () => void; timer?: number }> = []; + + container.querySelectorAll("[data-nb-pm-copy]").forEach((btn) => { + const handlerInfo: { btn: HTMLButtonElement; handler: () => void; timer?: number } = { + btn, + handler: async () => { + try { + await navigator.clipboard.writeText(btn.dataset.nbCommand ?? ""); + } catch { + return; + } + btn.replaceChildren(cloneIcon(checkTpl)); + if (handlerInfo.timer) window.clearTimeout(handlerInfo.timer); + handlerInfo.timer = window.setTimeout(() => { + btn.replaceChildren(cloneIcon(copyTpl)); + }, 1500); + }, + }; + btn.addEventListener("click", handlerInfo.handler); + copyHandlers.push(handlerInfo); + }); + + return () => { + tabs.destroy(); + copyHandlers.forEach(({ btn, handler, timer }) => { + btn.removeEventListener("click", handler); + if (timer) window.clearTimeout(timer); + }); + }; +} + +mount("[data-nb-pm]", initPackageManager); diff --git a/docs/src/components/ui/page-actions/PageActions.astro b/docs/src/components/ui/page-actions/PageActions.astro new file mode 100644 index 0000000..09719d6 --- /dev/null +++ b/docs/src/components/ui/page-actions/PageActions.astro @@ -0,0 +1,82 @@ +--- +import { Icon } from "astro-icon/components"; +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"div"> { + markdownUrl?: string; + lastUpdated?: Date; + /** Page was drafted by an AI agent and not yet reviewed by a human. */ + aiGenerated?: boolean; +} + +const { markdownUrl, lastUpdated, aiGenerated, class: className, ...attrs } = Astro.props; + +const baseBtn = + "inline-flex cursor-pointer items-center gap-1.5 rounded-md bg-transparent px-2 py-1 text-muted-foreground no-underline transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring focus-visible:outline-offset-2"; + +const formattedDate = lastUpdated + ? new Intl.DateTimeFormat(undefined, { year: "numeric", month: "short", day: "numeric" }).format(lastUpdated) + : null; +--- + +{(markdownUrl || lastUpdated || aiGenerated) && ( +
+ {aiGenerated && ( + <> + + + AI-generated · awaiting review + + {(lastUpdated || markdownUrl) && ( + + )} + + )} + + {lastUpdated && ( + + + Updated + + )} + + {markdownUrl && lastUpdated && ( + + )} + + {markdownUrl && ( + <> + + + + + + + View as Markdown + + + )} +
+)} + + diff --git a/docs/src/components/ui/page-actions/index.ts b/docs/src/components/ui/page-actions/index.ts new file mode 100644 index 0000000..3d7bcd1 --- /dev/null +++ b/docs/src/components/ui/page-actions/index.ts @@ -0,0 +1 @@ +export { default as PageActions } from "./PageActions.astro"; diff --git a/docs/src/components/ui/page-actions/page-actions.client.ts b/docs/src/components/ui/page-actions/page-actions.client.ts new file mode 100644 index 0000000..56c9d59 --- /dev/null +++ b/docs/src/components/ui/page-actions/page-actions.client.ts @@ -0,0 +1,55 @@ +import { mount } from "nimbus-docs/client"; + +function initPageActions(root: HTMLElement): () => void { + const copyBtn = root.querySelector("[data-nb-page-actions-copy]"); + const copyIcon = root.querySelector("[data-nb-page-actions-copy-icon]"); + const checkIcon = root.querySelector("[data-nb-page-actions-check-icon]"); + const label = root.querySelector("[data-nb-page-actions-label]"); + const mdUrl = root.dataset.mdUrl; + + if (!copyBtn || !mdUrl) return () => {}; + const markdownUrl = mdUrl; + + let resetTimer: number | undefined; + + function showState(state: "copied" | "error") { + if (!copyIcon || !checkIcon || !label) return; + if (state === "copied") { + copyIcon.classList.add("hidden"); + checkIcon.classList.remove("hidden"); + label.textContent = "Copied"; + } else { + label.textContent = "Couldn't copy"; + } + if (resetTimer) window.clearTimeout(resetTimer); + resetTimer = window.setTimeout(() => { + copyIcon.classList.remove("hidden"); + checkIcon.classList.add("hidden"); + label.textContent = "Copy page"; + }, 1500); + } + + async function handleCopyPage() { + try { + const res = await fetch(markdownUrl); + if (!res.ok) { + showState("error"); + return; + } + const text = await res.text(); + await navigator.clipboard.writeText(text); + showState("copied"); + } catch { + showState("error"); + } + } + + copyBtn.addEventListener("click", handleCopyPage); + + return () => { + if (resetTimer) window.clearTimeout(resetTimer); + copyBtn.removeEventListener("click", handleCopyPage); + }; +} + +mount("[data-nb-page-actions]", initPageActions); diff --git a/docs/src/components/ui/pagination/Pagination.astro b/docs/src/components/ui/pagination/Pagination.astro new file mode 100644 index 0000000..6768078 --- /dev/null +++ b/docs/src/components/ui/pagination/Pagination.astro @@ -0,0 +1,36 @@ +--- +import { Icon } from "astro-icon/components"; +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; +import type { PrevNext } from "nimbus-docs/types"; + +interface Props extends HTMLAttributes<"nav"> { + prevNext: PrevNext; +} + +const { prevNext, class: className, ...attrs } = Astro.props; +const { prev, next } = prevNext; +--- + +{(prev || next) && ( + +)} diff --git a/docs/src/components/ui/pagination/index.ts b/docs/src/components/ui/pagination/index.ts new file mode 100644 index 0000000..8972ed7 --- /dev/null +++ b/docs/src/components/ui/pagination/index.ts @@ -0,0 +1 @@ +export { default as Pagination } from "./Pagination.astro"; diff --git a/docs/src/components/ui/search/SearchDialog.astro b/docs/src/components/ui/search/SearchDialog.astro new file mode 100644 index 0000000..1dd0847 --- /dev/null +++ b/docs/src/components/ui/search/SearchDialog.astro @@ -0,0 +1,112 @@ +--- +import { Icon } from "astro-icon/components"; +import { Dialog, DialogClose, DialogContent } from "@/components/ui/dialog"; +--- + + + +
+
+ + + + Esc + +
+ +
+

+ Type to search… +

+
+
+ +
+ ↑↓ navigate + ↵ select + Esc close +
+
+
+ + diff --git a/docs/src/components/ui/search/SearchTrigger.astro b/docs/src/components/ui/search/SearchTrigger.astro new file mode 100644 index 0000000..4126e75 --- /dev/null +++ b/docs/src/components/ui/search/SearchTrigger.astro @@ -0,0 +1,40 @@ +--- +/** Button that opens the search dialog. Cmd+K on macOS, Ctrl+K elsewhere. */ +import { Icon } from "astro-icon/components"; +--- + + + + diff --git a/docs/src/components/ui/search/index.ts b/docs/src/components/ui/search/index.ts new file mode 100644 index 0000000..9f7c86a --- /dev/null +++ b/docs/src/components/ui/search/index.ts @@ -0,0 +1,2 @@ +export { default as SearchDialog } from "./SearchDialog.astro"; +export { default as SearchTrigger } from "./SearchTrigger.astro"; diff --git a/docs/src/components/ui/search/providers/pagefind.ts b/docs/src/components/ui/search/providers/pagefind.ts new file mode 100644 index 0000000..6a8d8e9 --- /dev/null +++ b/docs/src/components/ui/search/providers/pagefind.ts @@ -0,0 +1,75 @@ +import type { SearchProvider, SearchResult } from "nimbus-docs/types"; +import { config } from "virtual:nimbus/config"; + +interface PagefindSubResult { + title?: string; + url?: string; +} + +interface PagefindResultData { + url: string; + excerpt?: string; + meta?: { title?: string }; + sub_results?: PagefindSubResult[]; +} + +interface PagefindSearchResponse { + results: Array<{ data(): Promise }>; +} + +interface PagefindFilters { + [key: string]: string | string[] | { none?: string | string[]; any?: string | string[] }; +} + +interface PagefindApi { + init(): Promise; + search(query: string, options?: { filters?: PagefindFilters }): Promise; +} + +let pagefind: PagefindApi | undefined; + +/** + * Default Pagefind filters applied to every search. + * + * Versioning: when the site has a `versions.deprecated` list, the + * layout emits `data-pagefind-filter="status:deprecated"` on every + * deprecated-version page. Search defaults to excluding those results + * (readers searching for "auth" want the current version's auth page, + * not the deprecated one). Future UI work can expose a "include + * deprecated" toggle; for now the default is current + non-deprecated. + * + * Versions are still searchable individually — readers on a v0 page + * who explicitly search from there can opt the UI into a version-scoped + * filter. The default exclusion is just for the top-level search. + * + * Computed at module-import time so we don't pay the config lookup on + * every keystroke. + */ +const defaultFilters: PagefindFilters | undefined = + config.versions && config.versions.deprecated && config.versions.deprecated.length > 0 ? { status: { none: "deprecated" } } : undefined; + +export const provider: SearchProvider = { + async init() { + if (pagefind) return; + const baseUrl = new URL(import.meta.env.BASE_URL ?? "/", window.location.origin); + const pagefindUrl = new URL("pagefind/pagefind.js", baseUrl); + pagefind = (await import(/* @vite-ignore */ pagefindUrl.href)) as PagefindApi; + await pagefind.init(); + }, + + async search(query) { + if (!pagefind) await this.init?.(); + if (!pagefind) return []; + + const search = await pagefind.search(query, defaultFilters ? { filters: defaultFilters } : undefined); + const results = await Promise.all(search.results.slice(0, 10).map((result) => result.data())); + return results.map((result): SearchResult => ({ + title: result.meta?.title ?? "Untitled", + url: result.url, + snippet: result.excerpt, + subResults: result.sub_results + ?.filter((sub): sub is Required => Boolean(sub.title && sub.url)) + .map((sub) => ({ title: sub.title, url: sub.url })), + })); + }, +}; diff --git a/docs/src/components/ui/search/search.client.ts b/docs/src/components/ui/search/search.client.ts new file mode 100644 index 0000000..96f76f5 --- /dev/null +++ b/docs/src/components/ui/search/search.client.ts @@ -0,0 +1,208 @@ +import type { SearchProvider, SearchResult } from "nimbus-docs/types"; + +export interface SearchConfig { + input: HTMLInputElement; + resultsContainer: HTMLElement; + emptyState: HTMLElement; + provider: SearchProvider; + onNavigate?: () => void; +} + +export interface SearchInstance { + reset(): Promise; + destroy(): void; +} + +export function initSearch(config: SearchConfig): SearchInstance { + const { input, resultsContainer, emptyState, provider, onNavigate } = config; + + let initialized = false; + let activeIndex = -1; + let resultIdCounter = 0; + let debounceTimer: ReturnType | undefined; + let activeController: AbortController | undefined; + + function getOptions(): HTMLElement[] { + return Array.from(resultsContainer.querySelectorAll("[role='option']")); + } + + function updateActive(newIndex: number): void { + const options = getOptions(); + if (options.length === 0) { + activeIndex = -1; + input.removeAttribute("aria-activedescendant"); + return; + } + activeIndex = Math.max(-1, Math.min(newIndex, options.length - 1)); + options.forEach((option, index) => { + if (index === activeIndex) { + option.setAttribute("data-highlighted", ""); + option.scrollIntoView({ block: "nearest" }); + input.setAttribute("aria-activedescendant", option.id); + } else { + option.removeAttribute("data-highlighted"); + } + }); + if (activeIndex < 0) input.removeAttribute("aria-activedescendant"); + } + + function clearResults(): void { + for (const result of resultsContainer.querySelectorAll("[role='option']")) result.remove(); + input.setAttribute("aria-expanded", "false"); + input.removeAttribute("aria-activedescendant"); + } + + function resultLink(title: string, href: string, className: string): HTMLAnchorElement { + const link = document.createElement("a"); + link.href = href; + link.className = className; + link.textContent = title; + link.addEventListener("click", () => onNavigate?.()); + return link; + } + + function buildResult(result: SearchResult): HTMLElement { + const option = document.createElement("div"); + option.id = `search-result-${resultIdCounter++}`; + option.setAttribute("role", "option"); + option.className = + "rounded-lg px-2 py-2 transition-colors cursor-pointer hover:bg-accent focus-within:bg-accent data-[highlighted]:bg-accent"; + + const link = resultLink( + result.title, + result.url, + "block truncate text-sm font-medium text-foreground no-underline focus-visible:outline-none", + ); + option.appendChild(link); + + if (result.snippet) { + const snippet = document.createElement("p"); + snippet.className = "mt-1 line-clamp-2 text-xs leading-relaxed text-muted-foreground"; + snippet.innerHTML = result.snippet; + option.appendChild(snippet); + } + + if (result.subResults?.length) { + const subList = document.createElement("div"); + subList.className = "mt-2 border-l border-border pl-3"; + for (const sub of result.subResults.slice(0, 3)) { + subList.appendChild( + resultLink(sub.title, sub.url, "block truncate py-0.5 text-xs text-muted-foreground no-underline hover:text-foreground"), + ); + } + option.appendChild(subList); + } + + option.addEventListener("click", (event) => { + if ((event.target as Element | null)?.closest("a")) return; + link.click(); + }); + + return option; + } + + async function ensureInitialized(): Promise { + if (initialized) return true; + try { + await provider.init?.(); + initialized = true; + return true; + } catch { + emptyState.textContent = "Search is available after a production build."; + return false; + } + } + + async function runSearch(query: string): Promise { + activeController?.abort(); + activeController = new AbortController(); + const signal = activeController.signal; + + emptyState.style.display = ""; + emptyState.textContent = "Searching…"; + clearResults(); + + if (!(await ensureInitialized()) || signal.aborted) return; + + try { + const results = await provider.search(query, { signal }); + if (signal.aborted) return; + + clearResults(); + activeIndex = -1; + + if (results.length === 0) { + emptyState.style.display = ""; + emptyState.textContent = "No results found."; + return; + } + + emptyState.style.display = "none"; + input.setAttribute("aria-expanded", "true"); + for (const result of results) resultsContainer.appendChild(buildResult(result)); + } catch { + if (signal.aborted) return; + clearResults(); + emptyState.style.display = ""; + emptyState.textContent = "Search is temporarily unavailable."; + } + } + + function handleInput(): void { + if (debounceTimer) clearTimeout(debounceTimer); + debounceTimer = setTimeout(() => { + const query = input.value.trim(); + if (!query) { + activeController?.abort(); + clearResults(); + emptyState.style.display = ""; + emptyState.textContent = "Type to search…"; + return; + } + void runSearch(query); + }, 150); + } + + function handleKeydown(event: KeyboardEvent): void { + const options = getOptions(); + if (event.key === "ArrowDown") { + event.preventDefault(); + updateActive(activeIndex + 1); + } else if (event.key === "ArrowUp") { + event.preventDefault(); + updateActive(activeIndex - 1); + } else if (event.key === "Home") { + event.preventDefault(); + updateActive(0); + } else if (event.key === "End") { + event.preventDefault(); + updateActive(options.length - 1); + } else if (event.key === "Enter" && activeIndex >= 0) { + event.preventDefault(); + options[activeIndex]?.querySelector("a")?.click(); + } + } + + input.addEventListener("input", handleInput); + input.closest("dialog")?.addEventListener("keydown", handleKeydown); + + return { + async reset() { + activeController?.abort(); + if (debounceTimer) clearTimeout(debounceTimer); + input.value = ""; + input.focus(); + activeIndex = -1; + clearResults(); + emptyState.style.display = ""; + emptyState.textContent = "Type to search…"; + await ensureInitialized(); + }, + destroy() { + activeController?.abort(); + if (debounceTimer) clearTimeout(debounceTimer); + input.removeEventListener("input", handleInput); + input.closest("dialog")?.removeEventListener("keydown", handleKeydown); + }, + }; +} diff --git a/docs/src/components/ui/sidebar/Sidebar.astro b/docs/src/components/ui/sidebar/Sidebar.astro new file mode 100644 index 0000000..1ca6bcd --- /dev/null +++ b/docs/src/components/ui/sidebar/Sidebar.astro @@ -0,0 +1,64 @@ +--- +/** + * Sidebar — recursive navigation tree from a `SidebarItem[]`. Composes + * SidebarGroup + SidebarLink. Pass `persist` to opt into sessionStorage + * for open/scroll state (desktop only). + */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; +import SidebarGroup from "./SidebarGroup.astro"; +import SidebarLink from "./SidebarLink.astro"; +import type { SidebarItem } from "nimbus-docs/types"; +import { sidebarHash } from "nimbus-docs"; + +interface Props extends HTMLAttributes<"div"> { + items: SidebarItem[]; + /** Persist open/scroll state to sessionStorage. Desktop sidebar only. */ + persist?: boolean; +} + +const { items, persist = false, class: className, ...attrs } = Astro.props; +const hash = sidebarHash(items); +--- + +
+
    + {items.map((item) => + item.type === "group" ? ( +
  • + +
  • + ) : item.type === "external" ? ( +
  • + +
  • + ) : ( +
  • + +
  • + ), + )} +
+
+ + + + diff --git a/docs/src/components/ui/sidebar/SidebarFilter.astro b/docs/src/components/ui/sidebar/SidebarFilter.astro new file mode 100644 index 0000000..be9cb97 --- /dev/null +++ b/docs/src/components/ui/sidebar/SidebarFilter.astro @@ -0,0 +1,20 @@ +--- +/** SidebarFilter — text input that filters the adjacent Sidebar. Press "/" to focus. */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"div"> {} + +const { class: className, ...attrs } = Astro.props; +--- + +
+ +
diff --git a/docs/src/components/ui/sidebar/SidebarGroup.astro b/docs/src/components/ui/sidebar/SidebarGroup.astro new file mode 100644 index 0000000..fa22b55 --- /dev/null +++ b/docs/src/components/ui/sidebar/SidebarGroup.astro @@ -0,0 +1,209 @@ +--- +/** + * SidebarGroup — autogenerated section header in the sidebar rail. + * + * Renders in one of two shapes depending on whether the group has a + * landing page (`indexHref`): + * + * - Has landing: the label is an `` linking to indexHref. The + * collapse caret sits next to it as a separate ` diff --git a/docs/src/components/ui/tabs/index.ts b/docs/src/components/ui/tabs/index.ts new file mode 100644 index 0000000..07214f6 --- /dev/null +++ b/docs/src/components/ui/tabs/index.ts @@ -0,0 +1,5 @@ +export { default as Tabs } from "./Tabs.astro"; +export { default as TabItem } from "./TabItem.astro"; +export { default as TabsList } from "./TabsList.astro"; +export { default as TabsTrigger } from "./TabsTrigger.astro"; +export { default as TabsContent } from "./TabsContent.astro"; diff --git a/docs/src/components/ui/tabs/tabs.client.ts b/docs/src/components/ui/tabs/tabs.client.ts new file mode 100644 index 0000000..4e963a9 --- /dev/null +++ b/docs/src/components/ui/tabs/tabs.client.ts @@ -0,0 +1,72 @@ +/** Wires ; auto-detects manual triggers vs. synthesized-from-TabItem mode. */ + +import { mount, initTabs } from "nimbus-docs/client"; + +const TRIGGER_CLASS = + "cursor-pointer px-4 py-2 text-sm font-medium leading-6 whitespace-nowrap text-muted-foreground transition-colors hover:text-foreground aria-selected:text-primary focus-visible:rounded-sm focus-visible:outline-2 focus-visible:outline-ring focus-visible:outline-offset-[-2px]"; + +let counter = 0; + +function initTabContainer(container: HTMLElement): () => void { + const id = `nb-tabs-${counter++}`; + const syncKey = container.dataset.nbSyncKey; + const tablist = container.querySelector("[role=tablist]"); + const indicator = container.querySelector("[data-nb-tabs-indicator]"); + + // Scope to this container so a nested 's triggers don't flip the + // parent into manual mode (or vice-versa), independent of mount order. + const existingTriggers = Array.from(container.querySelectorAll("[data-nb-tabs-trigger]")).filter( + (t) => (t as HTMLElement).closest("[data-nb-tabs]") === container, + ); + const synthesize = existingTriggers.length === 0; + + if (synthesize && tablist) { + // Only this container's own panels — exclude a nested 's panels, + // whose nearest [data-nb-tabs] ancestor is the inner container. + const panels = Array.from(container.querySelectorAll("[data-nb-tabs-content]")).filter( + (p) => p.closest("[data-nb-tabs]") === container, + ); + + panels.forEach((panel, i) => { + const label = panel.dataset.nbTabLabel ?? "Tab"; + const btn = document.createElement("button"); + btn.role = "tab"; + btn.type = "button"; + btn.className = TRIGGER_CLASS; + btn.textContent = label; + btn.setAttribute("data-nb-tabs-trigger", ""); + + const panelId = `${id}-panel-${i}`; + const tabId = `${id}-tab-${i}`; + btn.id = tabId; + btn.setAttribute("aria-controls", panelId); + panel.id = panelId; + panel.setAttribute("aria-labelledby", tabId); + + if (indicator) { + tablist.insertBefore(btn, indicator); + } else { + tablist.appendChild(btn); + } + }); + } + + const instance = initTabs({ + container, + tabSelector: "[data-nb-tabs-trigger]", + panelSelector: "[data-nb-tabs-content]", + boundarySelector: "[data-nb-tabs]", + indicator, + sync: syncKey ? { key: `ui-synced-tabs__${syncKey}` } : undefined, + }); + + return () => { + instance.destroy(); + // Remove synthesized triggers so re-mount doesn't double up. + if (synthesize && tablist) { + tablist.querySelectorAll("[data-nb-tabs-trigger]").forEach((b) => b.remove()); + } + }; +} + +mount("[data-nb-tabs]", initTabContainer); diff --git a/docs/src/components/ui/theme-toggle/ThemeToggle.astro b/docs/src/components/ui/theme-toggle/ThemeToggle.astro new file mode 100644 index 0000000..1aded43 --- /dev/null +++ b/docs/src/components/ui/theme-toggle/ThemeToggle.astro @@ -0,0 +1,32 @@ +--- +/** + * ThemeToggle — light/dark switcher. Persists to localStorage; theme + * applies to `` via the inline script in BaseLayout + * (no FOUC). + */ +import { Icon } from "astro-icon/components"; +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; + +interface Props extends HTMLAttributes<"button"> {} + +const { class: className, ...attrs } = Astro.props; +--- + + + + diff --git a/docs/src/components/ui/theme-toggle/index.ts b/docs/src/components/ui/theme-toggle/index.ts new file mode 100644 index 0000000..23685f5 --- /dev/null +++ b/docs/src/components/ui/theme-toggle/index.ts @@ -0,0 +1 @@ +export { default as ThemeToggle } from "./ThemeToggle.astro"; diff --git a/docs/src/components/ui/theme-toggle/theme-toggle.client.ts b/docs/src/components/ui/theme-toggle/theme-toggle.client.ts new file mode 100644 index 0000000..f9624f6 --- /dev/null +++ b/docs/src/components/ui/theme-toggle/theme-toggle.client.ts @@ -0,0 +1,31 @@ +/** + * theme-toggle.client.ts — light/dark toggle. Writes pref to localStorage + * ("ui-mode"); BaseLayout's pre-paint script owns DOM application so view + * transitions, OS changes, and cross-tab edits stay in sync. + */ + +import { mount } from "nimbus-docs/client"; + +declare global { + interface Window { + __nbApplyTheme?: () => void; + } +} + +function initThemeToggle(button: HTMLElement): () => void { + function handleClick() { + const isDark = document.documentElement.getAttribute("data-mode") === "dark"; + try { + localStorage.setItem("ui-mode", isDark ? "light" : "dark"); + } catch { + // Ignore storage errors (private mode / restricted contexts). + } + window.__nbApplyTheme?.(); + } + + window.__nbApplyTheme?.(); + button.addEventListener("click", handleClick); + return () => button.removeEventListener("click", handleClick); +} + +mount("[data-nb-theme-toggle]", initThemeToggle); diff --git a/docs/src/components/ui/toc/TOC.astro b/docs/src/components/ui/toc/TOC.astro new file mode 100644 index 0000000..084dfd7 --- /dev/null +++ b/docs/src/components/ui/toc/TOC.astro @@ -0,0 +1,95 @@ +--- +/** + * TOC — on-this-page nav with scroll-spy. Static rail rendered inline + * (border-l + S-curve SVGs at indent changes); animated active indicator + * lives in toc.client.ts. + */ +import { cn } from "@/lib/cn"; +import type { HTMLAttributes } from "astro/types"; +import type { TOCItem } from "nimbus-docs/types"; + +interface Props extends HTMLAttributes<"div"> { + headings: TOCItem[]; +} + +const { headings, class: className, ...attrs } = Astro.props; +--- + +{headings.length > 0 && ( +
+

On this page

+ +
+)} + + diff --git a/docs/src/components/ui/toc/index.ts b/docs/src/components/ui/toc/index.ts new file mode 100644 index 0000000..8df1055 --- /dev/null +++ b/docs/src/components/ui/toc/index.ts @@ -0,0 +1 @@ +export { default as TOC } from "./TOC.astro"; diff --git a/docs/src/components/ui/toc/toc.client.ts b/docs/src/components/ui/toc/toc.client.ts new file mode 100644 index 0000000..9bf1a24 --- /dev/null +++ b/docs/src/components/ui/toc/toc.client.ts @@ -0,0 +1,325 @@ +/** + * Scroll-spy + animated rail indicator. Active heading tracked via a single + * IntersectionObserver; the dash slides by arc-length so it weaves through the + * rail's curves instead of cutting across. + */ + +import { mount } from "nimbus-docs/client"; + +const READING_BAND = 0.25; +const BOTTOM_EPSILON = 2; +const REVEAL_PADDING = 12; + +function initToc(root: HTMLElement): () => void { + const nav = root.querySelector("nav"); + const activePath = root.querySelector("[data-nb-toc-rail-active]"); + const links = root.querySelectorAll("[data-nb-toc-link]"); + if (!nav || !activePath || links.length === 0) return () => {}; + const navElement = nav; + const activeRailPath = activePath; + + const scrollHost = root.closest("[data-nb-toc-scroll-host]") ?? root; + const slugs = Array.from(links) + .map((link) => link.dataset.nbSlug) + .filter((slug): slug is string => typeof slug === "string" && slug.length > 0); + if (slugs.length !== links.length) return () => {}; + + const headingEls = slugs.map((slug) => document.getElementById(slug)).filter((el): el is HTMLElement => el instanceof HTMLElement); + if (headingEls.length === 0) return () => {}; + + let segments: { start: number; length: number }[] = []; + let totalLength = 0; + let currentIndex = -1; + let currentLink: HTMLElement | null = null; + let hasApplied = false; + + // Measure the rail from the DOM so the path stays pixel-perfect over the + // static gray rail, capturing each link's arc-length range as we go. + function buildRail() { + const navRect = navElement.getBoundingClientRect(); + + const m = Array.from(links).map((link) => { + const r = link.getBoundingClientRect(); + return { + x: r.left - navRect.left + 1, + yTop: r.top - navRect.top, + yBot: r.top - navRect.top + r.height, + }; + }); + + let d = ""; + const newSegments: { start: number; length: number }[] = []; + + // Measure each command in isolation (O(1)) and accumulate, rather than + // re-measuring the whole cumulatively-growing path with getTotalLength() + // on every iteration — the latter is O(n^2) and blocks the main thread on + // pages with hundreds of headings. Arc length is additive across + // contiguous commands, so summing isolated sub-paths matches the total. + // activePath doubles as the scratch measurer here; the full `d` is written + // back once at the end. + const measure = (subPath: string) => { + activeRailPath.setAttribute("d", subPath); + return activeRailPath.getTotalLength(); + }; + + let cumulative = 0; + let prevX = 0; + let prevYBot = 0; + + for (let i = 0; i < m.length; i++) { + const cur = m[i]; + + if (i === 0) { + d += `M ${cur.x} ${cur.yTop} `; + } else { + const prev = m[i - 1]; + let connector: string; + if (Math.abs(cur.x - prev.x) < 0.5) { + connector = `L ${cur.x} ${cur.yTop} `; + } else { + // Indent change → S-curve matching the static gap SVG. + const midY = (prev.yBot + cur.yTop) / 2; + connector = `C ${prev.x} ${midY}, ${cur.x} ${midY}, ${cur.x} ${cur.yTop} `; + } + d += connector; + cumulative += measure(`M ${prevX} ${prevYBot} ${connector}`); + } + + const start = cumulative; + + const seg = `L ${cur.x} ${cur.yBot} `; + d += seg; + cumulative += measure(`M ${cur.x} ${cur.yTop} ${seg}`); + + newSegments.push({ start, length: cumulative - start }); + + prevX = cur.x; + prevYBot = cur.yBot; + } + + activeRailPath.setAttribute("d", d); + segments = newSegments; + totalLength = cumulative; + } + + function applyActive(index: number, instant: boolean) { + const seg = segments[index]; + if (!seg) return; + + if (instant) { + activeRailPath.setAttribute("data-initial", "true"); + // Force recalc so only opacity transitions on first paint (no dash sweep). + void activeRailPath.getBoundingClientRect(); + } + + activeRailPath.style.strokeDasharray = `${seg.length} ${totalLength + 1}`; + activeRailPath.style.strokeDashoffset = `${-seg.start}`; + + if (instant) { + requestAnimationFrame(() => { + activeRailPath.setAttribute("data-ready", "true"); + requestAnimationFrame(() => { + activeRailPath.removeAttribute("data-initial"); + }); + }); + } + } + + function revealActiveLink(link: HTMLElement) { + const hostRect = scrollHost.getBoundingClientRect(); + const linkRect = link.getBoundingClientRect(); + + if (linkRect.top < hostRect.top + REVEAL_PADDING) { + scrollHost.scrollTop += linkRect.top - hostRect.top - REVEAL_PADDING; + return; + } + + if (linkRect.bottom > hostRect.bottom - REVEAL_PADDING) { + scrollHost.scrollTop += linkRect.bottom - hostRect.bottom + REVEAL_PADDING; + } + } + + function setActive(index: number) { + if (index === currentIndex) return; + currentIndex = index; + + currentLink?.removeAttribute("aria-current"); + const activeLink = links[index] ?? null; + activeLink?.setAttribute("aria-current", "true"); + currentLink = activeLink; + if (activeLink) revealActiveLink(activeLink); + + applyActive(index, !hasApplied); + hasApplied = true; + } + + const inBand = new Set(); + let observedIndex = 0; + let atBottom = false; + let pinnedIndex: number | null = null; + let pinnedEnteredViewport = false; + + function resolve() { + if (pinnedIndex !== null) { + setActive(pinnedIndex); + return; + } + setActive(atBottom ? headingEls.length - 1 : observedIndex); + } + + // rootMargin collapses the root to the top band; deepest in-band heading wins. + const spy = new IntersectionObserver( + (entries) => { + for (const entry of entries) { + const i = headingEls.indexOf(entry.target as HTMLElement); + if (i === -1) continue; + if (entry.isIntersecting) inBand.add(i); + else inBand.delete(i); + } + if (inBand.size > 0) observedIndex = Math.max(...inBand); + resolve(); + }, + { rootMargin: `0px 0px -${(1 - READING_BAND) * 100}% 0px`, threshold: 0 }, + ); + headingEls.forEach((h) => spy.observe(h)); + + function updateBottom() { + const scrollEl = document.scrollingElement ?? document.documentElement; + const maxScroll = scrollEl.scrollHeight - window.innerHeight; + const next = maxScroll > BOTTOM_EPSILON && scrollEl.scrollTop >= maxScroll - BOTTOM_EPSILON; + if (next !== atBottom) { + atBottom = next; + resolve(); + } + } + + function updateObservedIndex() { + const bandBottom = window.innerHeight * READING_BAND; + let nextIndex = 0; + for (let i = 0; i < headingEls.length; i++) { + if (headingEls[i].getBoundingClientRect().top <= bandBottom) nextIndex = i; + else break; + } + observedIndex = nextIndex; + } + + function releaseStalePin() { + if (pinnedIndex === null) return; + const pinnedSlug = slugs[pinnedIndex]; + const heading = pinnedSlug ? document.getElementById(pinnedSlug) : null; + if (!heading) { + pinnedIndex = null; + pinnedEnteredViewport = false; + return; + } + + const rect = heading.getBoundingClientRect(); + const inViewport = rect.bottom >= 0 && rect.top <= window.innerHeight; + if (inViewport) { + pinnedEnteredViewport = true; + return; + } + + if (pinnedEnteredViewport) { + pinnedIndex = null; + pinnedEnteredViewport = false; + } + } + + let ticking = false; + function onScroll() { + if (ticking) return; + ticking = true; + requestAnimationFrame(() => { + updateObservedIndex(); + updateBottom(); + releaseStalePin(); + resolve(); + ticking = false; + }); + } + + function onLayoutChange() { + buildRail(); + updateObservedIndex(); + updateBottom(); + releaseStalePin(); + resolve(); + if (currentIndex >= 0) { + applyActive(currentIndex, true); + const activeLink = links[currentIndex]; + if (activeLink) revealActiveLink(activeLink); + } + } + + const controller = new AbortController(); + + navElement.addEventListener( + "click", + (e) => { + if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return; + const link = (e.target as Element).closest("[data-nb-toc-link]"); + if (!link) return; + const linkSlug = link.dataset.nbSlug; + if (!linkSlug) return; + const i = slugs.indexOf(linkSlug); + if (i === -1) return; + pinnedIndex = i; + const headingSlug = slugs[i]; + const heading = headingSlug ? document.getElementById(headingSlug) : null; + const rect = heading?.getBoundingClientRect(); + pinnedEnteredViewport = !!rect && rect.bottom >= 0 && rect.top <= window.innerHeight; + resolve(); + }, + { signal: controller.signal }, + ); + + // Hand-driven scrolling releases the pin and resumes auto-tracking. + function releasePin() { + if (pinnedIndex === null) return; + pinnedIndex = null; + pinnedEnteredViewport = false; + resolve(); + } + const NAV_KEYS = new Set(["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " ", "Spacebar"]); + window.addEventListener("wheel", releasePin, { + passive: true, + signal: controller.signal, + }); + window.addEventListener("touchmove", releasePin, { + passive: true, + signal: controller.signal, + }); + window.addEventListener( + "keydown", + (e) => { + if (NAV_KEYS.has(e.key)) releasePin(); + }, + { signal: controller.signal }, + ); + + window.addEventListener("scroll", onScroll, { + passive: true, + signal: controller.signal, + }); + window.addEventListener("resize", onLayoutChange, { + passive: true, + signal: controller.signal, + }); + + const ro = new ResizeObserver(onLayoutChange); + ro.observe(navElement); + + buildRail(); + updateObservedIndex(); + updateBottom(); + resolve(); + + return () => { + controller.abort(); + ro.disconnect(); + spy.disconnect(); + }; +} + +mount("[data-nb-toc]", initToc); diff --git a/docs/src/content.config.ts b/docs/src/content.config.ts index 196db15..ec5e54a 100644 --- a/docs/src/content.config.ts +++ b/docs/src/content.config.ts @@ -1,13 +1,15 @@ import { defineCollection } from "astro:content"; -import { docsLoader } from "@astrojs/starlight/loaders"; -import { docsSchema } from "@astrojs/starlight/schema"; +import { z } from "astro/zod"; +import { docsCollection, partialsCollection } from "nimbus-docs/content"; -/** - * Single docs collection, loaded from `src/content/docs/**` via - * Starlight's filesystem loader. Schema follows Starlight's - * canonical shape so every page gets `title`, `description`, and - * the standard sidebar / hero fields. - */ export const collections = { - docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), + docs: defineCollection( + docsCollection({ + schemaFields: { + audience: z.literal("human").optional(), + aiGenerated: z.boolean().optional(), + }, + }), + ), + partials: defineCollection(partialsCollection()), }; diff --git a/docs/src/content/docs/adapters/custom-loader.md b/docs/src/content/docs/adapters/custom-loader.md index 5b36471..65b477e 100644 --- a/docs/src/content/docs/adapters/custom-loader.md +++ b/docs/src/content/docs/adapters/custom-loader.md @@ -1,6 +1,7 @@ --- title: Custom loader description: Wrapping a non-glob, non-file Astro loader to opt content into the translation pipeline. +aiGenerated: true --- Astro's content layer supports custom loaders — functions that diff --git a/docs/src/content/docs/adapters/markdown.md b/docs/src/content/docs/adapters/markdown.md index b213a5d..d3a3e7f 100644 --- a/docs/src/content/docs/adapters/markdown.md +++ b/docs/src/content/docs/adapters/markdown.md @@ -1,6 +1,7 @@ --- title: Markdown adapter description: "Translating .md files: frontmatter keys, body inline text, internal links." +aiGenerated: true --- The Markdown adapter handles `.md` files via Satteri by default. Use diff --git a/docs/src/content/docs/adapters/mdx.md b/docs/src/content/docs/adapters/mdx.md index a9c7e66..ff3d9f8 100644 --- a/docs/src/content/docs/adapters/mdx.md +++ b/docs/src/content/docs/adapters/mdx.md @@ -1,6 +1,7 @@ --- title: MDX adapter description: "Translating .mdx files — JSX, props, static data, and limits." +aiGenerated: true --- The MDX adapter reuses the Markdown adapter but parses `.mdx` with diff --git a/docs/src/content/docs/adapters/toml.md b/docs/src/content/docs/adapters/toml.md index dde75d5..cec15f6 100644 --- a/docs/src/content/docs/adapters/toml.md +++ b/docs/src/content/docs/adapters/toml.md @@ -1,6 +1,7 @@ --- title: TOML adapter description: "Translating structured TOML config: keys, urls, wildcards." +aiGenerated: true --- The TOML adapter translates structured data files like diff --git a/docs/src/content/docs/cli/audit-mdx.md b/docs/src/content/docs/cli/audit-mdx.md index f9a4e10..0808752 100644 --- a/docs/src/content/docs/cli/audit-mdx.md +++ b/docs/src/content/docs/cli/audit-mdx.md @@ -1,6 +1,7 @@ --- title: polystella audit-mdx description: "polystella audit-mdx — offline MDX extraction audit." +aiGenerated: true --- `audit-mdx` scans configured `.mdx` sources for likely missed diff --git a/docs/src/content/docs/cli/check-ui.md b/docs/src/content/docs/cli/check-ui.md index 5216244..ebd6388 100644 --- a/docs/src/content/docs/cli/check-ui.md +++ b/docs/src/content/docs/cli/check-ui.md @@ -1,6 +1,7 @@ --- title: polystella check-ui description: "polystella check-ui — offline drift detection over UI-string JSONs." +aiGenerated: true --- Pure drift detection over your project's UI-string JSON files. diff --git a/docs/src/content/docs/cli/index.md b/docs/src/content/docs/cli/index.md index a25cf3f..06518f1 100644 --- a/docs/src/content/docs/cli/index.md +++ b/docs/src/content/docs/cli/index.md @@ -1,6 +1,9 @@ --- title: CLI overview description: The polystella binary and its verb-style subcommands. +aiGenerated: true +sidebar: + label: Overview --- The package exposes a single `polystella` binary with verb-style diff --git a/docs/src/content/docs/cli/sync-ui.md b/docs/src/content/docs/cli/sync-ui.md index 204271c..fe6081f 100644 --- a/docs/src/content/docs/cli/sync-ui.md +++ b/docs/src/content/docs/cli/sync-ui.md @@ -1,6 +1,7 @@ --- title: polystella sync-ui description: "polystella sync-ui — mechanical UI-string key reconciliation." +aiGenerated: true --- Mechanical (no AI) key reconciliation for UI-string JSONs. Adds diff --git a/docs/src/content/docs/cli/translate-ui.md b/docs/src/content/docs/cli/translate-ui.md index f02dd97..c5175d0 100644 --- a/docs/src/content/docs/cli/translate-ui.md +++ b/docs/src/content/docs/cli/translate-ui.md @@ -1,6 +1,7 @@ --- title: polystella translate-ui description: "polystella translate-ui — sync followed by AI-fill of empty placeholders." +aiGenerated: true --- Sync (key add/remove) followed by AI-fill of empty values. Queued diff --git a/docs/src/content/docs/cli/translate.md b/docs/src/content/docs/cli/translate.md index 6e13100..8bdeaf3 100644 --- a/docs/src/content/docs/cli/translate.md +++ b/docs/src/content/docs/cli/translate.md @@ -1,6 +1,7 @@ --- title: polystella translate description: "polystella translate — markdown pipeline outside astro build." +aiGenerated: true --- Runs the same translation pipeline as `astro build` without booting diff --git a/docs/src/content/docs/concepts/ai-marker.md b/docs/src/content/docs/concepts/ai-marker.md index 3944a7d..a98c469 100644 --- a/docs/src/content/docs/concepts/ai-marker.md +++ b/docs/src/content/docs/concepts/ai-marker.md @@ -1,6 +1,7 @@ --- title: AI marker description: The aiTranslated frontmatter fields baked into every translated file. +aiGenerated: true --- Every AI-translated file gets three frontmatter fields added during diff --git a/docs/src/content/docs/concepts/glossaries.md b/docs/src/content/docs/concepts/glossaries.md index 79f63f6..7eec70e 100644 --- a/docs/src/content/docs/concepts/glossaries.md +++ b/docs/src/content/docs/concepts/glossaries.md @@ -1,6 +1,7 @@ --- title: Glossaries description: Per-locale YAML files that pin do-not-translate terms, preferred translations, and style rules. +aiGenerated: true --- A glossary tells the translator how to handle terminology that diff --git a/docs/src/content/docs/concepts/how-it-works.md b/docs/src/content/docs/concepts/how-it-works.md index b8e5bc2..d1472d7 100644 --- a/docs/src/content/docs/concepts/how-it-works.md +++ b/docs/src/content/docs/concepts/how-it-works.md @@ -1,6 +1,7 @@ --- title: How it works description: End-to-end overview of the PolyStella build pipeline. +aiGenerated: true --- PolyStella is an Astro integration that translates content into diff --git a/docs/src/content/docs/concepts/mode-boundary.md b/docs/src/content/docs/concepts/mode-boundary.md index 16f75ab..e22acdc 100644 --- a/docs/src/content/docs/concepts/mode-boundary.md +++ b/docs/src/content/docs/concepts/mode-boundary.md @@ -1,6 +1,7 @@ --- title: Mode boundary description: Standalone vs Starlight modes — what differs between them. +aiGenerated: true --- PolyStella ships **standalone mode** today. **Starlight mode** is diff --git a/docs/src/content/docs/concepts/overrides.md b/docs/src/content/docs/concepts/overrides.md index 5e1ee6d..4c3cfd6 100644 --- a/docs/src/content/docs/concepts/overrides.md +++ b/docs/src/content/docs/concepts/overrides.md @@ -1,6 +1,7 @@ --- title: Overrides description: Hand-translated files that win over AI output verbatim. +aiGenerated: true --- Sometimes the AI gets something wrong. Or a page is too important diff --git a/docs/src/content/docs/concepts/r2-cache.md b/docs/src/content/docs/concepts/r2-cache.md index d58f500..cbd2a67 100644 --- a/docs/src/content/docs/concepts/r2-cache.md +++ b/docs/src/content/docs/concepts/r2-cache.md @@ -1,6 +1,7 @@ --- title: R2 cache description: How translations are content-addressed and cached in Cloudflare R2. +aiGenerated: true --- PolyStella's R2 cache is the load-bearing piece of the whole diff --git a/docs/src/content/docs/concepts/runtime-bridge.md b/docs/src/content/docs/concepts/runtime-bridge.md index 323c6ff..bd2337a 100644 --- a/docs/src/content/docs/concepts/runtime-bridge.md +++ b/docs/src/content/docs/concepts/runtime-bridge.md @@ -1,6 +1,7 @@ --- title: Runtime bridge description: The seam between config-time and content-sync-time for custom-loader translation. +aiGenerated: true --- Most of PolyStella runs at `astro:config:setup`. File-based content diff --git a/docs/src/content/docs/configuration/index.md b/docs/src/content/docs/configuration/index.md index 491d2f1..d6a773f 100644 --- a/docs/src/content/docs/configuration/index.md +++ b/docs/src/content/docs/configuration/index.md @@ -1,6 +1,9 @@ --- title: Configuration overview description: Where polystella.config.mjs sits and how it relates to astro.config.mjs. +aiGenerated: true +sidebar: + label: Overview --- PolyStella's configuration lives in two files. Knowing which goes diff --git a/docs/src/content/docs/configuration/reference.md b/docs/src/content/docs/configuration/reference.md index 397a55e..794d277 100644 --- a/docs/src/content/docs/configuration/reference.md +++ b/docs/src/content/docs/configuration/reference.md @@ -1,6 +1,7 @@ --- title: Configuration reference description: Full polystella.config.mjs option reference, generated from the zod schema. +aiGenerated: true --- :::note[Auto-generated] diff --git a/docs/src/content/docs/cookbook/locale-picker.md b/docs/src/content/docs/cookbook/locale-picker.md index cd37c38..2c38d13 100644 --- a/docs/src/content/docs/cookbook/locale-picker.md +++ b/docs/src/content/docs/cookbook/locale-picker.md @@ -1,6 +1,7 @@ --- title: Locale picker description: A copy-paste locale-switcher component for PolyStella sites. +aiGenerated: true --- A minimal, unstyled locale-switcher component. Renders a list of diff --git a/docs/src/content/docs/getting-started/install.md b/docs/src/content/docs/getting-started/install.md index 9118b94..b0c4cc5 100644 --- a/docs/src/content/docs/getting-started/install.md +++ b/docs/src/content/docs/getting-started/install.md @@ -1,6 +1,7 @@ --- title: Install description: How to install PolyStella in your Astro project. +aiGenerated: true --- PolyStella is an Astro integration. It runs at build time, talks to diff --git a/docs/src/content/docs/getting-started/mental-model.md b/docs/src/content/docs/getting-started/mental-model.md index f12888f..dbe4258 100644 --- a/docs/src/content/docs/getting-started/mental-model.md +++ b/docs/src/content/docs/getting-started/mental-model.md @@ -1,6 +1,7 @@ --- title: Mental model description: How PolyStella thinks about content, locales, and the build pipeline. +aiGenerated: true --- PolyStella has three central ideas. Internalise these and the rest diff --git a/docs/src/content/docs/getting-started/quick-start.md b/docs/src/content/docs/getting-started/quick-start.md index 679694b..df892a3 100644 --- a/docs/src/content/docs/getting-started/quick-start.md +++ b/docs/src/content/docs/getting-started/quick-start.md @@ -1,6 +1,7 @@ --- title: Quick start description: "Five-minute setup — the four files that participate in a typical PolyStella project." +aiGenerated: true --- Four files participate in a typical PolyStella setup. None of them diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index fed994d..eb3081f 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -1,44 +1,54 @@ --- title: PolyStella description: AI-driven content localization for Astro — build-time markdown translation, R2-cached. -template: splash -hero: - tagline: AI-driven content localization for Astro. Build-time translation, R2-cached, no runtime AI calls. - actions: - - text: Get started - link: /getting-started/install/ - icon: right-arrow - variant: primary - - text: View on GitHub - link: https://github.com/cloudflare/polystella - icon: external - variant: minimal +aiGenerated: true +mode: custom --- -import { Card, CardGrid } from "@astrojs/starlight/components"; +
+
+

+ AI-driven localization for Astro +

+

+ Build-time translation, R2-cached, no runtime AI calls. +

+

+ PolyStella translates content into additional locales during your Astro build, caches the generated bytes in Cloudflare R2, and injects locale-prefixed routes for static delivery. +

+ +
- - + + Translates `.md`, `.mdx`, and `.toml` content into additional locales during `astro build`. Visitors get static bytes; no runtime AI calls. - + Translations are content-addressed by source bytes + glossary + model. Unchanged pages cost zero on rebuild. Translations are never committed to the repo. - + A YAML file per locale pins do-not-translate terms, preferred translations, and free-form translator notes. Edits re-translate only the pages that need it. - + Drop a markdown file under `i18n/overrides/{locale}/...` and it wins over AI output verbatim. The pipeline still locale-prefixes its internal links. - + Per-locale sibling content collections. Astro routes `/[lang]/...` through generated shims. `Astro.locals.t` and `Astro.locals.lhref` work in templates. - + Per-locale JSON files for chrome text. The CLI offers offline drift detection, key reconciliation, and AI-fill of empty placeholders. - + +
diff --git a/docs/src/content/docs/operations/branch-dispatch.md b/docs/src/content/docs/operations/branch-dispatch.md index 36f7bd9..5f58c25 100644 --- a/docs/src/content/docs/operations/branch-dispatch.md +++ b/docs/src/content/docs/operations/branch-dispatch.md @@ -1,6 +1,7 @@ --- title: Branch dispatch description: How polystella.config.mjs reads WORKERS_CI_BRANCH to switch prefixes. +aiGenerated: true --- Branch dispatch is a config-side pattern, not built into the diff --git a/docs/src/content/docs/operations/ci.md b/docs/src/content/docs/operations/ci.md index 0eaf952..a6d1446 100644 --- a/docs/src/content/docs/operations/ci.md +++ b/docs/src/content/docs/operations/ci.md @@ -1,6 +1,7 @@ --- title: CI / Workers Builds description: Wiring up PolyStella in CI so the right R2 prefix is targeted per branch. +aiGenerated: true --- PolyStella is designed to run inside Cloudflare Workers Builds (or diff --git a/docs/src/content/docs/operations/preview-isolation.md b/docs/src/content/docs/operations/preview-isolation.md index 9433e7b..7dddcf4 100644 --- a/docs/src/content/docs/operations/preview-isolation.md +++ b/docs/src/content/docs/operations/preview-isolation.md @@ -1,6 +1,7 @@ --- title: Preview isolation description: Using readFallbackPrefixes to read main's cache without writing back. +aiGenerated: true --- The combination of `r2.readFallbackPrefixes` and `r2.readOnly` diff --git a/docs/src/content/docs/providers/anthropic.md b/docs/src/content/docs/providers/anthropic.md index cde4826..dbb6d8a 100644 --- a/docs/src/content/docs/providers/anthropic.md +++ b/docs/src/content/docs/providers/anthropic.md @@ -1,6 +1,7 @@ --- title: Anthropic provider description: Anthropic Claude as the translation provider. +aiGenerated: true --- The Anthropic provider routes translation through Anthropic's diff --git a/docs/src/content/docs/providers/batching.md b/docs/src/content/docs/providers/batching.md index e7f19d8..2b2ada7 100644 --- a/docs/src/content/docs/providers/batching.md +++ b/docs/src/content/docs/providers/batching.md @@ -1,6 +1,7 @@ --- title: Batching description: "How translateBatch groups segments into LLM calls; batchInputTokenBudget." +aiGenerated: true --- For small files the translator processes the entire file in a diff --git a/docs/src/content/docs/providers/model-selection.md b/docs/src/content/docs/providers/model-selection.md index 23d996c..931e9c6 100644 --- a/docs/src/content/docs/providers/model-selection.md +++ b/docs/src/content/docs/providers/model-selection.md @@ -1,6 +1,7 @@ --- title: Model selection description: Single model id vs per-locale map; how model choice affects the cache. +aiGenerated: true --- The `provider.model` option is either a single model id or a per- diff --git a/docs/src/content/docs/providers/permanent-errors.md b/docs/src/content/docs/providers/permanent-errors.md index 1ee31d8..f3e077e 100644 --- a/docs/src/content/docs/providers/permanent-errors.md +++ b/docs/src/content/docs/providers/permanent-errors.md @@ -1,6 +1,7 @@ --- title: Permanent errors description: PermanentProviderError vs retriable failures — how the retry loop decides. +aiGenerated: true --- When a provider call fails, PolyStella has to decide: retry, or diff --git a/docs/src/content/docs/providers/workers-ai.md b/docs/src/content/docs/providers/workers-ai.md index c0aef5a..ea8e54f 100644 --- a/docs/src/content/docs/providers/workers-ai.md +++ b/docs/src/content/docs/providers/workers-ai.md @@ -1,6 +1,7 @@ --- title: Workers AI provider description: Cloudflare Workers AI as the translation provider. +aiGenerated: true --- The Workers AI provider routes translation through Cloudflare's diff --git a/docs/src/content/docs/reference/breaking-changes.md b/docs/src/content/docs/reference/breaking-changes.md index b0c3810..1cb74f6 100644 --- a/docs/src/content/docs/reference/breaking-changes.md +++ b/docs/src/content/docs/reference/breaking-changes.md @@ -1,6 +1,7 @@ --- title: Breaking changes description: Pre-1.0 breaking-change log. +aiGenerated: true --- PolyStella is in pre-1.0 development. Breaking changes happen. diff --git a/docs/src/content/docs/reference/exports.md b/docs/src/content/docs/reference/exports.md index f735332..aa095f2 100644 --- a/docs/src/content/docs/reference/exports.md +++ b/docs/src/content/docs/reference/exports.md @@ -1,6 +1,7 @@ --- title: Public exports description: "Every export path in package.json — what it provides and when to import from it." +aiGenerated: true --- PolyStella ships twelve public import paths. Each has a narrow, diff --git a/docs/src/content/docs/roadmap.md b/docs/src/content/docs/roadmap.md index 99c7a8f..cf002f3 100644 --- a/docs/src/content/docs/roadmap.md +++ b/docs/src/content/docs/roadmap.md @@ -1,6 +1,7 @@ --- title: Roadmap description: Status of shipped + planned features. +aiGenerated: true --- PolyStella is in active pre-1.0 development. The table below diff --git a/docs/src/content/docs/routing/configuration.md b/docs/src/content/docs/routing/configuration.md index 860c056..1b4fa3c 100644 --- a/docs/src/content/docs/routing/configuration.md +++ b/docs/src/content/docs/routing/configuration.md @@ -1,6 +1,7 @@ --- title: Route configuration description: "The routes and routesImports options." +aiGenerated: true --- Two `polystella.config.mjs` options control which source pages get diff --git a/docs/src/content/docs/routing/shims.md b/docs/src/content/docs/routing/shims.md index 9c442c5..fd9906a 100644 --- a/docs/src/content/docs/routing/shims.md +++ b/docs/src/content/docs/routing/shims.md @@ -1,6 +1,7 @@ --- title: Standalone shims description: How PolyStella generates locale-prefixed route shims that re-render source pages. +aiGenerated: true --- In standalone mode, PolyStella owns the routing layer for locale- diff --git a/docs/src/content/docs/runtime-api/explicit-imports.md b/docs/src/content/docs/runtime-api/explicit-imports.md index c7d0fff..7f9b3ed 100644 --- a/docs/src/content/docs/runtime-api/explicit-imports.md +++ b/docs/src/content/docs/runtime-api/explicit-imports.md @@ -1,6 +1,7 @@ --- title: Explicit imports description: Calling @cloudflare/polystella/runtime functions directly outside .astro templates. +aiGenerated: true --- `Astro.locals` only exists in request-scoped contexts (`.astro` diff --git a/docs/src/content/docs/runtime-api/locals.md b/docs/src/content/docs/runtime-api/locals.md index b824731..0ecf65b 100644 --- a/docs/src/content/docs/runtime-api/locals.md +++ b/docs/src/content/docs/runtime-api/locals.md @@ -1,6 +1,7 @@ --- title: Astro.locals description: "t, lhref, getLocalizedEntry, getLocalizedCollection." +aiGenerated: true --- PolyStella's middleware populates four properties on `Astro.locals` diff --git a/docs/src/content/docs/runtime-api/middleware.md b/docs/src/content/docs/runtime-api/middleware.md index f01b74e..1271ce0 100644 --- a/docs/src/content/docs/runtime-api/middleware.md +++ b/docs/src/content/docs/runtime-api/middleware.md @@ -1,6 +1,7 @@ --- title: Middleware description: How polystella's request middleware is auto-registered; opting out. +aiGenerated: true --- PolyStella registers a request middleware via Astro's diff --git a/docs/src/content/docs/runtime-api/react-hooks.md b/docs/src/content/docs/runtime-api/react-hooks.md index 76a5504..df7491a 100644 --- a/docs/src/content/docs/runtime-api/react-hooks.md +++ b/docs/src/content/docs/runtime-api/react-hooks.md @@ -1,6 +1,7 @@ --- title: React hooks description: useTranslations and useLocalizedHref for React islands. +aiGenerated: true --- For client-rendered React islands inside an Astro project, diff --git a/docs/src/content/docs/troubleshooting/missing-translations.md b/docs/src/content/docs/troubleshooting/missing-translations.md index a4da2f5..4d4ae9a 100644 --- a/docs/src/content/docs/troubleshooting/missing-translations.md +++ b/docs/src/content/docs/troubleshooting/missing-translations.md @@ -1,6 +1,7 @@ --- title: Missing translations description: Diagnosing when a translated page doesn't render. +aiGenerated: true --- A page that should be translated isn't showing up under diff --git a/docs/src/content/partials/example.mdx b/docs/src/content/partials/example.mdx new file mode 100644 index 0000000..e326161 --- /dev/null +++ b/docs/src/content/partials/example.mdx @@ -0,0 +1,4 @@ +This text lives in `src/content/partials/example.mdx` and is pulled in with +``. Edit the partial once and every page that renders +it stays in sync — handy for install steps, support notes, or any boilerplate +you'd otherwise copy between pages. diff --git a/docs/src/layouts/BaseLayout.astro b/docs/src/layouts/BaseLayout.astro new file mode 100644 index 0000000..40c2a9c --- /dev/null +++ b/docs/src/layouts/BaseLayout.astro @@ -0,0 +1,118 @@ +--- +import "@fontsource-variable/inter/index.css"; +import "@fontsource-variable/jetbrains-mono/index.css"; +import "../styles/globals.css"; +import "../styles/prose.css"; +import { config } from "virtual:nimbus/config"; +import { getCollectionLlmsUrl, getVersionStatus } from "nimbus-docs"; +import AgentDirective from "@/components/AgentDirective.astro"; +import { SearchDialog } from "@/components/ui/search"; +import NimbusHead from "nimbus-docs/components/NimbusHead.astro"; +import type { BasePageProps } from "nimbus-docs/types"; + +type Props = BasePageProps; + +const { + title, + description, + noindex, + markdownUrl, + socialImage, + lastUpdated, + head: pageHead = [], + collection, + entryId, +} = Astro.props; + +const lang = config.locale ?? "en"; +// Per-page agent-index pointer. For pages in non-primary or version +// collections, this resolves to `//llms.txt` (e.g. `/v0/llms.txt` +// for a v0 docs page, `/blog/llms.txt` for a blog post). Falls back to +// the root `/llms.txt` when no collection is provided. +// Hidden-version pages don't advertise an agent index (the per-version +// llms.txt isn't emitted for them); suppress the AgentDirective entirely. +const versionStatus = collection ? await getVersionStatus(collection) : null; +const isHiddenVersion = versionStatus?.isHidden === true; +const llmsIndexPath = collection + ? await getCollectionLlmsUrl(collection) + : "/llms.txt"; +const llmsUrl = Astro.site + ? new URL(llmsIndexPath, Astro.site).href + : llmsIndexPath; +--- + + + + + + + + + + + + + + Skip to content + + {markdownUrl && !isHiddenVersion && } + + {config.search !== false && } + + + + diff --git a/docs/src/layouts/DocsLayout.astro b/docs/src/layouts/DocsLayout.astro new file mode 100644 index 0000000..cbaca98 --- /dev/null +++ b/docs/src/layouts/DocsLayout.astro @@ -0,0 +1,333 @@ +--- +/** + * DocsLayout — three-column docs layout. + * + * Named slots for overrides (all optional, defaults render otherwise): + * header, sidebar, toc, page-title, content-footer, pagination + */ +import { Icon } from "astro-icon/components"; +import BaseLayout from "./BaseLayout.astro"; +import Header from "@/components/Header.astro"; +import { Banner } from "@/components/ui/banner"; +import { Sidebar, SidebarFilter } from "@/components/ui/sidebar"; +import { TOC } from "@/components/ui/toc"; +import { Breadcrumbs } from "@/components/ui/breadcrumbs"; +import { Pagination } from "@/components/ui/pagination"; +import { PageActions } from "@/components/ui/page-actions"; +import { Badge } from "@/components/ui/badge"; +import type { DocsPageProps } from "nimbus-docs/types"; +import { getVersionStatus, getVersionAlternates } from "nimbus-docs"; + +type Props = DocsPageProps & { audience?: "human"; aiGenerated?: boolean }; + +const { title, description, sidebar, headings, breadcrumbs, prevNext, mode = "doc", banner, head = [], searchable, noindex, markdownUrl, socialImage, lastUpdated, editUrl, draft, audience, aiGenerated, collection, entryId } = Astro.props; + +// `searchable` derives from `noindex` when omitted: a non-crawlable page is +// by default not in the site search either. Explicit `searchable: true` +// overrides for the edge case of "no search engines, yes internal search." +const effectiveSearchable = searchable ?? !noindex; +const isCustom = mode === "custom"; + +// `sidebar: false` / `tableOfContents: false` in frontmatter come through +// from the route as literal `false` (not coerced to `[]`). They drive +// per-column suppression — chrome, mobile dialog, header menu button. +const showSidebar = sidebar !== false; + +// Versioning: per-page status drives Pagefind faceting, deprecation +// banner, and the data-pagefind-ignore exclusion for hidden versions. +const versionStatus = collection ? await getVersionStatus(collection) : null; +const versionAlternates = collection && entryId + ? await getVersionAlternates(collection, entryId) + : null; +const currentSiblingUrl = versionAlternates?.canonical?.url ?? null; + +// Page-body attribute resolution: +// - If the user opted out via `searchable: false` (or `noindex: true` +// with no explicit override) → ignore. +// - If the page is in a hidden version → ignore unconditionally +// (hidden takes precedence; you can't index hidden content even +// if the page frontmatter says searchable=true). +// - Otherwise → mark as a Pagefind body, plus emit per-version and +// per-status filters so the search UI can scope by them. +const pagefindAttrs: Record = {}; +if (!effectiveSearchable || versionStatus?.isHidden) { + pagefindAttrs["data-pagefind-ignore"] = ""; +} else { + pagefindAttrs["data-pagefind-body"] = ""; + if (versionStatus) { + pagefindAttrs["data-pagefind-filter"] = `version:${versionStatus.version}`; + if (versionStatus.isDeprecated) { + // Pagefind supports multiple filter attributes on the same element + // via `data-pagefind-filter` repeated as a comma-separated list in + // the value. The status filter pairs with the version filter so a + // search UI can offer "exclude deprecated" as a default toggle. + pagefindAttrs["data-pagefind-filter"] += `, status:deprecated`; + } + } +} + +const hasHeader = Astro.slots.has("header"); +const hasSidebar = Astro.slots.has("sidebar"); +const hasToc = Astro.slots.has("toc"); +const hasPageTitle = Astro.slots.has("page-title"); +const hasContentFooter = Astro.slots.has("content-footer"); +const hasPagination = Astro.slots.has("pagination"); +--- + + +
+ {hasHeader ? :
} + + {isCustom ? ( +
+ +
+ ) : ( +
+
+ {showSidebar && ( + + )} + + {/* Sidebar state restore — pre-sets data attributes before the + disclosure module loads so collapsed/scrolled state survives nav. + Only emit when the sidebar is rendered; otherwise the script is + dead code (the `desktop-sidebar` element doesn't exist). */} + {showSidebar && ( + + )} + +
+
+ {versionStatus?.isDeprecated && ( + ${versionStatus.version} version of the docs and is no longer maintained. The latest version of this page is at ${currentSiblingUrl}.` + : `This is the ${versionStatus.version} version of the docs and is no longer maintained. See the current docs for up-to-date content.` + } + /> + )} + {banner && } + +
+ {hasPageTitle ? ( + + ) : ( + +
+

{title}

+ {draft && } +
+ {description && ( +

{description}

+ )} + + {(markdownUrl || audience === "human") && ( + audience === "human" ? ( +
+
+ +
+
+ ) : ( +
+ ) + )} + {!description && !markdownUrl && audience !== "human" &&
} + + )} +
+ +
+ {hasContentFooter ? ( + + ) : editUrl && ( + + )} +
+ {hasPagination ? : } +
+
+ + {headings !== false && (hasToc || headings.length > 0) && ( + + )} +
+
+ )} + +
+ + {showSidebar && ( + /* Mobile sidebar — native for free focus trap, escape, backdrop. */ + +
+
+ Navigation + +
+ +
+
+ )} + + + +
diff --git a/docs/src/lib/cn.ts b/docs/src/lib/cn.ts new file mode 100644 index 0000000..75424d6 --- /dev/null +++ b/docs/src/lib/cn.ts @@ -0,0 +1,7 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +/** Compose class names with Tailwind conflict resolution. Consumer class (last arg) wins. */ +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/docs/src/pages/404.astro b/docs/src/pages/404.astro new file mode 100644 index 0000000..ad970ae --- /dev/null +++ b/docs/src/pages/404.astro @@ -0,0 +1,23 @@ +--- +import Header from "../components/Header.astro"; +import BaseLayout from "../layouts/BaseLayout.astro"; +--- + + +
+
+
+

404

+

Page not found

+

+ This docs page may have moved or may not exist yet. +

+ + Back to the docs + +
+
+
diff --git a/docs/src/pages/[...slug].astro b/docs/src/pages/[...slug].astro new file mode 100644 index 0000000..d609143 --- /dev/null +++ b/docs/src/pages/[...slug].astro @@ -0,0 +1,88 @@ +--- +import DocsLayout from "../layouts/DocsLayout.astro"; +import { getCollection } from "astro:content"; +import { + getDocsPageProps, + getSidebar, + getPrevNext, + getBreadcrumbs, + getEditUrl, + getLastUpdated, + getTOC, +} from "nimbus-docs"; +import { config } from "virtual:nimbus/config"; +import { components } from "../components"; + +export const prerender = true; + +export async function getStaticPaths() { + const entries = await getCollection("docs", (entry) => import.meta.env.DEV || !entry.data.draft); + + return entries.map((entry) => ({ + params: { slug: entry.id === "index" ? undefined : entry.id }, + props: { entry }, + })); +} + +const { entry, Content, headings } = await getDocsPageProps(Astro); + +const currentSlug = Astro.url.pathname.replace(/\/$/, "") || "/"; + +// Column renders only when not custom mode AND site-wide flag on AND page hasn't opted out. +const isCustom = entry.data.mode === "custom"; +const sidebarOn = + !isCustom && + config.features?.sidebar !== false && + entry.data.sidebar !== false; +const tocOn = + !isCustom && + config.features?.tableOfContents !== false && + entry.data.tableOfContents !== false; + +const sidebar = sidebarOn + ? await getSidebar(currentSlug, { collection: entry.collection }) + : false; +const prevNext = await getPrevNext(currentSlug, { + sidebarTree: sidebar === false ? [] : sidebar, + overrides: { prev: entry.data.prev, next: entry.data.next }, +}); +// Pass `collection` so versioned pages (docs-) get version-prefixed +// breadcrumb hrefs — parity with the getSidebar call above. +const breadcrumbs = await getBreadcrumbs(currentSlug, { collection: entry.collection }); +const editUrl = await getEditUrl(entry); +// Frontmatter wins; git is the fallback. +const lastUpdated = entry.data.lastUpdated ?? await getLastUpdated(entry); +// `tocOn` already implies `tableOfContents !== false`, but TS can't carry +// that boolean narrowing to the value here — re-check it so `getTOC` only +// ever sees its options object (or undefined), never `false`. +const tocConfig = entry.data.tableOfContents; +const toc = tocOn && tocConfig !== false ? getTOC(headings, tocConfig) : false; +const markdownPath = entry.id === "index" ? "/index.md" : `/${entry.id}/index.md`; +const markdownUrl = Astro.site ? new URL(markdownPath, Astro.site).href : markdownPath; +const socialImage = entry.data.socialImage ?? `/og/${entry.id}.png`; +--- + + + + diff --git a/docs/src/pages/[...slug]/index.md.ts b/docs/src/pages/[...slug]/index.md.ts new file mode 100644 index 0000000..7dbfe23 --- /dev/null +++ b/docs/src/pages/[...slug]/index.md.ts @@ -0,0 +1,70 @@ +/** + * Per-page `//index.md` — the clean-markdown alternate for every + * indexable entry of the primary `docs` collection. + * + * Non-primary collections (`api`, `blog`, …) mount under their own + * URL namespace by convention; their `.md` alternates live at the + * sibling route `pages//[...slug]/index.md.ts`. This route + * filters to the primary collection so multi-collection sites don't + * generate conflicting `[...slug]` paths at root. + */ + +import { getIndexedEntries, renderEntryAsMarkdown, type IndexedEntry } from "nimbus-docs"; +import { config } from "virtual:nimbus/config"; + +export const prerender = true; + +const PRIMARY_COLLECTION = "docs"; + +interface SlugProps { + item: IndexedEntry; +} + +export async function getStaticPaths() { + const indexed = await getIndexedEntries(); + return indexed + .filter((item) => item.collection === PRIMARY_COLLECTION) + .map((item) => ({ + // Root index (`entry.id === "index"`) emits at `/index.md`; Astro's + // rest-segment treats `undefined` as "no segment" so the URL is + // `/index.md` rather than `/index/index.md`. Every other entry emits + // at `//index.md` — the convention `/index.md`. + params: { + slug: item.entry.id === "index" ? undefined : item.entry.id, + }, + props: { item } as SlugProps, + })); +} + +export async function GET({ props }: { props: SlugProps }) { + const { item } = props; + const { entry, title, description, markdownUrl } = item; + const data = (entry.data ?? {}) as Record; + const rawImage = data.socialImage; + const socialImage = typeof rawImage === "string" && rawImage.length > 0 ? rawImage : config.socialImage; + + const markdown = renderEntryAsMarkdown(entry); + + const body = [ + "---", + `title: ${JSON.stringify(title)}`, + ...(description ? [`description: ${JSON.stringify(description)}`] : []), + ...(socialImage ? [`image: ${JSON.stringify(new URL(socialImage, config.site).href)}`] : []), + "---", + "", + "> Documentation Index", + `> Fetch the complete documentation index at: ${new URL("/llms.txt", config.site).href}`, + "> Use this file to discover all available pages before exploring further.", + "", + `# ${title}`, + "", + markdown, + "", + `Source: ${new URL(markdownUrl, config.site).href}`, + "", + ].join("\n"); + + return new Response(body, { + headers: { "Content-Type": "text/markdown; charset=utf-8" }, + }); +} diff --git a/docs/src/pages/[section]/llms.txt.ts b/docs/src/pages/[section]/llms.txt.ts new file mode 100644 index 0000000..f511cc8 --- /dev/null +++ b/docs/src/pages/[section]/llms.txt.ts @@ -0,0 +1,64 @@ +/** + * Per-section /
/llms.txt — sub-index files that drill down + * from the root `/llms.txt` into a named slice of the site's docs. + * + * A "section" is one of two things: + * 1. A folder inside the primary `docs` collection with more than + * one page (e.g. `src/content/docs//*` → `//llms.txt`). + * 2. A whole non-primary collection — `api`, `blog`, etc. — which + * becomes a single section mounted at `//llms.txt`. + * + * Both cases produce the same shape at the same URL pattern, so + * agents follow one rule: every link in `/llms.txt` that ends in + * `.llms.txt` resolves here. + * + * `getIndexedTopLevel()` decides which sections exist and what they + * contain; this route just renders one file per section it returns. + */ + +import { getIndexedTopLevel, type IndexedEntry } from "nimbus-docs"; +import { config } from "virtual:nimbus/config"; + +export const prerender = true; + +interface SectionProps { + slug: string; + label: string; + members: IndexedEntry[]; +} + +export async function getStaticPaths() { + const { groups } = await getIndexedTopLevel(); + return ( + groups + // Versioning: hidden versions don't get a per-section llms.txt + // index. They're URL-reachable for direct navigation, but every + // agent-discovery surface should treat them as if they don't exist. + .filter((group) => !group.hidden) + .map((group) => ({ + params: { section: group.slug }, + props: { + slug: group.slug, + label: group.label, + members: group.members, + } as SectionProps, + })) + ); +} + +export async function GET({ props }: { props: SectionProps }) { + const { label, members } = props; + + const lines = [`# ${label}`, "", "## Pages", ""]; + + for (const item of members) { + const description = item.description ? ` — ${item.description}` : ""; + lines.push(`- [${item.title}](${new URL(item.markdownUrl, config.site).href})${description}`); + } + + lines.push(""); + + return new Response(lines.join("\n"), { + headers: { "Content-Type": "text/plain; charset=utf-8" }, + }); +} diff --git a/docs/src/pages/llms.txt.ts b/docs/src/pages/llms.txt.ts new file mode 100644 index 0000000..bdc0593 --- /dev/null +++ b/docs/src/pages/llms.txt.ts @@ -0,0 +1,41 @@ +// Root /llms.txt — sectioned index for AI agents. +import { getIndexedTopLevel } from "nimbus-docs"; +import { config } from "virtual:nimbus/config"; + +export const prerender = true; + +export async function GET() { + const { leaves, groups } = await getIndexedTopLevel(); + + const lines = [`# ${config.title}`, "", config.description ?? "Documentation index for AI agents.", "", "## Pages", ""]; + + // Sort leaves + groups alphabetically into a single stable list. + type Row = { key: string; line: string }; + const rows: Row[] = []; + + for (const leaf of leaves) { + const description = leaf.description ? ` — ${leaf.description}` : ""; + rows.push({ + key: leaf.url, + line: `- [${leaf.title}](${new URL(leaf.markdownUrl, config.site).href})${description}`, + }); + } + + for (const group of groups) { + // Older doc versions have their own //llms.txt; don't list them here. + if (group.kind === "version") continue; + rows.push({ + key: `/${group.slug}`, + line: `- [${group.label}](${new URL(`/${group.slug}/llms.txt`, config.site).href})`, + }); + } + + rows.sort((a, b) => a.key.localeCompare(b.key)); + for (const row of rows) lines.push(row.line); + + lines.push(""); + + return new Response(lines.join("\n"), { + headers: { "Content-Type": "text/plain; charset=utf-8" }, + }); +} diff --git a/docs/src/pages/og.png.ts b/docs/src/pages/og.png.ts new file mode 100644 index 0000000..e03cacb --- /dev/null +++ b/docs/src/pages/og.png.ts @@ -0,0 +1,17 @@ +import { generateOpenGraphImage } from "astro-og-canvas"; +import { config } from "virtual:nimbus/config"; +import { ogCardConfig } from "./og/_og-card-config"; + +export const prerender = true; + +export async function GET() { + const body = await generateOpenGraphImage({ + title: config.title, + description: config.description, + ...ogCardConfig, + }); + + return new Response(body, { + headers: { "Content-Type": "image/png" }, + }); +} diff --git a/docs/src/pages/og/[...slug].ts b/docs/src/pages/og/[...slug].ts new file mode 100644 index 0000000..9e16df1 --- /dev/null +++ b/docs/src/pages/og/[...slug].ts @@ -0,0 +1,24 @@ +import { getCollection } from "astro:content"; +import { OGImageRoute } from "astro-og-canvas"; +import { ogCardConfig } from "./_og-card-config"; + +const entries = await getCollection("docs", (entry) => !entry.data.draft); + +const pages = Object.fromEntries( + entries.map((entry) => [ + entry.id, + { + title: entry.data.title, + description: entry.data.description ?? "", + }, + ]), +); + +export const { getStaticPaths, GET } = await OGImageRoute({ + pages, + getImageOptions: (_path, page) => ({ + title: page.title, + description: page.description, + ...ogCardConfig, + }), +}); diff --git a/docs/src/pages/og/_og-card-config.ts b/docs/src/pages/og/_og-card-config.ts new file mode 100644 index 0000000..61f8f41 --- /dev/null +++ b/docs/src/pages/og/_og-card-config.ts @@ -0,0 +1,39 @@ +/** + * Shared visual config for build-time OG cards. + * + * Edit this file to retune generated card colors, spacing, and fonts. Both + * the per-page endpoint (`og/[...slug].ts`) and the homepage fallback + * (`og.png.ts`) spread this object into `astro-og-canvas`. + * + * Leading underscore tells Astro to skip routing for this file — it sits + * inside `src/pages/` to be next to its consumers, but it's not a route. + */ + +import type { OGImageOptions } from "astro-og-canvas"; + +export const ogCardConfig = { + bgGradient: [ + [11, 11, 12], + [26, 26, 28], + ], + border: { color: [39, 39, 42], width: 2, side: "inline-start" }, + padding: 96, + fonts: ["./public/fonts/Inter-Bold.ttf"], + font: { + title: { + color: [250, 250, 250], + size: 64, + weight: "Bold", + families: ["Inter"], + lineHeight: 1.1, + }, + description: { + color: [161, 161, 170], + size: 32, + weight: "Bold", + families: ["Inter"], + lineHeight: 1.3, + }, + }, + format: "PNG", +} satisfies Partial; diff --git a/docs/src/pages/robots.txt.ts b/docs/src/pages/robots.txt.ts new file mode 100644 index 0000000..6d1e804 --- /dev/null +++ b/docs/src/pages/robots.txt.ts @@ -0,0 +1,11 @@ +import { config } from "virtual:nimbus/config"; + +export const prerender = true; + +export function GET() { + const body = ["User-agent: *", "Allow: /", "", `Sitemap: ${new URL("/sitemap-index.xml", config.site).href}`, ""].join("\n"); + + return new Response(body, { + headers: { "Content-Type": "text/plain; charset=utf-8" }, + }); +} diff --git a/docs/src/styles/custom.css b/docs/src/styles/custom.css deleted file mode 100644 index b1723d1..0000000 --- a/docs/src/styles/custom.css +++ /dev/null @@ -1,30 +0,0 @@ -/* - * PolyStella docs — Starlight theme overrides. - * - * Single accent colour (Cloudflare orange #f6821f) wired into - * Starlight's CSS-variable system. Everything else stays at - * Starlight defaults so a future Starlight upgrade doesn't fight - * with our customisation. - */ - -:root { - /* Light mode: orange-tinted blue-ish gray as the accent base. - Starlight derives hover / focus / link colours from these. */ - --sl-color-accent-low: #fff1e6; - --sl-color-accent: #f6821f; - --sl-color-accent-high: #c1631a; -} - -:root[data-theme="dark"] { - --sl-color-accent-low: #3a1f08; - --sl-color-accent: #f6821f; - --sl-color-accent-high: #fcb15c; -} - -/* Wordmark SVG inherits currentColor so the "Poly" half follows - Starlight's foreground (white on dark, near-black on light) and - "Stella" stays Cloudflare orange across themes. */ -.site-title svg { - height: 1.6rem; - width: auto; -} diff --git a/docs/src/styles/globals.css b/docs/src/styles/globals.css new file mode 100644 index 0000000..70f5f70 --- /dev/null +++ b/docs/src/styles/globals.css @@ -0,0 +1,489 @@ +@import "tailwindcss/index.css"; + +/* ============================================================ + * Nimbus Theme — THE file you edit to customize your site. + * + * Architecture: + * 1. CSS custom properties (--nb-*) define the design tokens + * 2. `@theme` block exposes them to Tailwind so utilities like + * `bg-card`, `text-foreground`, `border-border` work + * 3. Dark mode uses the `[data-mode="dark"]` attribute + * 4. All colors use oklch for perceptual uniformity + * + * Naming convention: + * - Surfaces paired with foregrounds: `card` / `card-foreground` + * - Functional names: `primary` (action), `accent` (hover surface), + * `muted` (de-emphasized), not visual relationships + * - Reserved Tailwind keywords avoided (no `text-base`, `font-sans`, + * `shadow-lg`, etc. as color names — they collide with built-ins) + * ============================================================ */ + +/* ---- Light mode (default) ---- */ +:root { + color-scheme: light; + + /* Surfaces (paired with foregrounds for contrast) */ + --nb-background: oklch(0.99 0 0); + --nb-foreground: oklch(0.21 0 0); + + --nb-card: oklch(1 0 0); + --nb-card-foreground: var(--nb-foreground); + + --nb-muted: oklch(0.967 0 0); + --nb-muted-foreground: oklch(0.556 0 0); + + --nb-accent: #fff1e6; + --nb-accent-foreground: var(--nb-foreground); + + /* Primary action / brand */ + --nb-primary: #f6821f; + --nb-primary-foreground: #1f1308; + --nb-primary-hover: #c1631a; + + /* Borders / focus */ + --nb-border: oklch(0.935 0 0); + --nb-border-strong: oklch(0.87 0 0); + --nb-selected: oklch(0.89 0 0); + --nb-ring: rgb(246 130 31 / 0.35); + + /* Status colors — paired (saturated for text/border + muted for bg) */ + --nb-info: oklch(0.45 0.18 255); + --nb-info-foreground: oklch(0.45 0.18 255); + --nb-info-muted: oklch(0.965 0.015 255); + + --nb-success: oklch(0.42 0.14 152); + --nb-success-foreground: oklch(0.42 0.14 152); + --nb-success-muted: oklch(0.965 0.015 152); + + --nb-warning: oklch(0.48 0.15 65); + --nb-warning-foreground: oklch(0.48 0.15 65); + --nb-warning-muted: oklch(0.97 0.02 70); + + --nb-danger: oklch(0.47 0.18 25); + --nb-danger-foreground: oklch(0.47 0.18 25); + --nb-danger-muted: oklch(0.965 0.015 25); + + /* Layout */ + --nb-sidebar-width: 18.75rem; + --nb-toc-width: 18rem; + --nb-content-max: 43.5rem; + + /* Typography — self-hosted via @fontsource-variable in BaseLayout.astro */ + --nb-font-sans: "Inter Variable", "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + --nb-font-mono: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace; + --nb-h1-size: 2.1875rem; + --nb-h1-weight: 600; + --nb-h1-tracking: -0.025em; + --nb-h2-size: 1.3rem; + --nb-h2-weight: 650; + --nb-h2-tracking: -0.015em; + --nb-h3-size: 1.1rem; + --nb-h3-weight: 600; + --nb-h3-tracking: -0.01em; + --nb-h4-weight: 600; + + /* Shadows */ + --nb-shadow-sm: 0 1px 2px oklch(0 0 0 / 0.04); + --nb-shadow: 0 1px 3px oklch(0 0 0 / 0.06), 0 1px 2px oklch(0 0 0 / 0.04); + --nb-shadow-lg: 0 4px 12px oklch(0 0 0 / 0.08), 0 2px 4px oklch(0 0 0 / 0.04); +} + +/* Wider content area on large displays (e.g. MacBook Pro 16″) */ +@media (min-width: 1536px) { + :root { + --nb-content-max: 52rem; + } +} + +/* ---- Dark mode ---- */ +[data-mode="dark"] { + color-scheme: dark; + + --nb-background: oklch(0.085 0 0); + --nb-foreground: oklch(0.97 0 0); + + --nb-card: #0f0f0f; + --nb-card-foreground: var(--nb-foreground); + + --nb-muted: #060606; + --nb-muted-foreground: oklch(0.556 0 0); + + --nb-accent: #3a1f08; + --nb-accent-foreground: var(--nb-foreground); + + --nb-primary: #f6821f; + --nb-primary-foreground: #1f1308; + --nb-primary-hover: #fcb15c; + + --nb-border: oklch(0.269 0 0); + --nb-border-strong: oklch(0.371 0 0); + --nb-selected: oklch(0.371 0 0); + --nb-ring: rgb(246 130 31 / 0.35); + + --nb-info: oklch(0.75 0.12 255); + --nb-info-foreground: oklch(0.75 0.12 255); + --nb-info-muted: oklch(0.17 0.03 260); + + --nb-success: oklch(0.72 0.12 150); + --nb-success-foreground: oklch(0.72 0.12 150); + --nb-success-muted: oklch(0.17 0.025 153); + + --nb-warning: oklch(0.78 0.11 80); + --nb-warning-foreground: oklch(0.78 0.11 80); + --nb-warning-muted: oklch(0.19 0.03 70); + + --nb-danger: oklch(0.72 0.14 25); + --nb-danger-foreground: oklch(0.72 0.14 25); + --nb-danger-muted: oklch(0.17 0.03 25); + + --nb-shadow-sm: 0 1px 2px oklch(0 0 0 / 0.2); + --nb-shadow: 0 1px 3px oklch(0 0 0 / 0.3), 0 1px 2px oklch(0 0 0 / 0.2); + --nb-shadow-lg: 0 4px 12px oklch(0 0 0 / 0.4), 0 2px 4px oklch(0 0 0 / 0.2); +} + +/* ---- Tailwind theme mapping ---- + * These generate Tailwind utility classes: + * bg-card, text-foreground, border-border, ring-ring, etc. + */ +@theme { + --color-background: var(--nb-background); + --color-foreground: var(--nb-foreground); + + --color-card: var(--nb-card); + --color-card-foreground: var(--nb-card-foreground); + + --color-muted: var(--nb-muted); + --color-muted-foreground: var(--nb-muted-foreground); + + --color-accent: var(--nb-accent); + --color-accent-foreground: var(--nb-accent-foreground); + + --color-primary: var(--nb-primary); + --color-primary-foreground: var(--nb-primary-foreground); + --color-primary-hover: var(--nb-primary-hover); + + --color-border: var(--nb-border); + --color-border-strong: var(--nb-border-strong); + --color-selected: var(--nb-selected); + --color-ring: var(--nb-ring); + + --color-info: var(--nb-info); + --color-info-foreground: var(--nb-info-foreground); + --color-info-muted: var(--nb-info-muted); + + --color-success: var(--nb-success); + --color-success-foreground: var(--nb-success-foreground); + --color-success-muted: var(--nb-success-muted); + + --color-warning: var(--nb-warning); + --color-warning-foreground: var(--nb-warning-foreground); + --color-warning-muted: var(--nb-warning-muted); + + --color-danger: var(--nb-danger); + --color-danger-foreground: var(--nb-danger-foreground); + --color-danger-muted: var(--nb-danger-muted); + + --font-sans: var(--nb-font-sans); + --font-mono: var(--nb-font-mono); + + --shadow-sm: var(--nb-shadow-sm); + --shadow-default: var(--nb-shadow); + --shadow-lg: var(--nb-shadow-lg); +} + +/* ---- Minimal overrides the plugin doesn't cover ---- */ +html { + font-family: var(--nb-font-sans); + font-feature-settings: "cv02", "cv03", "cv04", "cv11"; +} + +body { + opacity: 1; +} + +@media (prefers-reduced-motion: no-preference) { + html:focus-within { + scroll-behavior: smooth; + } +} + +::selection { + background: color-mix(in oklch, var(--nb-primary) 10%, transparent); + color: var(--nb-foreground); +} + +/* ---- Focus indicators ---- */ +@layer base { + :focus-visible { + outline: 2px solid var(--nb-ring); + outline-offset: 2px; + } +} + +/* ---- Reduced motion ---- */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} + +/* ---- Scroll lock (used by native overlays) ---- */ +[data-scroll-locked] { + overflow: hidden; +} + +/* ---- Scrollbar ---- */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-track { + background: transparent; +} +::-webkit-scrollbar-thumb { + background: color-mix(in oklch, var(--nb-foreground) 20%, transparent); + border-radius: 3px; +} +::-webkit-scrollbar-thumb:hover { + background: var(--nb-muted-foreground); +} + +/* ---- Shiki code-block styling + copy button ---- */ + +pre.astro-code { + position: relative; + margin: 1rem 0; + padding: 0.75rem 1rem; + border-radius: 0.5rem; + border: 1px solid var(--nb-border); + background-color: var(--nb-card); + overflow-x: auto; + font-family: var(--nb-font-mono); + font-size: 0.875rem; + line-height: 1.625; +} +pre.astro-code > code { + background: transparent; +} + +/* Classed Shiki tokens set --shiki-light/--shiki-dark once in _nimbus/shiki.css. */ +pre.astro-code span { + color: var(--shiki-light, inherit); +} +[data-mode="dark"] pre.astro-code span { + color: var(--shiki-dark, inherit); +} + +/* Copy button injected by initCodeCopy. */ +.nb-code-copy { + position: absolute; + top: 0.5rem; + right: 0.5rem; + display: inline-flex; + align-items: center; + justify-content: center; + width: 1.75rem; + height: 1.75rem; + margin: 0; + padding: 0; + border: 1px solid var(--nb-border); + border-radius: 0.375rem; + background: var(--nb-card); + color: var(--nb-muted-foreground); + cursor: pointer; + opacity: 0; + transition: + opacity 0.15s ease, + color 0.15s ease, + background 0.15s ease; + z-index: 2; +} +.nb-code-figure:hover .nb-code-copy, +.nb-code-copy:focus-visible { + opacity: 1; +} +.nb-code-copy:hover { + color: var(--nb-foreground); + background: var(--nb-muted); +} +.nb-code-copy svg { + width: 0.875rem; + height: 0.875rem; +} +.nb-code-copy[data-state="copied"] { + color: var(--nb-success); +} + +/* ---- Premium code chrome ---- */ + +/* Every Shiki block is wrapped in a .nb-code-figure (titled or not). + Chrome lives on the figure so the language badge + copy button can sit + on a non-scrolling ancestor — iOS Safari slides absolutely-positioned + children of overflow:auto containers. */ +.nb-code-figure { + position: relative; + margin: 1rem 0; + border: 1px solid var(--nb-border); + border-radius: 0.5rem; + background-color: var(--nb-card); + overflow: hidden; +} +.nb-code-figure > pre.astro-code { + margin: 0; + border: 0; + border-radius: 0; + background-color: transparent; +} +.nb-code-title { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + padding: 0.5rem 0.875rem; + border-bottom: 1px solid var(--nb-border); + background: color-mix(in oklch, var(--nb-muted) 50%, transparent); + font-family: var(--nb-font-mono); + font-size: 0.75rem; + line-height: 1.4; +} +.nb-code-title-name { + color: var(--nb-foreground); + font-weight: 500; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.nb-code-title-lang { + flex-shrink: 0; + padding: 0.0625rem 0.375rem; + border-radius: 0.25rem; + background: var(--nb-muted); + color: var(--nb-muted-foreground); + font-size: 0.6875rem; + letter-spacing: 0.02em; + text-transform: uppercase; +} + +/* Language badge — pinned to the figure (which doesn't scroll), so it + stays at top-right even when the pre overflows horizontally. Hidden + when a figcaption is already showing the language (titled blocks). */ +.nb-code-figure[data-nb-lang]:not(.nb-code-figure-titled)::before { + content: attr(data-nb-lang); + position: absolute; + top: 0.5rem; + right: 0.625rem; + padding: 0.0625rem 0.375rem; + border-radius: 0.25rem; + background: var(--nb-muted); + color: var(--nb-muted-foreground); + font-family: var(--nb-font-mono); + font-size: 0.6875rem; + letter-spacing: 0.02em; + text-transform: uppercase; + pointer-events: none; + opacity: 0.75; + transition: opacity 0.15s ease; + z-index: 1; +} +.nb-code-figure:hover::before { + opacity: 0; +} +/* Hide plaintext/text "language" — it's noise. */ +.nb-code-figure[data-nb-lang="text"]::before, +.nb-code-figure[data-nb-lang="plaintext"]::before, +.nb-code-figure[data-nb-lang="plain"]::before, +.nb-code-figure[data-nb-lang="txt"]::before { + display: none; +} + +/* Block-level lines so tints + gutters paint across the full row. */ +pre.astro-code code { + display: block; + width: max-content; + min-width: 100%; +} +pre.astro-code .line { + display: inline-block; + width: 100%; + padding-inline: 1rem; + margin-inline: -1rem; + box-sizing: content-box; +} + +/* Highlighted lines (`{1,3-5}` meta or `// [!code highlight]`). */ +pre.astro-code .line.highlighted { + background: color-mix(in oklch, var(--nb-info) 12%, transparent); + box-shadow: inset 2px 0 0 var(--nb-info); +} + +/* Diff lines (`// [!code ++]` / `// [!code --]`). */ +pre.astro-code .line.diff { + position: relative; +} +pre.astro-code .line.diff.add { + background: color-mix(in oklch, var(--nb-success) 10%, transparent); + box-shadow: inset 2px 0 0 var(--nb-success); +} +pre.astro-code .line.diff.remove { + background: color-mix(in oklch, var(--nb-danger) 10%, transparent); + box-shadow: inset 2px 0 0 var(--nb-danger); +} +pre.astro-code .line.diff.add::before, +pre.astro-code .line.diff.remove::before { + position: absolute; + left: 0.25rem; + color: var(--nb-muted-foreground); + font-weight: 600; +} +pre.astro-code .line.diff.add::before { + content: "+"; + color: var(--nb-success); +} +pre.astro-code .line.diff.remove::before { + content: "−"; + color: var(--nb-danger); +} + +/* Focus mode — dim non-focused lines; clears on hover. */ +pre.astro-code.has-focused .line:not(.focused) { + opacity: 0.45; + filter: blur(0.25px); + transition: + opacity 0.2s ease, + filter 0.2s ease; +} +pre.astro-code.has-focused:hover .line:not(.focused) { + opacity: 1; + filter: none; +} + +/* Error / warning lines — use muted tokens for theme-tuned tints. */ +pre.astro-code .line.highlighted.error { + background: var(--nb-danger-muted); + box-shadow: inset 2px 0 0 var(--nb-danger); +} +pre.astro-code .line.highlighted.warning { + background: var(--nb-warning-muted); + box-shadow: inset 2px 0 0 var(--nb-warning); +} + +/* Word highlight (`// [!code word:foo]` and meta `/foo/`). */ +pre.astro-code .highlighted-word { + padding: 0.0625rem 0.25rem; + margin: -0.0625rem -0.125rem; + border-radius: 0.25rem; + background: color-mix(in oklch, var(--nb-info) 18%, transparent); + box-shadow: 0 0 0 1px color-mix(in oklch, var(--nb-info) 30%, transparent); +} + +/* ---- Mobile sidebar toggle ---- */ + +/* Hide hamburger on pages without a sidebar dialog. */ +body:not(:has([data-mobile-sidebar])) [data-menu-btn] { + display: none; +} diff --git a/docs/src/styles/prose.css b/docs/src/styles/prose.css new file mode 100644 index 0000000..192cbec --- /dev/null +++ b/docs/src/styles/prose.css @@ -0,0 +1,312 @@ +/* Docs markdown styling scoped to docs content containers only. */ + +.docs-content { + font-size: 0.9375rem; + line-height: 1.75; + color: var(--nb-foreground); +} + +/* Vertical rhythm — every direct child gets spacing by default. + Components can override with their own margin utilities (my-4, mt-6, etc.) + because :where() keeps specificity at (0,1,0) and utilities come later. */ +.docs-content > :where(:not(:first-child)) { + margin-top: 1.25rem; +} + +.docs-content :where(ul:not([class])) { + padding-left: 1.25rem; + list-style-type: disc; +} + +.docs-content :where(ol:not([class])) { + padding-left: 1.25rem; + list-style-type: decimal; +} + +.docs-content :where(ul:not([class]) ul:not([class])) { + list-style-type: circle; +} + +.docs-content :where(ul:not([class]) ul:not([class]) ul:not([class])) { + list-style-type: square; +} + +.docs-content :where(li:not([class])) { + margin: 0.25rem 0; +} + +.docs-content :where(blockquote:not([class])) { + margin: 1.25rem 0; + padding-left: 1rem; + border-left: 2px solid var(--nb-border); + color: var(--nb-muted-foreground); +} + +.docs-content :where(hr:not([class])) { + border: 0; + border-top: 1px solid var(--nb-border); + margin: 1.5rem 0; +} + +/* Component boundary — elements with a class attribute are component-owned. + Markdown never adds classes to h1–h6 or p; components always do. */ +.docs-content :where(h1, h2, h3, h4, h5, h6, p):where([class]) { + margin: 0; + font-size: inherit; +} + +/* Markdown heading typography is token-driven from globals.css. */ +.docs-content :where(h1:not([class])) { + font-size: var(--nb-h1-size); + font-weight: var(--nb-h1-weight); + letter-spacing: var(--nb-h1-tracking); + margin-top: 0; +} + +.docs-content :where(h2:not([class])) { + font-size: var(--nb-h2-size); + font-weight: var(--nb-h2-weight); + letter-spacing: var(--nb-h2-tracking); + margin-top: 2.5rem; +} + +.docs-content :where(h3:not([class])) { + font-size: var(--nb-h3-size); + font-weight: var(--nb-h3-weight); + letter-spacing: var(--nb-h3-tracking); + margin-top: 2rem; +} + +.docs-content :where(h4:not([class]), h5:not([class]), h6:not([class])) { + font-weight: var(--nb-h4-weight); +} + +.docs-content :where(h1:not([class]), h2:not([class]), h3:not([class]), h4:not([class])) { + scroll-margin-top: 5rem; +} + +/* Typographic wrapping — balance multi-line headings (no orphan words), + pretty-wrap body copy (no single-word last lines). Progressive + enhancement; unsupported browsers ignore both. */ +.docs-content :where(h1:not([class]), h2:not([class]), h3:not([class]), h4:not([class])) { + text-wrap: balance; +} + +.docs-content :where(p:not([class]), li:not([class]), blockquote:not([class])) { + text-wrap: pretty; +} + +.docs-content :where(h2[id], h3[id], h4[id]) { + position: relative; +} + +.docs-content .heading-anchor { + margin-left: 0.5rem; + color: var(--nb-muted-foreground); + text-decoration: none; + opacity: 0; + transition: + opacity 0.15s, + color 0.15s; +} + +.docs-content :where(h2[id], h3[id], h4[id]):hover .heading-anchor, +.docs-content .heading-anchor:focus-visible { + opacity: 1; +} + +.docs-content .heading-anchor:hover { + color: var(--nb-foreground); +} + +.docs-content :where(code:not([class])):not(:where(pre *)) { + font-family: var(--nb-font-mono); + direction: ltr; + unicode-bidi: isolate; + background: var(--nb-muted); + border: 1px solid var(--nb-border); + border-radius: 0.375rem; + padding: 0.125rem 0.375rem; + font-size: 0.8125em; + font-weight: 450; +} + +.docs-content :where(code:not([class])):not(:where(pre *))::before, +.docs-content :where(code:not([class])):not(:where(pre *))::after { + content: none; +} + +.docs-content :where(pre:not([class])) { + font-family: var(--nb-font-mono); +} + +/* Shiki-rendered code blocks — wider vertical margin than base rhythm + (1.25rem) because code blocks are visually dense. Inline code-token + styling (background, border, padding) is reset because Shiki spans + already carry their own colors via inline styles. */ +.docs-content .nb-code-figure { + margin: 1.5rem 0; +} + +.docs-content pre.astro-code code { + direction: ltr; + unicode-bidi: isolate; + background: none; + border: none; + padding: 0; + font-size: inherit; + font-weight: inherit; + border-radius: 0; +} + +/* Rounded bordered table that fills its container on desktop and falls back to + horizontal scroll on narrow viewports. The earlier rule used `display:block` + unconditionally, which kept the outer border at 100% but let thead/tbody + shrink to content width — leaving dead space on the right for tables with + short cells. */ +.docs-content :where(table:not([class])) { + display: table; + width: 100%; + max-width: 100%; + text-align: left; + border-collapse: separate; + border-spacing: 0; + border-radius: 0.75rem; + border: 1px solid var(--nb-border); + table-layout: auto; +} + +@media (max-width: 640px) { + .docs-content :where(table:not([class])) { + display: block; + overflow-x: auto; + overflow-y: hidden; + overscroll-behavior-x: contain; + -webkit-overflow-scrolling: touch; + } +} + +.docs-content :where(th:not([class])), +.docs-content :where(td:not([class])) { + padding: 0.625rem 0.75rem; + text-align: left; + vertical-align: top; + border-bottom: 1px solid var(--nb-border); +} + +.docs-content :where(th:not([class])) { + background: var(--nb-muted); + font-weight: 600; + font-size: 0.8125rem; + white-space: nowrap; +} + +.docs-content :where(tbody:not([class]) tr:not([class]):last-child td:not([class])) { + border-bottom: none; +} + +.docs-content :where(a:not([class])) { + color: var(--nb-foreground); + text-decoration-line: underline; + text-decoration-color: var(--nb-border-strong); + text-underline-offset: 3px; + text-decoration-thickness: 1px; + font-weight: 500; + transition: text-decoration-color 0.15s; +} + +.docs-content :where(a:not([class]):hover) { + text-decoration-color: var(--nb-foreground); +} + +/* ---- Long-tail prose vocabulary ---- + Elements markdown/MDX authors can reach for that would otherwise + render with raw browser defaults. Same component boundary as the rest + of the file: `:not([class])` leaves component-owned markup alone. */ + +/* Keycaps. The thicker bottom border stands in for a pressed edge — + border darkening, not a drop shadow. */ +.docs-content :where(kbd:not([class])) { + display: inline-block; + font-family: var(--nb-font-mono); + font-size: 0.75em; + font-weight: 500; + line-height: 1; + color: var(--nb-foreground); + background: var(--nb-muted); + border: 1px solid var(--nb-border); + border-bottom-width: 2px; + border-radius: 0.375rem; + padding: 0.1875rem 0.375rem; + vertical-align: 0.0625rem; +} + +/* Inline highlight — harmonized with ::selection instead of the + browser's fluorescent yellow. `box-decoration-break` keeps the tint + coherent when the highlight wraps across lines. */ +.docs-content :where(mark:not([class])) { + background: color-mix(in oklch, var(--nb-primary) 12%, transparent); + color: var(--nb-foreground); + border-radius: 0.25rem; + padding: 0.0625rem 0.25rem; + -webkit-box-decoration-break: clone; + box-decoration-break: clone; +} + +/* Native disclosure. Scope guard: FileTree builds classless
+ internally (`.file-tree :global(details)`), so exclude its subtree — + without this the rows below would grow double carets and borders. */ +.docs-content :where(details:not([class]):not(.file-tree *)) { + border: 1px solid var(--nb-border); + border-radius: 0.5rem; + padding: 0.625rem 0.875rem; +} + +.docs-content :where(details:not([class]):not(.file-tree *) > summary) { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.625rem; + cursor: pointer; + font-weight: 500; + list-style: none; + user-select: none; +} + +.docs-content :where(details:not([class]):not(.file-tree *) > summary)::-webkit-details-marker { + display: none; +} + +/* Trailing chevron — label left, indicator right, matching Collapsible. */ +.docs-content :where(details:not([class]):not(.file-tree *) > summary)::after { + content: ""; + flex-shrink: 0; + width: 0.4375em; + height: 0.4375em; + border-right: 1.5px solid var(--nb-muted-foreground); + border-bottom: 1.5px solid var(--nb-muted-foreground); + transform: rotate(-45deg); + transition: transform 0.2s cubic-bezier(0.32, 0.72, 0, 1); +} + +.docs-content :where(details[open]:not([class]):not(.file-tree *) > summary)::after { + transform: rotate(45deg) translateY(-0.125em); +} + +.docs-content :where(details[open]:not([class]):not(.file-tree *) > summary) { + margin-bottom: 0.5rem; +} + +/* Definition lists — term/description pairs. */ +.docs-content :where(dt:not([class])) { + font-weight: 600; +} + +.docs-content :where(dt:not([class]):not(:first-child)) { + margin-top: 0.75rem; +} + +.docs-content :where(dd:not([class])) { + margin-left: 1rem; + color: var(--nb-muted-foreground); +} diff --git a/docs/tsconfig.json b/docs/tsconfig.json index 8a81642..abc8919 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -1,5 +1,11 @@ { "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, "include": [".astro/types.d.ts", "**/*"], "exclude": ["dist", "scripts"] } diff --git a/docs/wrangler.jsonc b/docs/wrangler.jsonc index e08f3fa..6b313f6 100644 --- a/docs/wrangler.jsonc +++ b/docs/wrangler.jsonc @@ -19,7 +19,7 @@ /** * On unmatched routes, serve the Astro-generated `404.html` with * a 404 status. Single-page-application mode is wrong for - * Starlight (it's MPA); `none` would return a bare 404 with no + * Nimbus (it's MPA); `none` would return a bare 404 with no * branding. */ "not_found_handling": "404-page", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2bd80db..b33a00e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 8.17.0 astro: specifier: ^7.0.0 - version: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) + version: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) p-retry: specifier: ^8.0.0 version: 8.0.0 @@ -80,26 +80,62 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.9 - version: 4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0)) + version: 4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) docs: dependencies: - '@astrojs/starlight': - specifier: ^0.41.3 - version: 0.41.3(@astrojs/markdown-remark@7.2.1)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0))(typescript@6.0.3) + '@fontsource-variable/inter': + specifier: ^5.2.8 + version: 5.2.8 + '@fontsource-variable/jetbrains-mono': + specifier: ^5.2.8 + version: 5.2.8 + '@iconify-json/ph': + specifier: ^1.2.0 + version: 1.2.2 astro: specifier: ^7.0.0 - version: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) + version: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) + astro-icon: + specifier: ^1.1.0 + version: 1.1.5 + astro-og-canvas: + specifier: ^0.13.0 + version: 0.13.0(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0)) + canvaskit-wasm: + specifier: ^0.41.1 + version: 0.41.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + nimbus-docs: + specifier: ^0.1.22 + version: 0.1.22(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0))(react@19.2.6)(shiki@4.3.1) sharp: specifier: ^0.35.3 version: 0.35.3(@types/node@26.1.0) + shiki: + specifier: ^4.2.0 + version: 4.3.1 + tailwind-merge: + specifier: ^3.5.0 + version: 3.6.0 devDependencies: '@astrojs/check': specifier: ^0.9.9 version: 0.9.9(prettier@3.9.4)(typescript@6.0.3) + '@tailwindcss/postcss': + specifier: ^4.1.4 + version: 4.3.2 '@types/node': specifier: ^26.1.0 version: 26.1.0 + pagefind: + specifier: ^1.5.2 + version: 1.5.2 + tailwindcss: + specifier: ^4.1.4 + version: 4.3.2 tsx: specifier: ^4.19.0 version: 4.22.2 @@ -114,13 +150,13 @@ importers: dependencies: '@astrojs/mdx': specifier: ^7.0.0 - version: 7.0.2(@astrojs/markdown-satteri@0.3.3)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0)) + version: 7.0.2(@astrojs/markdown-satteri@0.3.3)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0)) '@cloudflare/polystella': specifier: workspace:* version: link:../.. astro: specifier: ^7.0.0 - version: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) + version: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) devDependencies: '@types/node': specifier: ^26.1.0 @@ -131,6 +167,16 @@ importers: packages: + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@antfu/utils@8.1.1': + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} + '@astrojs/check@0.9.9': resolution: {integrity: sha512-A5UW8uIuErLWEoRQvzgXpO1gTjUFtK8r7nU2Z7GewAMxUb7bPvpk11qaKKgxqXlHJWlAvaaxy+Xg28A6bmQ1Tg==} hasBin: true @@ -205,6 +251,9 @@ packages: '@astrojs/compiler@2.13.1': resolution: {integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==} + '@astrojs/internal-helpers@0.10.0': + resolution: {integrity: sha512-Ry2R3VPeIN4uPCSA4xQc+e+vsJXkalKpEbDc07hV+a/o5Bs2N/s/uDcPJH/05L19DKh9tAy7e6JM3YZ6Cxfezw==} + '@astrojs/internal-helpers@0.10.1': resolution: {integrity: sha512-5phcroT/vmOOrYuuAxtkbPixy5hePtlz9i8K4OeDv3dNK6/UQRuXPOSRTxIOBbUY5Sonw2UaxjbuVc43Mcir6Q==} @@ -220,12 +269,28 @@ packages: prettier-plugin-astro: optional: true + '@astrojs/markdown-remark@7.2.0': + resolution: {integrity: sha512-+YxmVQu1Bd+MFfSzjq1rOJvD9+nIOJzz5YIIhdIH01RrxRkKbyKoEgyIqP3yv51MhzMDgd79QaPv+kCVPT8vHw==} + '@astrojs/markdown-remark@7.2.1': resolution: {integrity: sha512-jPVNIqTvk+yKviikszv/Y1U4jGUSKpp/Nw48QZV4qjWgp70j4Lkq3lhSDRbWwCfgKvEyO9GHuVbV1dM2WYXy1w==} + '@astrojs/markdown-satteri@0.2.1': + resolution: {integrity: sha512-rsdT8ucMLmu1v/POYApJcfH/t30Yuae6pZdfFU0yG3Kya8pwNItcJ6TLqUACRlRV9W50g4gLIxCwwfWjKsJ67w==} + '@astrojs/markdown-satteri@0.3.3': resolution: {integrity: sha512-Lje33Ittd8UQGgbIIWQvhPkj5X5c4b1sZnZWX3JQV/AWpfbuQGxVi2ONt6+ScydcwfR4egilslEWyczMclrJ1g==} + '@astrojs/mdx@6.0.1': + resolution: {integrity: sha512-J5K8F7A1LMH+cj+dcxm+uAeIznkfwxMcRpG7DD6ABNDOt8da98ph6ie4TD+4FV/ojVOJK0PQGWY4hmxQORLv0w==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@astrojs/markdown-satteri': 0.2.1 + astro: ^6.4.0 + peerDependenciesMeta: + '@astrojs/markdown-satteri': + optional: true + '@astrojs/mdx@7.0.2': resolution: {integrity: sha512-l+sJY5U1KkGZUdr+bIL4Y6BefeS549qoSHVSkUSs6A9INwdCND+/0+vN0NroPBXwl5Vcg5u78t7VQRsJjePxbw==} engines: {node: '>=22.12.0'} @@ -243,15 +308,6 @@ packages: '@astrojs/sitemap@3.7.3': resolution: {integrity: sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==} - '@astrojs/starlight@0.41.3': - resolution: {integrity: sha512-8xsG6UpK581TJmtOc7/pnxHKEbP16rV06VLWaVa7FOyE/VEwnaHOsLtL+miifCEfuiuv0Wn+j8u3JSluRQesMQ==} - peerDependencies: - '@astrojs/markdown-remark': ^7.2.0 - astro: ^7.0.2 - peerDependenciesMeta: - '@astrojs/markdown-remark': - optional: true - '@astrojs/telemetry@3.3.2': resolution: {integrity: sha512-j8DNruA8ors99Al39RYZPJK4DC1bKkoNm93mAMuBhY9TCNC4R8n1q7ovFnJ5qhGh5Lsh7pa1gpQVpYpsJPeTHQ==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} @@ -280,11 +336,21 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@bruits/satteri-darwin-arm64@0.6.3': + resolution: {integrity: sha512-oKgMfpmNzQ8vaqmkE37PBu8tOyVjoOc4s+DV2tLpWvO6WO467qn/+Nbcirm/ceer7wUM8v4vMLGcZO0gkRzBEg==} + cpu: [arm64] + os: [darwin] + '@bruits/satteri-darwin-arm64@0.9.4': resolution: {integrity: sha512-W3MSUkr2mZRR8Stoe+lqNAyzQzRuFMU8WffV9IvFSxTok0LGWR0ZZQPLELU4QTRiUbhL2Y4VUP9vV7pj8rHjgg==} cpu: [arm64] os: [darwin] + '@bruits/satteri-darwin-x64@0.6.3': + resolution: {integrity: sha512-9I5pbwZRWH5LvhoCtwpRr4rYSDe43/dLvps6zO70ipVF2XbH4rJ20T+EfvPcmou5jsWMsq9Ybn5GX3PwlSrBaw==} + cpu: [x64] + os: [darwin] + '@bruits/satteri-darwin-x64@0.9.4': resolution: {integrity: sha512-DXOuuaE1lsv7mpk2mOvGrzqoEWEvOIZEO/fXVa7zfM23Iob+CBjBkRAMwpHA4pmZ3j6Gj7WJzPKw0kQ7w741AQ==} cpu: [x64] @@ -302,6 +368,12 @@ packages: os: [linux] libc: [musl] + '@bruits/satteri-linux-x64-gnu@0.6.3': + resolution: {integrity: sha512-aFfw2DL2HpIcAQ8I3ZEtKuz+/GoF0H0sq387jAlvr00Q7buiiFbvARFuQlvTk00N7u3SJIh/3+YkKssTJDT+yQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + '@bruits/satteri-linux-x64-gnu@0.9.4': resolution: {integrity: sha512-MR1Q+wMx65FQlbSV7cRqWW87Knp0zkoaIV55Dt+xZl028wJABXEPEEmG3670SLq7lVZvcGIDwCgSg2kCYxvRwA==} cpu: [x64] @@ -314,6 +386,11 @@ packages: os: [linux] libc: [musl] + '@bruits/satteri-wasm32-wasi@0.6.3': + resolution: {integrity: sha512-DdpfnJ+04Mb4YtHaxAeETUvhdxFKg3URnroGY39FvweJEgeXx8cFNutuF5w904BhqaiblhmF76AoBnJwNLxsXg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + '@bruits/satteri-wasm32-wasi@0.9.4': resolution: {integrity: sha512-/CEG8LUlpaBEnhFnYVn0UnlHFLs51UhrkJBUPDUXLzkadzAcnR88iRA/nOl7Zwhjb4WhfBV4p3P5qeOJMtH0iA==} engines: {node: '>=14.0.0'} @@ -324,6 +401,11 @@ packages: cpu: [arm64] os: [win32] + '@bruits/satteri-win32-x64-msvc@0.6.3': + resolution: {integrity: sha512-J/CZqACnBbv77eImx/JeO5RmCuCyliihiC81u3M4VobA8eupsygaPen3/UFFqf3yfeHvMlE3myilouh/2iHMOA==} + cpu: [x64] + os: [win32] + '@bruits/satteri-win32-x64-msvc@0.9.4': resolution: {integrity: sha512-5I7SiarsNdAUuhJb50CXJPTwr/ECVrBoU+fymoLjChK5fW//+srhY4lstcNTzgFRtQSYfVtm4OQZz16CVMeTeA==} cpu: [x64] @@ -394,10 +476,16 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@clack/core@0.4.1': + resolution: {integrity: sha512-Pxhij4UXg8KSr7rPek6Zowm+5M22rbd2g1nfojHJkxp5YkFqiZ2+YLEM/XGVIzvGOcM0nqjIFxrpDwWRZYWYjA==} + '@clack/core@1.3.1': resolution: {integrity: sha512-fT1qHVGAag4IEkrupZ6lRRbNCs1vS9P01KB/sG8zKgvUztbYtFBtQpjSITNwooDZ83tpsPzP0mRNs1/KVszCRA==} engines: {node: '>= 20.12.0'} + '@clack/prompts@0.9.1': + resolution: {integrity: sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==} + '@clack/prompts@1.4.0': resolution: {integrity: sha512-S0My7XPGIgpRWMDG8uRqalbgT+a6FmCUdOW+HaIOVVpUPHOb7RrpvjTjiODadKp06fsrVDJZlIzc6yCTp4AnxA==} engines: {node: '>= 20.12.0'} @@ -449,10 +537,6 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@ctrl/tinycolor@4.2.0': - resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} - engines: {node: '>=14'} - '@emmetio/abbreviation@2.3.3': resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} @@ -477,6 +561,9 @@ packages: '@emnapi/core@1.11.1': resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} @@ -486,6 +573,12 @@ packages: '@emnapi/runtime@1.11.2': resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} @@ -801,17 +894,23 @@ packages: cpu: [x64] os: [win32] - '@expressive-code/core@0.44.0': - resolution: {integrity: sha512-xgiF2P6tYUbrhi3+x0S8xHZWT1t3Bvb3U91tAtRbLb9HLejLvYc5GZUqKICKLaUN4iSGhhNJu2fM/aH8e5yCMg==} + '@fontsource-variable/inter@5.2.8': + resolution: {integrity: sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==} + + '@fontsource-variable/jetbrains-mono@5.2.8': + resolution: {integrity: sha512-WBA9elru6Jdp5df2mES55wuOO0WIrn3kpXnI4+W2ek5u3ZgLS9XS4gmIlcQhiZOWEKl95meYdvK7xI+ETLCq/Q==} - '@expressive-code/plugin-frames@0.44.0': - resolution: {integrity: sha512-V6M6+zVc1GzqCvXkQHc2m5rcFOIVzJgMq5gnfrMnVf2gwtj/sg4H93c1f/mGeqHycubwkHFUDyParAOiGeDZeA==} + '@iconify-json/ph@1.2.2': + resolution: {integrity: sha512-PgkEZNtqa8hBGjHXQa4pMwZa93hmfu8FUSjs/nv4oUU6yLsgv+gh9nu28Kqi8Fz9CCVu4hj1MZs9/60J57IzFw==} - '@expressive-code/plugin-shiki@0.44.0': - resolution: {integrity: sha512-RZsdaqlbGqyAQKuoX4myQXxjmiE2l5KBpJ/gKPh62tCdIdpWyjbzVqSo8+5XsezZxkfi8AJ/J6EUaBTPROFX/Q==} + '@iconify/tools@4.2.0': + resolution: {integrity: sha512-WRxPva/ipxYkqZd1+CkEAQmd86dQmrwH0vwK89gmp2Kh2WyyVw57XbPng0NehP3x4V1LzLsXUneP1uMfTMZmUA==} - '@expressive-code/plugin-text-markers@0.44.0': - resolution: {integrity: sha512-0/m3A5b+lz2upyNq+wzZ1S69HRoJmyFs5LsR42lVZ9pmGRlBiSBYQpvqlji4DBj1+Riamxc0AvcCr5kuzOQeWA==} + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.3.0': + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} @@ -1133,6 +1232,16 @@ packages: '@types/node': optional: true + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -1140,6 +1249,9 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -1186,9 +1298,6 @@ packages: cpu: [x64] os: [darwin] - '@pagefind/default-ui@1.5.2': - resolution: {integrity: sha512-pm1LMnQg8N2B3n2TnjKlhaFihpz6zTiA4HiGQ6/slKO/+8K9CAU5kcjdSSPgpuk1PMuuN4hxLipUIifnrkl3Sg==} - '@pagefind/freebsd-x64@1.5.2': resolution: {integrity: sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==} cpu: [x64] @@ -1492,6 +1601,10 @@ packages: resolution: {integrity: sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==} engines: {node: '>=20'} + '@shikijs/transformers@4.3.1': + resolution: {integrity: sha512-z6ir0bGDgWcF2FduktEfPgIsdOtIlDiLAjFBgBzE42Q9xHbkkIXZtORHzlLVB71iZP9elEcqKg6keajvOUwE2A==} + engines: {node: '>=20'} + '@shikijs/types@4.3.1': resolution: {integrity: sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==} engines: {node: '>=20'} @@ -1509,6 +1622,98 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tailwindcss/node@4.3.2': + resolution: {integrity: sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==} + + '@tailwindcss/oxide-android-arm64@4.3.2': + resolution: {integrity: sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.2': + resolution: {integrity: sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.2': + resolution: {integrity: sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.2': + resolution: {integrity: sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': + resolution: {integrity: sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': + resolution: {integrity: sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': + resolution: {integrity: sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': + resolution: {integrity: sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.2': + resolution: {integrity: sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.2': + resolution: {integrity: sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': + resolution: {integrity: sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': + resolution: {integrity: sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.2': + resolution: {integrity: sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.2': + resolution: {integrity: sha512-rjVWYCa7Ngbi5AarT6k8TkxUG3Wl1QKzHdIZVsjZSzf36Jmo2IKZt/NHRAwly8oDkbBOH0YTu+CHuf9jPxMc+g==} + '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} @@ -1533,9 +1738,6 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - '@types/js-yaml@4.0.9': - resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} - '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -1572,9 +1774,16 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@ungap/structured-clone@1.3.1': resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + '@vercel/detect-agent@1.2.3': + resolution: {integrity: sha512-VYNCgUc0nOmC4WJmWw9GkrKdfr8Zl4/rxhC5SvgacBgxiW9W/9NRttUoHHXV8xdII3MaRgkZZVX8Ikzc/Jmjag==} + engines: {node: '>=14'} + '@vitest/expect@4.1.9': resolution: {integrity: sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==} @@ -1630,6 +1839,9 @@ packages: '@vscode/l10n@0.0.18': resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + '@webgpu/types@0.1.21': + resolution: {integrity: sha512-pUrWq3V5PiSGFLeLxoGqReTZmiiXwY3jRkIG5sLLKjyqNxrwm/04b4nw7LSmGWJcKk59XOM/YRTUwOzo4MMlow==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1699,10 +1911,13 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true - astro-expressive-code@0.44.0: - resolution: {integrity: sha512-b1wN/ZvbJprzxlGKIpIes2kQrCY5KRLwys2tWbZAZyjGZcW5ZtgneZnBwzNRiBna9/48d4mQl19KLjcRuhO1hw==} + astro-icon@1.1.5: + resolution: {integrity: sha512-CJYS5nWOw9jz4RpGWmzNQY7D0y2ZZacH7atL2K9DeJXJVaz7/5WrxeyIxO8KASk1jCM96Q4LjRx/F3R+InjJrw==} + + astro-og-canvas@0.13.0: + resolution: {integrity: sha512-jcIDhE9OGIbd7LstZQ4CyzOpbbEKAlxJqEgdkVu6r26m7yJKlQjKysszfDxlox717cnCLPXKivyFjsufcq8sYA==} peerDependencies: - astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta || ^7.0.0 + astro: ^5.0.0 || ^6.0.0 || ^7.0.0 astro@7.0.6: resolution: {integrity: sha512-Myw0sFia+zs/Y0yqfZEsUYXfDPh3ELcLf1f0Q/qQzVXBh/af1qO62WNT+P89DCcfGVV51nMoQhEfkBYqJmoUOQ==} @@ -1721,11 +1936,8 @@ packages: bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - bcp-47-match@2.0.3: - resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} - - bcp-47@2.1.1: - resolution: {integrity: sha512-KLw+H/gd2p4zly1X7Yh/qziuyae5/w/QFnvTng9eZL5fvszL7Whl3MBoWF8yxL7ksUjBfOD+OxkytiqbBpG+Fw==} + base-64@1.0.0: + resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} @@ -1741,6 +1953,12 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + canvaskit-wasm@0.41.1: + resolution: {integrity: sha512-gO2rNMIE0lOQ8MaarM4qNeq2zZAEknAObKP2XAKidMSAY8P5sURGdFkrx1TSdHuBFqTf5w35JqjuUzjibqkD5g==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1763,6 +1981,13 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.2.0: + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} + engines: {node: '>=20.18.1'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -1771,6 +1996,10 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + ci-info@4.4.0: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} @@ -1800,10 +2029,20 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + common-ancestor-path@2.0.0: resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} engines: {node: '>= 18'} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1824,13 +2063,14 @@ packages: css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - css-selector-parser@3.3.0: - resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} - css-tree@2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-tree@3.2.1: resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} @@ -1839,11 +2079,6 @@ packages: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - csso@5.0.5: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -1884,6 +2119,10 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + deterministic-object-hash@2.0.2: + resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==} + engines: {node: '>=18'} + devalue@5.8.1: resolution: {integrity: sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==} @@ -1898,10 +2137,6 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - direction@2.0.1: - resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} - hasBin: true - dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -1929,6 +2164,16 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -1941,6 +2186,14 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} @@ -2007,8 +2260,8 @@ packages: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} - expressive-code@0.44.0: - resolution: {integrity: sha512-JXVWVNCKlLuZLMQH8cOiDUSosT0Bb+elwE/dbAkpwFwDFmyFyWlECoWZIohh2FkIF1iI67TQJ+Ts9k7oNDh2qA==} + exsolve@1.1.0: + resolution: {integrity: sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==} extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -2016,6 +2269,11 @@ packages: extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -2041,6 +2299,9 @@ packages: fault@2.0.1: resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2090,6 +2351,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-tsconfig@5.0.0-beta.4: resolution: {integrity: sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==} engines: {node: '>=20.20.0'} @@ -2101,6 +2366,10 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -2111,42 +2380,21 @@ packages: h3@1.15.11: resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} - hast-util-embedded@3.0.0: - resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} - - hast-util-format@1.1.0: - resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} - hast-util-from-html@2.0.3: resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} hast-util-from-parse5@8.0.3: resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} - hast-util-has-property@3.0.0: - resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} - - hast-util-is-body-ok-link@3.0.1: - resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} - hast-util-is-element@3.0.0: resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} - hast-util-minify-whitespace@1.0.1: - resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} - hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - hast-util-phrasing@3.0.1: - resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} - hast-util-raw@9.1.0: resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} - hast-util-select@6.0.4: - resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} - hast-util-to-estree@3.1.3: resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} @@ -2159,9 +2407,6 @@ packages: hast-util-to-parse5@8.0.1: resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} - hast-util-to-string@3.0.1: - resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} - hast-util-to-text@4.0.2: resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} @@ -2177,8 +2422,8 @@ packages: html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - html-whitespace-sensitive-tag-names@3.0.1: - resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} @@ -2187,13 +2432,9 @@ packages: resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} hasBin: true - i18next@26.3.4: - resolution: {integrity: sha512-pa7m0d7pBDqGHZxljT+WPFeyFgQ7P7SciPPo1tTqYuO0z4sqADYhwnBESmmGp/wEof1inwdls/k8ZgTg8rxFHA==} - peerDependencies: - typescript: ^5 || ^6 - peerDependenciesMeta: - typescript: - optional: true + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} @@ -2275,6 +2516,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + js-yaml@3.15.0: resolution: {integrity: sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==} hasBin: true @@ -2299,9 +2544,8 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - klona@2.0.6: - resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} - engines: {node: '>= 8'} + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} @@ -2377,6 +2621,10 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + local-pkg@1.2.1: + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} + engines: {node: '>=14'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -2407,9 +2655,6 @@ packages: mdast-util-definitions@6.0.0: resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} - mdast-util-directive@3.1.0: - resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} - mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -2464,6 +2709,9 @@ packages: mdn-data@2.0.28: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} @@ -2474,9 +2722,6 @@ packages: micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - micromark-extension-directive@4.0.0: - resolution: {integrity: sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==} - micromark-extension-frontmatter@2.0.0: resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} @@ -2591,6 +2836,17 @@ packages: engines: {node: '>=22.0.0'} hasBin: true + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -2614,6 +2870,20 @@ packages: resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} engines: {node: '>= 10'} + nimbus-docs@0.1.22: + resolution: {integrity: sha512-XLtC4CXg9BM+nhNH0zmVwb6H9eXRPAH0UpbgbhtkKJapckDViKLhryW8WcNZa9KBnfnIIH9Eqxq65IzJQS7O+g==} + hasBin: true + peerDependencies: + astro: '>=6.4.0' + react: '>=19.0.0' + react-dom: '>=19.0.0' + shiki: ^4.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + nlcst-to-string@4.0.0: resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} @@ -2649,6 +2919,9 @@ packages: ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + oniguruma-parser@0.12.2: resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} @@ -2710,6 +2983,12 @@ packages: parse-latin@7.0.0: resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -2734,6 +3013,9 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + piccolore@0.1.3: resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} @@ -2756,15 +3038,11 @@ packages: resolution: {integrity: sha512-u9mdErTewKSMsr+ceCt8VcNuNP0ro5AXiPXhUVApuEyqr2Zlvt+DdCFBcm+yGWN8mhOdZJ27meIDbnoZgfzpOw==} hasBin: true - postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - postcss-selector-parser@6.1.4: - resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} - engines: {node: '>=4'} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} postcss@8.5.16: resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} @@ -2796,12 +3074,18 @@ packages: property-information@7.2.0: resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quotation@2.0.3: + resolution: {integrity: sha512-yEc24TEgCFLXx7D4JHJJkK4JFVtatO8fziwUxY4nB/Jbea9o9CVS3gt22mA0W7rPYAGW2fWzYDSOtD94PwOyqA==} + radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} @@ -2844,15 +3128,6 @@ packages: regex@6.1.0: resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} - rehype-expressive-code@0.44.0: - resolution: {integrity: sha512-5r74C5F2sMR3X+QJH8OKWgZBO/cqRw5W1fLT6GVlSfLqepk+4j8tGFkyPqZYWjwntsBHzKPDH2zI68sZ7ScLfA==} - - rehype-format@5.0.1: - resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} - - rehype-parse@9.0.1: - resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} - rehype-raw@7.0.0: resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} @@ -2862,18 +3137,36 @@ packages: rehype-stringify@10.0.1: resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} - rehype@13.0.2: - resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} - - remark-directive@4.0.0: - resolution: {integrity: sha512-7sxn4RfF1o3izevPV1DheyGDD6X4c9hrGpfdUpm7uC++dqrnJxIZVkk7CoKqcLm0VUMAuOol7Mno3m6g8cfMuA==} - remark-frontmatter@5.0.0: resolution: {integrity: sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==} remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + remark-lint-emphasis-marker@4.0.1: + resolution: {integrity: sha512-BF1WWsAxai3XoKk48sfiqT3L8m02AZLj3BnipWkHDRXuLfz6VwsHVaHWyNvvE0p6b2B3A5dSYbcfJu5RmPx4tQ==} + + remark-lint-fenced-code-flag@4.2.0: + resolution: {integrity: sha512-QWGTrnYbcopOFZR98djDREmKApLonJ7hmXE7pEcOGee9JY/EUIVS7Lq54Hy9CtU3cVIvQQmiMTxCwUhfddDJFA==} + + remark-lint-heading-increment@4.0.1: + resolution: {integrity: sha512-uat7RTQn0hGlMv62p7yjLlg3tO3RljFbH6C+0M+5BNEF+s3NrA8jJgqW0UwLLNdCd3EABCKaWloHumT57ND7PQ==} + + remark-lint-no-duplicate-headings@4.0.1: + resolution: {integrity: sha512-6lggqnpIe5FepikjYF2me3ovKV4oD/rAz8WmwVbLR2cLkce1iH+PB7jyxk/A2gQQqrDcIlRMA5Ct2Yj56cEwhQ==} + + remark-lint-no-heading-punctuation@4.0.1: + resolution: {integrity: sha512-lpSVFEHPDKGWi8YPeO51xmLNVON5A2cGz0Y8VRkW0f2l6LvEkPTMjQAvA84AQu/10TrxTbIzU/tQlRLpG96QUA==} + + remark-lint-no-literal-urls@4.0.1: + resolution: {integrity: sha512-RhTANFkFFXE6bM+WxWcPo2TTPEfkWG3lJZU50ycW7tJJmxUzDNzRed/z80EVJIdGwFa0NntVooLUJp3xrogalQ==} + + remark-lint-no-multiple-toplevel-headings@4.0.1: + resolution: {integrity: sha512-8sepobIOu3PlDOuMH7jtri+LH4tFNVQU+aqKSkrlNRdp831fYz9S+jA2crTVqWqxVbTwiF96uJWePv8/9qmHnA==} + + remark-lint-unordered-list-marker-style@4.0.1: + resolution: {integrity: sha512-HMrVQC0Qbr8ktSy+1lJGRGU10qecL3T14L6s/THEQXR5Tk0wcsLLG0auNvB4r2+H+ClhVO/Vnm1TEosh1OCsfw==} + remark-mdx@3.1.1: resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} @@ -2947,6 +3240,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + satteri@0.6.3: + resolution: {integrity: sha512-iY5xd2tBDQveYRFkL1F0cegkabWSVoXHi64e1p49SiCs1bZDaqTQPGQI+PqEQIaWkz0iqK80CuQQUYvhsssviw==} + satteri@0.9.4: resolution: {integrity: sha512-BKob126Tay84diOZsnVNH/Q/c+3njPJTCad3w5zLKa6j8bVjxskPNHDtxrMwYK4bN/RlqUSdMnPwKY4k65EMOQ==} @@ -3063,11 +3359,30 @@ packages: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} + svgo@3.3.3: + resolution: {integrity: sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==} + engines: {node: '>=14.0.0'} + hasBin: true + svgo@4.0.1: resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} engines: {node: '>=16'} hasBin: true + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + + tailwindcss@4.3.2: + resolution: {integrity: sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tar@7.5.19: + resolution: {integrity: sha512-4LeEWl96twnS2Q7Bz4MGqgazLqO+hJN63GZxXoIqh1T3VweYD997gbU1ItNsQafqqXTXd5WFyFdReLtwvRBNiw==} + engines: {node: '>=18'} + term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} @@ -3148,6 +3463,9 @@ packages: unenv@2.0.0-rc.24: resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + unified-lint-rule@3.0.1: + resolution: {integrity: sha512-HxIeQOmwL19DGsxHXbeyzKHBsoSCFO7UtRVUvT2v61ptw/G+GbysWcrpHdfs5jqbIFDA11MoKngIhQK0BeTVjA==} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -3250,13 +3568,6 @@ packages: uploadthing: optional: true - url-extras@0.1.0: - resolution: {integrity: sha512-8tzwTeXFPuX/5PHuCDQE5Dd9Ts4rwoq2t9aIT+HS4iAVpmj5l4Ao7Q+BuuFjvWRqrLswBhQDk8O96ZicgCqQqw==} - engines: {node: '>=20'} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -3456,6 +3767,15 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -3492,6 +3812,9 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -3511,6 +3834,10 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yaml-language-server@1.20.0: resolution: {integrity: sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==} hasBin: true @@ -3537,6 +3864,9 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yocto-queue@1.2.2: resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} @@ -3555,6 +3885,15 @@ packages: snapshots: + '@alloc/quick-lru@5.2.0': {} + + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.2.4 + + '@antfu/utils@8.1.1': {} + '@astrojs/check@0.9.9(prettier@3.9.4)(typescript@6.0.3)': dependencies: '@astrojs/language-server': 2.16.9(prettier@3.9.4)(typescript@6.0.3) @@ -3622,6 +3961,17 @@ snapshots: '@astrojs/compiler@2.13.1': {} + '@astrojs/internal-helpers@0.10.0': + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + js-yaml: 4.3.0 + picomatch: 4.0.5 + retext-smartypants: 6.2.0 + shiki: 4.3.1 + smol-toml: 1.7.0 + unified: 11.0.5 + '@astrojs/internal-helpers@0.10.1': dependencies: '@types/hast': 3.0.4 @@ -3658,6 +4008,28 @@ snapshots: transitivePeerDependencies: - typescript + '@astrojs/markdown-remark@7.2.0': + dependencies: + '@astrojs/internal-helpers': 0.10.0 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.2 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + '@astrojs/markdown-remark@7.2.1': dependencies: '@astrojs/internal-helpers': 0.10.1 @@ -3680,6 +4052,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@astrojs/markdown-satteri@0.2.1': + dependencies: + '@astrojs/internal-helpers': 0.10.0 + github-slugger: 2.0.0 + satteri: 0.6.3 + '@astrojs/markdown-satteri@0.3.3': dependencies: '@astrojs/internal-helpers': 0.10.1 @@ -3687,13 +4065,13 @@ snapshots: github-slugger: 2.0.0 satteri: 0.9.4 - '@astrojs/mdx@7.0.2(@astrojs/markdown-satteri@0.3.3)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0))': + '@astrojs/mdx@6.0.1(@astrojs/markdown-satteri@0.2.1)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0))': dependencies: - '@astrojs/internal-helpers': 0.10.1 - '@astrojs/markdown-remark': 7.2.1 + '@astrojs/internal-helpers': 0.10.0 + '@astrojs/markdown-remark': 7.2.0 '@mdx-js/mdx': 3.1.1 acorn: 8.17.0 - astro: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) + astro: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) es-module-lexer: 2.3.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -3705,11 +4083,33 @@ snapshots: unist-util-visit: 5.1.0 vfile: 6.0.3 optionalDependencies: - '@astrojs/markdown-satteri': 0.3.3 + '@astrojs/markdown-satteri': 0.2.1 transitivePeerDependencies: - supports-color - '@astrojs/prism@4.0.2': + '@astrojs/mdx@7.0.2(@astrojs/markdown-satteri@0.3.3)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0))': + dependencies: + '@astrojs/internal-helpers': 0.10.1 + '@astrojs/markdown-remark': 7.2.1 + '@mdx-js/mdx': 3.1.1 + acorn: 8.17.0 + astro: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) + es-module-lexer: 2.3.0 + estree-util-visit: 2.0.0 + hast-util-to-html: 9.0.5 + piccolore: 0.1.3 + rehype-raw: 7.0.0 + remark-gfm: 4.0.1 + remark-smartypants: 3.0.2 + source-map: 0.7.6 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + optionalDependencies: + '@astrojs/markdown-satteri': 0.3.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/prism@4.0.2': dependencies: prismjs: 1.30.0 @@ -3719,44 +4119,6 @@ snapshots: stream-replace-string: 2.0.0 zod: 4.4.3 - '@astrojs/starlight@0.41.3(@astrojs/markdown-remark@7.2.1)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0))(typescript@6.0.3)': - dependencies: - '@astrojs/markdown-satteri': 0.3.3 - '@astrojs/mdx': 7.0.2(@astrojs/markdown-satteri@0.3.3)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0)) - '@astrojs/sitemap': 3.7.3 - '@pagefind/default-ui': 1.5.2 - '@types/hast': 3.0.4 - '@types/js-yaml': 4.0.9 - '@types/mdast': 4.0.4 - astro: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) - astro-expressive-code: 0.44.0(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0)) - bcp-47: 2.1.1 - hast-util-from-html: 2.0.3 - hast-util-select: 6.0.4 - hast-util-to-string: 3.0.1 - hastscript: 9.0.1 - i18next: 26.3.4(typescript@6.0.3) - js-yaml: 4.3.0 - klona: 2.0.6 - magic-string: 0.30.21 - mdast-util-directive: 3.1.0 - mdast-util-to-markdown: 2.1.2 - mdast-util-to-string: 4.0.0 - pagefind: 1.5.2 - rehype: 13.0.2 - rehype-format: 5.0.1 - remark-directive: 4.0.0 - satteri: 0.9.4 - ultrahtml: 1.6.0 - unified: 11.0.5 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - optionalDependencies: - '@astrojs/markdown-remark': 7.2.1 - transitivePeerDependencies: - - supports-color - - typescript - '@astrojs/telemetry@3.3.2': dependencies: ci-info: 4.4.0 @@ -3784,9 +4146,15 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@bruits/satteri-darwin-arm64@0.6.3': + optional: true + '@bruits/satteri-darwin-arm64@0.9.4': optional: true + '@bruits/satteri-darwin-x64@0.6.3': + optional: true + '@bruits/satteri-darwin-x64@0.9.4': optional: true @@ -3796,12 +4164,22 @@ snapshots: '@bruits/satteri-linux-arm64-musl@0.9.4': optional: true + '@bruits/satteri-linux-x64-gnu@0.6.3': + optional: true + '@bruits/satteri-linux-x64-gnu@0.9.4': optional: true '@bruits/satteri-linux-x64-musl@0.9.4': optional: true + '@bruits/satteri-wasm32-wasi@0.6.3': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + optional: true + '@bruits/satteri-wasm32-wasi@0.9.4': dependencies: '@emnapi/core': 1.11.1 @@ -3812,6 +4190,9 @@ snapshots: '@bruits/satteri-win32-arm64-msvc@0.9.4': optional: true + '@bruits/satteri-win32-x64-msvc@0.6.3': + optional: true + '@bruits/satteri-win32-x64-msvc@0.9.4': optional: true @@ -3977,11 +4358,22 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 + '@clack/core@0.4.1': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + '@clack/core@1.3.1': dependencies: fast-wrap-ansi: 0.2.0 sisteransi: 1.0.5 + '@clack/prompts@0.9.1': + dependencies: + '@clack/core': 0.4.1 + picocolors: 1.1.1 + sisteransi: 1.0.5 + '@clack/prompts@1.4.0': dependencies: '@clack/core': 1.3.1 @@ -4016,8 +4408,6 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@ctrl/tinycolor@4.2.0': {} - '@emmetio/abbreviation@2.3.3': dependencies: '@emmetio/scanner': 1.0.4 @@ -4047,6 +4437,12 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 @@ -4062,6 +4458,16 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/wasi-threads@1.2.2': dependencies: tslib: 2.8.1 @@ -4223,30 +4629,42 @@ snapshots: '@esbuild/win32-x64@0.28.0': optional: true - '@expressive-code/core@0.44.0': - dependencies: - '@ctrl/tinycolor': 4.2.0 - hast-util-select: 6.0.4 - hast-util-to-html: 9.0.5 - hast-util-to-text: 4.0.2 - hastscript: 9.0.1 - postcss: 8.5.16 - postcss-nested: 6.2.0(postcss@8.5.16) - unist-util-visit: 5.1.0 - unist-util-visit-parents: 6.0.2 + '@fontsource-variable/inter@5.2.8': {} + + '@fontsource-variable/jetbrains-mono@5.2.8': {} - '@expressive-code/plugin-frames@0.44.0': + '@iconify-json/ph@1.2.2': dependencies: - '@expressive-code/core': 0.44.0 + '@iconify/types': 2.0.0 - '@expressive-code/plugin-shiki@0.44.0': + '@iconify/tools@4.2.0': dependencies: - '@expressive-code/core': 0.44.0 - shiki: 4.3.1 + '@iconify/types': 2.0.0 + '@iconify/utils': 2.3.0 + cheerio: 1.2.0 + domhandler: 5.0.3 + extract-zip: 2.0.1 + local-pkg: 1.2.1 + pathe: 2.0.3 + svgo: 3.3.3 + tar: 7.5.19 + transitivePeerDependencies: + - supports-color + + '@iconify/types@2.0.0': {} - '@expressive-code/plugin-text-markers@0.44.0': + '@iconify/utils@2.3.0': dependencies: - '@expressive-code/core': 0.44.0 + '@antfu/install-pkg': 1.1.0 + '@antfu/utils': 8.1.1 + '@iconify/types': 2.0.0 + debug: 4.4.3 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.2.1 + mlly: 1.8.2 + transitivePeerDependencies: + - supports-color '@img/colour@1.1.0': {} @@ -4455,10 +4873,29 @@ snapshots: optionalDependencies: '@types/node': 26.1.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -4524,6 +4961,13 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.3 + optional: true + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4546,8 +4990,6 @@ snapshots: '@pagefind/darwin-x64@1.5.2': optional: true - '@pagefind/default-ui@1.5.2': {} - '@pagefind/freebsd-x64@1.5.2': optional: true @@ -4742,6 +5184,11 @@ snapshots: dependencies: '@shikijs/types': 4.3.1 + '@shikijs/transformers@4.3.1': + dependencies: + '@shikijs/core': 4.3.1 + '@shikijs/types': 4.3.1 + '@shikijs/types@4.3.1': dependencies: '@shikijs/vscode-textmate': 10.0.2 @@ -4755,6 +5202,75 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@tailwindcss/node@4.3.2': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.2 + + '@tailwindcss/oxide-android-arm64@4.3.2': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.2': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.2': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.2': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.2': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': + optional: true + + '@tailwindcss/oxide@4.3.2': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.2 + '@tailwindcss/oxide-darwin-arm64': 4.3.2 + '@tailwindcss/oxide-darwin-x64': 4.3.2 + '@tailwindcss/oxide-freebsd-x64': 4.3.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.2 + '@tailwindcss/oxide-linux-x64-musl': 4.3.2 + '@tailwindcss/oxide-wasm32-wasi': 4.3.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 + + '@tailwindcss/postcss@4.3.2': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.3.2 + '@tailwindcss/oxide': 4.3.2 + postcss: 8.5.16 + tailwindcss: 4.3.2 + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 @@ -4784,8 +5300,6 @@ snapshots: dependencies: '@types/unist': 3.0.3 - '@types/js-yaml@4.0.9': {} - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -4822,8 +5336,15 @@ snapshots: '@types/unist@3.0.3': {} + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 26.1.0 + optional: true + '@ungap/structured-clone@1.3.1': {} + '@vercel/detect-agent@1.2.3': {} + '@vitest/expect@4.1.9': dependencies: '@standard-schema/spec': 1.1.0 @@ -4833,13 +5354,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.9(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0))': + '@vitest/mocker@4.1.9(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0) '@vitest/pretty-format@4.1.9': dependencies: @@ -4915,6 +5436,8 @@ snapshots: '@vscode/l10n@0.0.18': {} + '@webgpu/types@0.1.21': {} + acorn-jsx@5.3.2(acorn@8.17.0): dependencies: acorn: 8.17.0 @@ -4967,13 +5490,22 @@ snapshots: astring@1.9.0: {} - astro-expressive-code@0.44.0(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0)): + astro-icon@1.1.5: dependencies: - astro: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) - rehype-expressive-code: 0.44.0 - url-extras: 0.1.0 + '@iconify/tools': 4.2.0 + '@iconify/types': 2.0.0 + '@iconify/utils': 2.3.0 + transitivePeerDependencies: + - supports-color + + astro-og-canvas@0.13.0(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0)): + dependencies: + astro: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) + canvaskit-wasm: 0.41.1 + deterministic-object-hash: 2.0.2 + entities: 8.0.0 - astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0): + astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0): dependencies: '@astrojs/compiler-rs': 0.3.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2) '@astrojs/internal-helpers': 0.10.1 @@ -5023,8 +5555,8 @@ snapshots: ultrahtml: 1.6.0 unifont: 0.7.4 unstorage: 1.17.5 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0)) + vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) xxhash-wasm: 1.1.0 yargs-parser: 22.0.0 zod: 4.4.3 @@ -5070,13 +5602,7 @@ snapshots: bail@2.0.2: {} - bcp-47-match@2.0.3: {} - - bcp-47@2.1.1: - dependencies: - is-alphabetical: 2.0.1 - is-alphanumerical: 2.0.1 - is-decimal: 2.0.1 + base-64@1.0.0: {} better-path-resolve@1.0.0: dependencies: @@ -5090,6 +5616,12 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer-crc32@0.2.13: {} + + canvaskit-wasm@0.41.1: + dependencies: + '@webgpu/types': 0.1.21 + ccount@2.0.1: {} chai@6.2.2: {} @@ -5104,6 +5636,29 @@ snapshots: chardet@2.1.1: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.2.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.1.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.24.8 + whatwg-mimetype: 4.0.0 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -5112,6 +5667,8 @@ snapshots: dependencies: readdirp: 5.0.0 + chownr@3.0.0: {} + ci-info@4.4.0: {} cliui@8.0.1: @@ -5134,8 +5691,14 @@ snapshots: commander@11.1.0: {} + commander@7.2.0: {} + common-ancestor-path@2.0.0: {} + confbox@0.1.8: {} + + confbox@0.2.4: {} + convert-source-map@2.0.0: {} cookie-es@1.2.3: {} @@ -5160,13 +5723,16 @@ snapshots: domutils: 3.2.2 nth-check: 2.1.1 - css-selector-parser@3.3.0: {} - css-tree@2.2.1: dependencies: mdn-data: 2.0.28 source-map-js: 1.2.1 + css-tree@2.3.1: + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.1 + css-tree@3.2.1: dependencies: mdn-data: 2.27.1 @@ -5174,8 +5740,6 @@ snapshots: css-what@6.2.2: {} - cssesc@3.0.0: {} - csso@5.0.5: dependencies: css-tree: 2.2.1 @@ -5202,6 +5766,10 @@ snapshots: detect-libc@2.1.2: {} + deterministic-object-hash@2.0.2: + dependencies: + base-64: 1.0.0 + devalue@5.8.1: {} devlop@1.1.0: @@ -5214,8 +5782,6 @@ snapshots: dependencies: path-type: 4.0.0 - direction@2.0.1: {} - dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -5245,6 +5811,20 @@ snapshots: emoji-regex@8.0.0: {} + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + enhanced-resolve@5.21.6: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 @@ -5254,6 +5834,10 @@ snapshots: entities@6.0.1: {} + entities@7.0.1: {} + + entities@8.0.0: {} + error-stack-parser-es@1.0.5: {} es-module-lexer@2.3.0: {} @@ -5375,17 +5959,22 @@ snapshots: expect-type@1.4.0: {} - expressive-code@0.44.0: - dependencies: - '@expressive-code/core': 0.44.0 - '@expressive-code/plugin-frames': 0.44.0 - '@expressive-code/plugin-shiki': 0.44.0 - '@expressive-code/plugin-text-markers': 0.44.0 + exsolve@1.1.0: {} extend@3.0.2: {} extendable-error@0.1.7: {} + extract-zip@2.0.1: + dependencies: + debug: 4.4.3 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -5416,6 +6005,10 @@ snapshots: dependencies: format: 0.2.2 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: picomatch: 4.0.5 @@ -5458,6 +6051,10 @@ snapshots: get-caller-file@2.0.5: {} + get-stream@5.2.0: + dependencies: + pump: 3.0.4 + get-tsconfig@5.0.0-beta.4: dependencies: resolve-pkg-maps: 1.0.0 @@ -5468,6 +6065,8 @@ snapshots: dependencies: is-glob: 4.0.3 + globals@15.15.0: {} + globby@11.1.0: dependencies: array-union: 2.1.0 @@ -5491,21 +6090,6 @@ snapshots: ufo: 1.6.4 uncrypto: 0.1.3 - hast-util-embedded@3.0.0: - dependencies: - '@types/hast': 3.0.4 - hast-util-is-element: 3.0.0 - - hast-util-format@1.1.0: - dependencies: - '@types/hast': 3.0.4 - hast-util-embedded: 3.0.0 - hast-util-minify-whitespace: 1.0.1 - hast-util-phrasing: 3.0.1 - hast-util-whitespace: 3.0.0 - html-whitespace-sensitive-tag-names: 3.0.1 - unist-util-visit-parents: 6.0.2 - hast-util-from-html@2.0.3: dependencies: '@types/hast': 3.0.4 @@ -5526,38 +6110,14 @@ snapshots: vfile-location: 5.0.3 web-namespaces: 2.0.1 - hast-util-has-property@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-is-body-ok-link@3.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-is-element@3.0.0: dependencies: '@types/hast': 3.0.4 - hast-util-minify-whitespace@1.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-embedded: 3.0.0 - hast-util-is-element: 3.0.0 - hast-util-whitespace: 3.0.0 - unist-util-is: 6.0.1 - hast-util-parse-selector@4.0.0: dependencies: '@types/hast': 3.0.4 - hast-util-phrasing@3.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-embedded: 3.0.0 - hast-util-has-property: 3.0.0 - hast-util-is-body-ok-link: 3.0.1 - hast-util-is-element: 3.0.0 - hast-util-raw@9.1.0: dependencies: '@types/hast': 3.0.4 @@ -5574,24 +6134,6 @@ snapshots: web-namespaces: 2.0.1 zwitch: 2.0.4 - hast-util-select@6.0.4: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - bcp-47-match: 2.0.3 - comma-separated-tokens: 2.0.3 - css-selector-parser: 3.3.0 - devlop: 1.1.0 - direction: 2.0.1 - hast-util-has-property: 3.0.0 - hast-util-to-string: 3.0.1 - hast-util-whitespace: 3.0.0 - nth-check: 2.1.1 - property-information: 7.2.0 - space-separated-tokens: 2.0.2 - unist-util-visit: 5.1.0 - zwitch: 2.0.4 - hast-util-to-estree@3.1.3: dependencies: '@types/estree': 1.0.9 @@ -5657,10 +6199,6 @@ snapshots: web-namespaces: 2.0.1 zwitch: 2.0.4 - hast-util-to-string@3.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-to-text@4.0.2: dependencies: '@types/hast': 3.0.4 @@ -5684,15 +6222,20 @@ snapshots: html-void-elements@3.0.0: {} - html-whitespace-sensitive-tag-names@3.0.1: {} + htmlparser2@10.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 7.0.1 http-cache-semantics@4.2.0: {} human-id@4.1.3: {} - i18next@26.3.4(typescript@6.0.3): - optionalDependencies: - typescript: 6.0.3 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 iconv-lite@0.7.2: dependencies: @@ -5749,6 +6292,8 @@ snapshots: isexe@2.0.0: {} + jiti@2.7.0: {} + js-yaml@3.15.0: dependencies: argparse: 1.0.10 @@ -5770,7 +6315,7 @@ snapshots: kleur@4.1.5: {} - klona@2.0.6: {} + kolorist@1.8.0: {} lightningcss-android-arm64@1.32.0: optional: true @@ -5821,6 +6366,12 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + local-pkg@1.2.1: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.1 + quansync: 0.2.11 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -5851,20 +6402,6 @@ snapshots: '@types/unist': 3.0.3 unist-util-visit: 5.1.0 - mdast-util-directive@3.1.0: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - parse-entities: 4.0.2 - stringify-entities: 4.0.4 - unist-util-visit-parents: 6.0.2 - transitivePeerDependencies: - - supports-color - mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -6041,6 +6578,8 @@ snapshots: mdn-data@2.0.28: {} + mdn-data@2.0.30: {} + mdn-data@2.27.1: {} merge2@1.4.1: {} @@ -6064,16 +6603,6 @@ snapshots: micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - micromark-extension-directive@4.0.0: - dependencies: - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-factory-whitespace: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - parse-entities: 4.0.2 - micromark-extension-frontmatter@2.0.0: dependencies: fault: 2.0.1 @@ -6343,6 +6872,19 @@ snapshots: - bufferutil - utf-8-validate + minipass@7.1.3: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + mlly@1.8.2: + dependencies: + acorn: 8.17.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + mri@1.2.0: {} mrmime@2.0.1: {} @@ -6355,6 +6897,37 @@ snapshots: neotraverse@0.6.18: {} + nimbus-docs@0.1.22(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0))(react@19.2.6)(shiki@4.3.1): + dependencies: + '@astrojs/markdown-satteri': 0.2.1 + '@astrojs/mdx': 6.0.1(@astrojs/markdown-satteri@0.2.1)(astro@7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0)) + '@astrojs/sitemap': 3.7.3 + '@clack/prompts': 0.9.1 + '@shikijs/transformers': 4.3.1 + '@vercel/detect-agent': 1.2.3 + astro: 7.0.6(@astrojs/markdown-remark@7.2.1)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.2)(@types/node@26.1.0)(jiti@2.7.0)(rollup@4.60.4)(tsx@4.22.2)(yaml@2.9.0) + clsx: 2.1.1 + github-slugger: 2.0.0 + mri: 1.2.0 + remark-lint-emphasis-marker: 4.0.1 + remark-lint-fenced-code-flag: 4.2.0 + remark-lint-heading-increment: 4.0.1 + remark-lint-no-duplicate-headings: 4.0.1 + remark-lint-no-heading-punctuation: 4.0.1 + remark-lint-no-literal-urls: 4.0.1 + remark-lint-no-multiple-toplevel-headings: 4.0.1 + remark-lint-unordered-list-marker-style: 4.0.1 + satteri: 0.6.3 + shiki: 4.3.1 + tailwind-merge: 3.6.0 + unified: 11.0.5 + vfile: 6.0.3 + yaml: 2.9.0 + optionalDependencies: + react: 19.2.6 + transitivePeerDependencies: + - supports-color + nlcst-to-string@4.0.0: dependencies: '@types/nlcst': 2.0.3 @@ -6383,6 +6956,10 @@ snapshots: ohash@2.0.11: {} + once@1.4.0: + dependencies: + wrappy: 1.0.2 + oniguruma-parser@0.12.2: {} oniguruma-to-es@4.3.6: @@ -6459,6 +7036,15 @@ snapshots: unist-util-visit-children: 3.0.0 vfile: 6.0.3 + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -6475,6 +7061,8 @@ snapshots: pathe@2.0.3: {} + pend@1.2.0: {} + piccolore@0.1.3: {} picocolors@1.1.1: {} @@ -6487,15 +7075,17 @@ snapshots: pkg-pr-new@0.0.75: {} - postcss-nested@6.2.0(postcss@8.5.16): + pkg-types@1.3.1: dependencies: - postcss: 8.5.16 - postcss-selector-parser: 6.1.4 + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 - postcss-selector-parser@6.1.4: + pkg-types@2.3.1: dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 + confbox: 0.2.4 + exsolve: 1.1.0 + pathe: 2.0.3 postcss@8.5.16: dependencies: @@ -6515,10 +7105,17 @@ snapshots: property-information@7.2.0: {} + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + quansync@0.2.11: {} queue-microtask@1.2.3: {} + quotation@2.0.3: {} + radix3@1.1.2: {} react@19.2.6: {} @@ -6573,21 +7170,6 @@ snapshots: dependencies: regex-utilities: 2.3.0 - rehype-expressive-code@0.44.0: - dependencies: - expressive-code: 0.44.0 - - rehype-format@5.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-format: 1.1.0 - - rehype-parse@9.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-from-html: 2.0.3 - unified: 11.0.5 - rehype-raw@7.0.0: dependencies: '@types/hast': 3.0.4 @@ -6608,22 +7190,6 @@ snapshots: hast-util-to-html: 9.0.5 unified: 11.0.5 - rehype@13.0.2: - dependencies: - '@types/hast': 3.0.4 - rehype-parse: 9.0.1 - rehype-stringify: 10.0.1 - unified: 11.0.5 - - remark-directive@4.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-directive: 3.1.0 - micromark-extension-directive: 4.0.0 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - remark-frontmatter@5.0.0: dependencies: '@types/mdast': 4.0.4 @@ -6644,6 +7210,85 @@ snapshots: transitivePeerDependencies: - supports-color + remark-lint-emphasis-marker@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + vfile-message: 4.0.3 + + remark-lint-fenced-code-flag@4.2.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-phrasing: 4.1.0 + quotation: 2.0.3 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + + remark-lint-heading-increment@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-mdx: 3.0.0 + unified-lint-rule: 3.0.1 + unist-util-visit-parents: 6.0.2 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + remark-lint-no-duplicate-headings@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-mdx: 3.0.0 + mdast-util-to-string: 4.0.0 + unified-lint-rule: 3.0.1 + unist-util-visit-parents: 6.0.2 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + remark-lint-no-heading-punctuation@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-mdx: 3.0.0 + mdast-util-to-string: 4.0.0 + unified-lint-rule: 3.0.1 + unist-util-visit-parents: 6.0.2 + transitivePeerDependencies: + - supports-color + + remark-lint-no-literal-urls@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-string: 4.0.0 + micromark-util-character: 2.1.1 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + + remark-lint-no-multiple-toplevel-headings@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-mdx: 3.0.0 + unified-lint-rule: 3.0.1 + unist-util-visit-parents: 6.0.2 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + remark-lint-unordered-list-marker-style@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-phrasing: 4.1.0 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + vfile-message: 4.0.3 + remark-mdx@3.1.1: dependencies: mdast-util-mdx: 3.0.0 @@ -6781,6 +7426,19 @@ snapshots: safer-buffer@2.1.2: {} + satteri@0.6.3: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + optionalDependencies: + '@bruits/satteri-darwin-arm64': 0.6.3 + '@bruits/satteri-darwin-x64': 0.6.3 + '@bruits/satteri-linux-x64-gnu': 0.6.3 + '@bruits/satteri-wasm32-wasi': 0.6.3 + '@bruits/satteri-win32-x64-msvc': 0.6.3 + satteri@0.9.4: dependencies: '@types/estree-jsx': 1.0.5 @@ -6948,6 +7606,16 @@ snapshots: supports-color@10.2.2: {} + svgo@3.3.3: + dependencies: + commander: 7.2.0 + css-select: 5.2.2 + css-tree: 2.3.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.0 + svgo@4.0.1: dependencies: commander: 11.1.0 @@ -6958,6 +7626,20 @@ snapshots: picocolors: 1.1.1 sax: 1.6.0 + tailwind-merge@3.6.0: {} + + tailwindcss@4.3.2: {} + + tapable@2.3.3: {} + + tar@7.5.19: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + term-size@2.2.1: {} tiny-inflate@1.0.3: {} @@ -7018,6 +7700,13 @@ snapshots: dependencies: pathe: 2.0.3 + unified-lint-rule@3.0.1: + dependencies: + '@types/unist': 3.0.3 + trough: 2.2.0 + unified: 11.0.5 + vfile: 6.0.3 + unified@11.0.5: dependencies: '@types/unist': 3.0.3 @@ -7093,10 +7782,6 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.4 - url-extras@0.1.0: {} - - util-deprecate@1.0.2: {} - vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 @@ -7112,7 +7797,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0): + vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.5 @@ -7123,17 +7808,18 @@ snapshots: '@types/node': 26.1.0 esbuild: 0.28.0 fsevents: 2.3.3 + jiti: 2.7.0 tsx: 4.22.2 yaml: 2.9.0 - vitefu@1.1.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0)): + vitefu@1.1.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)): optionalDependencies: - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0) - vitest@4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0)): + vitest@4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.9 - '@vitest/mocker': 4.1.9(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0)) + '@vitest/mocker': 4.1.9(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.9 '@vitest/runner': 4.1.9 '@vitest/snapshot': 4.1.9 @@ -7150,7 +7836,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(tsx@4.22.2)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.1.0 @@ -7258,6 +7944,12 @@ snapshots: webidl-conversions@3.0.1: {} + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -7304,12 +7996,16 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrappy@1.0.2: {} + ws@8.18.0: {} xxhash-wasm@1.1.0: {} y18n@5.0.8: {} + yallist@5.0.0: {} + yaml-language-server@1.20.0: dependencies: '@vscode/l10n': 0.0.18 @@ -7342,6 +8038,11 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yocto-queue@1.2.2: {} youch-core@0.3.3: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7c106b8..00493df 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -7,3 +7,6 @@ allowBuilds: esbuild: true sharp: true workerd: true + +minimumReleaseAgeExclude: + - nimbus-docs@0.1.22