From 892956ccff2685747476013c274542f362b3c4b7 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 07:53:16 -0400 Subject: [PATCH 01/21] Add top-level `pnpm dev` to simplify development / running the docs, and split `pnpm clean` --- package.json | 7 +++++-- packages/svelte-actions/package.json | 5 +++-- packages/svelte-state/package.json | 5 +++-- packages/svelte-stores/package.json | 5 +++-- packages/svelte-table/package.json | 5 +++-- packages/tailwind/package.json | 5 +++-- packages/utils/package.json | 5 +++-- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index c8162b7..c0bea92 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,12 @@ "license": "MIT", "type": "module", "scripts": { + "dev": "pnpm clean && pnpm package && pnpm --parallel --filter './packages/*' --filter @layerstack/docs-site --if-present dev", "test:unit": "pnpm -r test:unit", - "build": "rimraf packages/*/dist && pnpm -r build", - "build:packages": "rimraf packages/*/dist && pnpm --filter './packages/*' build", + "clean": "rimraf packages/*/dist", + "build": "pnpm clean && pnpm -r build", + "build:packages": "pnpm clean && pnpm --filter './packages/*' build", + "package": "pnpm --filter './packages/*' package", "check": "pnpm -r check", "lint": "pnpm -r lint", "format": "pnpm -r format", diff --git a/packages/svelte-actions/package.json b/packages/svelte-actions/package.json index e808d24..874c24a 100644 --- a/packages/svelte-actions/package.json +++ b/packages/svelte-actions/package.json @@ -6,8 +6,9 @@ "repository": "techniq/layerstack", "version": "1.0.1-next.18", "scripts": { - "dev": "rimraf dist && tsc -p tsconfig.build.json --watch", - "build": "rimraf dist && tsc -p tsconfig.build.json", + "dev": "tsc -p tsconfig.build.json --watch", + "clean": "rimraf dist", + "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", "package": "svelte-package", "prepublishOnly": "svelte-package", diff --git a/packages/svelte-state/package.json b/packages/svelte-state/package.json index 87f815d..a699e60 100644 --- a/packages/svelte-state/package.json +++ b/packages/svelte-state/package.json @@ -6,8 +6,9 @@ "repository": "techniq/layerstack", "version": "0.1.0-next.23", "scripts": { - "dev": "rimraf dist && tsc -p tsconfig.build.json --watch", - "build": "rimraf dist && tsc -p tsconfig.build.json", + "dev": "tsc -p tsconfig.build.json --watch", + "clean": "rimraf dist", + "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", "package": "svelte-package", "prepublishOnly": "svelte-package", diff --git a/packages/svelte-stores/package.json b/packages/svelte-stores/package.json index 3f47671..ac40e68 100644 --- a/packages/svelte-stores/package.json +++ b/packages/svelte-stores/package.json @@ -6,8 +6,9 @@ "repository": "techniq/layerstack", "version": "1.0.2-next.18", "scripts": { - "dev": "rimraf dist && tsc -p tsconfig.build.json --watch", - "build": "rimraf dist && tsc -p tsconfig.build.json", + "dev": "tsc -p tsconfig.build.json --watch", + "clean": "rimraf dist", + "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", "package": "svelte-package", "prepublishOnly": "svelte-package", diff --git a/packages/svelte-table/package.json b/packages/svelte-table/package.json index 0612031..06860ad 100644 --- a/packages/svelte-table/package.json +++ b/packages/svelte-table/package.json @@ -6,8 +6,9 @@ "repository": "techniq/layerstack", "version": "1.0.1-next.18", "scripts": { - "dev": "rimraf dist && tsc -p tsconfig.build.json --watch", - "build": "rimraf dist && tsc -p tsconfig.build.json", + "dev": "tsc -p tsconfig.build.json --watch", + "clean": "rimraf dist", + "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", "package": "svelte-package", "prepublishOnly": "svelte-package", diff --git a/packages/tailwind/package.json b/packages/tailwind/package.json index c497637..169da63 100644 --- a/packages/tailwind/package.json +++ b/packages/tailwind/package.json @@ -6,8 +6,9 @@ "repository": "techniq/layerstack", "version": "2.0.0-next.22", "scripts": { - "dev": "rimraf dist && tsc -p tsconfig.build.json --watch", - "build": "rimraf dist && tsc -p tsconfig.build.json && pnpm build:css && cp -r ./src/lib/css dist", + "dev": "tsc -p tsconfig.build.json --watch", + "clean": "rimraf dist", + "build": "pnpm clean && tsc -p tsconfig.build.json && pnpm build:css && cp -r ./src/lib/css dist", "build:css": "tsc --noEmit && tsx ./src/lib/cli/index.ts", "preview": "vite preview", "package": "svelte-package", diff --git a/packages/utils/package.json b/packages/utils/package.json index 413400f..fb0a82a 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -6,8 +6,9 @@ "repository": "techniq/layerstack", "version": "2.0.0-next.18", "scripts": { - "dev": "rimraf dist && tsc -p tsconfig.build.json --watch", - "build": "rimraf dist && tsc -p tsconfig.build.json", + "dev": "tsc -p tsconfig.build.json --watch", + "clean": "rimraf dist", + "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", "package": "svelte-package", "prepublishOnly": "svelte-package", From ebb151d536657f4a2467a0344b3cfc929bc25640 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 09:12:46 -0400 Subject: [PATCH 02/21] Initial @layerstack/docs setup --- .gitignore | 7 + packages/docs/README.md | 80 + packages/docs/bin/layerstack-docs.js | 23 + packages/docs/package.json | 182 ++ packages/docs/src/app.d.ts | 10 + packages/docs/src/cli.ts | 174 ++ packages/docs/src/lib/api-types.ts | 32 + packages/docs/src/lib/catalog.ts | 66 + packages/docs/src/lib/collections.ts | 11 + .../docs/src/lib/components/Blockquote.svelte | 17 + packages/docs/src/lib/components/Code.svelte | 175 ++ .../src/lib/components/ComponentLink.svelte | 75 + .../src/lib/components/ExampleLink.svelte | 63 + .../src/lib/components/ExampleListing.svelte | 173 ++ .../lib/components/ExampleScreenshot.svelte | 70 + .../docs/src/lib/components/ImageLink.svelte | 61 + packages/docs/src/lib/components/Json.svelte | 36 + .../lib/components/LoadingPlaceholder.svelte | 8 + .../src/lib/components/OpenWithButton.svelte | 221 ++ .../src/lib/components/RelatedLink.svelte | 59 + packages/docs/src/lib/components/Step.svelte | 36 + packages/docs/src/lib/components/Steps.svelte | 9 + .../src/lib/components/TableOfContents.svelte | 78 + packages/docs/src/lib/components/Tabs.svelte | 62 + .../lib/components/ViewSourceButton.svelte | 53 + packages/docs/src/lib/components/index.js | 16 + .../docs/src/lib/content-collections/index.js | 318 ++ packages/docs/src/lib/content.ts | 159 + packages/docs/src/lib/context.ts | 4 + packages/docs/src/lib/examples-glob.ts | 35 + packages/docs/src/lib/examples.ts | 109 + packages/docs/src/lib/index.js | 10 + .../blueprints/default/blueprint.svelte | 30 + .../src/lib/markdown/components/Button.svelte | 38 + .../lib/markdown/components/LiveCode.svelte | 20 + .../src/lib/markdown/components/Note.svelte | 39 + .../src/lib/markdown/components/Steps.svelte | 9 + .../src/lib/markdown/components/Tab.svelte | 34 + .../src/lib/markdown/components/Tabs.svelte | 109 + .../docs/src/lib/markdown/components/a.svelte | 26 + .../lib/markdown/components/blockquote.svelte | 17 + .../src/lib/markdown/components/code.svelte | 10 + .../src/lib/markdown/components/h-base.svelte | 23 + .../src/lib/markdown/components/h1.svelte | 9 + .../src/lib/markdown/components/h2.svelte | 13 + .../src/lib/markdown/components/h3.svelte | 13 + .../src/lib/markdown/components/h4.svelte | 13 + .../src/lib/markdown/components/img.svelte | 8 + .../docs/src/lib/markdown/components/index.js | 25 + .../src/lib/markdown/components/li.svelte | 10 + .../src/lib/markdown/components/ol.svelte | 10 + .../docs/src/lib/markdown/components/p.svelte | 10 + .../src/lib/markdown/components/pre.svelte | 84 + .../src/lib/markdown/components/strong.svelte | 5 + .../src/lib/markdown/components/table.svelte | 12 + .../src/lib/markdown/components/td.svelte | 16 + .../src/lib/markdown/components/th.svelte | 16 + .../src/lib/markdown/components/tr.svelte | 10 + .../src/lib/markdown/components/ul.svelte | 10 + .../docs/src/lib/markdown/config/index.js | 95 + .../src/lib/markdown/config/pretty-code.js | 18 + packages/docs/src/lib/markdown/index.js | 2 + .../lib/markdown/rehype/component-example.js | 98 + .../lib/markdown/rehype/handle-code-blocks.js | 76 + .../docs/src/lib/markdown/rehype/live-code.js | 158 + .../src/lib/markdown/remark/components.js | 262 ++ packages/docs/src/lib/markdown/toc.ts | 31 + .../lib/markdown/transformers/shiki-diff.js | 46 + packages/docs/src/lib/markdown/utils.ts | 36 + packages/docs/src/lib/node/component-api.js | 506 +++ packages/docs/src/lib/node/example-catalog.js | 258 ++ packages/docs/src/lib/node/releases.js | 118 + packages/docs/src/lib/node/screenshots.js | 430 +++ packages/docs/src/lib/node/stackblitz.js | 113 + packages/docs/src/lib/page-transitions.ts | 16 + packages/docs/src/lib/project-stats.ts | 108 + packages/docs/src/lib/styles.css | 105 + packages/docs/src/lib/utils/string.ts | 17 + packages/docs/svelte.config.js | 11 + .../templates/stackblitz-template/.gitignore | 20 + .../templates/stackblitz-template/README.md | 28 + .../stackblitz-template/package.json | 35 + .../templates/stackblitz-template/src/app.css | 6 + .../stackblitz-template/src/app.html | 56 + .../src/routes/+layout.svelte | 9 + .../stackblitz-template/svelte.config.js | 21 + .../stackblitz-template/vite.config.js | 14 + packages/docs/tsconfig.json | 15 + packages/svelte-actions/package.json | 2 +- packages/svelte-state/package.json | 2 +- packages/svelte-stores/package.json | 2 +- packages/svelte-table/package.json | 2 +- packages/tailwind/package.json | 2 +- packages/utils/package.json | 2 +- pnpm-lock.yaml | 2719 +++++++++++++++-- sites/docs/content-collections.ts | 11 + sites/docs/mdsx.config.js | 7 + sites/docs/package.json | 12 +- .../reference/svelte-stores/debounceStore.md | 8 + .../components/debounceStore/basic.svelte | 12 + sites/docs/src/lib/components/Example.svelte | 81 + sites/docs/src/lib/content.ts | 32 + sites/docs/src/lib/examples.ts | 26 + sites/docs/src/routes/app.css | 2 + sites/docs/src/routes/docs/+layout.svelte | 5 + .../docs/[packageName]/[name]/+page.svelte | 97 + .../routes/docs/[packageName]/[name]/+page.ts | 13 + .../[packageName]/[name]/llms.txt/+server.ts | 14 + .../docs/svelte-stores/debounceStore/+page.md | 30 - .../docs/svelte-stores/debounceStore/+page.ts | 12 - sites/docs/svelte.config.js | 11 +- sites/docs/vite.config.js | 3 +- 112 files changed, 8627 insertions(+), 239 deletions(-) create mode 100644 packages/docs/README.md create mode 100755 packages/docs/bin/layerstack-docs.js create mode 100644 packages/docs/package.json create mode 100644 packages/docs/src/app.d.ts create mode 100644 packages/docs/src/cli.ts create mode 100644 packages/docs/src/lib/api-types.ts create mode 100644 packages/docs/src/lib/catalog.ts create mode 100644 packages/docs/src/lib/collections.ts create mode 100644 packages/docs/src/lib/components/Blockquote.svelte create mode 100644 packages/docs/src/lib/components/Code.svelte create mode 100644 packages/docs/src/lib/components/ComponentLink.svelte create mode 100644 packages/docs/src/lib/components/ExampleLink.svelte create mode 100644 packages/docs/src/lib/components/ExampleListing.svelte create mode 100644 packages/docs/src/lib/components/ExampleScreenshot.svelte create mode 100644 packages/docs/src/lib/components/ImageLink.svelte create mode 100644 packages/docs/src/lib/components/Json.svelte create mode 100644 packages/docs/src/lib/components/LoadingPlaceholder.svelte create mode 100644 packages/docs/src/lib/components/OpenWithButton.svelte create mode 100644 packages/docs/src/lib/components/RelatedLink.svelte create mode 100644 packages/docs/src/lib/components/Step.svelte create mode 100644 packages/docs/src/lib/components/Steps.svelte create mode 100644 packages/docs/src/lib/components/TableOfContents.svelte create mode 100644 packages/docs/src/lib/components/Tabs.svelte create mode 100644 packages/docs/src/lib/components/ViewSourceButton.svelte create mode 100644 packages/docs/src/lib/components/index.js create mode 100644 packages/docs/src/lib/content-collections/index.js create mode 100644 packages/docs/src/lib/content.ts create mode 100644 packages/docs/src/lib/context.ts create mode 100644 packages/docs/src/lib/examples-glob.ts create mode 100644 packages/docs/src/lib/examples.ts create mode 100644 packages/docs/src/lib/index.js create mode 100644 packages/docs/src/lib/markdown/blueprints/default/blueprint.svelte create mode 100644 packages/docs/src/lib/markdown/components/Button.svelte create mode 100644 packages/docs/src/lib/markdown/components/LiveCode.svelte create mode 100644 packages/docs/src/lib/markdown/components/Note.svelte create mode 100644 packages/docs/src/lib/markdown/components/Steps.svelte create mode 100644 packages/docs/src/lib/markdown/components/Tab.svelte create mode 100644 packages/docs/src/lib/markdown/components/Tabs.svelte create mode 100644 packages/docs/src/lib/markdown/components/a.svelte create mode 100644 packages/docs/src/lib/markdown/components/blockquote.svelte create mode 100644 packages/docs/src/lib/markdown/components/code.svelte create mode 100644 packages/docs/src/lib/markdown/components/h-base.svelte create mode 100644 packages/docs/src/lib/markdown/components/h1.svelte create mode 100644 packages/docs/src/lib/markdown/components/h2.svelte create mode 100644 packages/docs/src/lib/markdown/components/h3.svelte create mode 100644 packages/docs/src/lib/markdown/components/h4.svelte create mode 100644 packages/docs/src/lib/markdown/components/img.svelte create mode 100644 packages/docs/src/lib/markdown/components/index.js create mode 100644 packages/docs/src/lib/markdown/components/li.svelte create mode 100644 packages/docs/src/lib/markdown/components/ol.svelte create mode 100644 packages/docs/src/lib/markdown/components/p.svelte create mode 100644 packages/docs/src/lib/markdown/components/pre.svelte create mode 100644 packages/docs/src/lib/markdown/components/strong.svelte create mode 100644 packages/docs/src/lib/markdown/components/table.svelte create mode 100644 packages/docs/src/lib/markdown/components/td.svelte create mode 100644 packages/docs/src/lib/markdown/components/th.svelte create mode 100644 packages/docs/src/lib/markdown/components/tr.svelte create mode 100644 packages/docs/src/lib/markdown/components/ul.svelte create mode 100644 packages/docs/src/lib/markdown/config/index.js create mode 100644 packages/docs/src/lib/markdown/config/pretty-code.js create mode 100644 packages/docs/src/lib/markdown/index.js create mode 100644 packages/docs/src/lib/markdown/rehype/component-example.js create mode 100644 packages/docs/src/lib/markdown/rehype/handle-code-blocks.js create mode 100644 packages/docs/src/lib/markdown/rehype/live-code.js create mode 100644 packages/docs/src/lib/markdown/remark/components.js create mode 100644 packages/docs/src/lib/markdown/toc.ts create mode 100644 packages/docs/src/lib/markdown/transformers/shiki-diff.js create mode 100644 packages/docs/src/lib/markdown/utils.ts create mode 100644 packages/docs/src/lib/node/component-api.js create mode 100644 packages/docs/src/lib/node/example-catalog.js create mode 100644 packages/docs/src/lib/node/releases.js create mode 100644 packages/docs/src/lib/node/screenshots.js create mode 100644 packages/docs/src/lib/node/stackblitz.js create mode 100644 packages/docs/src/lib/page-transitions.ts create mode 100644 packages/docs/src/lib/project-stats.ts create mode 100644 packages/docs/src/lib/styles.css create mode 100644 packages/docs/src/lib/utils/string.ts create mode 100644 packages/docs/svelte.config.js create mode 100644 packages/docs/templates/stackblitz-template/.gitignore create mode 100644 packages/docs/templates/stackblitz-template/README.md create mode 100644 packages/docs/templates/stackblitz-template/package.json create mode 100644 packages/docs/templates/stackblitz-template/src/app.css create mode 100644 packages/docs/templates/stackblitz-template/src/app.html create mode 100644 packages/docs/templates/stackblitz-template/src/routes/+layout.svelte create mode 100644 packages/docs/templates/stackblitz-template/svelte.config.js create mode 100644 packages/docs/templates/stackblitz-template/vite.config.js create mode 100644 packages/docs/tsconfig.json create mode 100644 sites/docs/content-collections.ts create mode 100644 sites/docs/mdsx.config.js create mode 100644 sites/docs/src/content/reference/svelte-stores/debounceStore.md create mode 100644 sites/docs/src/examples/components/debounceStore/basic.svelte create mode 100644 sites/docs/src/lib/components/Example.svelte create mode 100644 sites/docs/src/lib/content.ts create mode 100644 sites/docs/src/lib/examples.ts create mode 100644 sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte create mode 100644 sites/docs/src/routes/docs/[packageName]/[name]/+page.ts create mode 100644 sites/docs/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/debounceStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/debounceStore/+page.ts diff --git a/.gitignore b/.gitignore index 5535d88..a825ad2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,11 @@ coverage/ .env .DS_Store +# Generated by @content-collections and the docs markdown live-code pipeline +.content-collections/ +.live-code/ + +# Playwright MCP run artifacts +.playwright-mcp/ + test-* \ No newline at end of file diff --git a/packages/docs/README.md b/packages/docs/README.md new file mode 100644 index 0000000..d95d3e5 --- /dev/null +++ b/packages/docs/README.md @@ -0,0 +1,80 @@ +# @layerstack/docs + +Reusable documentation framework and tooling for LayerStack projects (LayerStack, LayerChart, …). + +It provides: + +- **Markdown rendering** — a shared [mdsx](https://github.com/huntabyte/mdsx) config (`createMdsxConfig`) with GFM, MDC directives, [Shiki](https://shiki.style/) syntax highlighting, automatic heading slugs, and a set of styled markdown element components. +- **Content collections** — a [`@content-collections`](https://www.content-collections.dev/) config factory (`createContentConfig`) that turns `src/content/**/*.md` into typed collections (components, utils, guides, references, releases) with TOC, source links, and generated API/catalog data. +- **Doc UI components** — `Code`, `Json`, `TableOfContents`, `ViewSourceButton`, `ExampleLink`, `ExampleListing`, `RelatedLink`, `LoadingPlaceholder`, etc. +- **Example/content loaders** — `createExampleLoaders` / `createContentLoaders` to wire a docs app's `import.meta.glob` to the framework. +- **CLI (`layerstack-docs`)** — build-time generators for component API JSON, example catalogs, screenshots, StackBlitz projects, and release notes. + +## Usage + +A docs app depends on this package via `workspace:*` (in this monorepo) or `link:` (cross-repo), and follows this convention: + +``` +docs-app/ + content-collections.ts # createContentConfig({ packageName, repo }) + mdsx.config.js # createMdsxConfig({ exampleComponentPath }) + src/ + content/ # *.md docs (components/, utils/, guides/, reference/) + examples/ # *.svelte examples referenced from markdown + lib/ + content.ts # createContentLoaders(...) + examples.ts # createExampleLoaders(...) + generated/ # CLI output (api/, releases/) +``` + +### Markdown (`mdsx.config.js`) + +```js +import { createMdsxConfig } from '@layerstack/docs/markdown/config'; + +export const mdsxConfig = createMdsxConfig({ + exampleComponentPath: '$lib/components' +}); +``` + +The `reference` collection infers each doc's source file from its path by convention — +`src/content/reference//.md` → `packages//src/lib/.{ts,svelte.ts}` +(with a camelCase fallback, e.g. `Duration` → `duration.ts`, `SelectionState` → `selectionState.svelte.ts`). +Add a `sourceFile:` frontmatter (relative to `packages/`) only to override the inferred path. + +### Content collections (`content-collections.ts`) + +```ts +import { createContentConfig } from '@layerstack/docs/content-collections'; + +export default createContentConfig({ + packageName: 'layerstack', + repo: 'techniq/layerstack' +}); +``` + +### Styles (`app.css`) + +```css +@import 'tailwindcss'; +@import '@layerstack/tailwind/core.css'; +@import '@layerstack/tailwind/utils.css'; +@import '@layerstack/tailwind/themes/all.css'; +@import '@layerstack/docs/styles.css'; +``` + +### CLI + +```jsonc +{ + "scripts": { + "generate:api": "layerstack-docs generate-api ../packages//src/lib/components generated/api", + "generate:catalog": "layerstack-docs generate-catalog ../packages//src/lib/components src/examples/components src/examples/catalog", + "generate:screenshots": "layerstack-docs generate-screenshots src/examples/components static/screenshots", + "generate:stackblitz": "layerstack-docs generate-stackblitz src static/stackblitz-files.json [remote-sources.json]", + "generate:releases": "layerstack-docs generate-releases techniq/ generated/releases" + } +} +``` + +`generate-stackblitz` uses this package's bundled template at `templates/stackblitz-template` by default; `--template-dir` overrides it. diff --git a/packages/docs/bin/layerstack-docs.js b/packages/docs/bin/layerstack-docs.js new file mode 100755 index 0000000..cddfb5f --- /dev/null +++ b/packages/docs/bin/layerstack-docs.js @@ -0,0 +1,23 @@ +#!/usr/bin/env node +/** + * Thin launcher that runs the TypeScript CLI (`src/cli.ts`) through `tsx`, + * resolved from this package's own dependencies (no global install required). + */ +import { spawn } from 'node:child_process'; +import { createRequire } from 'node:module'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const cliPath = join(__dirname, '../src/cli.ts'); + +const require = createRequire(import.meta.url); +const tsxPkgPath = require.resolve('tsx/package.json'); +const tsxPkg = require(tsxPkgPath); +const binRel = typeof tsxPkg.bin === 'string' ? tsxPkg.bin : tsxPkg.bin.tsx; +const tsxBin = join(dirname(tsxPkgPath), binRel); + +const child = spawn(process.execPath, [tsxBin, cliPath, ...process.argv.slice(2)], { + stdio: 'inherit' +}); +child.on('exit', (code) => process.exit(code ?? 0)); diff --git a/packages/docs/package.json b/packages/docs/package.json new file mode 100644 index 0000000..bc5098f --- /dev/null +++ b/packages/docs/package.json @@ -0,0 +1,182 @@ +{ + "name": "@layerstack/docs", + "description": "Reusable documentation framework and tooling for LayerStack projects", + "author": "Sean Lynch ", + "license": "MIT", + "repository": "techniq/layerstack", + "private": true, + "version": "0.0.0", + "type": "module", + "bin": { + "layerstack-docs": "./bin/layerstack-docs.js" + }, + "scripts": { + "build": "svelte-package", + "package": "svelte-package", + "prepare": "svelte-kit sync", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --check .", + "format": "prettier --write ." + }, + "dependencies": { + "@content-collections/core": "^0.14.3", + "@content-collections/markdown": "^0.1.4", + "@iconify-json/simple-icons": "^1.2.84", + "@layerstack/tailwind": "workspace:*", + "@layerstack/utils": "workspace:*", + "@shikijs/transformers": "^4.1.0", + "@sveltejs/svelte-json-tree": "^2.2.1", + "@webcontainer/api": "^1.6.4", + "github-slugger": "^2.0.0", + "mdsx": "^0.0.7", + "playwright": "^1.60.0", + "rehype-pretty-code": "^0.14.3", + "rehype-slug": "^6.0.0", + "remark-gfm": "^4.0.1", + "remark-mdc": "^3.11.0", + "runed": "^0.37.1", + "sharp": "^0.34.5", + "shiki": "^4.1.0", + "svelte-ux": "2.0.0-next.22", + "tsx": "^4.22.3", + "typescript": "^5.8.3", + "unist-builder": "^4.0.0", + "unist-util-visit": "^5.1.0", + "zod": "^4.4.3" + }, + "devDependencies": { + "@sveltejs/kit": "^2.21.0", + "@sveltejs/package": "^2.3.11", + "@sveltejs/vite-plugin-svelte": "^5.0.3", + "@types/node": "^24.0.1", + "prettier": "^3.5.3", + "prettier-plugin-svelte": "^3.3.3", + "svelte": "^5.28.2", + "svelte-check": "^4.1.6", + "tslib": "^2.8.1", + "unplugin-icons": "^22.1.0", + "vite": "^6.3.5" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.0.0", + "svelte": "^5.0.0" + }, + "type": "module", + "main": "./dist/index.js", + "svelte": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "svelte": "./dist/index.js", + "default": "./dist/index.js" + }, + "./api": { + "types": "./dist/api-types.d.ts", + "default": "./dist/api-types.js" + }, + "./catalog": { + "types": "./dist/catalog.d.ts", + "default": "./dist/catalog.js" + }, + "./collections": { + "types": "./dist/collections.d.ts", + "default": "./dist/collections.js" + }, + "./content": { + "types": "./dist/content.d.ts", + "default": "./dist/content.js" + }, + "./context": { + "types": "./dist/context.d.ts", + "svelte": "./dist/context.js", + "default": "./dist/context.js" + }, + "./examples": { + "types": "./dist/examples.d.ts", + "default": "./dist/examples.js" + }, + "./examples-glob": { + "types": "./dist/examples-glob.d.ts", + "default": "./dist/examples-glob.js" + }, + "./page-transitions": { + "types": "./dist/page-transitions.d.ts", + "default": "./dist/page-transitions.js" + }, + "./project-stats": { + "types": "./dist/project-stats.d.ts", + "default": "./dist/project-stats.js" + }, + "./components": { + "types": "./dist/components/index.d.ts", + "svelte": "./dist/components/index.js", + "default": "./dist/components/index.js" + }, + "./components/*.svelte": { + "types": "./dist/components/*.svelte.d.ts", + "svelte": "./dist/components/*.svelte", + "default": "./dist/components/*.svelte" + }, + "./markdown": { + "types": "./dist/markdown/index.d.ts", + "default": "./dist/markdown/index.js" + }, + "./markdown/config": { + "types": "./dist/markdown/config/index.d.ts", + "default": "./dist/markdown/config/index.js" + }, + "./markdown/rehype/live-code": { + "types": "./dist/markdown/rehype/live-code.d.ts", + "default": "./dist/markdown/rehype/live-code.js" + }, + "./markdown/components": { + "types": "./dist/markdown/components/index.d.ts", + "svelte": "./dist/markdown/components/index.js", + "default": "./dist/markdown/components/index.js" + }, + "./markdown/components/*.svelte": { + "types": "./dist/markdown/components/*.svelte.d.ts", + "svelte": "./dist/markdown/components/*.svelte", + "default": "./dist/markdown/components/*.svelte" + }, + "./markdown/blueprints/default/blueprint.svelte": { + "types": "./dist/markdown/blueprints/default/blueprint.svelte.d.ts", + "svelte": "./dist/markdown/blueprints/default/blueprint.svelte", + "default": "./dist/markdown/blueprints/default/blueprint.svelte" + }, + "./content-collections": { + "types": "./dist/content-collections/index.d.ts", + "default": "./dist/content-collections/index.js" + }, + "./node/stackblitz": { + "types": "./dist/node/stackblitz.d.ts", + "default": "./dist/node/stackblitz.js" + }, + "./node/component-api": { + "types": "./dist/node/component-api.d.ts", + "default": "./dist/node/component-api.js" + }, + "./node/example-catalog": { + "types": "./dist/node/example-catalog.d.ts", + "default": "./dist/node/example-catalog.js" + }, + "./node/screenshots": { + "types": "./dist/node/screenshots.d.ts", + "default": "./dist/node/screenshots.js" + }, + "./node/releases": { + "types": "./dist/node/releases.d.ts", + "default": "./dist/node/releases.js" + }, + "./styles.css": "./dist/styles.css", + "./package.json": "./package.json" + }, + "files": [ + "dist", + "bin", + "src", + "templates" + ] +} diff --git a/packages/docs/src/app.d.ts b/packages/docs/src/app.d.ts new file mode 100644 index 0000000..777ed40 --- /dev/null +++ b/packages/docs/src/app.d.ts @@ -0,0 +1,10 @@ +/// +/// +/// + +// See https://svelte.dev/docs/kit/types#app.d.ts +declare global { + namespace App {} +} + +export {}; diff --git a/packages/docs/src/cli.ts b/packages/docs/src/cli.ts new file mode 100644 index 0000000..e3bfff5 --- /dev/null +++ b/packages/docs/src/cli.ts @@ -0,0 +1,174 @@ +/** + * `layerstack-docs` CLI — build-time generators for LayerStack docs apps. + * + * Commands: + * generate-api + * generate-catalog + * generate-screenshots [--base-url ] [--route-base ] [--all] + * generate-stackblitz [remote-sources-file] [--template-dir ] [--source out=src ...] [--remote out=src ...] + * generate-releases + */ +import { writeComponentAPIs } from './lib/node/component-api.js'; +import { writeExampleCatalogs } from './lib/node/example-catalog.js'; +import { generateScreenshots } from './lib/node/screenshots.js'; +import { + generateStackBlitzFiles, + getDefaultStackBlitzTemplateDir +} from './lib/node/stackblitz.js'; +import { generateReleases } from './lib/node/releases.js'; + +type ParsedArgs = { + positionals: string[]; + options: Record; + multi: Record; +}; + +/** Flags that may be repeated and collected into a list (e.g. `--source a=b --source c=d`). */ +const MULTI_FLAGS = new Set(['source', 'remote']); + +function parseArgs(argv: string[]): ParsedArgs { + const positionals: string[] = []; + const options: Record = {}; + const multi: Record = {}; + + for (let i = 0; i < argv.length; i++) { + const arg = argv[i]; + if (arg.startsWith('--')) { + let key = arg.slice(2); + let value: string | boolean; + const eq = key.indexOf('='); + if (eq !== -1) { + value = key.slice(eq + 1); + key = key.slice(0, eq); + } else if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) { + value = argv[++i]; + } else { + value = true; + } + if (MULTI_FLAGS.has(key) && typeof value === 'string') { + (multi[key] ??= []).push(value); + } else { + options[key] = value; + } + } else { + positionals.push(arg); + } + } + + return { positionals, options, multi }; +} + +/** Parse `output=source` pairs into a `{ [output]: source }` record. */ +function parseKeyValueList(items: string[] = []): Record { + const result: Record = {}; + for (const item of items) { + const eq = item.indexOf('='); + if (eq === -1) continue; + result[item.slice(0, eq)] = item.slice(eq + 1); + } + return result; +} + +function optString(options: Record, key: string): string | undefined { + const value = options[key]; + return typeof value === 'string' ? value : undefined; +} + +const HELP = `layerstack-docs [...args] + +Commands: + generate-api + generate-catalog + generate-screenshots [--base-url ] [--route-base ] [--all] + generate-stackblitz [remote-sources-file] + [--template-dir ] [--source out=src ...] [--remote out=src ...] + generate-releases +`; + +async function main() { + const [command, ...rest] = process.argv.slice(2); + const { positionals, options, multi } = parseArgs(rest); + + switch (command) { + case 'generate-api': { + const [componentsDir, outputDir] = positionals; + if (!componentsDir || !outputDir) { + throw new Error('Usage: layerstack-docs generate-api '); + } + writeComponentAPIs({ componentsDir, outputDir }); + break; + } + + case 'generate-catalog': { + const [componentsDir, examplesDir, catalogDir] = positionals; + if (!componentsDir || !examplesDir || !catalogDir) { + throw new Error( + 'Usage: layerstack-docs generate-catalog ' + ); + } + await writeExampleCatalogs({ componentsDir, examplesDir, catalogDir }); + break; + } + + case 'generate-screenshots': { + const [examplesDir, screenshotsDir] = positionals; + if (!examplesDir || !screenshotsDir) { + throw new Error( + 'Usage: layerstack-docs generate-screenshots ' + ); + } + await generateScreenshots({ + examplesDir, + screenshotsDir, + baseUrl: optString(options, 'base-url'), + routeBase: optString(options, 'route-base'), + forceAll: options['all'] === true + }); + break; + } + + case 'generate-stackblitz': { + const [sourceDir, outputFile, remoteSourcesFile] = positionals; + if (!sourceDir || !outputFile) { + throw new Error( + 'Usage: layerstack-docs generate-stackblitz [remote-sources-file]' + ); + } + const templateDir = optString(options, 'template-dir') ?? getDefaultStackBlitzTemplateDir(); + generateStackBlitzFiles({ + templateDir, + sourceDir, + outputFile, + remoteSourcesFile, + sources: parseKeyValueList(multi['source']), + remoteSources: parseKeyValueList(multi['remote']) + }); + break; + } + + case 'generate-releases': { + const [repo, outputDir] = positionals; + if (!repo || !outputDir) { + throw new Error('Usage: layerstack-docs generate-releases '); + } + await generateReleases({ repo, outputDir }); + break; + } + + case undefined: + case '--help': + case '-h': + console.log(HELP); + break; + + default: + console.error(`Unknown command: ${command}\n`); + console.log(HELP); + process.exit(1); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/docs/src/lib/api-types.ts b/packages/docs/src/lib/api-types.ts new file mode 100644 index 0000000..8b5f1cf --- /dev/null +++ b/packages/docs/src/lib/api-types.ts @@ -0,0 +1,32 @@ +/** + * Shared types for component API documentation + */ +export interface PropertyInfo { + name: string; + type: string; + required: boolean; + description?: string; + descriptionHtml?: string; + default?: string; + tags?: Record; + properties?: PropertyInfo[]; +} + +export interface ExtendedType { + name: string; + /** The full type expression, e.g., "SVGAttributes" */ + fullType: string; + /** For HTML/SVG element types, the element name, e.g., "SVGRectElement" */ + elementType?: string; + /** Whether this is a known library type that should be documented separately */ + isLibraryType?: boolean; +} + +export interface ComponentAPI { + generatedAt: string; + component: string; + propsType: string; + properties: PropertyInfo[]; + /** Types that are extended/intersected (e.g., CommonEvents, SVGAttributes) */ + extends?: ExtendedType[]; +} diff --git a/packages/docs/src/lib/catalog.ts b/packages/docs/src/lib/catalog.ts new file mode 100644 index 0000000..a4d6a8c --- /dev/null +++ b/packages/docs/src/lib/catalog.ts @@ -0,0 +1,66 @@ +/** + * Type definitions for LayerChart component catalogs + * + * These types describe the structure of catalog JSON files generated by + * the `layerstack-docs generate-catalog` command. + */ + +/** + * Information about a component usage within an example + */ +export interface ComponentUsageInExample { + /** The component name */ + component: string; + /** The line number where the component is used */ + lineNumber: number; + /** The trimmed line of code containing the component usage */ + line: string; +} + +/** + * Information about a specific example for a component + */ +export interface ExampleInfo { + /** The name of the example (filename without .svelte extension) */ + name: string; + /** Human-readable title (from + +
a]:font-medium [&>a]:underline [&>a]:decoration-dashed [&>a]:decoration-primary/50 [&>a]:underline-offset-2' + )} +> + + {@render children()} +
diff --git a/packages/docs/src/lib/components/Code.svelte b/packages/docs/src/lib/components/Code.svelte new file mode 100644 index 0000000..a1d90e7 --- /dev/null +++ b/packages/docs/src/lib/components/Code.svelte @@ -0,0 +1,175 @@ + + + + +
+ {#if title} +
+ {#if language === 'css'} + + {:else if language === 'javascript'} + + {:else if language === 'ts'} + + {:else if language === 'json'} + + {:else if language === 'sh' || language === 'bash'} + + {:else if language === 'svelte'} + + {:else if language === 'html'} + + {:else} + Icon ERROR: {language} + {/if} + {title} +
+ {/if} +
+ {#if source} +
+				
+					{#if highlighter}
+						
+						{@html highlighter.codeToHtml(
+							sourceStr,
+							{
+								lang: language,
+								themes: {
+									light: 'github-light-default',
+									dark: 'github-dark-default'
+								},
+								meta: highlight ? { __raw: `{${highlight}}` } : undefined,
+								transformers: highlight ? [transformerMetaHighlight()] : undefined
+							}
+						)}
+					{:else}
+						
Loading...
+ {/if} +
+
+ + {#if copyButton !== false} +
+ +
+ {/if} + {/if} +
+
+ + diff --git a/packages/docs/src/lib/components/ComponentLink.svelte b/packages/docs/src/lib/components/ComponentLink.svelte new file mode 100644 index 0000000..db3238f --- /dev/null +++ b/packages/docs/src/lib/components/ComponentLink.svelte @@ -0,0 +1,75 @@ + + + + {#snippet image()} + + {/snippet} + + {#snippet label()} + + + {component} + +
+ {#each supportedLayers ?? [] as layer} +
+ {layer} +
+ {/each} +
+ {/snippet} +
diff --git a/packages/docs/src/lib/components/ExampleLink.svelte b/packages/docs/src/lib/components/ExampleLink.svelte new file mode 100644 index 0000000..4e7f10e --- /dev/null +++ b/packages/docs/src/lib/components/ExampleLink.svelte @@ -0,0 +1,63 @@ + + + + {#snippet image()} + + {/snippet} + + {#snippet label()} + + + {#if showComponent} + {component} + + {/if} + {title ?? example.replaceAll('-', ' ')} + {/snippet} + diff --git a/packages/docs/src/lib/components/ExampleListing.svelte b/packages/docs/src/lib/components/ExampleListing.svelte new file mode 100644 index 0000000..cce26e1 --- /dev/null +++ b/packages/docs/src/lib/components/ExampleListing.svelte @@ -0,0 +1,173 @@ + + +{#if hasContent} +
+

{title}

+
+ {#if viewAllHref && catalog.examples?.length} + + {/if} + + + {#snippet prepend()} + + {/snippet} + + +
+
+
+
+ + {#if examples.length} +
+ {#each examples as example (example.name)} + + {/each} +
+ {:else if catalog.examples?.length} +

No examples match your filter.

+ {/if} + + {#if uniqueUsage.length} + {#if examples.length} + + {showDetails ? 'show less' : 'show more'}... +
+
+ {#each uniqueUsage as usage (`${usage.component}::${usage.example}`)} + + {/each} +
+
+
+ {:else if catalog.examples?.length === 0} +
+ {#each uniqueUsage as usage (`${usage.component}::${usage.example}`)} + + {/each} +
+ {:else if catalog.usage?.length} +

+ No additional usage examples match your filter. +

+ {/if} + {/if} +{/if} diff --git a/packages/docs/src/lib/components/ExampleScreenshot.svelte b/packages/docs/src/lib/components/ExampleScreenshot.svelte new file mode 100644 index 0000000..3c8b90a --- /dev/null +++ b/packages/docs/src/lib/components/ExampleScreenshot.svelte @@ -0,0 +1,70 @@ + + +
+ {#if hasError && fallbackIcon} + {@const FallbackIcon = fallbackIcon} +
+ +
+ {:else if !hasError} + {#each ['light', 'dark'] as mode (mode)} + {#each sizes as size (size.width)} + {component} - {example} (hasError = true)} + /> + {/each} + {/each} + {/if} +
diff --git a/packages/docs/src/lib/components/ImageLink.svelte b/packages/docs/src/lib/components/ImageLink.svelte new file mode 100644 index 0000000..2f060b0 --- /dev/null +++ b/packages/docs/src/lib/components/ImageLink.svelte @@ -0,0 +1,61 @@ + + + + {#if image} +
+ {@render image()} +
+ {/if} + + {#if label && variant !== 'screenshot-only'} +

+ + {@render label()} + + + +

+ {/if} +
diff --git a/packages/docs/src/lib/components/Json.svelte b/packages/docs/src/lib/components/Json.svelte new file mode 100644 index 0000000..7d6335c --- /dev/null +++ b/packages/docs/src/lib/components/Json.svelte @@ -0,0 +1,36 @@ + + +
+ +
diff --git a/packages/docs/src/lib/components/LoadingPlaceholder.svelte b/packages/docs/src/lib/components/LoadingPlaceholder.svelte new file mode 100644 index 0000000..fb31a55 --- /dev/null +++ b/packages/docs/src/lib/components/LoadingPlaceholder.svelte @@ -0,0 +1,8 @@ + + +
+ + Loading... +
diff --git a/packages/docs/src/lib/components/OpenWithButton.svelte b/packages/docs/src/lib/components/OpenWithButton.svelte new file mode 100644 index 0000000..97e92e4 --- /dev/null +++ b/packages/docs/src/lib/components/OpenWithButton.svelte @@ -0,0 +1,221 @@ + + + + + + + + + + (openSourceModal = false)} + class="max-h-[98dvh] md:max-h-[90dvh] max-w-[98vw] md:max-w-[90vw] grid grid-rows-[auto_1fr_auto]" +> +
+
+
Source
+
{sourceUrl}
+
+ + {#if sourceUrl} + + {/if} +
+ +
+ +
+ +
+ +
+
+ + (openMarkdownModal = false)} + class="max-h-[98dvh] md:max-h-[90dvh] max-w-[98vw] md:max-w-[90vw] grid grid-rows-[auto_1fr_auto]" +> +
+
+
Page Markdown
+
{pageUrl}/llms.txt
+
+ + +
+ +
+ +
+ +
+ +
+
diff --git a/packages/docs/src/lib/components/RelatedLink.svelte b/packages/docs/src/lib/components/RelatedLink.svelte new file mode 100644 index 0000000..3039bdd --- /dev/null +++ b/packages/docs/src/lib/components/RelatedLink.svelte @@ -0,0 +1,59 @@ + + +{#if type === 'component'} + +{:else} + +{/if} diff --git a/packages/docs/src/lib/components/Step.svelte b/packages/docs/src/lib/components/Step.svelte new file mode 100644 index 0000000..51a1696 --- /dev/null +++ b/packages/docs/src/lib/components/Step.svelte @@ -0,0 +1,36 @@ + + +
+
+
+
+
+

+ {@html title} +

+ {@render children?.()} +
+ + diff --git a/packages/docs/src/lib/components/Steps.svelte b/packages/docs/src/lib/components/Steps.svelte new file mode 100644 index 0000000..162915b --- /dev/null +++ b/packages/docs/src/lib/components/Steps.svelte @@ -0,0 +1,9 @@ + + +
+ {@render children?.()} +
diff --git a/packages/docs/src/lib/components/TableOfContents.svelte b/packages/docs/src/lib/components/TableOfContents.svelte new file mode 100644 index 0000000..30d6a87 --- /dev/null +++ b/packages/docs/src/lib/components/TableOfContents.svelte @@ -0,0 +1,78 @@ + + +{#if items.length} + +{/if} diff --git a/packages/docs/src/lib/components/Tabs.svelte b/packages/docs/src/lib/components/Tabs.svelte new file mode 100644 index 0000000..071a9e5 --- /dev/null +++ b/packages/docs/src/lib/components/Tabs.svelte @@ -0,0 +1,62 @@ + + + + {#each keys as key, v} + {@const isActive = value === v} + {@const Icon = icons?.[v] ?? null} + (value = v)} + selected={isActive} + >{#if Icon}{:else}{/if}{key} + {/each} + +
+ {@render content?.(value)} +
+
+
diff --git a/packages/docs/src/lib/components/ViewSourceButton.svelte b/packages/docs/src/lib/components/ViewSourceButton.svelte new file mode 100644 index 0000000..140c788 --- /dev/null +++ b/packages/docs/src/lib/components/ViewSourceButton.svelte @@ -0,0 +1,53 @@ + + +{#if source} + + + +
+
+
{label}
+
{href}
+
+ + {#if href} + + {/if} +
+ +
+ +
+ +
+ +
+
+
+{:else if href} + + + +{/if} diff --git a/packages/docs/src/lib/components/index.js b/packages/docs/src/lib/components/index.js new file mode 100644 index 0000000..94c2e6c --- /dev/null +++ b/packages/docs/src/lib/components/index.js @@ -0,0 +1,16 @@ +export { default as Blockquote } from './Blockquote.svelte'; +export { default as Code } from './Code.svelte'; +export { default as ComponentLink } from './ComponentLink.svelte'; +export { default as ExampleLink } from './ExampleLink.svelte'; +export { default as ExampleListing } from './ExampleListing.svelte'; +export { default as ExampleScreenshot } from './ExampleScreenshot.svelte'; +export { default as ImageLink } from './ImageLink.svelte'; +export { default as Json } from './Json.svelte'; +export { default as LoadingPlaceholder } from './LoadingPlaceholder.svelte'; +export { default as OpenWithButton } from './OpenWithButton.svelte'; +export { default as RelatedLink } from './RelatedLink.svelte'; +export { default as Step } from './Step.svelte'; +export { default as Steps } from './Steps.svelte'; +export { default as TableOfContents } from './TableOfContents.svelte'; +export { default as Tabs } from './Tabs.svelte'; +export { default as ViewSourceButton } from './ViewSourceButton.svelte'; diff --git a/packages/docs/src/lib/content-collections/index.js b/packages/docs/src/lib/content-collections/index.js new file mode 100644 index 0000000..0dcf171 --- /dev/null +++ b/packages/docs/src/lib/content-collections/index.js @@ -0,0 +1,318 @@ +import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; +import { join } from 'node:path'; +import { defineCollection, defineConfig } from '@content-collections/core'; +import { compileMarkdown } from '@content-collections/markdown'; +import { toPascalCase } from '@layerstack/utils'; +import { z } from 'zod'; +import rehypePrettyCode from 'rehype-pretty-code'; +import remarkGfm from 'remark-gfm'; +import { extractTocFromMarkdown } from '../markdown/index.js'; +import { prettyCodeOptions } from '../markdown/config/pretty-code.js'; +import { getFirstExampleName } from '../content.js'; +export const componentSchema = z.object({ + name: z.string().optional(), + description: z.string().optional(), + category: z.string().optional(), + layers: z.array(z.string()).default([]), + /** + * Whether the component renders inside an `` layer. + */ + withinLayer: z.boolean().default(true), + related: z.array(z.string()).default([]), + resize: z.boolean().optional(), + tableOfContents: z.boolean().default(true), + order: z.number().optional(), + content: z.string() +}); +export const utilSchema = z.object({ + name: z.string().optional(), + description: z.string().optional(), + category: z.string().optional(), + layers: z.array(z.string()).default([]), + related: z.array(z.string()).default([]), + resize: z.boolean().optional(), + tableOfContents: z.boolean().default(true), + order: z.number().optional(), + content: z.string() +}); +export const guideSchema = z.object({ + title: z.string(), + description: z.string().optional(), + category: z.string().optional(), + order: z.number().optional(), + draft: z.boolean().default(false), + content: z.string() +}); +export const referenceSchema = z.object({ + title: z.string(), + description: z.string().optional(), + category: z.string().optional(), + packageName: z.string().optional(), + kind: z.string().optional(), + sourceFile: z.string().optional(), + related: z.array(z.string()).default([]), + features: z.array(z.string()).optional(), + hideUsage: z.boolean().optional(), + hideTableOfContents: z.boolean().optional(), + tableOfContents: z.boolean().default(true), + status: z.string().optional(), + order: z.number().optional(), + draft: z.boolean().default(false), + content: z.string() +}); +export const releaseSchema = z.object({ + title: z.string(), + tag: z.string(), + date: z.coerce.date(), + url: z.string(), + draft: z.boolean().default(false), + prerelease: z.boolean().default(false), + author: z.string(), + content: z.string() +}); +function sourceBase(options) { + return `https://github.com/${options.repo}/blob/${options.branch}/packages/${options.packageName}/src/lib`; +} +function readSource(root, sourceUrlBase, rel) { + const full = join(root, rel); + if (!existsSync(full)) + return null; + try { + return { + source: readFileSync(full, 'utf-8'), + url: `${sourceUrlBase}/${rel}` + }; + } + catch { + return null; + } +} +function normalizeOptions(options) { + return { + packageName: options.packageName, + repo: options.repo ?? `techniq/${options.packageName}`, + branch: options.branch ?? 'next', + packagesRoot: options.packagesRoot ?? '../packages', + referenceDirectory: options.referenceDirectory ?? 'src/content/reference' + }; +} +export function createContentConfig(options) { + const normalized = normalizeOptions(options); + const packagesRoot = join(process.cwd(), normalized.packagesRoot); + const packageRoot = join(packagesRoot, `${normalized.packageName}/src/lib`); + const githubBase = sourceBase(normalized); + const components = defineCollection({ + name: 'components', + directory: 'src/content/components', + include: '**/*.md', + schema: componentSchema, + transform: async (doc, context) => { + const { fileName, path } = doc._meta; + const name = doc.name ?? toPascalCase(fileName.replace('.md', '')); + const componentsRoot = join(packageRoot, 'components'); + const componentsSourceBase = `${githubBase}/components`; + const subdirs = existsSync(componentsRoot) + ? readdirSync(componentsRoot).filter((entry) => !entry.startsWith('.') && statSync(join(componentsRoot, entry)).isDirectory()) + : []; + const searchDirs = ['', ...subdirs.map((d) => `${d}/`)]; + const sources = {}; + const sourceUrls = {}; + let primary = null; + let splitDir = ''; + for (const dir of searchDirs) { + const hit = readSource(componentsRoot, componentsSourceBase, `${dir}${path}/${path}.base.svelte`) ?? + readSource(componentsRoot, componentsSourceBase, `${dir}${path}/${path}.svelte`) ?? + readSource(componentsRoot, componentsSourceBase, `${dir}${path}.svelte`); + if (hit) { + primary = hit; + splitDir = `${dir}${path}/`; + break; + } + } + if (primary && !primary.url.endsWith('.base.svelte')) { + for (const layer of ['svg', 'canvas', 'html']) { + const variant = readSource(componentsRoot, componentsSourceBase, `${splitDir}${path}.${layer}.svelte`); + if (variant) { + sources[layer] = variant.source; + sourceUrls[layer] = variant.url; + } + } + } + const toc = extractTocFromMarkdown(doc.content); + const catalogPath = join(process.cwd(), `src/examples/catalog/${path}.json`); + let catalogFirstExample; + if (existsSync(catalogPath)) { + if (!toc.some((t) => t.id === 'examples')) { + toc.push({ id: 'examples', text: 'Examples', level: 2 }); + } + try { + const catalog = JSON.parse(readFileSync(catalogPath, 'utf-8')); + catalogFirstExample = catalog.examples?.[0]?.name; + } + catch { + // ignore malformed generated catalog files + } + } + const apiPath = join(process.cwd(), `generated/api/${path}.json`); + let api = null; + if (existsSync(apiPath)) { + try { + api = JSON.parse(readFileSync(apiPath, 'utf-8')); + const renderInline = async (text) => { + const html = await compileMarkdown(context, { ...doc, content: text }, { + remarkPlugins: [remarkGfm] + }); + return html + .replace(/^

/, '') + .replace(/<\/p>\s*$/, '') + .trim(); + }; + const walk = async (props = []) => { + for (const p of props) { + if (p.description) + p.descriptionHtml = await renderInline(p.description); + if (p.properties) + await walk(p.properties); + } + }; + await walk(api.properties); + if (api.properties?.length) { + toc.push({ id: 'api-reference', text: 'API Reference', level: 2 }); + } + } + catch { + // ignore malformed generated API files + } + } + if (doc.related.length) { + toc.push({ id: 'related', text: 'Related', level: 2 }); + } + return { + ...doc, + name, + slug: path, + source: primary?.source ?? '', + sourceUrl: primary?.url ?? '', + sources, + sourceUrls, + defaultExample: getFirstExampleName(doc.content) ?? catalogFirstExample, + toc, + api + }; + } + }); + const utils = defineCollection({ + name: 'utils', + directory: 'src/content/utils', + include: '**/*.md', + schema: utilSchema, + transform: async (doc) => { + const { fileName, path } = doc._meta; + const source = readSource(join(packageRoot, 'utils'), `${githubBase}/utils`, `${path}.ts`); + return { + ...doc, + name: doc.name ?? fileName.replace('.md', ''), + slug: fileName.replace('.md', '').toLowerCase(), + source: source?.source ?? '', + sourceUrl: source?.url ?? '', + toc: extractTocFromMarkdown(doc.content) + }; + } + }); + const guides = defineCollection({ + name: 'guides', + directory: 'src/content/guides', + include: '**/*.md', + schema: guideSchema, + transform: async (doc) => { + const { path } = doc._meta; + return { + ...doc, + name: doc.title, + slug: path, + toc: extractTocFromMarkdown(doc.content) + }; + } + }); + const references = defineCollection({ + name: 'references', + directory: normalized.referenceDirectory, + include: '**/*.md', + schema: referenceSchema, + transform: async (doc) => { + const { path } = doc._meta; + const referenceSourceBase = `https://github.com/${normalized.repo}/blob/${normalized.branch}/packages`; + + // Explicit `sourceFile` (relative to `packages/`) always wins. Otherwise infer + // the source from the conventional `/src/lib/.{ts,svelte.ts}` location + // derived from the doc path (e.g. `svelte-stores/debounceStore`). A camelCase fallback + // covers PascalCase items (`utils/Duration` -> `duration.ts`, + // `svelte-state/SelectionState` -> `selectionState.svelte.ts`). + const explicit = doc.sourceFile?.replace(/^\/?packages\//, '').replace(/^\//, ''); + let source = null; + let sourceFile = explicit; + + if (explicit) { + source = readSource(packagesRoot, referenceSourceBase, explicit); + } else { + const segments = path.split('/'); + const pkg = segments[0]; + const rest = segments.slice(1); + if (pkg && rest.length) { + const dir = rest.slice(0, -1).join('/'); + const item = rest[rest.length - 1]; + const camelItem = item.charAt(0).toLowerCase() + item.slice(1); + const prefix = `${pkg}/src/lib/${dir ? `${dir}/` : ''}`; + const candidates = [ + `${prefix}${item}.ts`, + `${prefix}${item}.svelte.ts`, + `${prefix}${camelItem}.ts`, + `${prefix}${camelItem}.svelte.ts` + ]; + for (const candidate of candidates) { + const hit = readSource(packagesRoot, referenceSourceBase, candidate); + if (hit) { + source = hit; + sourceFile = candidate; + break; + } + } + } + } + + const toc = extractTocFromMarkdown(doc.content); + if (doc.related.length) { + toc.push({ id: 'related', text: 'Related', level: 2 }); + } + return { + ...doc, + name: doc.title, + slug: path, + sourceFile, + source: source?.source ?? '', + sourceUrl: source?.url ?? '', + toc + }; + } + }); + const releases = defineCollection({ + name: 'releases', + directory: 'generated/releases', + include: '**/*.md', + schema: releaseSchema, + transform: async (doc, context) => { + const { fileName } = doc._meta; + return { + ...doc, + slug: fileName.replace('.md', ''), + html: await compileMarkdown(context, doc, { + remarkPlugins: [remarkGfm], + rehypePlugins: [[rehypePrettyCode, prettyCodeOptions]] + }) + }; + } + }); + return defineConfig({ + content: [components, utils, guides, references, releases] + }); +} diff --git a/packages/docs/src/lib/content.ts b/packages/docs/src/lib/content.ts new file mode 100644 index 0000000..19f28c4 --- /dev/null +++ b/packages/docs/src/lib/content.ts @@ -0,0 +1,159 @@ +import type { Component } from 'svelte'; +import type { ExampleType, LoadedExample } from './examples.js'; + +export type ContentType = 'components' | 'utils' | 'guides' | 'reference'; +export type ContentPaths = Partial>; +export type { Examples } from './examples.js'; + +export type ExampleReference = + | { kind: 'component'; component?: string; name: string } + | { kind: 'path'; path: string }; + +const defaultContentPaths: Record = { + components: '/src/content/components', + utils: '/src/content/utils', + guides: '/src/content/guides', + reference: '/src/content/reference' +}; + +function getContentPath(type: ContentType, contentPaths?: ContentPaths): string { + return contentPaths?.[type] ?? defaultContentPaths[type]; +} + +/** + * Resolve a relative or absolute example path to the conventional Vite `/src/...` key. + */ +export function resolveExamplePath( + path: string, + currentPath: string, + type: ContentType = 'components', + contentPaths?: ContentPaths +): string { + if ( + (type === 'guides' || type === 'reference') && + (path.startsWith('./') || !path.startsWith('/')) + ) { + const relativePath = path.startsWith('./') ? path.slice(2) : path; + return `${getContentPath(type, contentPaths)}/${relativePath}`; + } + if (path.startsWith('./')) { + return `/src/routes${currentPath}/${path.slice(2)}`; + } + if (path.startsWith('/')) { + return `/src${path}`; + } + return `/src/routes${currentPath}/${path}`; +} + +/** + * Extract examples referenced by `` or `:example{...}` markdown syntax. + */ +export function extractExampleReferences(markdownContent: string): ExampleReference[] { + const componentRegex = /]*?)\/>/g; + const mdcRegex = /:example\{([^}]*?)\}/g; + const matches = [ + ...markdownContent.matchAll(componentRegex), + ...markdownContent.matchAll(mdcRegex) + ]; + return matches.flatMap((match): ExampleReference[] => { + const attrs = match[1]; + const path = attrs.match(/path="([^"]*?)"/)?.[1]; + if (path) return [{ kind: 'path', path }]; + const component = attrs.match(/component="([^"]*?)"/)?.[1]; + const name = attrs.match(/name="([^"]*?)"/)?.[1]; + if (!name) return []; + return [{ kind: 'component', component, name }]; + }); +} + +export function getFirstExampleName(markdownContent: string): string | undefined { + return ( + markdownContent.match(/]*name=["']([^"']+)["'][^>]*>/)?.[1] || + markdownContent.match(/:example\{[^}]*name=["']([^"']+)["'][^}]*\}/)?.[1] + ); +} + +export type MarkdownModule = { + default: Component; + metadata: Metadata; +}; + +export function createContentLoaders(options: { + modules: Record Promise>>; + contentPaths?: ContentPaths; + getMetadata: (slug: string, type: ContentType) => Metadata | undefined; + loadExample: ( + component: string, + name: string, + type?: ExampleType + ) => Promise; + loadExampleByPath: (path: string) => Promise; + notFound: () => never; +}) { + async function getMarkdownComponent( + slug: string = 'index', + type: ContentType = 'components' + ): Promise<{ PageComponent: Component; metadata: Metadata }> { + const resolver = options.modules[`${getContentPath(type, options.contentPaths)}/${slug}.md`]; + const [doc, metadata] = await Promise.all([resolver?.(), options.getMetadata(slug, type)]); + if (!doc || !metadata) { + options.notFound(); + } + return { + PageComponent: doc.default, + metadata + }; + } + + async function loadExamplesFromMarkdown( + markdownContent: string, + defaultComponent?: string, + type: ContentType = 'components', + currentPath?: string + ): Promise>> { + const refs = extractExampleReferences(markdownContent); + const componentExamples = refs.flatMap((ref) => { + if (ref.kind !== 'component') return []; + const component = ref.component ?? defaultComponent; + if (!component) return []; + return [{ component, name: ref.name }]; + }); + const pathExamples = refs.flatMap((ref) => { + if (ref.kind !== 'path' || !currentPath) return []; + return [ + { + path: ref.path, + resolvedPath: resolveExamplePath(ref.path, currentPath, type, options.contentPaths) + } + ]; + }); + + const examples: Record> = {}; + await Promise.all( + componentExamples.map(async (ex) => { + const exampleType: ExampleType = type === 'utils' ? 'utils' : 'components'; + const loaded = await options.loadExample(ex.component, ex.name, exampleType); + if (loaded) { + if (!examples[ex.component]) { + examples[ex.component] = {}; + } + examples[ex.component][ex.name] = loaded; + } + }) + ); + if (pathExamples.length > 0) { + examples['__path__'] = {}; + await Promise.all( + pathExamples.map(async (ex) => { + const loaded = await options.loadExampleByPath(ex.resolvedPath); + if (loaded) { + examples['__path__'][ex.resolvedPath] = loaded; + } + }) + ); + } + return examples; + } + + return { getMarkdownComponent, loadExamplesFromMarkdown }; +} diff --git a/packages/docs/src/lib/context.ts b/packages/docs/src/lib/context.ts new file mode 100644 index 0000000..607f463 --- /dev/null +++ b/packages/docs/src/lib/context.ts @@ -0,0 +1,4 @@ +import { Context } from 'runed'; +import type { Examples } from './examples.js'; + +export const examples = new Context<{ readonly current: Examples }>('examples'); diff --git a/packages/docs/src/lib/examples-glob.ts b/packages/docs/src/lib/examples-glob.ts new file mode 100644 index 0000000..62b5399 --- /dev/null +++ b/packages/docs/src/lib/examples-glob.ts @@ -0,0 +1,35 @@ +/** + * Glob-based example loaders. + * + * ONLY import this module when you need to iterate over ALL examples + * (for example, screenshot generation). For normal page loading, keep a + * docs-local lazy dynamic import adapter. + * + * Using import.meta.glob causes Vite to pre-transform all matched files during development. + */ +export const componentExamples: Record Promise> = import.meta.glob( + '/src/examples/components/**/*.svelte', + { + import: 'default' + } +); +export const componentSources: Record Promise> = import.meta.glob( + '/src/examples/components/**/*.svelte', + { + import: 'default', + query: '?raw' + } +); +export const utilExamples: Record Promise> = import.meta.glob( + '/src/examples/utils/**/*.svelte', + { + import: 'default' + } +); +export const utilSources: Record Promise> = import.meta.glob( + '/src/examples/utils/**/*.svelte', + { + import: 'default', + query: '?raw' + } +); diff --git a/packages/docs/src/lib/examples.ts b/packages/docs/src/lib/examples.ts new file mode 100644 index 0000000..2951d23 --- /dev/null +++ b/packages/docs/src/lib/examples.ts @@ -0,0 +1,109 @@ +import type { Component } from 'svelte'; + +export type LoadedExample = { + component: Component; + source: string; + module?: { + title?: string; + description?: string; + layers?: string[]; + }; +}; +export type Examples = Record>; +export type ExampleType = 'components' | 'utils'; + +export type ComponentExampleImporter = ( + type: ExampleType, + component: string, + name: string +) => Promise<{ default: Component; title?: string; description?: string; layers?: string[] }>; +export type RawExampleImporter = ( + type: ExampleType, + component: string, + name: string +) => Promise; +export type PathExampleImporter = (path: string) => Promise<{ default: Component } | undefined>; +export type RawPathExampleImporter = (path: string) => Promise; + +export function cleanExampleSource(source: string): string { + return source + .replace(/[\s\S]*?<\/script>\n*/g, '') + .replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n'); +} + +export function cleanPathExampleSource(source: string): string { + return source.replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n'); +} + +export function createExampleLoaders(options: { + loadComponentExample: ComponentExampleImporter; + loadRawExample: RawExampleImporter; + loadPathExample: PathExampleImporter; + loadRawPathExample: RawPathExampleImporter; + warn?: typeof console.warn; +}) { + const warn = options.warn ?? console.warn; + + async function loadExample( + component: string, + name: string, + type: ExampleType = 'components' + ): Promise { + try { + const [componentModule, rawSource] = await Promise.all([ + options.loadComponentExample(type, component, name), + options.loadRawExample(type, component, name) + ]); + const { default: comp, ...module } = componentModule; + return { + component: comp, + source: cleanExampleSource(rawSource), + module + }; + } catch (e) { + warn(`Failed to load example: ${type}/${component}/${name}`, e); + return null; + } + } + + async function loadExamples( + items: Array<{ component: string; name: string }>, + type: ExampleType = 'components' + ): Promise { + const results: Examples = {}; + await Promise.all( + items.map(async ({ component, name }) => { + const example = await loadExample(component, name, type); + if (example) { + if (!results[component]) { + results[component] = {}; + } + results[component][name] = example; + } + }) + ); + return results; + } + + async function loadExampleByPath(resolvedPath: string): Promise { + try { + const [componentModule, rawSource] = await Promise.all([ + options.loadPathExample(resolvedPath), + options.loadRawPathExample(resolvedPath) + ]); + if (!componentModule || rawSource === undefined) { + warn(`Failed to load example by path: ${resolvedPath}`); + return null; + } + return { + component: componentModule.default, + source: cleanPathExampleSource(rawSource) + }; + } catch (e) { + warn(`Failed to load example by path: ${resolvedPath}`, e); + return null; + } + } + + return { loadExample, loadExamples, loadExampleByPath }; +} diff --git a/packages/docs/src/lib/index.js b/packages/docs/src/lib/index.js new file mode 100644 index 0000000..7a78d58 --- /dev/null +++ b/packages/docs/src/lib/index.js @@ -0,0 +1,10 @@ +export * from './api-types.js'; +export * from './catalog.js'; +export * from './collections.js'; +export * from './components/index.js'; +export * from './content.js'; +export * from './context.js'; +export * from './examples.js'; +export * from './markdown/index.js'; +export * from './page-transitions.js'; +export * from './project-stats.js'; diff --git a/packages/docs/src/lib/markdown/blueprints/default/blueprint.svelte b/packages/docs/src/lib/markdown/blueprints/default/blueprint.svelte new file mode 100644 index 0000000..52715c1 --- /dev/null +++ b/packages/docs/src/lib/markdown/blueprints/default/blueprint.svelte @@ -0,0 +1,30 @@ + + + + +{@render children?.()} diff --git a/packages/docs/src/lib/markdown/components/Button.svelte b/packages/docs/src/lib/markdown/components/Button.svelte new file mode 100644 index 0000000..c3252fc --- /dev/null +++ b/packages/docs/src/lib/markdown/components/Button.svelte @@ -0,0 +1,38 @@ + + + diff --git a/packages/docs/src/lib/markdown/components/LiveCode.svelte b/packages/docs/src/lib/markdown/components/LiveCode.svelte new file mode 100644 index 0000000..7560cb7 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/LiveCode.svelte @@ -0,0 +1,20 @@ + + +

+
+ {@render preview()} +
+ {#if showCode} + {@render children()} + {/if} +
diff --git a/packages/docs/src/lib/markdown/components/Note.svelte b/packages/docs/src/lib/markdown/components/Note.svelte new file mode 100644 index 0000000..29ea7da --- /dev/null +++ b/packages/docs/src/lib/markdown/components/Note.svelte @@ -0,0 +1,39 @@ + + +
+ +
+ {@render children?.()} +
+
diff --git a/packages/docs/src/lib/markdown/components/Steps.svelte b/packages/docs/src/lib/markdown/components/Steps.svelte new file mode 100644 index 0000000..a327f80 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/Steps.svelte @@ -0,0 +1,9 @@ + + +
+ {@render children?.()} +
diff --git a/packages/docs/src/lib/markdown/components/Tab.svelte b/packages/docs/src/lib/markdown/components/Tab.svelte new file mode 100644 index 0000000..8eec7cf --- /dev/null +++ b/packages/docs/src/lib/markdown/components/Tab.svelte @@ -0,0 +1,34 @@ + + +
+ {@render children?.()} +
diff --git a/packages/docs/src/lib/markdown/components/Tabs.svelte b/packages/docs/src/lib/markdown/components/Tabs.svelte new file mode 100644 index 0000000..44838dd --- /dev/null +++ b/packages/docs/src/lib/markdown/components/Tabs.svelte @@ -0,0 +1,109 @@ + + + + +
+ +
+ {#each tabs as tab, index} + {@const isActive = activeTab === index} + + {/each} +
+ + +
+ {@render children?.()} +
+
diff --git a/packages/docs/src/lib/markdown/components/a.svelte b/packages/docs/src/lib/markdown/components/a.svelte new file mode 100644 index 0000000..728b2aa --- /dev/null +++ b/packages/docs/src/lib/markdown/components/a.svelte @@ -0,0 +1,26 @@ + + + + {@render children?.()}{#if !internal} + + {/if} + diff --git a/packages/docs/src/lib/markdown/components/blockquote.svelte b/packages/docs/src/lib/markdown/components/blockquote.svelte new file mode 100644 index 0000000..8361807 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/blockquote.svelte @@ -0,0 +1,17 @@ + + +
a]:font-medium [&>a]:underline [&>a]:decoration-dashed [&>a]:decoration-primary/50 [&>a]:underline-offset-2', + className + )} + {...restProps} +> + {@render children?.()} +
diff --git a/packages/docs/src/lib/markdown/components/code.svelte b/packages/docs/src/lib/markdown/components/code.svelte new file mode 100644 index 0000000..47ee310 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/code.svelte @@ -0,0 +1,10 @@ + + + + {@render children?.()} + diff --git a/packages/docs/src/lib/markdown/components/h-base.svelte b/packages/docs/src/lib/markdown/components/h-base.svelte new file mode 100644 index 0000000..9ca08dd --- /dev/null +++ b/packages/docs/src/lib/markdown/components/h-base.svelte @@ -0,0 +1,23 @@ + + + + + + {@render children?.()} + + diff --git a/packages/docs/src/lib/markdown/components/h1.svelte b/packages/docs/src/lib/markdown/components/h1.svelte new file mode 100644 index 0000000..1671972 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/h1.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/docs/src/lib/markdown/components/h2.svelte b/packages/docs/src/lib/markdown/components/h2.svelte new file mode 100644 index 0000000..ac20663 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/h2.svelte @@ -0,0 +1,13 @@ + + + diff --git a/packages/docs/src/lib/markdown/components/h3.svelte b/packages/docs/src/lib/markdown/components/h3.svelte new file mode 100644 index 0000000..93b7fc6 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/h3.svelte @@ -0,0 +1,13 @@ + + + diff --git a/packages/docs/src/lib/markdown/components/h4.svelte b/packages/docs/src/lib/markdown/components/h4.svelte new file mode 100644 index 0000000..28ae065 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/h4.svelte @@ -0,0 +1,13 @@ + + + diff --git a/packages/docs/src/lib/markdown/components/img.svelte b/packages/docs/src/lib/markdown/components/img.svelte new file mode 100644 index 0000000..153b391 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/img.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/docs/src/lib/markdown/components/index.js b/packages/docs/src/lib/markdown/components/index.js new file mode 100644 index 0000000..73cbdcc --- /dev/null +++ b/packages/docs/src/lib/markdown/components/index.js @@ -0,0 +1,25 @@ +export { default as a, default as A } from './a.svelte'; +export { default as blockquote, default as Blockquote } from './blockquote.svelte'; +export { default as code, default as Code } from './code.svelte'; +export { default as h1, default as H1 } from './h1.svelte'; +export { default as h2, default as H2 } from './h2.svelte'; +export { default as h3, default as H3 } from './h3.svelte'; +export { default as h4, default as H4 } from './h4.svelte'; +export { default as img, default as Img } from './img.svelte'; +export { default as li, default as Li } from './li.svelte'; +export { default as ol, default as Ol } from './ol.svelte'; +export { default as p, default as P } from './p.svelte'; +export { default as pre, default as Pre } from './pre.svelte'; +export { default as strong, default as Strong } from './strong.svelte'; +export { default as table, default as Table } from './table.svelte'; +export { default as td, default as Td } from './td.svelte'; +export { default as th, default as Th } from './th.svelte'; +export { default as tr, default as Tr } from './tr.svelte'; +export { default as ul, default as Ul } from './ul.svelte'; +// Directive components +export { default as Button } from './Button.svelte'; +export { default as LiveCode } from './LiveCode.svelte'; +export { default as Note } from './Note.svelte'; +export { default as Tab } from './Tab.svelte'; +export { default as Tabs } from './Tabs.svelte'; +export { default as Steps } from './Steps.svelte'; diff --git a/packages/docs/src/lib/markdown/components/li.svelte b/packages/docs/src/lib/markdown/components/li.svelte new file mode 100644 index 0000000..e5c5da0 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/li.svelte @@ -0,0 +1,10 @@ + + +
  • + {@render children?.()} +
  • diff --git a/packages/docs/src/lib/markdown/components/ol.svelte b/packages/docs/src/lib/markdown/components/ol.svelte new file mode 100644 index 0000000..b229521 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/ol.svelte @@ -0,0 +1,10 @@ + + +
      + {@render children?.()} +
    diff --git a/packages/docs/src/lib/markdown/components/p.svelte b/packages/docs/src/lib/markdown/components/p.svelte new file mode 100644 index 0000000..a23bd14 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/p.svelte @@ -0,0 +1,10 @@ + + +

    &]:my-5 leading-relaxed', className)} {...restProps}> + {@render children?.()} +

    diff --git a/packages/docs/src/lib/markdown/components/pre.svelte b/packages/docs/src/lib/markdown/components/pre.svelte new file mode 100644 index 0000000..068e6f6 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/pre.svelte @@ -0,0 +1,84 @@ + + +
    + {#if dataTitle} +
    + + {dataTitle} +
    + {/if} + +
    {@render children?.()}
    + +
    + +
    +
    diff --git a/packages/docs/src/lib/markdown/components/strong.svelte b/packages/docs/src/lib/markdown/components/strong.svelte new file mode 100644 index 0000000..28b0f41 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/strong.svelte @@ -0,0 +1,5 @@ + + +{@render children?.()} diff --git a/packages/docs/src/lib/markdown/components/table.svelte b/packages/docs/src/lib/markdown/components/table.svelte new file mode 100644 index 0000000..d218982 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/table.svelte @@ -0,0 +1,12 @@ + + +
    + + {@render children?.()} +
    +
    diff --git a/packages/docs/src/lib/markdown/components/td.svelte b/packages/docs/src/lib/markdown/components/td.svelte new file mode 100644 index 0000000..bae6bb2 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/td.svelte @@ -0,0 +1,16 @@ + + + + {@render children?.()} + diff --git a/packages/docs/src/lib/markdown/components/th.svelte b/packages/docs/src/lib/markdown/components/th.svelte new file mode 100644 index 0000000..c3e1493 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/th.svelte @@ -0,0 +1,16 @@ + + + + {@render children?.()} + diff --git a/packages/docs/src/lib/markdown/components/tr.svelte b/packages/docs/src/lib/markdown/components/tr.svelte new file mode 100644 index 0000000..2ac46d0 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/tr.svelte @@ -0,0 +1,10 @@ + + + + {@render children?.()} + diff --git a/packages/docs/src/lib/markdown/components/ul.svelte b/packages/docs/src/lib/markdown/components/ul.svelte new file mode 100644 index 0000000..4a92b64 --- /dev/null +++ b/packages/docs/src/lib/markdown/components/ul.svelte @@ -0,0 +1,10 @@ + + +
      + {@render children?.()} +
    diff --git a/packages/docs/src/lib/markdown/config/index.js b/packages/docs/src/lib/markdown/config/index.js new file mode 100644 index 0000000..10710ab --- /dev/null +++ b/packages/docs/src/lib/markdown/config/index.js @@ -0,0 +1,95 @@ +// @ts-nocheck +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +import { defineConfig } from 'mdsx'; +import rehypeSlug from 'rehype-slug'; +import remarkGfm from 'remark-gfm'; +import remarkMDC from 'remark-mdc'; +import rehypePrettyCode from 'rehype-pretty-code'; +import { visit } from 'unist-util-visit'; + +// Remark plugins +export { remarkLiveCode } from '../rehype/live-code.js'; +export { remarkComponents } from '../remark/components.js'; + +// Rehype plugins +export { rehypeCodeBlocks } from '../rehype/handle-code-blocks.js'; + +// Transformers +export { shikiDiffTransformer } from '../transformers/shiki-diff.js'; + +// Configuration +export { prettyCodeOptions } from './pretty-code.js'; + +import { prettyCodeOptions } from './pretty-code.js'; +import { rehypeCodeBlocks } from '../rehype/handle-code-blocks.js'; +import { remarkLiveCode } from '../rehype/live-code.js'; +import { remarkComponents } from '../remark/components.js'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +/** Strip leading/trailing dashes from heading IDs produced by rehype-slug. */ +export function rehypeCleanSlugIds() { + return (tree) => { + visit(tree, 'element', (node) => { + if (/^h[1-6]$/.test(node.tagName) && node.properties?.id) { + node.properties.id = node.properties.id.replace(/^-+|-+$/g, ''); + } + }); + }; +} + +export function getDefaultBlueprintPath() { + return join(__dirname, '../blueprints/default/blueprint.svelte'); +} + +/** + * Create the shared MDSX config used by LayerStack docs apps. + * + * @param {{ + * markdownComponentsPath?: string; + * exampleComponentPath?: string; + * liveCodeComponent?: string; + * liveCodeOutputDir?: string; + * liveCodeImportPrefix?: string; + * blueprintPath?: string; + * }} [options] + */ +export function createMdsxConfig(options = {}) { + return defineConfig({ + extensions: ['.md'], + remarkPlugins: [ + remarkGfm, + remarkMDC, + [ + remarkComponents, + { + markdownComponentsPath: + options.markdownComponentsPath ?? '@layerstack/docs/markdown/components', + exampleComponentPath: options.exampleComponentPath ?? '$lib/components' + } + ], + [ + remarkLiveCode, + { + outputDir: options.liveCodeOutputDir, + importPrefix: options.liveCodeImportPrefix, + liveCodeComponent: + options.liveCodeComponent ?? + '@layerstack/docs/markdown/components/LiveCode.svelte' + } + ] + ], + rehypePlugins: [ + rehypeSlug, + rehypeCleanSlugIds, + [rehypePrettyCode, prettyCodeOptions], + rehypeCodeBlocks + ], + blueprints: { + default: { + path: options.blueprintPath ?? getDefaultBlueprintPath() + } + } + }); +} diff --git a/packages/docs/src/lib/markdown/config/pretty-code.js b/packages/docs/src/lib/markdown/config/pretty-code.js new file mode 100644 index 0000000..df2e8c9 --- /dev/null +++ b/packages/docs/src/lib/markdown/config/pretty-code.js @@ -0,0 +1,18 @@ +import { transformerMetaHighlight } from '@shikijs/transformers'; +import { shikiDiffTransformer } from '../transformers/shiki-diff.js'; + +/** + * @type {import('rehype-pretty-code').Options} + */ +export const prettyCodeOptions = { + theme: { + light: 'github-light-default', + dark: 'github-dark-default' + }, + keepBackground: false, + defaultLang: { + block: 'plaintext' + // inline: "plaintext", + }, + transformers: [shikiDiffTransformer(), transformerMetaHighlight()] +}; diff --git a/packages/docs/src/lib/markdown/index.js b/packages/docs/src/lib/markdown/index.js new file mode 100644 index 0000000..4b22e4f --- /dev/null +++ b/packages/docs/src/lib/markdown/index.js @@ -0,0 +1,2 @@ +export * from './toc.js'; +export * from './utils.js'; diff --git a/packages/docs/src/lib/markdown/rehype/component-example.js b/packages/docs/src/lib/markdown/rehype/component-example.js new file mode 100644 index 0000000..9df93cf --- /dev/null +++ b/packages/docs/src/lib/markdown/rehype/component-example.js @@ -0,0 +1,98 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { u } from 'unist-builder'; +import { visit } from 'unist-util-visit'; + +/** + * Adds the source code to component examples. + * @returns {(tree: import('unist').Node) => Promise} + */ +export function rehypeComponentExample() { + return async (tree) => { + const componentRegex = /component="([^"]+)"/; + const nameRegex = /name="([^"]+)"/; + + visit(tree, (node, index, parent) => { + // Use type narrowing - node can have custom properties + if ( + !node || + typeof node !== 'object' || + !('type' in node) || + !('value' in node) || + node.type !== 'raw' || + typeof node.value !== 'string' || + !node.value.startsWith(' void} + */ +export function rehypeCodeBlocks() { + return (tree) => { + visit(tree, 'element', (node) => { + if (node.tagName === 'pre') { + node.properties.className = node.properties.className || []; + + // Check if the code element has a data-meta attribute from rehype-pretty-code + const codeNode = node.children?.find( + (child) => child.type === 'element' && child.tagName === 'code' + ); + + if (!codeNode || codeNode.type !== 'element') return; + + // @ts-expect-error - rehype-pretty-code adds custom meta property + const meta = codeNode.data?.meta || codeNode.properties?.metastring; + + if (meta) { + // Check for 'frame' keyword + if (meta.includes('frame')) { + node.properties['data-frame'] = ''; + } + + // Extract title="..." if present + const titleMatch = meta.match(/title="([^"]+)"/); + if (titleMatch) { + node.properties['data-title'] = titleMatch[1]; + } + + // Check for line numbers flag in meta + if (meta.includes('showLineNumbers') || meta.includes('ln')) { + node.properties['data-line-numbers'] = ''; + } + } + + // Check recursively for [data-line] attribute in nested children + /** + * @param {import('hast').Element} element + * @returns {boolean} + */ + function hasDataLine(element) { + if (element.properties?.['data-line'] !== undefined) { + return true; + } + if (element.children) { + return element.children.some((child) => child.type === 'element' && hasDataLine(child)); + } + return false; + } + + if (hasDataLine(codeNode)) { + node.properties['data-line-numbers'] = ''; + } + + // Extract language from code element + const codeClassName = codeNode.properties?.className; + if (Array.isArray(codeClassName)) { + const langClass = codeClassName.find( + (cls) => typeof cls === 'string' && cls.startsWith('language-') + ); + if (typeof langClass === 'string') { + const language = langClass.replace('language-', ''); + node.properties['data-language'] = language; + } + } + } + }); + }; +} diff --git a/packages/docs/src/lib/markdown/rehype/live-code.js b/packages/docs/src/lib/markdown/rehype/live-code.js new file mode 100644 index 0000000..ac09dab --- /dev/null +++ b/packages/docs/src/lib/markdown/rehype/live-code.js @@ -0,0 +1,158 @@ +// @ts-nocheck +import { createHash } from 'node:crypto'; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import process from 'node:process'; +import { visit } from 'unist-util-visit'; + +/** + * Remark plugin to handle live code blocks (e.g., ```svelte live) + * Writes live code to .svelte files and imports them + * MUST run BEFORE any rehype plugins (operates on markdown AST, not HTML) + * @param {{ outputDir?: string; importPrefix?: string; liveCodeComponent?: string }} [options] + * @returns {(tree: import('mdast').Root, vFile: import('vfile').VFile) => void} + */ +export function remarkLiveCode(options = {}) { + const basePath = resolve(process.cwd(), options.outputDir ?? '.live-code'); + const liveCodeMap = resolve(basePath, 'live-code-map.json'); + const importPrefix = options.importPrefix ?? '/.live-code'; + const liveCodeComponent = + options.liveCodeComponent ?? '@layerstack/docs/markdown/components/LiveCode.svelte'; + + // Ensure directory exists + if (!existsSync(basePath)) { + mkdirSync(basePath, { recursive: true }); + } + + // Initialize or load the map file + if (!existsSync(liveCodeMap)) { + writeFileSync(liveCodeMap, '{}'); + } + + return (tree, vFile) => { + const liveCodeImports = new Map(); // Use Map to dedupe identical code blocks + let hasScript = false; + + visit(tree, 'code', (node, index, parent) => { + if (index === null || !parent) return; + const { meta, lang, value } = node; + const metaArray = (meta || '').split(' ').filter(Boolean); + + // Check if this is a live code block + if (lang !== 'svelte' || !metaArray.includes('live')) return; + + // Parse all key=value props from meta string + /** @type {Record} */ + const props = {}; + const propsRegex = /(\w+)=(?:"([^"]*)"|(\w+))/g; + let match; + while ((match = propsRegex.exec(meta || '')) !== null) { + const key = match[1]; + const value = match[2] || match[3]; // quoted or unquoted value + // Convert boolean strings to actual booleans + if (value === 'true') { + props[key] = true; + } else if (value === 'false') { + props[key] = false; + } else { + props[key] = value; + } + } + + // Convert props object to Svelte props string + const propsString = Object.entries(props) + .map(([key, value]) => { + if (typeof value === 'boolean') { + return `${key}={${value}}`; + } else { + return `${key}="${value}"`; + } + }) + .join(' '); + const propsWithSpace = propsString ? ' ' + propsString : ''; + + // Use the raw code value + const rawCode = value || ''; + + // Generate unique ID for this code block based on file path and content hash + const contentHash = createHash('md5').update(rawCode).digest('hex').substring(0, 8); + const blockId = `${vFile.path}-${contentHash}`; + const idMap = JSON.parse(readFileSync(liveCodeMap, 'utf-8')); + + let componentFileName = idMap[blockId]; + if (!componentFileName) { + // Generate unique filename + const hash = Math.random().toString(36).substring(2, 11); + componentFileName = `LiveCode${hash}.svelte`; + idMap[blockId] = componentFileName; + writeFileSync(liveCodeMap, JSON.stringify(idMap, null, 2)); + } + + // Write the live code to a .svelte file + const componentPath = resolve(basePath, componentFileName); + writeFileSync(componentPath, rawCode); + + // Generate component name (remove .svelte extension) + const componentName = componentFileName.replace(/\.svelte$/, ''); + + // Track import for later injection (Map dedupes identical code blocks) + liveCodeImports.set(componentName, `${importPrefix}/${componentFileName}`); + + // Create the live code container structure wrapped in LiveCodeWrapper + const liveCodeContainer = { + type: 'paragraph', + data: { + hName: 'div', + hProperties: {} + }, + children: [ + { + type: 'html', + value: `{#snippet preview()}<${componentName} />{/snippet}
    ` + } + ] + }; + + // Add code section with original code block (title will be handled by rehype-code-block-title) + liveCodeContainer.children.push(node); + + liveCodeContainer.children.push({ + type: 'html', + value: '
    ' // Close live-code-source and LiveCode + }); + + // Replace the code node with the container + parent.children[index] = liveCodeContainer; + }); + + // Inject imports at the beginning of the file + if (liveCodeImports.size > 0) { + const importStatements = [ + `import LiveCode from '${liveCodeComponent}';`, + ...[...liveCodeImports.entries()].map( + ([componentName, path]) => `import ${componentName} from '${path}';` + ) + ].join('\n'); + + // Find existing script tag or create new one + visit(tree, 'html', (node, idx, parent) => { + if (node.value.startsWith(']*>/, + (match) => `${match}\n${importStatements}` + ); + return visit.EXIT; + } + }); + + if (!hasScript) { + // Create new script tag at the beginning + tree.children.unshift({ + type: 'html', + value: `` + }); + } + } + }; +} diff --git a/packages/docs/src/lib/markdown/remark/components.js b/packages/docs/src/lib/markdown/remark/components.js new file mode 100644 index 0000000..adfe31c --- /dev/null +++ b/packages/docs/src/lib/markdown/remark/components.js @@ -0,0 +1,262 @@ +// @ts-nocheck +import { cls } from '@layerstack/tailwind'; +import { toCamelCase } from '@layerstack/utils'; +import { visit, EXIT } from 'unist-util-visit'; + +/** + * Remark plugin to transform MDC components (::tip, ::note, ::steps, etc.) into custom Svelte components + * Works with remark-mdc to convert MDC components into Svelte components + * + * Supported components: + * - ::tip / :::tip - renders as Note component with variant="tip" + * - ::note / :::note - renders as Note component with variant="note" + * - ::warning / :::warning - renders as Note component with variant="warning" + * - ::caution / :::caution - renders as Note component with variant="caution" + * - ::steps / :::steps - renders as Steps component + * - ::tabs / :::tabs - renders as Tabs component (supports nested ::tab) + * - ::tab / :::tab - renders as Tab component (used inside tabs, supports icon attribute via unplugin-icons) + * - :icon - renders as unplugin-icons component (inline icon with name attribute) + * - :button - renders as Button component (inline button, supports icon attribute via unplugin-icons) + * - :example - renders as Example component (inline example) + * + * @returns {(tree: any) => void} A remark transformer function + */ +/** + * Convert kebab-case attributes to camelCase for Svelte props + * @param {Record} attributes - Attributes object with potentially kebab-cased keys + * @returns {Record} - Attributes object with camelCase keys + */ +function kebabToCamelCase(attributes) { + /** @type {Record} */ + const camelCaseAttributes = {}; + for (const [key, value] of Object.entries(attributes)) { + // Convert kebab-case to camelCase + const camelKey = toCamelCase(key); + camelCaseAttributes[camelKey] = value; + } + return camelCaseAttributes; +} + +/** + * Convert icon name from various formats to unplugin-icons import format + * @param {string} name - Icon name (e.g., "logos:tailwindcss-icon", "i-logos-tailwindcss-icon", "lucide:code") + * @returns {{importPath: string, componentName: string}} - Import path and PascalCase component name + */ +function convertIconName(name) { + // Remove i- prefix if present + let iconName = name; + if (iconName.startsWith('i-')) { + iconName = iconName.slice(2); + } + + // Split by colon to get collection and icon name + let collection, icon; + if (iconName.includes(':')) { + [collection, icon] = iconName.split(':'); + } else { + // For i-collection-icon format without colon, we need to parse differently + // This is tricky because collections can have hyphens (e.g., vscode-icons) + // For now, assume everything after first hyphen is the icon name + const parts = iconName.split('-'); + collection = parts[0]; + icon = parts.slice(1).join('-'); + } + + // Create PascalCase component name by converting both collection and icon parts + /** @param {string} str */ + const toPascalCase = (str) => + str + .split('-') + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(''); + + const componentName = toPascalCase(collection) + toPascalCase(icon); + const importPath = `~icons/${collection}/${icon}`; + + return { importPath, componentName }; +} + +/** + * @param {{ markdownComponentsPath?: string; exampleComponentPath?: string }} [options] + */ +export function remarkComponents(options = {}) { + const markdownComponentsPath = options.markdownComponentsPath ?? '@layerstack/docs/markdown/components'; + const exampleComponentPath = options.exampleComponentPath ?? '$lib/components'; + + return (tree) => { + const componentsToImport = new Set(); + const iconImports = new Map(); // Map of componentName -> importPath + + // Process MDC components (remark-mdc creates leafComponent and containerComponent nodes) + visit(tree, (node) => { + // Handle both leafComponent (::component) and containerComponent (::component...::) + if (node.type === 'leafComponent' || node.type === 'containerComponent') { + const componentName = node.name; + + // Alert variants all use the Note component + const alertVariants = ['tip', 'note', 'warning', 'caution']; + + // Map component names to Svelte component names and variants + let svelteComponent; + let variant; + + if (alertVariants.includes(componentName)) { + svelteComponent = 'Note'; + variant = componentName; + } else if (componentName === 'steps') { + svelteComponent = 'Steps'; + } else if (componentName === 'tabs') { + svelteComponent = 'Tabs'; + } else if (componentName === 'tab') { + svelteComponent = 'Tab'; + } else { + // Unknown component, skip transformation + return; + } + + // Track which components we need to import + componentsToImport.add(svelteComponent); + + // Get component attributes from MDC + const attributes = node.attributes || {}; + + // Convert kebab-case to camelCase for Svelte props + let processedAttributes = kebabToCamelCase(attributes); + + // Handle icon attribute on tab components (e.g., ::tab{label="pnpm" icon="vscode-icons:file-type-pnpm"}) + if (componentName === 'tab' && processedAttributes.icon) { + const { importPath, componentName: iconCompName } = convertIconName( + processedAttributes.icon + ); + iconImports.set(iconCompName, importPath); + + // Replace icon string with component reference expression + // Remove quotes so it becomes {ComponentName} instead of "ComponentName" + processedAttributes = { + ...processedAttributes, + icon: `{${iconCompName}}` + }; + } + + // Convert the MDC component into a component that rehype can handle + // We set data.hName to tell rehype to convert this to the component + const data = node.data || (node.data = {}); + data.hName = svelteComponent; + data.hProperties = { + ...processedAttributes, + // Pass variant for alert components + ...(variant && { variant }) + }; + } + + // Handle inline text components (:component) + if (node.type === 'textComponent') { + const componentName = node.name; + + // Support :icon{name="logos:tailwindcss-icon"} or :icon{name="i-lucide-code"} syntax + if (componentName === 'icon') { + const iconName = node.attributes?.name; + if (iconName) { + const { importPath, componentName: iconComponentName } = convertIconName(iconName); + + // Track this icon import + iconImports.set(iconComponentName, importPath); + + // Get other attributes (excluding 'name') + const { name: _, class: className, ...otherAttributes } = node.attributes || {}; + + // Convert to the icon component + const data = node.data || (node.data = {}); + data.hName = iconComponentName; + data.hProperties = { + ...otherAttributes, + class: cls('inline-block', className) + }; + } + } else if (componentName === 'button') { + componentsToImport.add('Button'); + + const attributes = node.attributes || {}; + + // Convert kebab-case to camelCase for Svelte props + let processedAttributes = kebabToCamelCase(attributes); + + // Handle icon attribute on button components (e.g., :button{icon="lucide:github"}) + if (processedAttributes.icon) { + const { importPath, componentName: iconCompName } = convertIconName( + processedAttributes.icon + ); + iconImports.set(iconCompName, importPath); + + // Replace icon string with component reference expression + processedAttributes = { + ...processedAttributes, + icon: `{${iconCompName}}` + }; + } + + const data = node.data || (node.data = {}); + data.hName = 'Button'; + data.hProperties = processedAttributes; + } else if (componentName === 'example') { + componentsToImport.add('Example'); + + const attributes = node.attributes || {}; + + // Convert kebab-case to camelCase for Svelte props + const processedAttributes = kebabToCamelCase(attributes); + + const data = node.data || (node.data = {}); + data.hName = 'Example'; + data.hProperties = processedAttributes; + } + } + }); + + // Inject component imports at the beginning of the file + if (componentsToImport.size > 0 || iconImports.size > 0) { + // Generate regular component imports + const componentArray = Array.from(componentsToImport); + const componentImportStatements = componentArray + .map((comp) => { + const path = comp === 'Example' ? exampleComponentPath : markdownComponentsPath; + return `import ${comp} from '${path}/${comp}.svelte';`; + }) + .join('\n'); + + // Generate icon imports from unplugin-icons + const iconImportStatements = Array.from(iconImports.entries()) + .map(([componentName, importPath]) => { + return `import ${componentName} from '${importPath}';`; + }) + .join('\n'); + + // Combine all imports + const importStatements = [componentImportStatements, iconImportStatements] + .filter(Boolean) + .join('\n'); + + // Check if there's already a script tag + let hasScript = false; + visit(tree, 'html', (node) => { + if (node.value.startsWith(']*>/, + /** @param {string} match */ + (match) => `${match}\n${importStatements}` + ); + return EXIT; + } + }); + + if (!hasScript) { + // Create new script tag at the beginning + tree.children.unshift({ + type: 'html', + value: `` + }); + } + } + }; +} diff --git a/packages/docs/src/lib/markdown/toc.ts b/packages/docs/src/lib/markdown/toc.ts new file mode 100644 index 0000000..8607ca0 --- /dev/null +++ b/packages/docs/src/lib/markdown/toc.ts @@ -0,0 +1,31 @@ +import { slug as githubSlug } from 'github-slugger'; + +/** + * Extract table of contents from markdown content + */ +export function extractTocFromMarkdown( + content: string +): { id: string; text: string; level: number }[] { + const toc: { id: string; text: string; level: number }[] = []; + + // Strip HTML comments so commented-out headings are ignored + const stripped = content.replace(//g, ''); + + const headingRegex = /^(#{1,6})\s+(.+)$/gm; + let match: RegExpExecArray | null; + while ((match = headingRegex.exec(stripped)) !== null) { + const level = match[1].length; + // Strip inline MDC directives (e.g. `:icon{name="lucide:user" class="..."}`) + // and markdown links (e.g. `[text](url)` → `text`) + const text = match[2] + .replace(/:[a-zA-Z][\w-]*\{[^}]*\}/g, '') + .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') + .trim(); + if (!text) continue; + // Use github-slugger then strip leading/trailing dashes (matching rehypeCleanSlugIds) + const id = githubSlug(text); + toc.push({ id, text, level }); + } + + return toc; +} diff --git a/packages/docs/src/lib/markdown/transformers/shiki-diff.js b/packages/docs/src/lib/markdown/transformers/shiki-diff.js new file mode 100644 index 0000000..18beaeb --- /dev/null +++ b/packages/docs/src/lib/markdown/transformers/shiki-diff.js @@ -0,0 +1,46 @@ +/** + * Custom transformer for diff highlighting + * Processes code blocks with 'diff' in the meta string to add/remove line styling + * @returns {import('shiki').ShikiTransformer} + */ +export function shikiDiffTransformer() { + return { + name: 'diff-transformer', + code(node) { + // Trigger on either ```diff (language) or ``` diff (meta string) + const metaString = this.options.meta?.__raw || ''; + const lang = this.options.lang || ''; + if (lang !== 'diff' && !metaString.includes('diff')) return; + + // Add class to the pre element + this.addClassToHast(this.pre, 'has-diff'); + + // Get all line elements + const lines = node.children.filter((child) => child.type === 'element'); + + for (const line of lines) { + // Get all text tokens in this line + const tokens = line.children.filter((child) => child.type === 'element'); + + if (tokens.length === 0) continue; + + // Check the first token's text content + const firstToken = tokens[0]; + const textNodes = firstToken.children?.filter((child) => child.type === 'text'); + + if (!textNodes || textNodes.length === 0) continue; + + const firstText = textNodes[0]; + const text = firstText.value; + + if (text.startsWith('+')) { + this.addClassToHast(line, 'diff-add'); + firstText.value = text.slice(1); + } else if (text.startsWith('-')) { + this.addClassToHast(line, 'diff-remove'); + firstText.value = text.slice(1); + } + } + } + }; +} diff --git a/packages/docs/src/lib/markdown/utils.ts b/packages/docs/src/lib/markdown/utils.ts new file mode 100644 index 0000000..ad83cb3 --- /dev/null +++ b/packages/docs/src/lib/markdown/utils.ts @@ -0,0 +1,36 @@ +/** + * Strip markdown syntax to get plain text. + * Useful for search indexing or generating plain text excerpts. + */ +export function stripMarkdown(content: string): string { + return ( + content + // Remove code blocks + .replace(/```[\s\S]*?```/g, '') + // Remove inline code + .replace(/`[^`]+`/g, '') + // Remove links but keep text + .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') + // Remove images + .replace(/!\[([^\]]*)\]\([^)]+\)/g, '') + // Remove HTML tags + .replace(/<[^>]+>/g, '') + // Remove headings markup + .replace(/^#{1,6}\s+/gm, '') + // Remove bold/italic + .replace(/\*{1,2}([^*]+)\*{1,2}/g, '$1') + .replace(/_{1,2}([^_]+)_{1,2}/g, '$1') + // Remove blockquotes + .replace(/^>\s+/gm, '') + // Remove horizontal rules + .replace(/^[-*_]{3,}\s*$/gm, '') + // Remove list markers + .replace(/^[\s]*[-*+]\s+/gm, '') + .replace(/^[\s]*\d+\.\s+/gm, '') + // Remove MDX/directives like :example{...} or ::directive + .replace(/:{1,2}\w+(\{[^}]*\})?/g, '') + // Collapse multiple whitespace/newlines + .replace(/\s+/g, ' ') + .trim() + ); +} diff --git a/packages/docs/src/lib/node/component-api.js b/packages/docs/src/lib/node/component-api.js new file mode 100644 index 0000000..4ba31d4 --- /dev/null +++ b/packages/docs/src/lib/node/component-api.js @@ -0,0 +1,506 @@ +/** + * LayerChart Component API Extractor + * + * This script extracts TypeScript type definitions and JSDoc documentation from + * Svelte components in the layerchart library. + * + * @description + * Scans all .svelte files in packages/layerchart/src/lib/components and extracts: + * - Component prop types (*PropsWithoutHTML or *Props patterns, exported or not) + * - JSDoc descriptions for each property + * - Default values from @default tags + * - Optional/required status + * - Additional JSDoc tags (@bindable, etc.) + * - Nested object properties + * + * @output + * Generates individual JSON files in generated/api/ for each component, plus an index.json file + * + * @usage + * pnpm extract:api + * + * @example + * // Generated output structure: + * { + * "generatedAt": "2025-11-02T00:00:00.000Z", + * "components": [ + * { + * "component": "Rect", + * "propsType": "RectPropsWithoutHTML", + * "properties": [ + * { + * "name": "x", + * "type": "number", + * "optional": true, + * "description": "The x-coordinate", + * "default": "0" + * } + * ] + * } + * ] + * } + */ +import fs from 'fs'; +import path from 'path'; +import ts from 'typescript'; +/** + * Get all canonical .svelte files in a directory (recursively). + * + * Skips per-layer variants (`*.svg.svelte`, `*.canvas.svelte`, `*.html.svelte`) + * and the shared base impl (`*.base.svelte`) — the canonical `.svelte` + * delegator re-exports the public Props type, which is what docs reference. + */ +export function getSvelteFiles(dir) { + const files = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + // Recursively scan subdirectories (charts, layers, tooltip) + files.push(...getSvelteFiles(fullPath)); + } + else if (entry.isFile() && entry.name.endsWith('.svelte')) { + if (/\.(svg|canvas|html|base)\.svelte$/.test(entry.name)) + continue; + files.push(fullPath); + } + } + return files; +} +/** + * Extract JSDoc comments from a node + */ +function extractJsDoc(node) { + const jsDocTags = ts.getJSDocTags(node); + const jsDocComments = node.jsDoc; + let description; + const tags = {}; + let defaultValue; + // Extract description from JSDoc comment + if (jsDocComments && jsDocComments.length > 0) { + const comment = jsDocComments[0].comment; + if (typeof comment === 'string') { + description = comment; + } + else if (Array.isArray(comment)) { + description = comment.map((c) => c.text).join(''); + } + } + // Extract tags + for (const tag of jsDocTags) { + const tagName = tag.tagName.text; + let tagValue = ''; + if (tag.comment) { + if (typeof tag.comment === 'string') { + tagValue = tag.comment; + } + else if (Array.isArray(tag.comment)) { + tagValue = tag.comment.map((c) => c.text).join(''); + } + } + if (tagName === 'default') { + defaultValue = tagValue; + } + else { + tags[tagName] = tagValue; + } + } + return { + description, + tags: Object.keys(tags).length > 0 ? tags : undefined, + default: defaultValue + }; +} +/** + * Get type as string + */ +function getTypeString(typeNode, checker) { + if (!typeNode) + return 'any'; + // Use the printer to get a string representation + const printer = ts.createPrinter({ removeComments: true }); + const typeString = printer.printNode(ts.EmitHint.Unspecified, typeNode, typeNode.getSourceFile()); + // Normalize whitespace - collapse multiple spaces/newlines into single spaces + return typeString.replace(/\s+/g, ' ').trim(); +} +/** + * Extract properties from a type literal or interface + */ +function extractProperties(node, checker) { + const properties = []; + for (const member of node.members) { + if (ts.isPropertySignature(member) && member.name) { + const name = member.name.getText(); + const required = !member.questionToken; // Inverted: required = not optional + const type = getTypeString(member.type, checker); + const jsDoc = extractJsDoc(member); + // Check if this is a nested object type + let nestedProperties; + if (member.type && ts.isTypeLiteralNode(member.type)) { + nestedProperties = extractProperties(member.type, checker); + } + properties.push({ + name, + type, + required, + ...jsDoc, + ...(nestedProperties && nestedProperties.length > 0 ? { properties: nestedProperties } : {}) + }); + } + } + return properties; +} +/** + * Resolve intersection types and extract all properties + */ +function extractPropertiesFromType(typeNode, checker, sourceFile) { + let properties = []; + if (ts.isIntersectionTypeNode(typeNode)) { + // Handle intersection types (A & B & C) + for (const type of typeNode.types) { + properties = properties.concat(extractPropertiesFromType(type, checker, sourceFile)); + } + } + else if (ts.isTypeLiteralNode(typeNode)) { + // Handle inline type literals + properties = extractProperties(typeNode, checker); + } + else if (ts.isTypeReferenceNode(typeNode)) { + // Handle type references (e.g., CommonStyleProps) + const typeName = typeNode.typeName.getText(); + // Try to find the type definition in the same file + ts.forEachChild(sourceFile, (node) => { + if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) { + properties = properties.concat(extractPropertiesFromType(node.type, checker, sourceFile)); + } + else if (ts.isInterfaceDeclaration(node) && node.name.text === typeName) { + properties = properties.concat(extractProperties(node, checker)); + } + }); + } + return properties; +} +/** + * Extract element type from generic types like SVGAttributes + */ +function extractElementType(typeString) { + const match = typeString.match(/(?:SVG|HTML)Attributes<(\w+)>/); + return match?.[1]; +} +/** + * Parse extended types from an intersection type + */ +function parseExtendedTypes(typeNode, sourceFile) { + const extendedTypes = []; + if (!ts.isIntersectionTypeNode(typeNode)) { + return extendedTypes; + } + for (const type of typeNode.types) { + const typeText = type.getText(sourceFile); + // Skip the base PropsWithoutHTML type (but not Without<> that contains PropsWithoutHTML) + if (!typeText.startsWith('Without<') && typeText.includes('PropsWithoutHTML')) { + continue; + } + // Check if this is a Without<> wrapper (used to exclude props) + // Extract the element type from inside Without, ...> + const elementTypeFromWithout = extractElementType(typeText); + if (typeText.startsWith('Without<') && elementTypeFromWithout) { + extendedTypes.push({ + name: elementTypeFromWithout.replace(/Element$/, 'Attributes'), + fullType: typeText, + elementType: elementTypeFromWithout, + isLibraryType: true + }); + continue; + } + // Check if this is an SVG/HTML Attributes type + const elementType = extractElementType(typeText); + if (elementType) { + extendedTypes.push({ + name: elementType.replace(/Element$/, 'Attributes'), + fullType: typeText, + elementType, + isLibraryType: true + }); + continue; + } + // Check if this is a reference to another type (like CommonEvents) + if (ts.isTypeReferenceNode(type)) { + const typeName = type.typeName.getText(sourceFile); + extendedTypes.push({ + name: typeName, + fullType: typeText, + isLibraryType: false // We should extract these types + }); + } + } + return extendedTypes; +} +/** + * Find the main Props type for a component + * Looks for patterns like: ComponentPropsWithoutHTML, ComponentProps + */ +function findPropsTypeName(componentName, moduleScript) { + // Try different patterns in order of preference + const patterns = [ + // First try exported types with exact component name match + { pattern: `${componentName}PropsWithoutHTML`, requireExport: true }, + { pattern: `${componentName}Props`, requireExport: true }, + // Then try non-exported types with exact component name match + { pattern: `${componentName}PropsWithoutHTML`, requireExport: false }, + { pattern: `${componentName}Props`, requireExport: false }, + // Finally, try any exported Props type + { regex: new RegExp(`export type (\\w*PropsWithoutHTML)`, 'g') }, + { regex: new RegExp(`export type (\\w*Props)(?!WithoutHTML)`, 'g') }, + // Last resort: any Props type (exported or not) + { regex: new RegExp(`type (\\w*PropsWithoutHTML)`, 'g') }, + { regex: new RegExp(`type (\\w*Props)(?!WithoutHTML)`, 'g') } + ]; + for (const config of patterns) { + if ('regex' in config && config.regex) { + // For regex patterns, find all matches + const matches = [...moduleScript.matchAll(config.regex)]; + if (matches.length > 0) { + // Prefer types ending with "WithoutHTML" + const withoutHTMLMatch = matches.find((m) => m[1].endsWith('WithoutHTML')); + if (withoutHTMLMatch) { + return withoutHTMLMatch[1]; + } + // Otherwise return the first match + return matches[0][1]; + } + } + else if ('pattern' in config && config.pattern) { + // String pattern + const searchStr = config.requireExport + ? `export type ${config.pattern}` + : `type ${config.pattern}`; + if (moduleScript.includes(searchStr)) { + return config.pattern; + } + } + } + return null; +} +/** + * Inline `export type { Foo } from './X.shared.svelte.js'` re-exports by + * appending the source `.ts` file's contents. The canonical layer-delegator + * components only re-export their public Props type from a sibling + * `*.shared.svelte.ts`, so without this the TS parser sees no type definition. + */ +function resolveSharedReExports(filePath, moduleScript) { + const reExportRegex = /export\s+type\s*\{[^}]+\}\s*from\s+['"](\.\/[^'"]+\.shared\.svelte)\.js['"]\s*;?/g; + const dir = path.dirname(filePath); + let combined = moduleScript; + for (const match of moduleScript.matchAll(reExportRegex)) { + const sharedPath = path.join(dir, `${match[1].slice(2)}.ts`); + if (fs.existsSync(sharedPath)) { + combined += '\n' + fs.readFileSync(sharedPath, 'utf-8'); + } + } + return combined; +} +/** + * Extract component API from a Svelte file + */ +export function extractComponentAPI(filePath) { + const content = fs.readFileSync(filePath, 'utf-8'); + // Extract the module script content + const moduleScriptMatch = content.match(/]*lang="ts"[^>]*module[^>]*>([\s\S]*?)<\/script>/); + if (!moduleScriptMatch) { + return null; + } + const moduleScript = resolveSharedReExports(filePath, moduleScriptMatch[1]); + // Look for the main Props type + const componentName = path.basename(filePath, '.svelte'); + const propsTypeName = findPropsTypeName(componentName, moduleScript); + if (!propsTypeName) { + return null; + } + // Create a temporary TypeScript file for parsing + const tempFile = `temp-${componentName}.ts`; + const tempPath = path.join(path.dirname(filePath), tempFile); + // Write the module script to a temp file with necessary imports resolved + // We keep the original imports but add stub types for common ones that might not resolve + const tempContent = ` +import type { SVGAttributes, HTMLAttributes, MouseEventHandler, PointerEventHandler } from 'svelte/elements'; +import type { Snippet, Component } from 'svelte'; + +// Stub types that might not resolve (only if not already defined) +type CommonStyleProps = { + /** Fill color */ + fill?: string; + /** Fill opacity (0-1) */ + fillOpacity?: number; + /** Stroke color */ + stroke?: string; + /** Stroke width in pixels */ + strokeWidth?: number; + /** Stroke opacity (0-1) */ + strokeOpacity?: number; + /** Overall opacity (0-1) */ + opacity?: number; +}; + +type CommonEvents = { + /** Click event handler */ + onclick?: MouseEventHandler | null; + /** Double click event handler */ + ondblclick?: MouseEventHandler | null; + /** Pointer enter event handler */ + onpointerenter?: PointerEventHandler | null; + /** Pointer move event handler */ + onpointermove?: PointerEventHandler | null; + /** Pointer leave event handler */ + onpointerleave?: PointerEventHandler | null; + /** Pointer over event handler */ + onpointerover?: PointerEventHandler | null; + /** Pointer out event handler */ + onpointerout?: PointerEventHandler | null; +}; + +type Without = Omit; +type MotionProp = any; +type SingleDomainType = any; +type Placement = 'top' | 'right' | 'bottom' | 'left'; + +${moduleScript} +`; + fs.writeFileSync(tempPath, tempContent); + try { + // Parse the TypeScript file + const program = ts.createProgram([tempPath], { + target: ts.ScriptTarget.ES2020, + module: ts.ModuleKind.ESNext + }); + const sourceFile = program.getSourceFile(tempPath); + if (!sourceFile) { + return null; + } + const checker = program.getTypeChecker(); + let properties = []; + const extendedTypes = []; + // Find the PropsWithoutHTML type for properties + ts.forEachChild(sourceFile, (node) => { + if (ts.isTypeAliasDeclaration(node) && node.name.text === propsTypeName) { + properties = extractPropertiesFromType(node.type, checker, sourceFile); + } + }); + // Also look for the full Props type to extract extended types + // Try both removing "WithoutHTML" and looking for types that end with "Props" + const possibleFullPropsNames = [ + propsTypeName.replace('WithoutHTML', ''), + `${componentName}Props` + ]; + for (const fullPropsTypeName of possibleFullPropsNames) { + ts.forEachChild(sourceFile, (node) => { + if (ts.isTypeAliasDeclaration(node) && node.name.text === fullPropsTypeName) { + const newExtendedTypes = parseExtendedTypes(node.type, sourceFile); + // Merge with existing, avoiding duplicates + for (const extType of newExtendedTypes) { + if (!extendedTypes.some((et) => et.name === extType.name)) { + extendedTypes.push(extType); + } + } + // Extract properties from non-library extended types (like CommonEvents) + for (const extType of extendedTypes) { + if (!extType.isLibraryType) { + // Find this type definition and extract its properties + ts.forEachChild(sourceFile, (typeNode) => { + if (ts.isTypeAliasDeclaration(typeNode) && typeNode.name.text === extType.name) { + const extProperties = extractPropertiesFromType(typeNode.type, checker, sourceFile); + // Add these properties to the main list, avoiding duplicates + for (const prop of extProperties) { + if (!properties.some((p) => p.name === prop.name)) { + properties.push(prop); + } + } + } + }); + } + } + } + }); + } + if (properties.length === 0) { + return null; + } + const result = { + generatedAt: new Date().toISOString(), + component: componentName, + propsType: propsTypeName, + properties + }; + // Only add extends if there are extended types + if (extendedTypes.length > 0) { + result.extends = extendedTypes; + } + return result; + } + finally { + // Clean up temp file + if (fs.existsSync(tempPath)) { + fs.unlinkSync(tempPath); + } + } +} +/** + * Extract APIs for all components in a directory + */ +export function extractAPIs(dir) { + const svelteFiles = getSvelteFiles(dir); + const apis = []; + for (const filePath of svelteFiles) { + const api = extractComponentAPI(filePath); + if (api) { + apis.push(api); + } + } + return apis.sort((a, b) => a.component.localeCompare(b.component)); +} +export function writeComponentAPIs({ componentsDir, outputDir, logger = console }) { + logger.log('Extracting component APIs...'); + const svelteFiles = getSvelteFiles(componentsDir); + logger.log(`Found ${svelteFiles.length} Svelte files`); + const apis = []; + for (const filePath of svelteFiles) { + const componentName = path.basename(filePath, '.svelte'); + logger.log(`Processing ${componentName}...`); + const api = extractComponentAPI(filePath); + if (api) { + apis.push(api); + logger.log(` ✓ Extracted ${api.properties.length} properties`); + } + else { + logger.log(` ⚠ No Props type found`); + } + } + // Sort by component name + apis.sort((a, b) => a.component.localeCompare(b.component)); + // Create output directory if it doesn't exist + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + // Write individual component files + logger.log(`\nWriting individual component files...`); + for (const api of apis) { + const componentFile = path.join(outputDir, `${api.component}.json`); + fs.writeFileSync(componentFile, JSON.stringify(api, null, 2)); + } + // Write index file with list of all components + const indexFile = path.join(outputDir, 'index.json'); + const indexOutput = { + generatedAt: new Date().toISOString(), + components: apis.map((api) => ({ + component: api.component, + propsType: api.propsType, + propertyCount: api.properties.length, + file: `${api.component}.json` + })) + }; + fs.writeFileSync(indexFile, JSON.stringify(indexOutput, null, 2)); + logger.log(`\n✅ Generated ${apis.length} component API files in ${outputDir}`); + logger.log(`✅ Generated index file: ${indexFile}`); + logger.log(` Extracted ${apis.length} component APIs`); + return apis; +} diff --git a/packages/docs/src/lib/node/example-catalog.js b/packages/docs/src/lib/node/example-catalog.js new file mode 100644 index 0000000..574e81d --- /dev/null +++ b/packages/docs/src/lib/node/example-catalog.js @@ -0,0 +1,258 @@ +/** + * LayerChart Example Index Generator + * + * This script generates a catalog for each component that shows: + * - All examples available for that component + * - All usage of that component across all examples + * + * @description + * Scans all components in packages/layerchart/src/lib/components and for each: + * - Finds examples in docs/src/examples/[ComponentName]/ + * - Searches all examples for usage of .svelte` is treated as a public component. + */ +function getComponents(dir) { + const components = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isFile() && entry.name.endsWith('.svelte')) { + if (/\.(svg|canvas|html|base)\.svelte$/.test(entry.name)) + continue; + // Remove .svelte extension to get component name + const componentName = entry.name.replace('.svelte', ''); + components.push(componentName); + } + else if (entry.isDirectory()) { + // Recursively scan subdirectories + components.push(...getComponents(fullPath)); + } + } + return components.sort(); +} +/** + * Extract all component usages from an example file + */ +function extractComponentsFromExample(filePath, allComponents) { + const components = []; + const content = fs.readFileSync(filePath, 'utf-8'); + const lines = content.split('\n'); + // Track which components we've found to avoid duplicates + const foundComponents = new Set(); + // Search for each known component in the file + for (const componentName of allComponents) { + // Use word boundary to avoid matching components with similar prefixes + // Match if followed by: whitespace, >, /, ., :, or end-of-line + const searchPattern = new RegExp(`<${componentName}(?:\\s|>|/|\\.|:|$)`, 'i'); + lines.forEach((line, index) => { + if (searchPattern.test(line) && !foundComponents.has(componentName)) { + foundComponents.add(componentName); + components.push({ + component: componentName, + lineNumber: index + 1, + line: line.trim() + }); + } + }); + } + // Sort by line number + return components.sort((a, b) => a.lineNumber - b.lineNumber); +} +/** + * Extract module-level exports (title, description, tags) from a + + +
    %sveltekit.body%
    + + diff --git a/packages/docs/templates/stackblitz-template/src/routes/+layout.svelte b/packages/docs/templates/stackblitz-template/src/routes/+layout.svelte new file mode 100644 index 0000000..c5cd34f --- /dev/null +++ b/packages/docs/templates/stackblitz-template/src/routes/+layout.svelte @@ -0,0 +1,9 @@ + + +
    + {@render children?.()} +
    diff --git a/packages/docs/templates/stackblitz-template/svelte.config.js b/packages/docs/templates/stackblitz-template/svelte.config.js new file mode 100644 index 0000000..f571400 --- /dev/null +++ b/packages/docs/templates/stackblitz-template/svelte.config.js @@ -0,0 +1,21 @@ +import adapter from '@sveltejs/adapter-auto'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: { + adapter: adapter(), + alias: { + '$static/*': 'static/*' + }, + experimental: { + remoteFunctions: true + } + }, + compilerOptions: { + experimental: { + async: true + } + } +}; + +export default config; diff --git a/packages/docs/templates/stackblitz-template/vite.config.js b/packages/docs/templates/stackblitz-template/vite.config.js new file mode 100644 index 0000000..1ed35fe --- /dev/null +++ b/packages/docs/templates/stackblitz-template/vite.config.js @@ -0,0 +1,14 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; +import tailwindcss from '@tailwindcss/vite'; +import Icons from 'unplugin-icons/vite'; + +export default defineConfig({ + plugins: [ + tailwindcss(), + sveltekit(), + Icons({ + compiler: 'svelte' + }) + ] +}); diff --git a/packages/docs/tsconfig.json b/packages/docs/tsconfig.json new file mode 100644 index 0000000..e37c0e4 --- /dev/null +++ b/packages/docs/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + }, + "exclude": ["node_modules", "dist", "templates"] +} diff --git a/packages/svelte-actions/package.json b/packages/svelte-actions/package.json index 874c24a..365b3c1 100644 --- a/packages/svelte-actions/package.json +++ b/packages/svelte-actions/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "1.0.1-next.18", "scripts": { - "dev": "tsc -p tsconfig.build.json --watch", + "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/packages/svelte-state/package.json b/packages/svelte-state/package.json index a699e60..d1e2a1b 100644 --- a/packages/svelte-state/package.json +++ b/packages/svelte-state/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "0.1.0-next.23", "scripts": { - "dev": "tsc -p tsconfig.build.json --watch", + "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/packages/svelte-stores/package.json b/packages/svelte-stores/package.json index ac40e68..d4cde91 100644 --- a/packages/svelte-stores/package.json +++ b/packages/svelte-stores/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "1.0.2-next.18", "scripts": { - "dev": "tsc -p tsconfig.build.json --watch", + "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/packages/svelte-table/package.json b/packages/svelte-table/package.json index 06860ad..e7e9e04 100644 --- a/packages/svelte-table/package.json +++ b/packages/svelte-table/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "1.0.1-next.18", "scripts": { - "dev": "tsc -p tsconfig.build.json --watch", + "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/packages/tailwind/package.json b/packages/tailwind/package.json index 169da63..61c25fc 100644 --- a/packages/tailwind/package.json +++ b/packages/tailwind/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "2.0.0-next.22", "scripts": { - "dev": "tsc -p tsconfig.build.json --watch", + "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json && pnpm build:css && cp -r ./src/lib/css dist", "build:css": "tsc --noEmit && tsx ./src/lib/cli/index.ts", diff --git a/packages/utils/package.json b/packages/utils/package.json index fb0a82a..0b2d904 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "2.0.0-next.18", "scripts": { - "dev": "tsc -p tsconfig.build.json --watch", + "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 03bcb25..270c064 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,6 +21,115 @@ importers: specifier: ^4.14.4 version: 4.14.4(@cloudflare/workers-types@4.20250514.0) + packages/docs: + dependencies: + '@content-collections/core': + specifier: ^0.14.3 + version: 0.14.3(typescript@5.8.3) + '@content-collections/markdown': + specifier: ^0.1.4 + version: 0.1.4(@content-collections/core@0.14.3(typescript@5.8.3)) + '@iconify-json/simple-icons': + specifier: ^1.2.84 + version: 1.2.84 + '@layerstack/tailwind': + specifier: workspace:* + version: link:../tailwind + '@layerstack/utils': + specifier: workspace:* + version: link:../utils + '@shikijs/transformers': + specifier: ^4.1.0 + version: 4.1.0 + '@sveltejs/svelte-json-tree': + specifier: ^2.2.1 + version: 2.2.1(svelte@5.28.6) + '@webcontainer/api': + specifier: ^1.6.4 + version: 1.6.4 + github-slugger: + specifier: ^2.0.0 + version: 2.0.0 + mdsx: + specifier: ^0.0.7 + version: 0.0.7(svelte@5.28.6) + playwright: + specifier: ^1.60.0 + version: 1.60.0 + rehype-pretty-code: + specifier: ^0.14.3 + version: 0.14.3(shiki@4.1.0) + rehype-slug: + specifier: ^6.0.0 + version: 6.0.0 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + remark-mdc: + specifier: ^3.11.0 + version: 3.11.0 + runed: + specifier: ^0.37.1 + version: 0.37.1(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(zod@4.4.3) + sharp: + specifier: ^0.34.5 + version: 0.34.5 + shiki: + specifier: ^4.1.0 + version: 4.1.0 + svelte-ux: + specifier: 2.0.0-next.22 + version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3)(svelte@5.28.6) + tsx: + specifier: ^4.22.3 + version: 4.22.3 + typescript: + specifier: ^5.8.3 + version: 5.8.3 + unist-builder: + specifier: ^4.0.0 + version: 4.0.0 + unist-util-visit: + specifier: ^5.1.0 + version: 5.1.0 + zod: + specifier: ^4.4.3 + version: 4.4.3 + devDependencies: + '@sveltejs/kit': + specifier: ^2.21.0 + version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) + '@sveltejs/package': + specifier: ^2.3.11 + version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) + '@sveltejs/vite-plugin-svelte': + specifier: ^5.0.3 + version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) + '@types/node': + specifier: ^24.0.1 + version: 24.0.1 + prettier: + specifier: ^3.5.3 + version: 3.5.3 + prettier-plugin-svelte: + specifier: ^3.3.3 + version: 3.3.3(prettier@3.5.3)(svelte@5.28.6) + svelte: + specifier: ^5.28.2 + version: 5.28.6 + svelte-check: + specifier: ^4.1.6 + version: 4.1.7(picomatch@4.0.2)(svelte@5.28.6)(typescript@5.8.3) + tslib: + specifier: ^2.8.1 + version: 2.8.1 + unplugin-icons: + specifier: ^22.1.0 + version: 22.1.0(svelte@5.28.6) + vite: + specifier: ^6.3.5 + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) + packages/svelte-actions: dependencies: '@floating-ui/dom': @@ -38,7 +147,7 @@ importers: version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 - version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@types/d3-scale': specifier: ^4.0.9 version: 4.0.9 @@ -68,10 +177,10 @@ importers: version: 5.8.3 vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) vitest: specifier: ^3.1.3 - version: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) packages/svelte-state: dependencies: @@ -81,13 +190,13 @@ importers: devDependencies: '@sveltejs/kit': specifier: ^2.20.8 - version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@sveltejs/package': specifier: ^2.3.11 version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 - version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -114,10 +223,10 @@ importers: version: 5.8.3 vite: specifier: ^6.3.4 - version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) vitest: specifier: ^3.1.2 - version: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) packages/svelte-stores: dependencies: @@ -133,13 +242,13 @@ importers: devDependencies: '@sveltejs/kit': specifier: ^2.21.0 - version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@sveltejs/package': specifier: ^2.3.11 version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 - version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 @@ -169,10 +278,10 @@ importers: version: 5.8.3 vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) vitest: specifier: ^3.1.3 - version: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) packages/svelte-table: dependencies: @@ -191,7 +300,7 @@ importers: version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 - version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@types/d3-array': specifier: ^3.2.1 version: 3.2.1 @@ -224,10 +333,10 @@ importers: version: 5.8.3 vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) vitest: specifier: ^3.1.3 - version: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) packages/tailwind: dependencies: @@ -288,10 +397,10 @@ importers: version: 5.8.3 vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0) vitest: specifier: ^3.1.3 - version: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0) packages/utils: dependencies: @@ -310,7 +419,7 @@ importers: version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 - version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@types/d3-array': specifier: ^3.2.1 version: 3.2.1 @@ -346,16 +455,19 @@ importers: version: 5.8.3 vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) vitest: specifier: ^3.1.3 - version: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) sites/docs: dependencies: '@fortawesome/fontawesome-common-types': specifier: ^6.7.2 version: 6.7.2 + '@layerstack/docs': + specifier: workspace:* + version: link:../../packages/docs '@layerstack/svelte-actions': specifier: workspace:* version: link:../../packages/svelte-actions @@ -394,7 +506,7 @@ importers: version: 1.30.0 sveld: specifier: ^0.22.1 - version: 0.22.1(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1))(postcss@8.5.3) + version: 0.22.1(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3) tailwind-merge: specifier: ^3.2.0 version: 3.3.0 @@ -402,30 +514,42 @@ importers: '@changesets/cli': specifier: ^2.29.4 version: 2.29.4 + '@content-collections/core': + specifier: ^0.14.3 + version: 0.14.3(typescript@5.8.3) + '@content-collections/markdown': + specifier: ^0.1.4 + version: 0.1.4(@content-collections/core@0.14.3(typescript@5.8.3)) + '@content-collections/vite': + specifier: ^0.2.9 + version: 0.2.9(@content-collections/core@0.14.3(typescript@5.8.3))(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@fortawesome/free-solid-svg-icons': specifier: ^6.7.2 version: 6.7.2 '@iconify-json/lucide': specifier: ^1.2.53 version: 1.2.53 + '@iconify-json/simple-icons': + specifier: ^1.2.84 + version: 1.2.84 '@sveltejs/adapter-cloudflare': specifier: ^7.0.3 - version: 7.0.3(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(wrangler@4.14.4(@cloudflare/workers-types@4.20250514.0)) + version: 7.0.3(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(wrangler@4.14.4(@cloudflare/workers-types@4.20250514.0)) '@sveltejs/kit': specifier: ^2.21.0 - version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@sveltejs/package': specifier: ^2.3.11 version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 - version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@tailwindcss/typography': specifier: ^0.5.16 version: 0.5.16(tailwindcss@4.1.6) '@tailwindcss/vite': specifier: ^4.1.5 - version: 4.1.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + version: 4.1.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@types/d3-array': specifier: ^3.2.1 version: 3.2.1 @@ -435,6 +559,9 @@ importers: mdsvex: specifier: ^0.12.5 version: 0.12.6(svelte@5.28.6) + mdsx: + specifier: ^0.0.7 + version: 0.0.7(svelte@5.28.6) posthog-js: specifier: ^1.239.0 version: 1.242.1 @@ -457,8 +584,8 @@ importers: specifier: ^2.2.0 version: 2.2.0(svelte@5.28.6) svelte-ux: - specifier: 2.0.0-next.13 - version: 2.0.0-next.13(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1))(postcss@8.5.3)(svelte@5.28.6) + specifier: 2.0.0-next.22 + version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3)(svelte@5.28.6) svelte2tsx: specifier: ^0.7.36 version: 0.7.37(svelte@5.28.6)(typescript@5.8.3) @@ -479,7 +606,7 @@ importers: version: 22.1.0(svelte@5.28.6) vite: specifier: ^6.3.5 - version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) packages: @@ -601,163 +728,499 @@ packages: '@cloudflare/workers-types@4.20250514.0': resolution: {integrity: sha512-zjyqRjoFnAzg7n+mxMxJAbIeOggUXLJTXA8WyT+xGDE+6MF9bSf1ypEULu4DXQQYLf6nDM6NwzLex/8ABTH+Lw==} + '@content-collections/core@0.14.3': + resolution: {integrity: sha512-nbgfRswxudlKDBEO2AXVGGfsFMlenV2iVjNDddQGWD0qk3lBDkTRJy0AqdBvBOccB8/cj95nJyXEVocRRNyUcA==} + peerDependencies: + typescript: ^5.0.2 + + '@content-collections/integrations@0.5.0': + resolution: {integrity: sha512-1en7r518sct0Y8CQ5IsuuBN4uAmtNLaWuxmseW43OxeXyj43Uu2aPBfbopjL4b5xH8WZBdDrrPmikgOl42U46A==} + peerDependencies: + '@content-collections/core': 0.x + + '@content-collections/markdown@0.1.4': + resolution: {integrity: sha512-hUi+O9SDmYmn63aiftSw1KtmSZIjc6ger42rfQobBhPx+3n8kTJsWm1Cs//yU5iIAVRKyLX3qrtlheiOPdJT9w==} + peerDependencies: + '@content-collections/core': 0.x + + '@content-collections/vite@0.2.9': + resolution: {integrity: sha512-Eulni4LnzlvqYjWAOR/MYCQBnwn6/yRwJhQDNgsj5Aj56hwNG/zQMPBLhjxH+O2FGXbBTgYvdQickxwApRRu7w==} + peerDependencies: + '@content-collections/core': ^0.x + vite: ^5 || ^6 || ^7 + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.25.4': resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.0': + resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.25.4': resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.0': + resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.25.4': resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.0': + resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.25.4': resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.0': + resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.25.4': resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.0': + resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.25.4': resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.0': + resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.25.4': resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.0': + resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.4': resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.0': + resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.25.4': resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.0': + resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.25.4': resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.0': + resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.25.4': resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.0': + resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.25.4': resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.0': + resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.25.4': resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.0': + resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.25.4': resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.0': + resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.25.4': resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.0': + resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.25.4': resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.0': + resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.25.4': resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.0': + resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.25.4': resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.0': + resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.4': resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.0': + resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.25.4': resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.0': + resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.4': resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.0': + resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.28.0': + resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.25.4': resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.0': + resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.25.4': resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.0': + resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.25.4': resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.0': + resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.25.4': resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.0': + resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} @@ -765,17 +1228,17 @@ packages: '@floating-ui/core@1.7.0': resolution: {integrity: sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==} - '@floating-ui/core@1.7.2': - resolution: {integrity: sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} '@floating-ui/dom@1.7.0': resolution: {integrity: sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==} - '@floating-ui/dom@1.7.2': - resolution: {integrity: sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==} + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} '@floating-ui/utils@0.2.9': resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} @@ -791,117 +1254,257 @@ packages: '@iconify-json/lucide@1.2.53': resolution: {integrity: sha512-LAdOrHp70uYqf/Q9g13qPafF6qjg4XEez7C/0Np5oLSOzfEF49lpMk3xa6ysYTPoWdPYE0qSc/NP3ebJWg3aJg==} + '@iconify-json/simple-icons@1.2.84': + resolution: {integrity: sha512-v4JVu6xIewGoETD4mm2k6UAdFAbTlY1duw5ZNSxYORfs2yFsHDhoU9Omn/BgrV0nR/ptWkF3ZIr/ZHoYXI/6Jw==} + '@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==} + engines: {node: '>=18'} + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + '@img/sharp-darwin-x64@0.33.5': resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + '@img/sharp-libvips-darwin-arm64@1.0.4': resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} cpu: [arm64] os: [darwin] + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + '@img/sharp-libvips-darwin-x64@1.0.4': resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} cpu: [x64] os: [darwin] + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + '@img/sharp-libvips-linux-arm64@1.0.4': resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + '@img/sharp-win32-ia32@0.33.5': resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + '@img/sharp-win32-x64@0.33.5': resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -931,20 +1534,25 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@layerstack/svelte-actions@1.0.1-next.12': - resolution: {integrity: sha512-dndWTlYu8b1u6vw2nrO7NssccoACArGG75WoNlyVC13KuENZlWdKE9Q79/wlnbq00NeQMNKMjJwRMsrKQj2ULA==} + '@layerstack/svelte-actions@1.0.1-next.18': + resolution: {integrity: sha512-gxPzCnJ1c9LTfWtRqLUzefCx+k59ZpxDUQ2XB+LokveZQPe7IDSOwHaBOEMlaGoGrtwc3Ft8dSZq+2WT2o9u/g==} - '@layerstack/svelte-stores@1.0.2-next.12': - resolution: {integrity: sha512-XwKyGCXl3+NHQzB3LsPSo6Rb0TjoY3LZzb1Snw09VnOUxvA9skMmVnM8EO3eKFti/8tyOLReddEUA1ygUaT4Lg==} + '@layerstack/svelte-stores@1.0.2-next.18': + resolution: {integrity: sha512-+6cLiKKQIVIsJRiR2cogle40E54zXRm2Wecv4UolUFzCpfUH51DxDAaM1StDk9kXRJhHKNp+aspzS8tb91AzCQ==} - '@layerstack/svelte-table@1.0.1-next.12': - resolution: {integrity: sha512-u5zFdXQWlEJTGXNf52ku6hjyxmjp6ge6GwkW+oecqknY8v0b9d1MfrEw3dGJ4Ap88I0aBIdufmOkd0TTEwiCkQ==} + '@layerstack/svelte-table@1.0.1-next.18': + resolution: {integrity: sha512-xfZETwBYMTRo7aNNfxyYHKKkK8Lv8GXYEQTVCywFvmXNI6l+X/SvCU/0IDpDuQyktUKu38/e/EaIwcH2a17Otg==} - '@layerstack/tailwind@2.0.0-next.15': - resolution: {integrity: sha512-7tqKE3OV7/ybeDOORX++USYYCBJa7IgTya2czFpzbgXGo7CQDVyuv+0J1DggjRcEqhhXQA4MUhgnhcRaZvHxWg==} + '@layerstack/tailwind@2.0.0-next.22': + resolution: {integrity: sha512-IRp2yvZE7rPPKIt7rWcfm7PtSUAorpqexP73Set39iRS0POOHFqfD6pbV5If1eHMewAdk3xgEQ5QLoz3CPUiHQ==} - '@layerstack/utils@2.0.0-next.12': - resolution: {integrity: sha512-fhGZUlSr3N+D44BYm37WKMGSEFyZBW+dwIqtGU8Cl54mR4TLQ/UwyGhdpgIHyH/x/8q1abE0fP0Dn6ZsrDE3BA==} + '@layerstack/utils@2.0.0-next.18': + resolution: {integrity: sha512-EYILHpfBRYMMEahajInu9C2AXQom5IcAEdtCeucD3QIl/fdDgRbtzn6/8QW9ewumfyNZetdUvitOksmI1+gZYQ==} + + '@lucide/svelte@0.577.0': + resolution: {integrity: sha512-0P6mkySd2MapIEgq08tADPmcN4DHndC/02PWwaLkOerXlx5Sv9aT4BxyXLIY+eccr0g/nEyCYiJesqS61YdBZQ==} + peerDependencies: + svelte: ^5 '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -1090,11 +1698,49 @@ packages: cpu: [x64] os: [win32] + '@shikijs/core@4.1.0': + resolution: {integrity: sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@4.1.0': + resolution: {integrity: sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@4.1.0': + resolution: {integrity: sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg==} + engines: {node: '>=20'} + + '@shikijs/langs@4.1.0': + resolution: {integrity: sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.1.0': + resolution: {integrity: sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw==} + engines: {node: '>=20'} + + '@shikijs/themes@4.1.0': + resolution: {integrity: sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw==} + engines: {node: '>=20'} + + '@shikijs/transformers@4.1.0': + resolution: {integrity: sha512-YbuOcAA3kwqKDU9YSt00dtFLrY5lBXjKU3dWaMATyEyPSqBm9Jqblk/uVICxz7lcjwAHzYaEvIiMWX3mTpogkA==} + engines: {node: '>=20'} + + '@shikijs/types@4.1.0': + resolution: {integrity: sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@skeletonlabs/tw-plugin@0.4.1': resolution: {integrity: sha512-crrC8BGKis0GNTp7V2HF6mk1ECLUvAxgTTV26LMgt/rV3U6Xd7N7dL5qIL8fE4MTHvpKa1SBsdqsnMbEvATeEg==} peerDependencies: tailwindcss: '>=3.0.0' + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@sveltejs/acorn-typescript@1.0.5': resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==} peerDependencies: @@ -1122,6 +1768,12 @@ packages: peerDependencies: svelte: ^3.44.0 || ^4.0.0 || ^5.0.0-next.1 + '@sveltejs/svelte-json-tree@2.2.1': + resolution: {integrity: sha512-M8l23/R3y1fI2+RaOzfUzmkysTWWsw/NClUgGpvydl9vXRonPN1/btQQievaNyeWNfUj12tjPfh5yTrXWpaKkg==} + engines: {pnpm: ^9.0.0} + peerDependencies: + svelte: ^4.0.0 || ^5.0.0 + '@sveltejs/vite-plugin-svelte-inspector@4.0.1': resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22} @@ -1254,6 +1906,9 @@ packages: '@types/d3-time@3.0.4': resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + '@types/estree@0.0.39': resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} @@ -1275,12 +1930,12 @@ packages: '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@22.15.18': - resolution: {integrity: sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg==} - '@types/node@24.0.1': resolution: {integrity: sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==} @@ -1296,6 +1951,12 @@ packages: '@types/unist@3.0.2': resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + '@vitest/expect@3.1.3': resolution: {integrity: sha512-7FTQQuuLKmN1Ig/h+h/GO+44Q1IlglPlR2es4ab7Yvfx+Uk5xsv+Ykk+MEt/M2Yn/xGmzaLKxGw2lgy2bwuYqg==} @@ -1325,6 +1986,9 @@ packages: '@vitest/utils@3.1.3': resolution: {integrity: sha512-2Ltrpht4OmHO9+c/nmHtF09HWiyWdworqnHIwjfvDyWjuwKbdkcS9AnhsDn+8E2RM4x++foD1/tNuLPVvWG1Rg==} + '@webcontainer/api@1.6.4': + resolution: {integrity: sha512-r9sHCXg1FcC1AMgppGwAc0vYWaQhqvg282cnsuPbJEzYnWifAdCVvg+8ngJUEHyHcomhJJp+/zuytite4ITHLw==} + acorn-walk@8.3.2: resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} engines: {node: '>=0.4.0'} @@ -1381,6 +2045,9 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1410,10 +2077,29 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@5.2.0: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} engines: {node: '>=12'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} @@ -1454,6 +2140,9 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + comment-parser@1.4.1: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} @@ -1555,6 +2244,9 @@ packages: supports-color: optional: true + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + dedent-js@1.0.1: resolution: {integrity: sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==} @@ -1569,6 +2261,10 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -1577,9 +2273,16 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devalue@5.1.1: resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -1605,14 +2308,32 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.25.4: resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} engines: {node: '>=18'} hasBin: true + esbuild@0.28.0: + resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + esm-env@1.2.2: resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} @@ -1647,6 +2368,13 @@ packages: exsolve@1.0.7: resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -1683,6 +2411,11 @@ packages: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} + flat@6.0.1: + resolution: {integrity: sha512-/3FfIa8mbrg3xE7+wAhWeV+bd7L2Mof+xtZb5dRDKZ+wDvYJK4WDYeIOuOhre5Yv5aQObZrlbRmk3RTSiuQBtw==} + engines: {node: '>=18'} + hasBin: true + foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -1695,6 +2428,11 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1735,16 +2473,47 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + 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-heading-rank@3.0.0: resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + hast-util-to-string@3.0.0: resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==} + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + human-id@4.1.1: resolution: {integrity: sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==} hasBin: true @@ -1760,10 +2529,19 @@ packages: immer@10.1.1: resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} + immer@10.2.0: + resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} + internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} @@ -1775,6 +2553,13 @@ packages: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1787,6 +2572,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} @@ -1794,6 +2582,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} @@ -1823,6 +2615,10 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -1909,8 +2705,8 @@ packages: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} lodash.castarray@4.4.0: resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} @@ -1924,6 +2720,9 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loupe@3.1.3: resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} @@ -1934,9 +2733,52 @@ packages: resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==} engines: {node: 20 || >=22} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} @@ -1945,10 +2787,99 @@ packages: peerDependencies: svelte: ^3.56.0 || ^4.0.0 || ^5.0.0-next.120 + mdsx@0.0.7: + resolution: {integrity: sha512-Ftgb6Yq47WMaYoFznJ+jNxnn82sDUvot9Nw2uSaolbkghUV6Le1stDzEVHClaKA1hMJnc+jbMagK/HM7nT6FJg==} + peerDependencies: + svelte: ^5.0.0 + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -2018,6 +2949,12 @@ packages: ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} @@ -2033,6 +2970,10 @@ packages: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} + p-limit@6.2.0: + resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==} + engines: {node: '>=18'} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -2051,8 +2992,17 @@ packages: package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} - package-manager-detector@1.3.0: - resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-numeric-range@1.3.0: + resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} @@ -2110,6 +3060,20 @@ packages: pkg-types@2.1.1: resolution: {integrity: sha512-eY0QFb6eSwc9+0d/5D2lFFUq+A3n3QNGSy/X2Nvp+6MfzGw2u6EbA7S80actgjY1lkvvI0pqB+a4hioMh443Ew==} + playwright-core@1.60.0: + resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.60.0: + resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==} + engines: {node: '>=18'} + hasBin: true + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + postcss-js@4.0.1: resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} engines: {node: ^12 || ^14 || >= 16} @@ -2188,6 +3152,9 @@ packages: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + quansync@0.2.10: resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} @@ -2202,13 +3169,52 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + regexparam@3.0.0: resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==} engines: {node: '>=8'} + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-pretty-code@0.14.3: + resolution: {integrity: sha512-Cz692FeYusTjT5cfFWLc4r7JhgC3/JlJptgUh4iffBxWxUnWW1oqbWFi7jGCeq00DYUm8yzoTnvpocaYa5x82g==} + engines: {node: '>=18'} + peerDependencies: + shiki: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + rehype-slug@6.0.0: resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-mdc@3.11.0: + resolution: {integrity: sha512-xFrKmGRa+xgsfAZPA2CDaKILSHSOhX2irjJBrrPLxNrxaz2NFI+gXuVjo6Bkbh2vx7fKKTB5S9yyKyIwJh+FsQ==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -2254,6 +3260,18 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + runed@0.37.1: + resolution: {integrity: sha512-MeFY73xBW8IueWBm012nNFIGy19WUGPLtknavyUPMpnyt350M47PhGSGrGoSLbidwn+Zlt/O0cp8/OZE3LASWA==} + peerDependencies: + '@sveltejs/kit': ^2.21.0 + svelte: ^5.7.0 + zod: ^4.1.0 + peerDependenciesMeta: + '@sveltejs/kit': + optional: true + zod: + optional: true + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -2261,11 +3279,27 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + semver@7.7.2: resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} hasBin: true + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} + engines: {node: '>=10'} + hasBin: true + + serialize-javascript@7.0.5: + resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} + engines: {node: '>=20.0.0'} + set-cookie-parser@2.7.1: resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} @@ -2273,6 +3307,10 @@ packages: resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2281,6 +3319,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shiki@4.1.0: + resolution: {integrity: sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q==} + engines: {node: '>=20'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -2307,6 +3349,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} @@ -2334,6 +3379,9 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -2342,6 +3390,10 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -2404,8 +3456,8 @@ packages: typescript: optional: true - svelte-ux@2.0.0-next.13: - resolution: {integrity: sha512-PWugr8yFJDCrxCFOYcHQfySoi6UndguVIn5Xy7VuYtS75I+lW+wB4BRzMd+epOsMVib00yPOiH4XTblQaXIdDQ==} + svelte-ux@2.0.0-next.22: + resolution: {integrity: sha512-5IwO5hmQQ5YytcxpD/I+j0aPXOuqaS86IJG0OO9rmWTP8MkkUrokfJqIaGXRWw0zmacUw6doSJMRmnnkAYoyhA==} peerDependencies: svelte: ^3.56.0 || ^4.0.0 || ^5.0.0 @@ -2485,6 +3537,12 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -2493,6 +3551,11 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tsx@4.22.3: + resolution: {integrity: sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==} + engines: {node: '>=18.0.0'} + hasBin: true + typescript@5.8.3: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} @@ -2501,9 +3564,6 @@ packages: ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.8.0: resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} @@ -2514,27 +3574,45 @@ packages: unenv@2.0.0-rc.15: resolution: {integrity: sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA==} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-builder@4.0.0: + resolution: {integrity: sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg==} + unist-util-is@4.1.0: resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} unist-util-is@6.0.0: resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-stringify-position@2.0.3: resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + unist-util-visit-parents@3.1.1: resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} unist-util-visit-parents@6.0.1: resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + unist-util-visit@2.0.3: resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -2569,9 +3647,18 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + vfile-message@2.0.4: resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vite-node@3.1.3: resolution: {integrity: sha512-uHV4plJ2IxCl4u1up1FQRrqclylKAogbtBfOTwcuJ28xFi+89PZ57BRh+naIRvH70HPwxy5QHYzg1OrEaC7AbA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -2653,6 +3740,9 @@ packages: jsdom: optional: true + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-vitals@4.2.4: resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} @@ -2723,6 +3813,15 @@ packages: engines: {node: '>= 14'} hasBin: true + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + youch@3.3.4: resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} @@ -2738,6 +3837,12 @@ packages: zod@3.25.67: resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@ampproject/remapping@2.3.0': @@ -2930,111 +4035,308 @@ snapshots: '@cloudflare/workers-types@4.20250514.0': {} + '@content-collections/core@0.14.3(typescript@5.8.3)': + dependencies: + '@standard-schema/spec': 1.1.0 + camelcase: 8.0.0 + chokidar: 4.0.3 + esbuild: 0.25.12 + gray-matter: 4.0.3 + p-limit: 6.2.0 + picomatch: 4.0.2 + pluralize: 8.0.0 + serialize-javascript: 7.0.5 + tinyglobby: 0.2.13 + typescript: 5.8.3 + yaml: 2.7.1 + + '@content-collections/integrations@0.5.0(@content-collections/core@0.14.3(typescript@5.8.3))': + dependencies: + '@content-collections/core': 0.14.3(typescript@5.8.3) + + '@content-collections/markdown@0.1.4(@content-collections/core@0.14.3(typescript@5.8.3))': + dependencies: + '@content-collections/core': 0.14.3(typescript@5.8.3) + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + '@content-collections/vite@0.2.9(@content-collections/core@0.14.3(typescript@5.8.3))(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0))': + dependencies: + '@content-collections/core': 0.14.3(typescript@5.8.3) + '@content-collections/integrations': 0.5.0(@content-collections/core@0.14.3(typescript@5.8.3)) + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.4.3': dependencies: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.25.12': + optional: true + '@esbuild/aix-ppc64@0.25.4': optional: true + '@esbuild/aix-ppc64@0.28.0': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + '@esbuild/android-arm64@0.25.4': optional: true + '@esbuild/android-arm64@0.28.0': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + '@esbuild/android-arm@0.25.4': optional: true + '@esbuild/android-arm@0.28.0': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + '@esbuild/android-x64@0.25.4': optional: true + '@esbuild/android-x64@0.28.0': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + '@esbuild/darwin-arm64@0.25.4': optional: true + '@esbuild/darwin-arm64@0.28.0': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + '@esbuild/darwin-x64@0.25.4': optional: true + '@esbuild/darwin-x64@0.28.0': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + '@esbuild/freebsd-arm64@0.25.4': optional: true + '@esbuild/freebsd-arm64@0.28.0': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + '@esbuild/freebsd-x64@0.25.4': optional: true + '@esbuild/freebsd-x64@0.28.0': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + '@esbuild/linux-arm64@0.25.4': optional: true + '@esbuild/linux-arm64@0.28.0': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + '@esbuild/linux-arm@0.25.4': optional: true + '@esbuild/linux-arm@0.28.0': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + '@esbuild/linux-ia32@0.25.4': optional: true + '@esbuild/linux-ia32@0.28.0': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + '@esbuild/linux-loong64@0.25.4': optional: true + '@esbuild/linux-loong64@0.28.0': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + '@esbuild/linux-mips64el@0.25.4': optional: true + '@esbuild/linux-mips64el@0.28.0': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + '@esbuild/linux-ppc64@0.25.4': optional: true + '@esbuild/linux-ppc64@0.28.0': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + '@esbuild/linux-riscv64@0.25.4': optional: true + '@esbuild/linux-riscv64@0.28.0': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + '@esbuild/linux-s390x@0.25.4': optional: true + '@esbuild/linux-s390x@0.28.0': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + '@esbuild/linux-x64@0.25.4': optional: true + '@esbuild/linux-x64@0.28.0': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + '@esbuild/netbsd-arm64@0.25.4': optional: true + '@esbuild/netbsd-arm64@0.28.0': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + '@esbuild/netbsd-x64@0.25.4': optional: true + '@esbuild/netbsd-x64@0.28.0': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + '@esbuild/openbsd-arm64@0.25.4': optional: true + '@esbuild/openbsd-arm64@0.28.0': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + '@esbuild/openbsd-x64@0.25.4': optional: true + '@esbuild/openbsd-x64@0.28.0': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.28.0': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + '@esbuild/sunos-x64@0.25.4': optional: true + '@esbuild/sunos-x64@0.28.0': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + '@esbuild/win32-arm64@0.25.4': optional: true + '@esbuild/win32-arm64@0.28.0': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + '@esbuild/win32-ia32@0.25.4': optional: true + '@esbuild/win32-ia32@0.28.0': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + '@esbuild/win32-x64@0.25.4': optional: true + '@esbuild/win32-x64@0.28.0': + optional: true + '@fastify/busboy@2.1.1': {} '@floating-ui/core@1.7.0': dependencies: '@floating-ui/utils': 0.2.9 - '@floating-ui/core@1.7.2': + '@floating-ui/core@1.7.5': dependencies: - '@floating-ui/utils': 0.2.10 + '@floating-ui/utils': 0.2.11 '@floating-ui/dom@1.7.0': dependencies: '@floating-ui/core': 1.7.0 '@floating-ui/utils': 0.2.9 - '@floating-ui/dom@1.7.2': + '@floating-ui/dom@1.7.6': dependencies: - '@floating-ui/core': 1.7.2 - '@floating-ui/utils': 0.2.10 + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 - '@floating-ui/utils@0.2.10': {} + '@floating-ui/utils@0.2.11': {} '@floating-ui/utils@0.2.9': {} @@ -3048,6 +4350,10 @@ snapshots: dependencies: '@iconify/types': 2.0.0 + '@iconify-json/simple-icons@1.2.84': + dependencies: + '@iconify/types': 2.0.0 + '@iconify/types@2.0.0': {} '@iconify/utils@2.3.0': @@ -3063,81 +4369,177 @@ snapshots: transitivePeerDependencies: - supports-color + '@img/colour@1.1.0': {} + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 optional: true + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + '@img/sharp-darwin-x64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-x64': 1.0.4 optional: true + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + '@img/sharp-libvips-darwin-arm64@1.0.4': optional: true + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + '@img/sharp-libvips-darwin-x64@1.0.4': optional: true + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + '@img/sharp-libvips-linux-arm64@1.0.4': optional: true + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + '@img/sharp-libvips-linux-arm@1.0.5': optional: true + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + '@img/sharp-libvips-linux-s390x@1.0.4': optional: true + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + '@img/sharp-libvips-linux-x64@1.0.4': optional: true + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': optional: true + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + '@img/sharp-libvips-linuxmusl-x64@1.0.4': optional: true + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + '@img/sharp-linux-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-arm64': 1.0.4 optional: true + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + '@img/sharp-linux-arm@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-arm': 1.0.5 optional: true + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + '@img/sharp-linux-s390x@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-s390x': 1.0.4 optional: true + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + '@img/sharp-linux-x64@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-x64': 1.0.4 optional: true + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + '@img/sharp-linuxmusl-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 optional: true + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + '@img/sharp-linuxmusl-x64@0.33.5': optionalDependencies: '@img/sharp-libvips-linuxmusl-x64': 1.0.4 optional: true + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + '@img/sharp-wasm32@0.33.5': dependencies: '@emnapi/runtime': 1.4.3 optional: true + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + '@img/sharp-win32-ia32@0.33.5': optional: true + '@img/sharp-win32-ia32@0.34.5': + optional: true + '@img/sharp-win32-x64@0.33.5': optional: true + '@img/sharp-win32-x64@0.34.5': + optional: true + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -3173,40 +4575,40 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@layerstack/svelte-actions@1.0.1-next.12': + '@layerstack/svelte-actions@1.0.1-next.18': dependencies: - '@floating-ui/dom': 1.7.2 - '@layerstack/utils': 2.0.0-next.12 + '@floating-ui/dom': 1.7.6 + '@layerstack/utils': 2.0.0-next.18 d3-scale: 4.0.2 - '@layerstack/svelte-stores@1.0.2-next.12': + '@layerstack/svelte-stores@1.0.2-next.18': dependencies: - '@layerstack/utils': 2.0.0-next.12 - immer: 10.1.1 - lodash-es: 4.17.21 + '@layerstack/utils': 2.0.0-next.18 + immer: 10.2.0 zod: 3.25.67 - '@layerstack/svelte-table@1.0.1-next.12': + '@layerstack/svelte-table@1.0.1-next.18': dependencies: - '@layerstack/svelte-actions': 1.0.1-next.12 - '@layerstack/utils': 2.0.0-next.12 + '@layerstack/svelte-actions': 1.0.1-next.18 + '@layerstack/utils': 2.0.0-next.18 d3-array: 3.2.4 - lodash-es: 4.17.21 - '@layerstack/tailwind@2.0.0-next.15': + '@layerstack/tailwind@2.0.0-next.22': dependencies: - '@layerstack/utils': 2.0.0-next.12 + '@layerstack/utils': 2.0.0-next.18 clsx: 2.1.1 d3-array: 3.2.4 - lodash-es: 4.17.21 tailwind-merge: 3.3.0 - '@layerstack/utils@2.0.0-next.12': + '@layerstack/utils@2.0.0-next.18': dependencies: d3-array: 3.2.4 d3-time: 3.1.0 d3-time-format: 4.1.0 - lodash-es: 4.17.21 + + '@lucide/svelte@0.577.0(svelte@5.28.6)': + dependencies: + svelte: 5.28.6 '@manypkg/find-root@1.1.0': dependencies: @@ -3325,25 +4727,72 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.40.2': optional: true + '@shikijs/core@4.1.0': + dependencies: + '@shikijs/primitive': 4.1.0 + '@shikijs/types': 4.1.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@4.1.0': + dependencies: + '@shikijs/types': 4.1.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@4.1.0': + dependencies: + '@shikijs/types': 4.1.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@4.1.0': + dependencies: + '@shikijs/types': 4.1.0 + + '@shikijs/primitive@4.1.0': + dependencies: + '@shikijs/types': 4.1.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/themes@4.1.0': + dependencies: + '@shikijs/types': 4.1.0 + + '@shikijs/transformers@4.1.0': + dependencies: + '@shikijs/core': 4.1.0 + '@shikijs/types': 4.1.0 + + '@shikijs/types@4.1.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + '@skeletonlabs/tw-plugin@0.4.1(tailwindcss@4.1.6)': dependencies: tailwindcss: 4.1.6 + '@standard-schema/spec@1.1.0': {} + '@sveltejs/acorn-typescript@1.0.5(acorn@8.14.1)': dependencies: acorn: 8.14.1 - '@sveltejs/adapter-cloudflare@7.0.3(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(wrangler@4.14.4(@cloudflare/workers-types@4.20250514.0))': + '@sveltejs/adapter-cloudflare@7.0.3(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(wrangler@4.14.4(@cloudflare/workers-types@4.20250514.0))': dependencies: '@cloudflare/workers-types': 4.20250514.0 - '@sveltejs/kit': 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + '@sveltejs/kit': 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) worktop: 0.8.0-next.18 wrangler: 4.14.4(@cloudflare/workers-types@4.20250514.0) - '@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1))': + '@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0))': dependencies: '@sveltejs/acorn-typescript': 1.0.5(acorn@8.14.1) - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@types/cookie': 0.6.0 acorn: 8.14.1 cookie: 0.6.0 @@ -3356,7 +4805,7 @@ snapshots: set-cookie-parser: 2.7.1 sirv: 3.0.1 svelte: 5.28.6 - vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) '@sveltejs/package@2.3.11(svelte@5.28.6)(typescript@5.8.3)': dependencies: @@ -3369,25 +4818,29 @@ snapshots: transitivePeerDependencies: - typescript - '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1))': + '@sveltejs/svelte-json-tree@2.2.1(svelte@5.28.6)': + dependencies: + svelte: 5.28.6 + + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) debug: 4.4.0 svelte: 5.28.6 - vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1))': + '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) debug: 4.4.0 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.17 svelte: 5.28.6 - vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) - vitefu: 1.0.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) + vitefu: 1.0.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) transitivePeerDependencies: - supports-color @@ -3470,12 +4923,12 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.1.6 - '@tailwindcss/vite@4.1.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1))': + '@tailwindcss/vite@4.1.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.1.6 '@tailwindcss/oxide': 4.1.6 tailwindcss: 4.1.6 - vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) '@types/cookie@0.6.0': {} @@ -3491,6 +4944,10 @@ snapshots: '@types/d3-time@3.0.4': {} + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + '@types/estree@0.0.39': {} '@types/estree@1.0.6': {} @@ -3511,11 +4968,9 @@ snapshots: dependencies: '@types/unist': 3.0.2 - '@types/node@12.20.55': {} + '@types/ms@2.1.0': {} - '@types/node@22.15.18': - dependencies: - undici-types: 6.21.0 + '@types/node@12.20.55': {} '@types/node@24.0.1': dependencies: @@ -3525,12 +4980,16 @@ snapshots: '@types/resolve@1.17.1': dependencies: - '@types/node': 22.15.18 + '@types/node': 24.0.1 '@types/unist@2.0.11': {} '@types/unist@3.0.2': {} + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.3.1': {} + '@vitest/expect@3.1.3': dependencies: '@vitest/spy': 3.1.3 @@ -3538,13 +4997,21 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.1.3(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1))': + '@vitest/mocker@3.1.3(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0))': dependencies: '@vitest/spy': 3.1.3 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0) + + '@vitest/mocker@3.1.3(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0))': + dependencies: + '@vitest/spy': 3.1.3 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) '@vitest/pretty-format@3.1.3': dependencies: @@ -3571,6 +5038,8 @@ snapshots: loupe: 3.1.3 tinyrainbow: 2.0.0 + '@webcontainer/api@1.6.4': {} + acorn-walk@8.3.2: {} acorn@8.14.0: {} @@ -3605,6 +5074,8 @@ snapshots: axobject-query@4.1.0: {} + bail@2.0.2: {} + balanced-match@1.0.2: {} better-path-resolve@1.0.0: @@ -3627,6 +5098,10 @@ snapshots: camelcase-css@2.0.1: {} + camelcase@8.0.0: {} + + ccount@2.0.1: {} + chai@5.2.0: dependencies: assertion-error: 2.0.1 @@ -3635,6 +5110,14 @@ snapshots: loupe: 3.1.3 pathval: 2.0.0 + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + chardet@0.7.0: {} check-error@2.1.1: {} @@ -3675,6 +5158,8 @@ snapshots: color-string: 1.9.1 optional: true + comma-separated-tokens@2.0.3: {} + comment-parser@1.4.1: {} confbox@0.1.8: {} @@ -3758,6 +5243,10 @@ snapshots: dependencies: ms: 2.1.3 + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + dedent-js@1.0.1: {} deep-eql@5.0.2: {} @@ -3766,12 +5255,20 @@ snapshots: defu@6.1.4: {} + dequal@2.0.3: {} + detect-indent@6.1.0: {} detect-libc@2.0.4: {} + detect-libc@2.1.2: {} + devalue@5.1.1: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -3794,8 +5291,39 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + entities@6.0.1: {} + es-module-lexer@1.7.0: {} + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + esbuild@0.25.4: optionalDependencies: '@esbuild/aix-ppc64': 0.25.4 @@ -3824,6 +5352,37 @@ snapshots: '@esbuild/win32-ia32': 0.25.4 '@esbuild/win32-x64': 0.25.4 + esbuild@0.28.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.0 + '@esbuild/android-arm': 0.28.0 + '@esbuild/android-arm64': 0.28.0 + '@esbuild/android-x64': 0.28.0 + '@esbuild/darwin-arm64': 0.28.0 + '@esbuild/darwin-x64': 0.28.0 + '@esbuild/freebsd-arm64': 0.28.0 + '@esbuild/freebsd-x64': 0.28.0 + '@esbuild/linux-arm': 0.28.0 + '@esbuild/linux-arm64': 0.28.0 + '@esbuild/linux-ia32': 0.28.0 + '@esbuild/linux-loong64': 0.28.0 + '@esbuild/linux-mips64el': 0.28.0 + '@esbuild/linux-ppc64': 0.28.0 + '@esbuild/linux-riscv64': 0.28.0 + '@esbuild/linux-s390x': 0.28.0 + '@esbuild/linux-x64': 0.28.0 + '@esbuild/netbsd-arm64': 0.28.0 + '@esbuild/netbsd-x64': 0.28.0 + '@esbuild/openbsd-arm64': 0.28.0 + '@esbuild/openbsd-x64': 0.28.0 + '@esbuild/openharmony-arm64': 0.28.0 + '@esbuild/sunos-x64': 0.28.0 + '@esbuild/win32-arm64': 0.28.0 + '@esbuild/win32-ia32': 0.28.0 + '@esbuild/win32-x64': 0.28.0 + + escape-string-regexp@5.0.0: {} + esm-env@1.2.2: {} esprima@4.0.1: {} @@ -3848,6 +5407,12 @@ snapshots: exsolve@1.0.7: {} + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend@3.0.2: {} + extendable-error@0.1.7: {} external-editor@3.1.0: @@ -3885,6 +5450,8 @@ snapshots: locate-path: 5.0.0 path-exists: 4.0.0 + flat@6.0.1: {} + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.6 @@ -3902,6 +5469,9 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -3946,18 +5516,103 @@ snapshots: graceful-fs@4.2.11: {} + gray-matter@4.0.3: + dependencies: + js-yaml: 3.14.1 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + hasown@2.0.2: dependencies: function-bind: 1.1.2 + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.2 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + hast-util-heading-rank@3.0.0: dependencies: '@types/hast': 3.0.4 + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.2 + '@ungap/structured-clone': 1.3.1 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.2 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + hast-util-to-string@3.0.0: dependencies: '@types/hast': 3.0.4 + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + html-void-elements@3.0.0: {} + human-id@4.1.1: {} iconv-lite@0.4.24: @@ -3968,8 +5623,17 @@ snapshots: immer@10.1.1: {} + immer@10.2.0: {} + internmap@2.0.3: {} + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-arrayish@0.3.2: optional: true @@ -3981,6 +5645,10 @@ snapshots: dependencies: hasown: 2.0.2 + is-decimal@2.0.1: {} + + is-extendable@0.1.1: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -3989,10 +5657,14 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-module@1.0.0: {} is-number@7.0.0: {} + is-plain-obj@4.1.0: {} + is-reference@3.0.3: dependencies: '@types/estree': 1.0.7 @@ -4022,6 +5694,8 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + kind-of@6.0.3: {} + kleur@4.1.5: {} kolorist@1.8.0: {} @@ -4044,83 +5718,412 @@ snapshots: lightningcss-linux-arm64-musl@1.29.2: optional: true - lightningcss-linux-x64-gnu@1.29.2: - optional: true + lightningcss-linux-x64-gnu@1.29.2: + optional: true + + lightningcss-linux-x64-musl@1.29.2: + optional: true + + lightningcss-win32-arm64-msvc@1.29.2: + optional: true + + lightningcss-win32-x64-msvc@1.29.2: + optional: true + + lightningcss@1.29.2: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.29.2 + lightningcss-darwin-x64: 1.29.2 + lightningcss-freebsd-x64: 1.29.2 + lightningcss-linux-arm-gnueabihf: 1.29.2 + lightningcss-linux-arm64-gnu: 1.29.2 + lightningcss-linux-arm64-musl: 1.29.2 + lightningcss-linux-x64-gnu: 1.29.2 + lightningcss-linux-x64-musl: 1.29.2 + lightningcss-win32-arm64-msvc: 1.29.2 + lightningcss-win32-x64-msvc: 1.29.2 + + lilconfig@3.1.3: + optional: true + + local-pkg@1.1.1: + dependencies: + mlly: 1.7.4 + pkg-types: 2.1.1 + quansync: 0.2.10 + + locate-character@3.0.0: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash-es@4.18.1: {} + + lodash.castarray@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + + lodash.startcase@4.4.0: {} + + longest-streak@3.1.0: {} + + loupe@3.1.3: {} + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lru-cache@11.0.0: {} + + lz-string@1.5.0: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + markdown-table@3.0.4: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.0 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.1 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.2 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdn-data@2.0.30: {} + + mdsvex@0.12.6(svelte@5.28.6): + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 2.0.11 + prism-svelte: 0.4.7 + prismjs: 1.30.0 + svelte: 5.28.6 + unist-util-visit: 2.0.3 + vfile-message: 2.0.4 + + mdsx@0.0.7(svelte@5.28.6): + dependencies: + esrap: 1.4.6 + hast-util-to-html: 9.0.5 + magic-string: 0.30.17 + mdast-util-to-markdown: 2.1.2 + rehype-stringify: 10.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + svelte: 5.28.6 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + yaml: 2.7.1 + zimmerframe: 1.1.2 + transitivePeerDependencies: + - supports-color + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 - lightningcss-linux-x64-musl@1.29.2: - optional: true + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - lightningcss-win32-arm64-msvc@1.29.2: - optional: true + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - lightningcss-win32-x64-msvc@1.29.2: - optional: true + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 - lightningcss@1.29.2: + micromark-factory-title@2.0.1: dependencies: - detect-libc: 2.0.4 - optionalDependencies: - lightningcss-darwin-arm64: 1.29.2 - lightningcss-darwin-x64: 1.29.2 - lightningcss-freebsd-x64: 1.29.2 - lightningcss-linux-arm-gnueabihf: 1.29.2 - lightningcss-linux-arm64-gnu: 1.29.2 - lightningcss-linux-arm64-musl: 1.29.2 - lightningcss-linux-x64-gnu: 1.29.2 - lightningcss-linux-x64-musl: 1.29.2 - lightningcss-win32-arm64-msvc: 1.29.2 - lightningcss-win32-x64-msvc: 1.29.2 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - lilconfig@3.1.3: - optional: true + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - local-pkg@1.1.1: + micromark-util-character@2.1.1: dependencies: - mlly: 1.7.4 - pkg-types: 2.1.1 - quansync: 0.2.10 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - locate-character@3.0.0: {} + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 - locate-path@5.0.0: + micromark-util-classify-character@2.0.1: dependencies: - p-locate: 4.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - lodash-es@4.17.21: {} + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 - lodash.castarray@4.4.0: {} + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 - lodash.isplainobject@4.0.6: {} + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 - lodash.merge@4.6.2: {} + micromark-util-encode@2.0.1: {} - lodash.startcase@4.4.0: {} + micromark-util-html-tag-name@2.0.1: {} - loupe@3.1.3: {} + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 - lower-case@2.0.2: + micromark-util-resolve-all@2.0.1: dependencies: - tslib: 2.8.1 + micromark-util-types: 2.0.2 - lru-cache@11.0.0: {} + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 - magic-string@0.30.17: + micromark-util-subtokenize@2.1.0: dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - mdn-data@2.0.30: {} + micromark-util-symbol@2.0.1: {} - mdsvex@0.12.6(svelte@5.28.6): - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 2.0.11 - prism-svelte: 0.4.7 - prismjs: 1.30.0 - svelte: 5.28.6 - unist-util-visit: 2.0.3 - vfile-message: 2.0.4 + micromark-util-types@2.0.2: {} - merge2@1.4.1: {} + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.1 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color micromatch@4.0.8: dependencies: @@ -4186,6 +6189,14 @@ snapshots: ohash@2.0.11: {} + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + os-tmpdir@1.0.2: {} outdent@0.5.0: {} @@ -4198,6 +6209,10 @@ snapshots: dependencies: p-try: 2.2.0 + p-limit@6.2.0: + dependencies: + yocto-queue: 1.2.2 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -4214,6 +6229,22 @@ snapshots: package-manager-detector@1.3.0: {} + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-numeric-range@1.3.0: {} + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + pascal-case@3.1.2: dependencies: no-case: 3.0.4 @@ -4264,19 +6295,29 @@ snapshots: exsolve: 1.0.7 pathe: 2.0.3 + playwright-core@1.60.0: {} + + playwright@1.60.0: + dependencies: + playwright-core: 1.60.0 + optionalDependencies: + fsevents: 2.3.2 + + pluralize@8.0.0: {} + postcss-js@4.0.1(postcss@8.5.3): dependencies: camelcase-css: 2.0.1 postcss: 8.5.3 - postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1): + postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.4.2 postcss: 8.5.3 - tsx: 4.19.4 - yaml: 2.7.1 + tsx: 4.22.3 + yaml: 2.9.0 optional: true postcss-selector-parser@6.0.10: @@ -4318,6 +6359,8 @@ snapshots: prismjs@1.30.0: {} + property-information@7.1.0: {} + quansync@0.2.10: {} queue-microtask@1.2.3: {} @@ -4331,15 +6374,110 @@ snapshots: readdirp@4.1.2: {} + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + regexparam@3.0.0: {} + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-pretty-code@0.14.3(shiki@4.1.0): + dependencies: + '@types/hast': 3.0.4 + hast-util-to-string: 3.0.0 + parse-numeric-range: 1.3.0 + rehype-parse: 9.0.1 + shiki: 4.1.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + rehype-slug@6.0.0: dependencies: '@types/hast': 3.0.4 github-slugger: 2.0.0 hast-util-heading-rank: 3.0.0 hast-util-to-string: 3.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdc@3.11.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + flat: 6.0.1 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark: 4.0.2 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + parse-entities: 4.0.2 + scule: 1.3.0 + stringify-entities: 4.0.4 + unified: 11.0.5 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + yaml: 2.9.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 resolve-from@5.0.0: {} @@ -4401,14 +6539,35 @@ snapshots: dependencies: queue-microtask: 1.2.3 + runed@0.37.1(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(zod@4.4.3): + dependencies: + dequal: 2.0.3 + esm-env: 1.2.2 + lz-string: 1.5.0 + svelte: 5.28.6 + optionalDependencies: + '@sveltejs/kit': 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) + zod: 4.4.3 + sade@1.8.1: dependencies: mri: 1.2.0 safer-buffer@2.1.2: {} + scule@1.3.0: {} + + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + semver@7.7.2: {} + semver@7.8.1: {} + + serialize-javascript@7.0.5: {} + set-cookie-parser@2.7.1: {} sharp@0.33.5: @@ -4438,12 +6597,54 @@ snapshots: '@img/sharp-win32-x64': 0.33.5 optional: true + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.1 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + shiki@4.1.0: + dependencies: + '@shikijs/core': 4.1.0 + '@shikijs/engine-javascript': 4.1.0 + '@shikijs/engine-oniguruma': 4.1.0 + '@shikijs/langs': 4.1.0 + '@shikijs/themes': 4.1.0 + '@shikijs/types': 4.1.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + siginfo@2.0.0: {} signal-exit@4.1.0: {} @@ -4465,6 +6666,8 @@ snapshots: source-map@0.6.1: {} + space-separated-tokens@2.0.2: {} + spawndamnit@3.0.1: dependencies: cross-spawn: 7.0.6 @@ -4495,6 +6698,11 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -4503,11 +6711,13 @@ snapshots: dependencies: ansi-regex: 6.0.1 + strip-bom-string@1.0.0: {} + strip-bom@3.0.0: {} supports-preserve-symlinks-flag@1.0.0: {} - sveld@0.22.1(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1))(postcss@8.5.3): + sveld@0.22.1(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3): dependencies: '@rollup/plugin-node-resolve': 13.3.0(rollup@2.79.2) acorn: 8.14.0 @@ -4516,7 +6726,7 @@ snapshots: rollup: 2.79.2 rollup-plugin-svelte: 7.2.2(rollup@2.79.2)(svelte@4.2.19) svelte: 4.2.19 - svelte-preprocess: 6.0.3(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1))(postcss@8.5.3)(svelte@4.2.19)(typescript@5.8.3) + svelte-preprocess: 6.0.3(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3)(svelte@4.2.19)(typescript@5.8.3) tinyglobby: 0.2.12 typescript: 5.8.3 transitivePeerDependencies: @@ -4546,32 +6756,32 @@ snapshots: dependencies: svelte: 5.28.6 - svelte-preprocess@6.0.3(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1))(postcss@8.5.3)(svelte@4.2.19)(typescript@5.8.3): + svelte-preprocess@6.0.3(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3)(svelte@4.2.19)(typescript@5.8.3): dependencies: svelte: 4.2.19 optionalDependencies: postcss: 8.5.3 - postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1) + postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0) typescript: 5.8.3 - svelte-ux@2.0.0-next.13(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1))(postcss@8.5.3)(svelte@5.28.6): + svelte-ux@2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3)(svelte@5.28.6): dependencies: - '@floating-ui/dom': 1.7.2 - '@layerstack/svelte-actions': 1.0.1-next.12 - '@layerstack/svelte-stores': 1.0.2-next.12 - '@layerstack/svelte-table': 1.0.1-next.12 - '@layerstack/tailwind': 2.0.0-next.15 - '@layerstack/utils': 2.0.0-next.12 - '@mdi/js': 7.4.47 + '@floating-ui/dom': 1.7.6 + '@layerstack/svelte-actions': 1.0.1-next.18 + '@layerstack/svelte-stores': 1.0.2-next.18 + '@layerstack/svelte-table': 1.0.1-next.18 + '@layerstack/tailwind': 2.0.0-next.22 + '@layerstack/utils': 2.0.0-next.18 + '@lucide/svelte': 0.577.0(svelte@5.28.6) d3-array: 3.2.4 d3-scale: 4.0.2 esm-env: 1.2.2 - immer: 10.1.1 - lodash-es: 4.17.21 + immer: 10.2.0 + lodash-es: 4.18.1 prism-svelte: 0.5.0 prism-themes: 1.9.0 prismjs: 1.30.0 - sveld: 0.22.1(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(yaml@2.7.1))(postcss@8.5.3) + sveld: 0.22.1(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3) svelte: 5.28.6 zod: 3.25.67 transitivePeerDependencies: @@ -4677,6 +6887,10 @@ snapshots: tr46@0.0.3: {} + trim-lines@3.0.1: {} + + trough@2.2.0: {} + tslib@2.8.1: {} tsx@4.19.4: @@ -4686,12 +6900,16 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tsx@4.22.3: + dependencies: + esbuild: 0.28.0 + optionalDependencies: + fsevents: 2.3.3 + typescript@5.8.3: {} ufo@1.6.1: {} - undici-types@6.21.0: {} - undici-types@7.8.0: {} undici@5.29.0: @@ -4706,16 +6924,38 @@ snapshots: pathe: 2.0.3 ufo: 1.6.1 + unified@11.0.5: + dependencies: + '@types/unist': 3.0.2 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-builder@4.0.0: + dependencies: + '@types/unist': 3.0.2 + unist-util-is@4.1.0: {} unist-util-is@6.0.0: dependencies: '@types/unist': 3.0.2 + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position@2.0.3: dependencies: '@types/unist': 2.0.11 + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit-parents@3.1.1: dependencies: '@types/unist': 2.0.11 @@ -4726,6 +6966,11 @@ snapshots: '@types/unist': 3.0.2 unist-util-is: 6.0.0 + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit@2.0.3: dependencies: '@types/unist': 2.0.11 @@ -4738,6 +6983,12 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + universalify@0.1.2: {} unplugin-icons@22.1.0(svelte@5.28.6): @@ -4760,18 +7011,54 @@ snapshots: util-deprecate@1.0.2: {} + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.2 + vfile: 6.0.3 + vfile-message@2.0.4: dependencies: '@types/unist': 2.0.11 unist-util-stringify-position: 2.0.3 - vite-node@3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1): + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.2 + vfile-message: 4.0.3 + + vite-node@3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0): + dependencies: + cac: 6.7.14 + debug: 4.4.1 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite-node@3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - jiti @@ -4786,7 +7073,7 @@ snapshots: - tsx - yaml - vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1): + vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0): dependencies: esbuild: 0.25.4 fdir: 6.4.4(picomatch@4.0.2) @@ -4800,16 +7087,72 @@ snapshots: jiti: 2.4.2 lightningcss: 1.29.2 tsx: 4.19.4 - yaml: 2.7.1 + yaml: 2.9.0 + + vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0): + dependencies: + esbuild: 0.25.4 + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.3 + rollup: 4.40.2 + tinyglobby: 0.2.13 + optionalDependencies: + '@types/node': 24.0.1 + fsevents: 2.3.3 + jiti: 2.4.2 + lightningcss: 1.29.2 + tsx: 4.22.3 + yaml: 2.9.0 + + vitefu@1.0.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)): + optionalDependencies: + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) - vitefu@1.0.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)): + vitest@3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0): + dependencies: + '@vitest/expect': 3.1.3 + '@vitest/mocker': 3.1.3(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0)) + '@vitest/pretty-format': 3.1.3 + '@vitest/runner': 3.1.3 + '@vitest/snapshot': 3.1.3 + '@vitest/spy': 3.1.3 + '@vitest/utils': 3.1.3 + chai: 5.2.0 + debug: 4.4.1 + expect-type: 1.2.1 + magic-string: 0.30.17 + pathe: 2.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.13 + tinypool: 1.0.2 + tinyrainbow: 2.0.0 + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0) + vite-node: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.9.0) + why-is-node-running: 2.3.0 optionalDependencies: - vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + '@types/debug': 4.1.13 + '@types/node': 24.0.1 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml - vitest@3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1): + vitest@3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0): dependencies: '@vitest/expect': 3.1.3 - '@vitest/mocker': 3.1.3(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1)) + '@vitest/mocker': 3.1.3(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) '@vitest/pretty-format': 3.1.3 '@vitest/runner': 3.1.3 '@vitest/snapshot': 3.1.3 @@ -4826,10 +7169,11 @@ snapshots: tinyglobby: 0.2.13 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) - vite-node: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) + vite-node: 3.1.3(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: + '@types/debug': 4.1.13 '@types/node': 24.0.1 transitivePeerDependencies: - jiti @@ -4845,6 +7189,8 @@ snapshots: - tsx - yaml + web-namespaces@2.0.1: {} + web-vitals@4.2.4: {} webidl-conversions@3.0.1: {} @@ -4912,8 +7258,11 @@ snapshots: yallist@5.0.0: {} - yaml@2.7.1: - optional: true + yaml@2.7.1: {} + + yaml@2.9.0: {} + + yocto-queue@1.2.2: {} youch@3.3.4: dependencies: @@ -4928,3 +7277,7 @@ snapshots: zod@3.24.4: {} zod@3.25.67: {} + + zod@4.4.3: {} + + zwitch@2.0.4: {} diff --git a/sites/docs/content-collections.ts b/sites/docs/content-collections.ts new file mode 100644 index 0000000..28d14dd --- /dev/null +++ b/sites/docs/content-collections.ts @@ -0,0 +1,11 @@ +import { createContentConfig } from '@layerstack/docs/content-collections'; + +export default createContentConfig({ + // LayerStack is a multi-package monorepo; docs are authored as `reference` content + // organized by package under `src/content/reference//.md`. + packageName: 'layerstack', + repo: 'techniq/layerstack', + branch: 'main', + // `sites/docs` -> repo root `packages` + packagesRoot: '../../packages' +}); diff --git a/sites/docs/mdsx.config.js b/sites/docs/mdsx.config.js new file mode 100644 index 0000000..ef3a1df --- /dev/null +++ b/sites/docs/mdsx.config.js @@ -0,0 +1,7 @@ +import { createMdsxConfig } from '@layerstack/docs/markdown/config'; + +export const mdsxConfig = createMdsxConfig({ + markdownComponentsPath: '@layerstack/docs/markdown/components', + exampleComponentPath: '$lib/components', + liveCodeComponent: '@layerstack/docs/markdown/components/LiveCode.svelte' +}); diff --git a/sites/docs/package.json b/sites/docs/package.json index e2e4a1c..5631c70 100644 --- a/sites/docs/package.json +++ b/sites/docs/package.json @@ -1,6 +1,6 @@ { - "name": "@layerstack/docs", - "description": "A collection of Svelte actions, stores and general utils", + "name": "@layerstack/docs-site", + "description": "Documentation site for LayerStack", "author": "Sean Lynch ", "license": "MIT", "private": true, @@ -20,8 +20,12 @@ }, "devDependencies": { "@changesets/cli": "^2.29.4", + "@content-collections/core": "^0.14.3", + "@content-collections/markdown": "^0.1.4", + "@content-collections/vite": "^0.2.9", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@iconify-json/lucide": "^1.2.53", + "@iconify-json/simple-icons": "^1.2.84", "@sveltejs/adapter-cloudflare": "^7.0.3", "@sveltejs/kit": "^2.21.0", "@sveltejs/package": "^2.3.11", @@ -31,6 +35,7 @@ "@types/d3-array": "^3.2.1", "@types/prismjs": "^1.26.5", "mdsvex": "^0.12.5", + "mdsx": "^0.0.7", "posthog-js": "^1.239.0", "prettier": "^3.5.3", "prettier-plugin-svelte": "^3.3.3", @@ -38,7 +43,7 @@ "svelte": "^5.28.2", "svelte-check": "^4.1.6", "svelte-json-tree": "^2.2.0", - "svelte-ux": "2.0.0-next.13", + "svelte-ux": "2.0.0-next.22", "svelte2tsx": "^0.7.36", "tailwindcss": "^4.1.5", "tslib": "^2.8.1", @@ -50,6 +55,7 @@ "type": "module", "dependencies": { "@fortawesome/fontawesome-common-types": "^6.7.2", + "@layerstack/docs": "workspace:*", "@layerstack/svelte-actions": "workspace:*", "@layerstack/svelte-state": "workspace:*", "@layerstack/svelte-stores": "workspace:*", diff --git a/sites/docs/src/content/reference/svelte-stores/debounceStore.md b/sites/docs/src/content/reference/svelte-stores/debounceStore.md new file mode 100644 index 0000000..4c11811 --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/debounceStore.md @@ -0,0 +1,8 @@ +--- +title: debounceStore +description: Delay store update until some time has passed since the last update +--- + +## Usage + +:example{name="basic" showCode} diff --git a/sites/docs/src/examples/components/debounceStore/basic.svelte b/sites/docs/src/examples/components/debounceStore/basic.svelte new file mode 100644 index 0000000..20b12ea --- /dev/null +++ b/sites/docs/src/examples/components/debounceStore/basic.svelte @@ -0,0 +1,12 @@ + + + +
    value: {$value}
    +
    debouncedValue: {$debouncedValue}
    diff --git a/sites/docs/src/lib/components/Example.svelte b/sites/docs/src/lib/components/Example.svelte new file mode 100644 index 0000000..6cf7384 --- /dev/null +++ b/sites/docs/src/lib/components/Example.svelte @@ -0,0 +1,81 @@ + + +
    + {#if example} + {@const ExampleComponent = example.component} +
    +
    + +
    +
    + + {#if example.source} + + + {#if codeVisible} +
    + +
    + {/if} + {/if} + {:else} +
    + Example not found{name + ? `: ${resolvedComponent}/${name}` + : path + ? `: ${path}` + : ''} +
    + {/if} +
    diff --git a/sites/docs/src/lib/content.ts b/sites/docs/src/lib/content.ts new file mode 100644 index 0000000..001089f --- /dev/null +++ b/sites/docs/src/lib/content.ts @@ -0,0 +1,32 @@ +import { error } from '@sveltejs/kit'; +import { + allReferences, + type Reference as ReferenceMetadata, + allGuides, + type Guide as GuideMetadata +} from 'content-collections'; +import { createContentLoaders, type ContentType } from '@layerstack/docs/content'; +import { loadExample, loadExampleByPath } from '$lib/examples.js'; + +type Metadata = ReferenceMetadata | GuideMetadata; + +const modules = import.meta.glob<{ default: import('svelte').Component; metadata: Metadata }>( + '/src/content/**/*.md' +); + +const contentLoaders = createContentLoaders({ + modules, + getMetadata, + loadExample, + loadExampleByPath, + notFound: () => error(404, 'Could not find the document.') +}); + +function getMetadata(slug: string, type: ContentType): Metadata | undefined { + if (type === 'guides') { + return allGuides.find((g) => g.slug === slug); + } + return allReferences.find((r) => r.slug === slug); +} + +export const { getMarkdownComponent, loadExamplesFromMarkdown } = contentLoaders; diff --git a/sites/docs/src/lib/examples.ts b/sites/docs/src/lib/examples.ts new file mode 100644 index 0000000..870ca1b --- /dev/null +++ b/sites/docs/src/lib/examples.ts @@ -0,0 +1,26 @@ +import type { Component } from 'svelte'; +import { createExampleLoaders } from '@layerstack/docs/examples'; + +const pathExamples = import.meta.glob<{ default: Component }>([ + '/src/routes/**/*.svelte', + '/src/content/**/*.svelte' +]); + +const rawPathExamples = import.meta.glob( + ['/src/routes/**/*.svelte', '/src/content/**/*.svelte'], + { + query: '?raw', + import: 'default' + } +); + +export const { loadExample, loadExamples, loadExampleByPath } = createExampleLoaders({ + loadComponentExample: (type, component, name) => + import(`../examples/${type}/${component}/${name}.svelte`), + loadRawExample: async (type, component, name) => { + const raw = await import(`../examples/${type}/${component}/${name}.svelte?raw`); + return raw.default as string; + }, + loadPathExample: (path) => pathExamples[path]?.(), + loadRawPathExample: (path) => rawPathExamples[path]?.() +}); diff --git a/sites/docs/src/routes/app.css b/sites/docs/src/routes/app.css index 39331aa..a212c93 100644 --- a/sites/docs/src/routes/app.css +++ b/sites/docs/src/routes/app.css @@ -4,8 +4,10 @@ /* @import '@layerstack/tailwind/themes/basic.css'; */ @import '@layerstack/tailwind/themes/all.css'; @import '@layerstack/tailwind/utils.css'; +@import '@layerstack/docs/styles.css'; @source '../../node_modules/svelte-ux/dist'; +@source '../../node_modules/@layerstack/docs/dist'; @plugin '@tailwindcss/typography'; /* Useful with `basic.css` */ diff --git a/sites/docs/src/routes/docs/+layout.svelte b/sites/docs/src/routes/docs/+layout.svelte index 79be6d2..bdad874 100644 --- a/sites/docs/src/routes/docs/+layout.svelte +++ b/sites/docs/src/routes/docs/+layout.svelte @@ -94,6 +94,10 @@ settings({ ...getSettings(), components: {} }); +{#if page.data.metadata} + + +{:else}
    @@ -304,3 +308,4 @@ {/if}
    +{/if} diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte new file mode 100644 index 0000000..b386ddd --- /dev/null +++ b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte @@ -0,0 +1,97 @@ + + +
    +
    +
    + Docs + + {page.params.packageName} +
    + +
    + {metadata.name} + {#if metadata.status} + + {metadata.status} + + {/if} +
    + + {#if metadata.description} +
    + {metadata.description} +
    + {/if} + +
    + +
    +
    + +
    +
    + {#if metadata.features?.length} +

    Features

    +
      + {#each metadata.features as feature} +
    • {@html feature}
    • + {/each} +
    + {/if} + + {#key page.url.pathname} + + {/key} +
    + + {#if !metadata.hideTableOfContents && metadata.toc?.length} + + {/if} +
    +
    diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/+page.ts b/sites/docs/src/routes/docs/[packageName]/[name]/+page.ts new file mode 100644 index 0000000..421aba7 --- /dev/null +++ b/sites/docs/src/routes/docs/[packageName]/[name]/+page.ts @@ -0,0 +1,13 @@ +import { getMarkdownComponent, loadExamplesFromMarkdown } from '$lib/content.js'; + +export const load = async ({ params }) => { + const slug = `${params.packageName}/${params.name}`; + + const { PageComponent, metadata } = await getMarkdownComponent(slug, 'reference'); + + // Eagerly load any examples referenced by the markdown (`:example{name="..."}`), + // defaulting the component to the current item name. + const examples = await loadExamplesFromMarkdown(metadata.content, params.name, 'reference'); + + return { PageComponent, metadata, examples }; +}; diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts b/sites/docs/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts new file mode 100644 index 0000000..4025f99 --- /dev/null +++ b/sites/docs/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts @@ -0,0 +1,14 @@ +import { allReferences } from 'content-collections'; +import { error, text } from '@sveltejs/kit'; + +/** Serve the raw markdown for a reference doc (consumed by `OpenWithButton`'s page/LLM actions). */ +export const GET = ({ params }) => { + const slug = `${params.packageName}/${params.name}`; + const doc = allReferences.find((r) => r.slug === slug); + if (!doc) { + error(404, 'Not found'); + } + + const body = [`# ${doc.title}`, doc.description, doc.content].filter(Boolean).join('\n\n'); + return text(body); +}; diff --git a/sites/docs/src/routes/docs/svelte-stores/debounceStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/debounceStore/+page.md deleted file mode 100644 index 40ad8a6..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/debounceStore/+page.md +++ /dev/null @@ -1,30 +0,0 @@ - - -

    Usage

    - -```svelte - -``` - -

    Example

    - - - -
    value: {$value}
    -
    debouncedValue: {$debouncedValue}
    -
    diff --git a/sites/docs/src/routes/docs/svelte-stores/debounceStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/debounceStore/+page.ts deleted file mode 100644 index 7f158ef..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/debounceStore/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$svelte-stores/debounceStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Delay store update until some time has passed since the last update', - }, - }; -} diff --git a/sites/docs/svelte.config.js b/sites/docs/svelte.config.js index a6669d0..bf987c1 100644 --- a/sites/docs/svelte.config.js +++ b/sites/docs/svelte.config.js @@ -1,14 +1,15 @@ import adapter from '@sveltejs/adapter-cloudflare'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; -import { mdsvex } from 'mdsvex'; +import { mdsx } from 'mdsx'; -import mdsvexConfig from './mdsvex.config.js'; +import { mdsxConfig } from './mdsx.config.js'; import { codePreview } from './src/lib/plugins/svelte.js'; /** @type {import('@sveltejs/kit').Config} */ const config = { - extensions: ['.svelte', ...mdsvexConfig.extensions], - preprocess: [mdsvex(mdsvexConfig), vitePreprocess(), codePreview()], + extensions: ['.svelte', '.md'], + // `codePreview` retained during migration for legacy ``-based pages; harmless otherwise. + preprocess: [mdsx(mdsxConfig), vitePreprocess(), codePreview()], vitePlugin: { inspector: { @@ -21,6 +22,8 @@ const config = { adapter: adapter(), alias: { $docs: 'src/docs', + $examples: 'src/examples', + 'content-collections': './.content-collections/generated', '$svelte-actions': '../../packages/svelte-actions/src/lib', '$svelte-state': '../../packages/svelte-state/src/lib', '$svelte-stores': '../../packages/svelte-stores/src/lib', diff --git a/sites/docs/vite.config.js b/sites/docs/vite.config.js index b003322..b355f10 100644 --- a/sites/docs/vite.config.js +++ b/sites/docs/vite.config.js @@ -2,9 +2,10 @@ import { defineConfig } from 'vite'; import { sveltekit } from '@sveltejs/kit/vite'; import tailwindcss from '@tailwindcss/vite'; import Icons from 'unplugin-icons/vite'; +import contentCollections from '@content-collections/vite'; export default defineConfig({ - plugins: [tailwindcss(), sveltekit(), Icons({ compiler: 'svelte' })], + plugins: [tailwindcss(), sveltekit(), contentCollections(), Icons({ compiler: 'svelte' })], resolve: { noExternal: true, // https://github.com/AdrianGonz97/refined-cf-pages-action/issues/26#issuecomment-2878397440 }, From af428e82318259babf71ceb8e13d896d2ba43414 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 09:49:27 -0400 Subject: [PATCH 03/21] Improve `pnpm dev` for packages --- package.json | 2 +- packages/docs/package.json | 1 + packages/svelte-actions/package.json | 2 +- packages/svelte-state/package.json | 2 +- packages/svelte-stores/package.json | 2 +- packages/svelte-table/package.json | 2 +- packages/tailwind/package.json | 2 +- .../tailwind/src/lib/css/themes/generated/all.css | 15 ++++++++++++++- .../src/lib/css/themes/generated/daisy.css | 15 ++++++++++++++- packages/utils/package.json | 2 +- sites/docs/svelte.config.js | 10 ++++++++++ 11 files changed, 46 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index c0bea92..9d19d31 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "type": "module", "scripts": { - "dev": "pnpm clean && pnpm package && pnpm --parallel --filter './packages/*' --filter @layerstack/docs-site --if-present dev", + "dev": "pnpm clean && pnpm --filter @layerstack/utils --filter @layerstack/tailwind --filter @layerstack/docs build && pnpm --parallel --filter @layerstack/docs --filter @layerstack/docs-site --if-present dev", "test:unit": "pnpm -r test:unit", "clean": "rimraf packages/*/dist", "build": "pnpm clean && pnpm -r build", diff --git a/packages/docs/package.json b/packages/docs/package.json index bc5098f..28a9740 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -11,6 +11,7 @@ "layerstack-docs": "./bin/layerstack-docs.js" }, "scripts": { + "dev": "trap 'exit 0' INT; svelte-package --watch", "build": "svelte-package", "package": "svelte-package", "prepare": "svelte-kit sync", diff --git a/packages/svelte-actions/package.json b/packages/svelte-actions/package.json index 365b3c1..874c24a 100644 --- a/packages/svelte-actions/package.json +++ b/packages/svelte-actions/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "1.0.1-next.18", "scripts": { - "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", + "dev": "tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/packages/svelte-state/package.json b/packages/svelte-state/package.json index d1e2a1b..a699e60 100644 --- a/packages/svelte-state/package.json +++ b/packages/svelte-state/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "0.1.0-next.23", "scripts": { - "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", + "dev": "tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/packages/svelte-stores/package.json b/packages/svelte-stores/package.json index d4cde91..ac40e68 100644 --- a/packages/svelte-stores/package.json +++ b/packages/svelte-stores/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "1.0.2-next.18", "scripts": { - "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", + "dev": "tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/packages/svelte-table/package.json b/packages/svelte-table/package.json index e7e9e04..06860ad 100644 --- a/packages/svelte-table/package.json +++ b/packages/svelte-table/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "1.0.1-next.18", "scripts": { - "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", + "dev": "tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/packages/tailwind/package.json b/packages/tailwind/package.json index 61c25fc..169da63 100644 --- a/packages/tailwind/package.json +++ b/packages/tailwind/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "2.0.0-next.22", "scripts": { - "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", + "dev": "tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json && pnpm build:css && cp -r ./src/lib/css dist", "build:css": "tsc --noEmit && tsx ./src/lib/cli/index.ts", diff --git a/packages/tailwind/src/lib/css/themes/generated/all.css b/packages/tailwind/src/lib/css/themes/generated/all.css index c6ebc49..9453e18 100644 --- a/packages/tailwind/src/lib/css/themes/generated/all.css +++ b/packages/tailwind/src/lib/css/themes/generated/all.css @@ -1059,6 +1059,15 @@ [data-theme="cyberpunk"] { color-scheme: light; + fontfamily: + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + Liberation Mono, + Courier New, + monospace; --color-primary: hsl(340.8799 100% 69.8833%); --color-secondary: hsl(185.3347 100% 50%); --color-accent: hsl(278.9515 100% 72.6993%); @@ -1580,7 +1589,7 @@ --color-danger-800: hsl(357.1922 53.6188% 43.5134%); --color-danger-900: hsl(357.1922 55.0988% 34.9232%); --color-surface-200: hsl(0 13.0424% 6.8651%); - --color-surface-300: hsl(360 14.1163% 5.7928%); + --color-surface-300: hsl(0 14.1163% 5.7928%); --color-surface-content: hsl(0.603 1.4217% 79.1884%); } @@ -2011,6 +2020,10 @@ [data-theme="wireframe"] { color-scheme: light; + fontfamily: + Chalkboard, + comic sans ms, + "sans-serif"; --color-primary: hsl(0 0% 72.1569%); --color-secondary: hsl(0 0% 72.1569%); --color-accent: hsl(0 0% 72.1569%); diff --git a/packages/tailwind/src/lib/css/themes/generated/daisy.css b/packages/tailwind/src/lib/css/themes/generated/daisy.css index eed275a..16e9161 100644 --- a/packages/tailwind/src/lib/css/themes/generated/daisy.css +++ b/packages/tailwind/src/lib/css/themes/generated/daisy.css @@ -1059,6 +1059,15 @@ [data-theme="cyberpunk"] { color-scheme: light; + fontfamily: + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + Liberation Mono, + Courier New, + monospace; --color-primary: hsl(340.8799 100% 69.8833%); --color-secondary: hsl(185.3347 100% 50%); --color-accent: hsl(278.9515 100% 72.6993%); @@ -1580,7 +1589,7 @@ --color-danger-800: hsl(357.1922 53.6188% 43.5134%); --color-danger-900: hsl(357.1922 55.0988% 34.9232%); --color-surface-200: hsl(0 13.0424% 6.8651%); - --color-surface-300: hsl(360 14.1163% 5.7928%); + --color-surface-300: hsl(0 14.1163% 5.7928%); --color-surface-content: hsl(0.603 1.4217% 79.1884%); } @@ -2011,6 +2020,10 @@ [data-theme="wireframe"] { color-scheme: light; + fontfamily: + Chalkboard, + comic sans ms, + "sans-serif"; --color-primary: hsl(0 0% 72.1569%); --color-secondary: hsl(0 0% 72.1569%); --color-accent: hsl(0 0% 72.1569%); diff --git a/packages/utils/package.json b/packages/utils/package.json index 0b2d904..fb0a82a 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -6,7 +6,7 @@ "repository": "techniq/layerstack", "version": "2.0.0-next.18", "scripts": { - "dev": "trap 'exit 0' INT; tsc -p tsconfig.build.json --watch", + "dev": "tsc -p tsconfig.build.json --watch", "clean": "rimraf dist", "build": "pnpm clean && tsc -p tsconfig.build.json", "preview": "vite preview", diff --git a/sites/docs/svelte.config.js b/sites/docs/svelte.config.js index bf987c1..1e4df3e 100644 --- a/sites/docs/svelte.config.js +++ b/sites/docs/svelte.config.js @@ -24,6 +24,16 @@ const config = { $docs: 'src/docs', $examples: 'src/examples', 'content-collections': './.content-collections/generated', + // Resolve workspace libraries to their *source* during dev/build so Vite compiles + // them directly — instant HMR, no per-package build/watch. (`@layerstack/tailwind` + // is intentionally excluded: its CSS themes are generated into `dist`, and + // `@layerstack/docs` keeps its custom export map, so both stay dist-resolved.) + '@layerstack/svelte-actions': '../../packages/svelte-actions/src/lib', + '@layerstack/svelte-state': '../../packages/svelte-state/src/lib', + '@layerstack/svelte-stores': '../../packages/svelte-stores/src/lib', + '@layerstack/svelte-table': '../../packages/svelte-table/src/lib', + '@layerstack/utils': '../../packages/utils/src/lib', + // `?raw` source-display aliases (kept for legacy pages) '$svelte-actions': '../../packages/svelte-actions/src/lib', '$svelte-state': '../../packages/svelte-state/src/lib', '$svelte-stores': '../../packages/svelte-stores/src/lib', From 925faae500322a7ef0bedf7cbe985c9b5657014e Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 10:08:39 -0400 Subject: [PATCH 04/21] migrate page.md docs --- packages/docs/src/lib/markdown/toc.ts | 10 +- .../reference/svelte-stores/changeStore.md | 12 ++ .../reference/svelte-stores/dirtyStore.md | 9 ++ .../reference/svelte-stores/fetchStore.md} | 11 +- .../reference/svelte-stores/formStore.md | 11 ++ .../reference/svelte-stores/graphStore.md | 11 ++ .../reference/svelte-stores/localStore.md | 17 ++ .../reference/svelte-stores/mapStore.md} | 20 +-- .../reference/svelte-stores/matchMedia.md | 36 +++++ .../svelte-stores/paginationStore.md | 11 ++ .../reference/svelte-stores/promiseStore.md | 10 ++ .../svelte-stores/queryParamsStore.md} | 42 +++-- .../reference/svelte-stores/selectionStore.md | 25 +++ .../reference/svelte-stores/timerStore.md | 19 +++ .../reference/svelte-stores/uniqueStore.md | 22 +++ .../content/reference/svelte-table/stores.md | 11 ++ .../src/content/reference/tailwind/utils.md | 15 ++ .../reference/utils/Logger.md} | 11 +- .../docs/src/content/reference/utils/json.md | 12 ++ .../components/changeStore/basic.svelte | 11 ++ .../components/changeStore/pagination.svelte | 12 ++ .../components/dirtyStore/basic.svelte | 12 ++ .../components/matchMedia/basic.svelte | 88 +++++++++++ .../components/selectionStore/basic.svelte | 20 +++ .../selectionStore/initial-selection.svelte | 20 +++ .../components/selectionStore/max.svelte | 21 +++ .../selectionStore/select-all.svelte | 27 ++++ .../components/selectionStore/single.svelte | 21 +++ .../components/timerStore/default.svelte | 13 ++ .../components/timerStore/tick-count.svelte | 13 ++ .../components/uniqueStore/basic.svelte | 17 ++ .../docs/svelte-stores/changeStore/+page.md | 39 ----- .../docs/svelte-stores/changeStore/+page.ts | 13 -- .../docs/svelte-stores/dirtyStore/+page.md | 30 ---- .../docs/svelte-stores/dirtyStore/+page.ts | 14 -- .../docs/svelte-stores/fetchStore/+page.ts | 14 -- .../docs/svelte-stores/formStore/+page.md | 11 -- .../docs/svelte-stores/formStore/+page.ts | 13 -- .../docs/svelte-stores/graphStore/+page.md | 13 -- .../docs/svelte-stores/graphStore/+page.ts | 13 -- .../docs/svelte-stores/localStore/+page.md | 24 --- .../docs/svelte-stores/localStore/+page.ts | 12 -- .../docs/svelte-stores/mapStore/+page.ts | 13 -- .../docs/svelte-stores/matchMedia/+page.md | 149 ------------------ .../docs/svelte-stores/matchMedia/+page.ts | 13 -- .../svelte-stores/paginationStore/+page.md | 11 -- .../svelte-stores/paginationStore/+page.ts | 14 -- .../docs/svelte-stores/promiseStore/+page.md | 13 -- .../docs/svelte-stores/promiseStore/+page.ts | 12 -- .../svelte-stores/queryParamsStore/+page.ts | 14 -- .../svelte-stores/selectionStore/+page.md | 107 ------------- .../svelte-stores/selectionStore/+page.ts | 14 -- .../docs/svelte-stores/timerStore/+page.md | 49 ------ .../docs/svelte-stores/timerStore/+page.ts | 13 -- .../docs/svelte-stores/uniqueStore/+page.md | 41 ----- .../docs/svelte-stores/uniqueStore/+page.ts | 14 -- .../routes/docs/svelte-table/stores/+page.md | 11 -- .../routes/docs/svelte-table/stores/+page.ts | 14 -- .../src/routes/docs/tailwind/utils/+page.md | 13 -- .../src/routes/docs/tailwind/utils/+page.ts | 13 -- .../src/routes/docs/utils/Logger/+page.ts | 13 -- .../docs/src/routes/docs/utils/json/+page.md | 18 --- .../docs/src/routes/docs/utils/json/+page.ts | 13 -- 63 files changed, 546 insertions(+), 812 deletions(-) create mode 100644 sites/docs/src/content/reference/svelte-stores/changeStore.md create mode 100644 sites/docs/src/content/reference/svelte-stores/dirtyStore.md rename sites/docs/src/{routes/docs/svelte-stores/fetchStore/+page.md => content/reference/svelte-stores/fetchStore.md} (86%) create mode 100644 sites/docs/src/content/reference/svelte-stores/formStore.md create mode 100644 sites/docs/src/content/reference/svelte-stores/graphStore.md create mode 100644 sites/docs/src/content/reference/svelte-stores/localStore.md rename sites/docs/src/{routes/docs/svelte-stores/mapStore/+page.md => content/reference/svelte-stores/mapStore.md} (56%) create mode 100644 sites/docs/src/content/reference/svelte-stores/matchMedia.md create mode 100644 sites/docs/src/content/reference/svelte-stores/paginationStore.md create mode 100644 sites/docs/src/content/reference/svelte-stores/promiseStore.md rename sites/docs/src/{routes/docs/svelte-stores/queryParamsStore/+page.md => content/reference/svelte-stores/queryParamsStore.md} (90%) create mode 100644 sites/docs/src/content/reference/svelte-stores/selectionStore.md create mode 100644 sites/docs/src/content/reference/svelte-stores/timerStore.md create mode 100644 sites/docs/src/content/reference/svelte-stores/uniqueStore.md create mode 100644 sites/docs/src/content/reference/svelte-table/stores.md create mode 100644 sites/docs/src/content/reference/tailwind/utils.md rename sites/docs/src/{routes/docs/utils/Logger/+page.md => content/reference/utils/Logger.md} (75%) create mode 100644 sites/docs/src/content/reference/utils/json.md create mode 100644 sites/docs/src/examples/components/changeStore/basic.svelte create mode 100644 sites/docs/src/examples/components/changeStore/pagination.svelte create mode 100644 sites/docs/src/examples/components/dirtyStore/basic.svelte create mode 100644 sites/docs/src/examples/components/matchMedia/basic.svelte create mode 100644 sites/docs/src/examples/components/selectionStore/basic.svelte create mode 100644 sites/docs/src/examples/components/selectionStore/initial-selection.svelte create mode 100644 sites/docs/src/examples/components/selectionStore/max.svelte create mode 100644 sites/docs/src/examples/components/selectionStore/select-all.svelte create mode 100644 sites/docs/src/examples/components/selectionStore/single.svelte create mode 100644 sites/docs/src/examples/components/timerStore/default.svelte create mode 100644 sites/docs/src/examples/components/timerStore/tick-count.svelte create mode 100644 sites/docs/src/examples/components/uniqueStore/basic.svelte delete mode 100644 sites/docs/src/routes/docs/svelte-stores/changeStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/changeStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/dirtyStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/dirtyStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/fetchStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/formStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/formStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/graphStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/graphStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/localStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/localStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/mapStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/matchMedia/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/matchMedia/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/paginationStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/paginationStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/promiseStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/promiseStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/queryParamsStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/selectionStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/selectionStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/timerStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/timerStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-stores/uniqueStore/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-stores/uniqueStore/+page.ts delete mode 100644 sites/docs/src/routes/docs/svelte-table/stores/+page.md delete mode 100644 sites/docs/src/routes/docs/svelte-table/stores/+page.ts delete mode 100644 sites/docs/src/routes/docs/tailwind/utils/+page.md delete mode 100644 sites/docs/src/routes/docs/tailwind/utils/+page.ts delete mode 100644 sites/docs/src/routes/docs/utils/Logger/+page.ts delete mode 100644 sites/docs/src/routes/docs/utils/json/+page.md delete mode 100644 sites/docs/src/routes/docs/utils/json/+page.ts diff --git a/packages/docs/src/lib/markdown/toc.ts b/packages/docs/src/lib/markdown/toc.ts index 8607ca0..961ab1b 100644 --- a/packages/docs/src/lib/markdown/toc.ts +++ b/packages/docs/src/lib/markdown/toc.ts @@ -1,4 +1,4 @@ -import { slug as githubSlug } from 'github-slugger'; +import GithubSlugger from 'github-slugger'; /** * Extract table of contents from markdown content @@ -8,6 +8,11 @@ export function extractTocFromMarkdown( ): { id: string; text: string; level: number }[] { const toc: { id: string; text: string; level: number }[] = []; + // A fresh slugger per document de-duplicates repeated slugs (e.g. headings + // `string` and `string[]` both slugify to `string`), matching `rehype-slug`'s + // behavior so TOC ids stay unique and line up with the rendered heading ids. + const slugger = new GithubSlugger(); + // Strip HTML comments so commented-out headings are ignored const stripped = content.replace(//g, ''); @@ -22,8 +27,7 @@ export function extractTocFromMarkdown( .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') .trim(); if (!text) continue; - // Use github-slugger then strip leading/trailing dashes (matching rehypeCleanSlugIds) - const id = githubSlug(text); + const id = slugger.slug(text); toc.push({ id, text, level }); } diff --git a/sites/docs/src/content/reference/svelte-stores/changeStore.md b/sites/docs/src/content/reference/svelte-stores/changeStore.md new file mode 100644 index 0000000..e2343ff --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/changeStore.md @@ -0,0 +1,12 @@ +--- +title: changeStore +description: Track previous value. Calls onChange callback only after first change (not initial value) +--- + +## Usage + +:example{name="basic" showCode} + +## Pagination + +:example{name="pagination"} diff --git a/sites/docs/src/content/reference/svelte-stores/dirtyStore.md b/sites/docs/src/content/reference/svelte-stores/dirtyStore.md new file mode 100644 index 0000000..46f84cd --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/dirtyStore.md @@ -0,0 +1,9 @@ +--- +title: dirtyStore +description: Track when a store becomes dirty (changed), with ability to reset. Useful to enable an apply button, etc +related: [components/MultiSelect] +--- + +## Usage + +:example{name="basic" showCode} diff --git a/sites/docs/src/routes/docs/svelte-stores/fetchStore/+page.md b/sites/docs/src/content/reference/svelte-stores/fetchStore.md similarity index 86% rename from sites/docs/src/routes/docs/svelte-stores/fetchStore/+page.md rename to sites/docs/src/content/reference/svelte-stores/fetchStore.md index 0195551..b931787 100644 --- a/sites/docs/src/routes/docs/svelte-stores/fetchStore/+page.md +++ b/sites/docs/src/content/reference/svelte-stores/fetchStore.md @@ -1,9 +1,10 @@ - +--- +title: fetchStore +description: Fetch request as a store, with support for body parsing (json, text, arrayBuffer, etc), out of order responses, context configuration, and global errors +related: [svelte-stores/graphStore] +--- -

    Usage

    +## Usage ```js import { fetchStore, initFetchClient } from '@layerstack/svelte-stores'; diff --git a/sites/docs/src/content/reference/svelte-stores/formStore.md b/sites/docs/src/content/reference/svelte-stores/formStore.md new file mode 100644 index 0000000..300c821 --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/formStore.md @@ -0,0 +1,11 @@ +--- +title: formStore +description: Manage form state via immer draft and zod schema, with undo history +related: [components/Form] +--- + +## Usage + +```js +import { formStore } from '@layerstack/svelte-stores'; +``` diff --git a/sites/docs/src/content/reference/svelte-stores/graphStore.md b/sites/docs/src/content/reference/svelte-stores/graphStore.md new file mode 100644 index 0000000..e87d2fc --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/graphStore.md @@ -0,0 +1,11 @@ +--- +title: graphStore +description: GraphQL requests powered by fetchStore +related: [svelte-stores/fetchStore] +--- + +## Usage + +```js +import { graphStore } from '@layerstack/svelte-stores'; +``` diff --git a/sites/docs/src/content/reference/svelte-stores/localStore.md b/sites/docs/src/content/reference/svelte-stores/localStore.md new file mode 100644 index 0000000..c63099c --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/localStore.md @@ -0,0 +1,17 @@ +--- +title: localStore +description: Read and write to localStorage with expiration support +--- + +## Usage + +```svelte + +``` diff --git a/sites/docs/src/routes/docs/svelte-stores/mapStore/+page.md b/sites/docs/src/content/reference/svelte-stores/mapStore.md similarity index 56% rename from sites/docs/src/routes/docs/svelte-stores/mapStore/+page.md rename to sites/docs/src/content/reference/svelte-stores/mapStore.md index d53dad9..749254e 100644 --- a/sites/docs/src/routes/docs/svelte-stores/mapStore/+page.md +++ b/sites/docs/src/content/reference/svelte-stores/mapStore.md @@ -1,18 +1,10 @@ - - -

    Usage

    +## Usage ```js import { mapStore } from '@layerstack/svelte-stores'; diff --git a/sites/docs/src/content/reference/svelte-stores/matchMedia.md b/sites/docs/src/content/reference/svelte-stores/matchMedia.md new file mode 100644 index 0000000..05f07d3 --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/matchMedia.md @@ -0,0 +1,36 @@ +--- +title: matchMedia +description: Store to monitor media query matching, including screen width/height, orientation, print media, prefers dark/light scheme, and prefers reduced motion +--- + +## Usage + +The returned store is truthy while its media query matches, so it can be used directly in markup (`{#if $isLargeScreen}…{/if}`). + +```svelte + +``` + +Convenient width helper: + +```svelte + +``` + +Convenient presets (Tailwind defaults) — `smScreen`, `mdScreen`, `lgScreen`, `xlScreen`, `xxlScreen` — plus `screen`, `print`, `darkColorScheme`, and `motionReduce`: + +```svelte + +``` + +## Example + +:example{name="basic"} diff --git a/sites/docs/src/content/reference/svelte-stores/paginationStore.md b/sites/docs/src/content/reference/svelte-stores/paginationStore.md new file mode 100644 index 0000000..afdeedb --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/paginationStore.md @@ -0,0 +1,11 @@ +--- +title: paginationStore +description: Manage pagination state including current page and page navigation (next/previous/first/last). See related Paginate/Pagination components +related: [components/Paginate, components/Pagination] +--- + +## Usage + +```js +import { paginationStore } from '@layerstack/svelte-stores'; +``` diff --git a/sites/docs/src/content/reference/svelte-stores/promiseStore.md b/sites/docs/src/content/reference/svelte-stores/promiseStore.md new file mode 100644 index 0000000..2df943d --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/promiseStore.md @@ -0,0 +1,10 @@ +--- +title: promiseStore +description: Wraps a Promise as a store. Useful for SvelteKit streamed data handling +--- + +## Usage + +```js +import { promiseStore } from '@layerstack/svelte-stores'; +``` diff --git a/sites/docs/src/routes/docs/svelte-stores/queryParamsStore/+page.md b/sites/docs/src/content/reference/svelte-stores/queryParamsStore.md similarity index 90% rename from sites/docs/src/routes/docs/svelte-stores/queryParamsStore/+page.md rename to sites/docs/src/content/reference/svelte-stores/queryParamsStore.md index 13aa1d6..594128e 100644 --- a/sites/docs/src/routes/docs/svelte-stores/queryParamsStore/+page.md +++ b/sites/docs/src/content/reference/svelte-stores/queryParamsStore.md @@ -1,10 +1,11 @@ - - -

    queryParamStore()

    +## queryParamStore() Manage a single query param @@ -52,7 +53,7 @@ const filters = queryParamStore({ $dataRange = newValue; ``` -

    queryParamsStore()

    +## queryParamsStore() Manage all query params as a single store @@ -122,8 +123,10 @@ const filters = queryParamsStore({ $filters = newFilters; ``` -

    Param types

    -

    string

    +## Param types + +### string + input ```js @@ -136,7 +139,8 @@ output ?value=example ``` -

    string[]

    +### string[] + input ```js @@ -149,7 +153,8 @@ output ?value=one_two_three ``` -

    number

    +### number + input ```js @@ -162,7 +167,8 @@ output ?value=1234 ``` -

    number[]

    +### number[] + input ```js @@ -175,7 +181,8 @@ output ?value=1_2_3_4 ``` -

    boolean

    +### boolean + input ```js @@ -188,7 +195,8 @@ output ?value=1 ``` -

    date

    +### date + input ```js @@ -201,7 +209,7 @@ output ?value=1982-03-30 ``` -

    datetime

    +### datetime input @@ -215,7 +223,7 @@ output ?value=1982-03-30T05:00:00.000Z ``` -

    json

    +### json input @@ -234,7 +242,7 @@ output ?value={"number":1234,"string":"example","bool":true,"date":"1982-03-30T05:00:00.000Z"} ``` -

    object

    +### object input diff --git a/sites/docs/src/content/reference/svelte-stores/selectionStore.md b/sites/docs/src/content/reference/svelte-stores/selectionStore.md new file mode 100644 index 0000000..8346ad3 --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/selectionStore.md @@ -0,0 +1,25 @@ +--- +title: selectionStore +description: Manage item selection state including toggling values, selecting all, and clear or reset selection +related: [components/MultiSelect, components/Selection] +--- + +## Basic + +:example{name="basic" showCode} + +## Initial selection + +:example{name="initial-selection" showCode} + +## Select all + +:example{name="select-all" showCode} + +## Single + +:example{name="single" showCode} + +## Max + +:example{name="max" showCode} diff --git a/sites/docs/src/content/reference/svelte-stores/timerStore.md b/sites/docs/src/content/reference/svelte-stores/timerStore.md new file mode 100644 index 0000000..10238a6 --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/timerStore.md @@ -0,0 +1,19 @@ +--- +title: timerStore +description: Manage interval ticks, useful for timely updates and countdowns +related: [components/Duration, components/ScrollingValue] +--- + +## Usage + +```js +const timer = timerStore(); +``` + +## Default + +:example{name="default" showCode} + +## Tick count + +:example{name="tick-count" showCode} diff --git a/sites/docs/src/content/reference/svelte-stores/uniqueStore.md b/sites/docs/src/content/reference/svelte-stores/uniqueStore.md new file mode 100644 index 0000000..e75d2f5 --- /dev/null +++ b/sites/docs/src/content/reference/svelte-stores/uniqueStore.md @@ -0,0 +1,22 @@ +--- +title: uniqueStore +description: Store to manage unique values using `Set` with improved ergonomics and better control of updates +related: [svelte-stores/selectionStore, svelte-stores/mapStore, components/MultiSelect] +--- + +## Usage + +```js +import { uniqueStore } from '@layerstack/svelte-stores'; + +const store = uniqueStore(); +// $store.has(value) +// $store.size +// store.add(value); +// store.delete(value); +// store.toggle(value); +``` + +## Example + +:example{name="basic" showCode} diff --git a/sites/docs/src/content/reference/svelte-table/stores.md b/sites/docs/src/content/reference/svelte-table/stores.md new file mode 100644 index 0000000..0f2b1cb --- /dev/null +++ b/sites/docs/src/content/reference/svelte-table/stores.md @@ -0,0 +1,11 @@ +--- +title: stores +description: Manage table column sorting selection and direction. Compliments Table component +related: [svelte-table/actions, components/Table] +--- + +## Usage + +```js +import { tableOrderStore } from '@layerstack/svelte-table'; +``` diff --git a/sites/docs/src/content/reference/tailwind/utils.md b/sites/docs/src/content/reference/tailwind/utils.md new file mode 100644 index 0000000..e3a53f3 --- /dev/null +++ b/sites/docs/src/content/reference/tailwind/utils.md @@ -0,0 +1,15 @@ +--- +title: utils +description: Wrapper around `tailwind-merge` and `clsx` for easy style overriding +related: ['https://github.com/dcastil/tailwind-merge', 'https://github.com/lukeed/clsx'] +--- + +## Usage + +```svelte + + + diff --git a/sites/docs/src/examples/components/matchMedia/basic.svelte b/sites/docs/src/examples/components/matchMedia/basic.svelte new file mode 100644 index 0000000..6f93182 --- /dev/null +++ b/sites/docs/src/examples/components/matchMedia/basic.svelte @@ -0,0 +1,88 @@ + + +
    + {#if $smScreen}{:else}{/if} + $smScreen (640px) + + {#if $mdScreen}{:else}{/if} + $mdScreen (768px) + + {#if $lgScreen}{:else}{/if} + $lgScreen (1024px) + + {#if $xlScreen}{:else}{/if} + $xlScreen (1280px) + + {#if $xxlScreen}{:else}{/if} + $xxlScreen (1536px) + + {#if $screen}{:else}{/if} + $screen + + {#if $print}{:else}{/if} + $print + + {#if $darkColorScheme}{:else}{/if} + $darkColorScheme + + {#if $motionReduce}{:else}{/if} + $motionReduce +
    + +
    + current width: {innerWidth}px +
    + + diff --git a/sites/docs/src/examples/components/selectionStore/basic.svelte b/sites/docs/src/examples/components/selectionStore/basic.svelte new file mode 100644 index 0000000..2818397 --- /dev/null +++ b/sites/docs/src/examples/components/selectionStore/basic.svelte @@ -0,0 +1,20 @@ + + +{#each data as d} +
    + $selection.toggleSelected(d.id)} + > + {d.id} + +
    +{/each} +selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/selectionStore/initial-selection.svelte b/sites/docs/src/examples/components/selectionStore/initial-selection.svelte new file mode 100644 index 0000000..d509b44 --- /dev/null +++ b/sites/docs/src/examples/components/selectionStore/initial-selection.svelte @@ -0,0 +1,20 @@ + + +{#each data as d} +
    + $selection.toggleSelected(d.id)} + > + {d.id} + +
    +{/each} +selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/selectionStore/max.svelte b/sites/docs/src/examples/components/selectionStore/max.svelte new file mode 100644 index 0000000..683de11 --- /dev/null +++ b/sites/docs/src/examples/components/selectionStore/max.svelte @@ -0,0 +1,21 @@ + + +{#each data as d} +
    + $selection.toggleSelected(d.id)} + disabled={$selection.isDisabled(d.id)} + > + {d.id} + +
    +{/each} +selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/selectionStore/select-all.svelte b/sites/docs/src/examples/components/selectionStore/select-all.svelte new file mode 100644 index 0000000..faa89f2 --- /dev/null +++ b/sites/docs/src/examples/components/selectionStore/select-all.svelte @@ -0,0 +1,27 @@ + + + $selection.toggleAll()} +> + Select all + +{#each data as d} +
    + $selection.toggleSelected(d.id)} + > + {d.id} + +
    +{/each} +selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/selectionStore/single.svelte b/sites/docs/src/examples/components/selectionStore/single.svelte new file mode 100644 index 0000000..bb0d791 --- /dev/null +++ b/sites/docs/src/examples/components/selectionStore/single.svelte @@ -0,0 +1,21 @@ + + +{#each data as d} +
    + $selection.toggleSelected(d.id)} + > + {d.id} + +
    +{/each} +selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/timerStore/default.svelte b/sites/docs/src/examples/components/timerStore/default.svelte new file mode 100644 index 0000000..5829178 --- /dev/null +++ b/sites/docs/src/examples/components/timerStore/default.svelte @@ -0,0 +1,13 @@ + + +
    {$dateTimer}
    + (e.target.checked ? dateTimer.start() : dateTimer.stop())} +/> diff --git a/sites/docs/src/examples/components/timerStore/tick-count.svelte b/sites/docs/src/examples/components/timerStore/tick-count.svelte new file mode 100644 index 0000000..36be262 --- /dev/null +++ b/sites/docs/src/examples/components/timerStore/tick-count.svelte @@ -0,0 +1,13 @@ + + +
    {$tickTimer}
    + (e.target.checked ? tickTimer.start() : tickTimer.stop())} +/> diff --git a/sites/docs/src/examples/components/uniqueStore/basic.svelte b/sites/docs/src/examples/components/uniqueStore/basic.svelte new file mode 100644 index 0000000..b9c0d11 --- /dev/null +++ b/sites/docs/src/examples/components/uniqueStore/basic.svelte @@ -0,0 +1,17 @@ + + +{#each data as d} +
    + selected.toggle(d.id)}> + {d.id} + +
    +{/each} +selected: {JSON.stringify([...$selected])} diff --git a/sites/docs/src/routes/docs/svelte-stores/changeStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/changeStore/+page.md deleted file mode 100644 index 8a7545b..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/changeStore/+page.md +++ /dev/null @@ -1,39 +0,0 @@ - - -

    Usage

    - -```svelte - -``` - -

    Example

    - - - -
    changed: {JSON.stringify($changed)}
    -
    - -

    Pagination

    - - -
    {JSON.stringify($paginationChanged, null, 2)}
    -
    diff --git a/sites/docs/src/routes/docs/svelte-stores/changeStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/changeStore/+page.ts deleted file mode 100644 index 5a5eb86..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/changeStore/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-stores/changeStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Track previous value. Calls onChange callback only after first change (not initial value)', - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/dirtyStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/dirtyStore/+page.md deleted file mode 100644 index ddefcac..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/dirtyStore/+page.md +++ /dev/null @@ -1,30 +0,0 @@ - - -

    Usage

    - -```svelte - -``` - -

    Example

    - - - -
    isDirty: {$isDirty}
    - -
    diff --git a/sites/docs/src/routes/docs/svelte-stores/dirtyStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/dirtyStore/+page.ts deleted file mode 100644 index 6eeaf2b..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/dirtyStore/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-stores/dirtyStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Track when a store becomes dirty (changed), with ability to reset. Useful to enable an apply button, etc', - related: ['components/MultiSelect'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/fetchStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/fetchStore/+page.ts deleted file mode 100644 index 0d3dcad..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/fetchStore/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-stores/fetchStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Fetch request as a store, with support for body parsing (json, text, arrayBuffer, etc), out of order responses, context configuration, and global errors', - related: ['svelte-stores/graphStore'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/formStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/formStore/+page.md deleted file mode 100644 index 2d7d761..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/formStore/+page.md +++ /dev/null @@ -1,11 +0,0 @@ - - -

    Usage

    - -```js -import { formStore } from '@layerstack/svelte-stores'; -``` diff --git a/sites/docs/src/routes/docs/svelte-stores/formStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/formStore/+page.ts deleted file mode 100644 index 154711c..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/formStore/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-stores/formStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Manage form state via immer draft and zod scehma, with undo history', - related: ['components/Form'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/graphStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/graphStore/+page.md deleted file mode 100644 index f69cb73..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/graphStore/+page.md +++ /dev/null @@ -1,13 +0,0 @@ - - -

    Usage

    - -```js -import { graphStore } from '@layerstack/svelte-stores'; -``` diff --git a/sites/docs/src/routes/docs/svelte-stores/graphStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/graphStore/+page.ts deleted file mode 100644 index c1e8c2b..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/graphStore/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-stores/graphStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: ['GraphQL requests powered by fetchStore'], - related: ['svelte-stores/fetchStore'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/localStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/localStore/+page.md deleted file mode 100644 index 81973d9..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/localStore/+page.md +++ /dev/null @@ -1,24 +0,0 @@ - - -

    Usage

    - -```svelte - -``` - -

    Tests

    - - diff --git a/sites/docs/src/routes/docs/svelte-stores/localStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/localStore/+page.ts deleted file mode 100644 index 30708a0..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/localStore/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$svelte-stores/localStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Read and write to localStorage with expiration support', - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/mapStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/mapStore/+page.ts deleted file mode 100644 index 42e2825..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/mapStore/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-stores/mapStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Store to wrap `Map` to simplify syncing state (set, delete, clear) with Svelte', - related: ['svelte-stores/uniqueStore'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/matchMedia/+page.md b/sites/docs/src/routes/docs/svelte-stores/matchMedia/+page.md deleted file mode 100644 index 1d45711..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/matchMedia/+page.md +++ /dev/null @@ -1,149 +0,0 @@ - - -

    Usage

    - -

    Full media query

    - -```svelte - - -{#if $isLargeScreen} -
    Only visible on 768px+ screens
    -{/if} -``` - -

    Convenient width media query

    - -```svelte - - -{#if $isLargeScreen} -
    Only visible on 768px+ screens
    -{/if} -``` - -

    Convenient presets (tailwind defaults)

    - -```svelte - - -{#if $mdScreen} -
    Only visible on 768px+ screens
    -{/if} -``` - -```svelte - - -{#if $print} -
    Only visable when printing
    -{/if} -``` - -

    Examples

    - - -
    - {#if $smScreen} - - {:else} - - {/if} - $smScreen (640px) - - {#if $mdScreen} - - {:else} - - {/if} - $mdScreen (768px) - - {#if $lgScreen} - - {:else} - - {/if} - $lgScreen (1024px) - - {#if $xlScreen} - - {:else} - - {/if} - $xlScreen (1280px) - - {#if $xxlScreen} - - {:else} - - {/if} - $xxlScreen (1536px) - - {#if $screen} - - {:else} - - {/if} - $screen - - {#if $print} - - {:else} - - {/if} - $print - - {#if $darkColorScheme} - - {:else} - - {/if} - $darkColorScheme - - {#if $motionReduce} - - {:else} - - {/if} - $motionReduce - -
    - -
    - current width: {innerWidth}px -
    -
    - - diff --git a/sites/docs/src/routes/docs/svelte-stores/matchMedia/+page.ts b/sites/docs/src/routes/docs/svelte-stores/matchMedia/+page.ts deleted file mode 100644 index 617704f..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/matchMedia/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-stores/matchMedia.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Store to monitor media query matching, including screen width/height, orientation, print media, prefers dark/light scheme, and prefers reduced motion', - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/paginationStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/paginationStore/+page.md deleted file mode 100644 index 10f658c..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/paginationStore/+page.md +++ /dev/null @@ -1,11 +0,0 @@ - - -

    Usage

    - -```js -import { paginationStore } from '@layerstack/svelte-stores'; -``` diff --git a/sites/docs/src/routes/docs/svelte-stores/paginationStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/paginationStore/+page.ts deleted file mode 100644 index 0fa0d21..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/paginationStore/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-stores/paginationStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Manage pagination state including current page and page navigation (next/previous/first/last). See related Paginate/Pagination components', - related: ['components/Paginate', 'components/Pagination'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/promiseStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/promiseStore/+page.md deleted file mode 100644 index 7219c21..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/promiseStore/+page.md +++ /dev/null @@ -1,13 +0,0 @@ - - -

    Usage

    - -```js -import { promiseStore } from '@layerstack/svelte-stores'; -``` diff --git a/sites/docs/src/routes/docs/svelte-stores/promiseStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/promiseStore/+page.ts deleted file mode 100644 index 76d2155..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/promiseStore/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$svelte-stores/promiseStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Wraps a Promise as a store. Useful for SvelteKit streamed data handling', - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/queryParamsStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/queryParamsStore/+page.ts deleted file mode 100644 index e67ef2d..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/queryParamsStore/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-stores/queryParamsStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - title: 'Query params', - description: 'Manage query params as a store, with multiple serialization strategies', - hideUsage: true, - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/selectionStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/selectionStore/+page.md deleted file mode 100644 index 44bd108..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/selectionStore/+page.md +++ /dev/null @@ -1,107 +0,0 @@ - - -

    Usage

    - -

    Max

    - -```js -const selection = selectionStore({ max: 3 }); -``` - - - {#each data as d} -
    - $selection5.toggleSelected(d.id)} disabled={$selection5.isDisabled(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify($selection5.selected)} -
    - -

    Basic

    - -```js -const selection = selectionStore(); -``` - - - {#each data as d} -
    - $selection.toggleSelected(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify($selection.selected)} -
    - -

    Initial selection

    - -```js -const selection2 = selectionStore({ initial: [3, 4, 5] }); -``` - - - {#each data as d} -
    - $selection2.toggleSelected(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify($selection2.selected)} -
    - -

    Select all

    - -```js -const selection3 = selectionStore({ all: data.map((d) => d.id) }); -``` - - - $selection3.toggleAll()}> - Select all - - {#each data as d} -
    - $selection3.toggleSelected(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify($selection3.selected)} -
    - -

    Single

    - -```js -const selection4 = selectionStore({ single: true }); -``` - - - {#each data as d} -
    - $selection4.toggleSelected(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify($selection4.selected)} -
    diff --git a/sites/docs/src/routes/docs/svelte-stores/selectionStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/selectionStore/+page.ts deleted file mode 100644 index d67bb39..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/selectionStore/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-stores/selectionStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Manage item selection state including toggling values, selecting all, and clear or reset selection', - related: ['components/MultiSelect', 'components/Selection'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/timerStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/timerStore/+page.md deleted file mode 100644 index 772b44c..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/timerStore/+page.md +++ /dev/null @@ -1,49 +0,0 @@ - - -

    Usage

    - -```js -const timer = timerStore(); -``` - -```ts -const timer = timerStore({ initial?: T, onTick?: (value: T) => {...}, delay?: number, disabled?: boolean }) -``` - -

    Examples

    - -

    Default

    - -```svelte - -``` - - -
    {$dateTimer}
    - e.target.checked ? dateTimer.start() : dateTimer.stop()} /> -
    - -

    Tick count

    - -```svelte - -``` - - -
    {$tickTimer}
    - e.target.checked ? tickTimer.start() : tickTimer.stop()} /> -
    diff --git a/sites/docs/src/routes/docs/svelte-stores/timerStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/timerStore/+page.ts deleted file mode 100644 index 9995ec8..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/timerStore/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-stores/timerStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Manage interval ticks, useful for timely updates and countdowns', - related: ['components/Duration', 'components/ScrollingValue'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-stores/uniqueStore/+page.md b/sites/docs/src/routes/docs/svelte-stores/uniqueStore/+page.md deleted file mode 100644 index c58b23c..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/uniqueStore/+page.md +++ /dev/null @@ -1,41 +0,0 @@ - - -

    Usage

    - -```js -import { uniqueStore } from '@layerstack/svelte-stores'; - -const store = uniqueStore(); -// $store.has(value) -// $store.size -// store.add(value); -// store.delete(value); -// store.toggle(value); -``` - -

    Examples

    - -

    Basic

    - - - {#each data as d} -
    - selected.toggle(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify([...$selected])} -
    diff --git a/sites/docs/src/routes/docs/svelte-stores/uniqueStore/+page.ts b/sites/docs/src/routes/docs/svelte-stores/uniqueStore/+page.ts deleted file mode 100644 index d990bce..0000000 --- a/sites/docs/src/routes/docs/svelte-stores/uniqueStore/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-stores/uniqueStore.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Store to manage unique values using `Set` with improves ergonomics and better control of updates', - related: ['svelte-stores/selectionStore', 'svelte-stores/mapStore', 'components/MultiSelect'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-table/stores/+page.md b/sites/docs/src/routes/docs/svelte-table/stores/+page.md deleted file mode 100644 index 7d49dba..0000000 --- a/sites/docs/src/routes/docs/svelte-table/stores/+page.md +++ /dev/null @@ -1,11 +0,0 @@ - - -

    Usage

    - -```js -import { tableOrderStore } from '@layerstack/svelte-table'; -``` diff --git a/sites/docs/src/routes/docs/svelte-table/stores/+page.ts b/sites/docs/src/routes/docs/svelte-table/stores/+page.ts deleted file mode 100644 index 52deed1..0000000 --- a/sites/docs/src/routes/docs/svelte-table/stores/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-table/stores.ts?raw'; -import pageSource from './+page.md?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Manage table column sorting selection and direction. Compliments Table component', - related: ['svelte-table/actions', 'components/Table'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/tailwind/utils/+page.md b/sites/docs/src/routes/docs/tailwind/utils/+page.md deleted file mode 100644 index 5f1c655..0000000 --- a/sites/docs/src/routes/docs/tailwind/utils/+page.md +++ /dev/null @@ -1,13 +0,0 @@ - - -

    Usage

    - -```svelte - - - -{/if} - -{#if data} - - - -
    -
    -
    Chart data
    -
    - - {#if copyValue} - - - - {/if} -
    - - - -
    - -
    -
    -
    -{/if} diff --git a/sites/docs/src/docs/ViewSourceButton.svelte b/sites/docs/src/docs/ViewSourceButton.svelte deleted file mode 100644 index 559a3ab..0000000 --- a/sites/docs/src/docs/ViewSourceButton.svelte +++ /dev/null @@ -1,50 +0,0 @@ - - -{#if source} - - - -
    -
    -
    {label}
    -
    {href}
    -
    - - {#if href} - - {/if} -
    - -
    - -
    - -
    - -
    -
    -
    -{:else if href} - - - -{/if} diff --git a/sites/docs/src/examples/components/Duration/format-date-range.svelte b/sites/docs/src/examples/components/Duration/format-date-range.svelte new file mode 100644 index 0000000..8daff36 --- /dev/null +++ b/sites/docs/src/examples/components/Duration/format-date-range.svelte @@ -0,0 +1,10 @@ + + +
    {new Duration({ start: intervalOffset('day', new Date(), 3) }).format()}
    +
    {new Duration({ start: intervalOffset('month', new Date(), 3) }).format()}
    +
    + {new Duration({ start: intervalOffset('month', new Date(), 3) }).format({ variant: 'long' })} +
    diff --git a/sites/docs/src/examples/components/Duration/format-duration-object.svelte b/sites/docs/src/examples/components/Duration/format-duration-object.svelte new file mode 100644 index 0000000..27e9937 --- /dev/null +++ b/sites/docs/src/examples/components/Duration/format-duration-object.svelte @@ -0,0 +1,7 @@ + + +
    {new Duration({ duration: { milliseconds: 300 } }).format()}
    +
    {new Duration({ duration: { hours: 1, minutes: 30 } }).format()}
    +
    {new Duration({ duration: { days: 5, hours: 26 } }).format()}
    diff --git a/sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte b/sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte new file mode 100644 index 0000000..d884617 --- /dev/null +++ b/sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte @@ -0,0 +1,6 @@ + + +
    {new Duration({ start: new Date('2023-02-28'), end: new Date('2023-03-01') }).format()}
    +
    {new Duration({ start: new Date('2024-02-28'), end: new Date('2024-03-01') }).format()}
    diff --git a/sites/docs/src/examples/components/Duration/format-string-range.svelte b/sites/docs/src/examples/components/Duration/format-string-range.svelte new file mode 100644 index 0000000..8dab416 --- /dev/null +++ b/sites/docs/src/examples/components/Duration/format-string-range.svelte @@ -0,0 +1,8 @@ + + +
    {new Duration({ start: '1982-03-30' }).format()}
    +
    {new Duration({ start: '2021-01-01', end: '2021-01-07' }).format()}
    +
    {new Duration({ start: '1982-03-30' }).format({ totalUnits: 2 })}
    +
    {new Duration({ start: '1982-03-30' }).format({ minUnits: DurationUnits.Hour })}
    diff --git a/sites/docs/src/examples/components/Duration/new-duration-date-range.svelte b/sites/docs/src/examples/components/Duration/new-duration-date-range.svelte new file mode 100644 index 0000000..b2c3950 --- /dev/null +++ b/sites/docs/src/examples/components/Duration/new-duration-date-range.svelte @@ -0,0 +1,8 @@ + + +
    + {JSON.stringify(new Duration({ start: intervalOffset('day', new Date(), 3) }), null, 2)} +
    diff --git a/sites/docs/src/examples/components/Duration/new-duration-string-range.svelte b/sites/docs/src/examples/components/Duration/new-duration-string-range.svelte new file mode 100644 index 0000000..09fb7df --- /dev/null +++ b/sites/docs/src/examples/components/Duration/new-duration-string-range.svelte @@ -0,0 +1,7 @@ + + +
    + {JSON.stringify(new Duration({ start: '2021-01-01', end: '2021-01-07' }), null, 2)} +
    diff --git a/sites/docs/src/examples/components/MediaQueryPresets/basic.svelte b/sites/docs/src/examples/components/MediaQueryPresets/basic.svelte new file mode 100644 index 0000000..d7aeaf4 --- /dev/null +++ b/sites/docs/src/examples/components/MediaQueryPresets/basic.svelte @@ -0,0 +1,98 @@ + + +
    + {#if smScreen.current} + + {:else} + + {/if} + smScreen (640px) + + {#if mdScreen.current} + + {:else} + + {/if} + mdScreen (768px) + + {#if lgScreen.current} + + {:else} + + {/if} + lgScreen (1024px) + + {#if xlScreen.current} + + {:else} + + {/if} + xlScreen (1280px) + + {#if xxlScreen.current} + + {:else} + + {/if} + xxlScreen (1536px) + + {#if screen.current} + + {:else} + + {/if} + screen + + {#if print.current} + + {:else} + + {/if} + print + + {#if dark.current} + + {:else} + + {/if} + dark + + {#if motion.current} + + {:else} + + {/if} + motion + + {#if motionReduce.current} + + {:else} + + {/if} + motionReduce +
    + +
    + current width: {innerWidth}px +
    + + diff --git a/sites/docs/src/examples/components/SelectionState/basic.svelte b/sites/docs/src/examples/components/SelectionState/basic.svelte new file mode 100644 index 0000000..62a8e73 --- /dev/null +++ b/sites/docs/src/examples/components/SelectionState/basic.svelte @@ -0,0 +1,21 @@ + + +{#each data as d} +
    + selection.toggle(d.id)}> + {d.id} + +
    +{/each} +selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/initial-selection.svelte b/sites/docs/src/examples/components/SelectionState/initial-selection.svelte new file mode 100644 index 0000000..ec3e764 --- /dev/null +++ b/sites/docs/src/examples/components/SelectionState/initial-selection.svelte @@ -0,0 +1,23 @@ + + + + +{#each data as d} +
    + selection.toggle(d.id)}> + {d.id} + +
    +{/each} +selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/max.svelte b/sites/docs/src/examples/components/SelectionState/max.svelte new file mode 100644 index 0000000..d452c7b --- /dev/null +++ b/sites/docs/src/examples/components/SelectionState/max.svelte @@ -0,0 +1,25 @@ + + +{#each data as d} +
    + selection.toggle(d.id)} + disabled={selection.isDisabled(d.id)} + > + {d.id} + +
    +{/each} +selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/select-all.svelte b/sites/docs/src/examples/components/SelectionState/select-all.svelte new file mode 100644 index 0000000..1f0f375 --- /dev/null +++ b/sites/docs/src/examples/components/SelectionState/select-all.svelte @@ -0,0 +1,28 @@ + + + selection.toggleAll()} +> + Select all + +{#each data as d} +
    + selection.toggle(d.id)}> + {d.id} + +
    +{/each} +selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/set-selection.svelte b/sites/docs/src/examples/components/SelectionState/set-selection.svelte new file mode 100644 index 0000000..14cb24c --- /dev/null +++ b/sites/docs/src/examples/components/SelectionState/set-selection.svelte @@ -0,0 +1,24 @@ + + + + + +{#each data as d} +
    + selection.toggle(d.id)}> + {d.id} + +
    +{/each} +selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/single.svelte b/sites/docs/src/examples/components/SelectionState/single.svelte new file mode 100644 index 0000000..b898e07 --- /dev/null +++ b/sites/docs/src/examples/components/SelectionState/single.svelte @@ -0,0 +1,21 @@ + + +{#each data as d} +
    + selection.toggle(d.id)}> + {d.id} + +
    +{/each} +selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/TimerState/basic.svelte b/sites/docs/src/examples/components/TimerState/basic.svelte new file mode 100644 index 0000000..7f73ddf --- /dev/null +++ b/sites/docs/src/examples/components/TimerState/basic.svelte @@ -0,0 +1,15 @@ + + +
    {dateTimer.current}
    + { + // @ts-expect-error + e.target?.checked ? dateTimer.start() : dateTimer.stop(); + }} +/> diff --git a/sites/docs/src/examples/components/TimerState/tick-count.svelte b/sites/docs/src/examples/components/TimerState/tick-count.svelte new file mode 100644 index 0000000..3302845 --- /dev/null +++ b/sites/docs/src/examples/components/TimerState/tick-count.svelte @@ -0,0 +1,15 @@ + + +
    {tickTimer.current}
    + { + // @ts-expect-error + e.target?.checked ? tickTimer.start() : tickTimer.stop(); + }} +/> diff --git a/sites/docs/src/examples/components/UniqueState/basic.svelte b/sites/docs/src/examples/components/UniqueState/basic.svelte new file mode 100644 index 0000000..b1f1e42 --- /dev/null +++ b/sites/docs/src/examples/components/UniqueState/basic.svelte @@ -0,0 +1,21 @@ + + +{#each data as d} +
    + state.toggle(d.id)}> + {d.id} + +
    +{/each} +selected: {JSON.stringify([...state.current])} diff --git a/sites/docs/src/examples/components/dataBackground/basic.svelte b/sites/docs/src/examples/components/dataBackground/basic.svelte new file mode 100644 index 0000000..40fcef5 --- /dev/null +++ b/sites/docs/src/examples/components/dataBackground/basic.svelte @@ -0,0 +1,115 @@ + + +
    +
    + + + Original + Derived + + + + + + + + + + +
    + +
    + +
    + min: + + max: + +
    +
    + + +
    + x: + + y: + +
    +
    +
    + +
    + + {duration} +
    +
    + + +
    + + + + {#each sorted ? sort(values) : values as value} + + {#key duration} + + + + {/key} + {/each} + +
    0 ? 'hsl(140 80% 80%)' : 'hsl(0 80% 80%)', + domain, + inset, + baseline, + tweened: { duration }, + }} + > + +
    diff --git a/sites/docs/src/routes/docs/svelte-actions/dataBackground/+page.svelte b/sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte similarity index 58% rename from sites/docs/src/routes/docs/svelte-actions/dataBackground/+page.svelte rename to sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte index 3e4d4ca..c6eb227 100644 --- a/sites/docs/src/routes/docs/svelte-actions/dataBackground/+page.svelte +++ b/sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte @@ -15,9 +15,6 @@ import { dataBackground } from '@layerstack/svelte-actions'; import { cls } from '@layerstack/tailwind'; - import Preview from '$docs/Preview.svelte'; - import Code from '$docs/Code.svelte'; - import { randomInteger } from '@layerstack/utils'; const originalDomain: [number, number] = [-100, 100]; @@ -42,15 +39,7 @@ : ([Math.min(...values), Math.max(...values)] as [number, number]); -

    Usage

    - - - -
    +
    @@ -98,66 +87,32 @@
    - +
    -

    Basic

    - - - - - {#each sorted ? sort(values) : values as value} - - {#key duration} - - - - {/key} - {/each} - -
    0 ? 'hsl(140 80% 80%)' : 'hsl(0 80% 80%)', - domain, - inset, - baseline, - tweened: { duration }, - }} - > - -
    -
    - -

    Tailwind gradient

    - - - - - {#each sorted ? sort(values) : values as value} - - {#key duration} - - - - {/key} - {/each} - -
    0 ? 'from-success-100 to-success-500' : 'from-danger-500 to-danger-100' - )} - use:dataBackground={{ - value, - domain, - inset, - baseline, - tweened: { duration }, - }} - > - -
    -
    + + + {#each sorted ? sort(values) : values as value} + + {#key duration} + + + + {/key} + {/each} + +
    0 ? 'from-success-100 to-success-500' : 'from-danger-500 to-danger-100' + )} + use:dataBackground={{ + value, + domain, + inset, + baseline, + tweened: { duration }, + }} + > + +
    diff --git a/sites/docs/src/examples/components/format/dates-custom.svelte b/sites/docs/src/examples/components/format/dates-custom.svelte new file mode 100644 index 0000000..3d07301 --- /dev/null +++ b/sites/docs/src/examples/components/format/dates-custom.svelte @@ -0,0 +1,26 @@ + + +
    +
    +

    With format string

    + {format(myDate, 'custom', { + custom: 'eee, MMMM do' + })} +
    +
    +

    With descriptive tokens

    + {format(myDate, 'custom', { + custom: [DateToken.DayOfWeek_short, DateToken.Month_long, DateToken.DayOfMonth_withOrdinal] + })} +
    +
    +

    With full intl

    + {format(myDate, 'custom', { + custom: { weekday: 'short', month: 'long', day: 'numeric', withOrdinal: true } + })} +
    +
    diff --git a/sites/docs/src/examples/components/format/dates-period-types.svelte b/sites/docs/src/examples/components/format/dates-period-types.svelte new file mode 100644 index 0000000..53f903f --- /dev/null +++ b/sites/docs/src/examples/components/format/dates-period-types.svelte @@ -0,0 +1,55 @@ + + +{#each periodTypeCodes as periodType} +

    {periodType}

    + + {#if periodType === 'week' || periodType === 'biweek1'} + + It will take your default weekStartsOn + settings, if you want to be specific, you can also use + {periodType === 'week' ? 'PeriodType.WeekSun' : 'PeriodType.BiWeek1Sun'} + + {/if} + +
    +
    +

    short

    + {format(myDate, periodType, { + variant: 'short' + })} +
    +
    +

    default

    + {format(myDate, periodType, { + // variant: 'default', + })} +
    +
    +

    long

    + {format(myDate, periodType, { + variant: 'long' + })} +
    +
    +{/each} diff --git a/sites/docs/src/examples/components/format/numbers-config.svelte b/sites/docs/src/examples/components/format/numbers-config.svelte new file mode 100644 index 0000000..83980e0 --- /dev/null +++ b/sites/docs/src/examples/components/format/numbers-config.svelte @@ -0,0 +1,17 @@ + + +
    {format(1234.56, { type: 'integer', options: { maximumSignificantDigits: 2 } })}
    +
    {format(1234.56, { type: 'decimal', options: { maximumSignificantDigits: 5 } })}
    +
    {format(1234.56, { type: 'currency', options: { currency: 'EUR' } })}
    +
    + {format(123_456_789.99, { + type: 'currency', + options: { notation: 'compact', maximumSignificantDigits: 3 } + })} +
    +
    {format(0.5678, { type: 'percent', options: { signDisplay: 'always' } })}
    +
    {format(0.5678, { type: 'percentRound', options: { signDisplay: 'always' } })}
    +
    {format(1_234_567, { type: 'metric', options: { minimumSignificantDigits: 12 } })}
    +
    {format(0.5678, { type: 'percent', options: { fractionDigits: 1 } })}
    diff --git a/sites/docs/src/examples/components/format/numbers-default.svelte b/sites/docs/src/examples/components/format/numbers-default.svelte new file mode 100644 index 0000000..0707af2 --- /dev/null +++ b/sites/docs/src/examples/components/format/numbers-default.svelte @@ -0,0 +1,12 @@ + + +
    {format(1234.56, 'integer')}
    +
    {format(1234.56, 'decimal')}
    +
    {format(1234.56, 'currency')}
    +
    {format(0.5678, 'percent')}
    +
    {format(0.5678, 'percentRound')}
    +
    {format(1_234_567, 'metric')}
    +
    {format(1_200_000, 'metric')}
    +
    {format(0.5678, 'percent')}
    diff --git a/sites/docs/src/examples/components/format/numbers-options.svelte b/sites/docs/src/examples/components/format/numbers-options.svelte new file mode 100644 index 0000000..c9f53bb --- /dev/null +++ b/sites/docs/src/examples/components/format/numbers-options.svelte @@ -0,0 +1,14 @@ + + +
    {format(1234.56, 'integer', { maximumSignificantDigits: 2 })}
    +
    {format(1234.56, 'decimal', { maximumSignificantDigits: 5 })}
    +
    {format(1234.56, 'currency', { currency: 'EUR' })}
    +
    + {format(123_456_789.99, 'currency', { notation: 'compact', maximumSignificantDigits: 3 })} +
    +
    {format(0.5678, 'percent', { signDisplay: 'always' })}
    +
    {format(0.5678, 'percentRound', { signDisplay: 'always' })}
    +
    {format(1_234_567, 'metric', { minimumSignificantDigits: 12 })}
    +
    {format(0.5678, 'percent', { fractionDigits: 1 })}
    diff --git a/sites/docs/src/examples/components/format/playground-dates.svelte b/sites/docs/src/examples/components/format/playground-dates.svelte new file mode 100644 index 0000000..ab11999 --- /dev/null +++ b/sites/docs/src/examples/components/format/playground-dates.svelte @@ -0,0 +1,43 @@ + + +
    + + + ({ label: value, value }))} + stepper + /> + + ({ label: value, value }))} + stepper + /> +
    + +
    {format(myDate, { type: periodType, locale })}
    diff --git a/sites/docs/src/examples/components/format/playground-numbers.svelte b/sites/docs/src/examples/components/format/playground-numbers.svelte new file mode 100644 index 0000000..7358d83 --- /dev/null +++ b/sites/docs/src/examples/components/format/playground-numbers.svelte @@ -0,0 +1,61 @@ + + +
    + + + ({ label: value, value }))} + stepper + /> + + ({ + label: value ?? 'None', + value + }))} + stepper + disabled={numberType !== 'currency' && numberType !== 'currencyRound'} + /> + + ({ label: value, value }))} + stepper + /> + + ({ + label: value, + value + }))} + stepper + /> +
    + +
    {format(value, { type: numberType, locale, options: { currency, notation } })}
    diff --git a/sites/docs/src/examples/components/input/auto-focus.svelte b/sites/docs/src/examples/components/input/auto-focus.svelte new file mode 100644 index 0000000..a91e809 --- /dev/null +++ b/sites/docs/src/examples/components/input/auto-focus.svelte @@ -0,0 +1,5 @@ + + + diff --git a/sites/docs/src/examples/components/input/auto-height.svelte b/sites/docs/src/examples/components/input/auto-height.svelte new file mode 100644 index 0000000..8dc58ce --- /dev/null +++ b/sites/docs/src/examples/components/input/auto-height.svelte @@ -0,0 +1,5 @@ + + + diff --git a/sites/docs/src/examples/components/input/blur-on-escape.svelte b/sites/docs/src/examples/components/input/blur-on-escape.svelte new file mode 100644 index 0000000..36d9625 --- /dev/null +++ b/sites/docs/src/examples/components/input/blur-on-escape.svelte @@ -0,0 +1,5 @@ + + + diff --git a/sites/docs/src/examples/components/input/debounce-event.svelte b/sites/docs/src/examples/components/input/debounce-event.svelte new file mode 100644 index 0000000..4154273 --- /dev/null +++ b/sites/docs/src/examples/components/input/debounce-event.svelte @@ -0,0 +1,16 @@ + + + { + // @ts-expect-error + console.log(e.target.value); + }, + timeout: 1000, + }} + class="border" +/> diff --git a/sites/docs/src/examples/components/input/select-on-focus.svelte b/sites/docs/src/examples/components/input/select-on-focus.svelte new file mode 100644 index 0000000..87d7587 --- /dev/null +++ b/sites/docs/src/examples/components/input/select-on-focus.svelte @@ -0,0 +1,5 @@ + + + diff --git a/sites/docs/src/examples/components/layout/overflow.svelte b/sites/docs/src/examples/components/layout/overflow.svelte new file mode 100644 index 0000000..da06615 --- /dev/null +++ b/sites/docs/src/examples/components/layout/overflow.svelte @@ -0,0 +1,31 @@ + + +
    + + +
    +
    { + overflowX = e.detail.overflowX; + overflowY = e.detail.overflowY; + }} +> + {#each { length: overflowItems } as _} +
    Resize the window to see text truncate and watch values
    + {/each} +
    +
    overflowX: {overflowX}
    +
    overflowY: {overflowY}
    diff --git a/sites/docs/src/examples/components/mouse/longpress.svelte b/sites/docs/src/examples/components/mouse/longpress.svelte new file mode 100644 index 0000000..f239c47 --- /dev/null +++ b/sites/docs/src/examples/components/mouse/longpress.svelte @@ -0,0 +1,16 @@ + + + +{#if longpressed} + Success! Repeat to hide +{/if} diff --git a/sites/docs/src/examples/components/mouse/movable-step-percent.svelte b/sites/docs/src/examples/components/mouse/movable-step-percent.svelte new file mode 100644 index 0000000..79ceed5 --- /dev/null +++ b/sites/docs/src/examples/components/mouse/movable-step-percent.svelte @@ -0,0 +1,27 @@ + + +
    +
    { + coords.stiffness = 1; + coords.damping = 1; + }} + on:move={(e) => { + $coords.x += e.detail.dx; + $coords.y += e.detail.dy; + }} + on:moveend={() => { + coords.stiffness = 0.2; + coords.damping = 0.4; + coords.set({ x: 0, y: 0 }); + }} + style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" + >
    +
    diff --git a/sites/docs/src/examples/components/mouse/movable-step.svelte b/sites/docs/src/examples/components/mouse/movable-step.svelte new file mode 100644 index 0000000..9097a07 --- /dev/null +++ b/sites/docs/src/examples/components/mouse/movable-step.svelte @@ -0,0 +1,27 @@ + + +
    +
    { + coords.stiffness = 1; + coords.damping = 1; + }} + on:move={(e) => { + $coords.x += e.detail.dx; + $coords.y += e.detail.dy; + }} + on:moveend={() => { + coords.stiffness = 0.2; + coords.damping = 0.4; + coords.set({ x: 0, y: 0 }); + }} + style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" + >
    +
    diff --git a/sites/docs/src/examples/components/mouse/movable-x-axis.svelte b/sites/docs/src/examples/components/mouse/movable-x-axis.svelte new file mode 100644 index 0000000..a14f29b --- /dev/null +++ b/sites/docs/src/examples/components/mouse/movable-x-axis.svelte @@ -0,0 +1,27 @@ + + +
    +
    { + coords.stiffness = 1; + coords.damping = 1; + }} + on:move={(e) => { + $coords.x += e.detail.dx; + $coords.y += e.detail.dy; + }} + on:moveend={() => { + coords.stiffness = 0.2; + coords.damping = 0.4; + coords.set({ x: 0, y: 0 }); + }} + style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" + >
    +
    diff --git a/sites/docs/src/examples/components/mouse/movable.svelte b/sites/docs/src/examples/components/mouse/movable.svelte new file mode 100644 index 0000000..77c9a2c --- /dev/null +++ b/sites/docs/src/examples/components/mouse/movable.svelte @@ -0,0 +1,27 @@ + + +
    +
    { + coords.stiffness = 1; + coords.damping = 1; + }} + on:move={(e) => { + $coords.x += e.detail.dx; + $coords.y += e.detail.dy; + }} + on:moveend={() => { + coords.stiffness = 0.2; + coords.damping = 0.4; + coords.set({ x: 0, y: 0 }); + }} + style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" + >
    +
    diff --git a/sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte b/sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte new file mode 100644 index 0000000..a6d11c4 --- /dev/null +++ b/sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte @@ -0,0 +1,27 @@ + + +
    + {#each { length: 10 } as _} +
    Scroll down
    + {/each} +
    { + if (e.detail.isIntersecting) { + // @ts-expect-error + e.target.classList.add('bg-danger'); + } else { + // @ts-expect-error + e.target.classList.remove('bg-danger'); + } + }} + class="transition-colors duration-500" + > + Watch me scroll away +
    + {#each { length: 10 } as _} +
    Scroll up
    + {/each} +
    diff --git a/sites/docs/src/examples/components/observer/basic.svelte b/sites/docs/src/examples/components/observer/basic.svelte new file mode 100644 index 0000000..b991aa5 --- /dev/null +++ b/sites/docs/src/examples/components/observer/basic.svelte @@ -0,0 +1,13 @@ + + +
    { + console.log(e.detail); + // @ts-expect-error + e.target.innerText = JSON.stringify(e.detail.contentRect, null, 2); + }} + class="resize overflow-auto whitespace-pre outline rounded-sm" +>
    diff --git a/sites/docs/src/examples/components/observer/full-coordinates.svelte b/sites/docs/src/examples/components/observer/full-coordinates.svelte new file mode 100644 index 0000000..91e57d4 --- /dev/null +++ b/sites/docs/src/examples/components/observer/full-coordinates.svelte @@ -0,0 +1,12 @@ + + +
    { + // @ts-expect-error + e.target.innerText = JSON.stringify(e.target.getBoundingClientRect(), null, 2); + }} + class="resize overflow-auto whitespace-pre outline rounded-sm" +>
    diff --git a/sites/docs/src/examples/components/observer/setting-css-variable.svelte b/sites/docs/src/examples/components/observer/setting-css-variable.svelte new file mode 100644 index 0000000..c34257e --- /dev/null +++ b/sites/docs/src/examples/components/observer/setting-css-variable.svelte @@ -0,0 +1,15 @@ + + +
    { + // @ts-expect-error + e.target.style.setProperty('--color', e.detail.contentRect.width % 255); + }} + style:background-color="hsl(var(--color), 100%, 70%)" + class="resize overflow-auto p-2 rounded-sm" +> + Resize and watch me change colors +
    diff --git a/sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte b/sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte new file mode 100644 index 0000000..34d849c --- /dev/null +++ b/sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte @@ -0,0 +1,44 @@ + + + +
    + {#if showHeader} +
    + Header +
    + {/if} +
    + {#each { length: 10 } as _} +
    Scroll down
    + {/each} +
    { + if (e.detail.isIntersecting) { + // Visible + toggleOff(); + } else { + if (e.detail.boundingClientRect.top < (e.detail.rootBounds?.top ?? 0)) { + // Scrolled off top + toggleOn(); + } else { + // Scrolled off bottom + } + } + }} + > + Watch me scroll away +
    + {#each { length: 10 } as _} +
    Scroll up
    + {/each} +
    +
    +
    diff --git a/sites/docs/src/examples/components/portal/ancestor-portal-target.svelte b/sites/docs/src/examples/components/portal/ancestor-portal-target.svelte new file mode 100644 index 0000000..d46cd12 --- /dev/null +++ b/sites/docs/src/examples/components/portal/ancestor-portal-target.svelte @@ -0,0 +1,23 @@ + + + +
    +
    + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    +
    diff --git a/sites/docs/src/examples/components/portal/basic.svelte b/sites/docs/src/examples/components/portal/basic.svelte new file mode 100644 index 0000000..0a282a2 --- /dev/null +++ b/sites/docs/src/examples/components/portal/basic.svelte @@ -0,0 +1,19 @@ + + +
    + + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    diff --git a/sites/docs/src/examples/components/portal/custom-target.svelte b/sites/docs/src/examples/components/portal/custom-target.svelte new file mode 100644 index 0000000..b6a3baa --- /dev/null +++ b/sites/docs/src/examples/components/portal/custom-target.svelte @@ -0,0 +1,22 @@ + + + +
    + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    +
    diff --git a/sites/docs/src/examples/components/portal/destroyable.svelte b/sites/docs/src/examples/components/portal/destroyable.svelte new file mode 100644 index 0000000..b30823f --- /dev/null +++ b/sites/docs/src/examples/components/portal/destroyable.svelte @@ -0,0 +1,29 @@ + + + + + {#if !destroyed} +
    +
    + + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    +
    + {:else} + + {/if} +
    +
    diff --git a/sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte b/sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte new file mode 100644 index 0000000..c18c59c --- /dev/null +++ b/sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte @@ -0,0 +1,22 @@ + + + +
    + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    +
    diff --git a/sites/docs/src/examples/components/scroll/basic.svelte b/sites/docs/src/examples/components/scroll/basic.svelte new file mode 100644 index 0000000..7805abe --- /dev/null +++ b/sites/docs/src/examples/components/scroll/basic.svelte @@ -0,0 +1,21 @@ + + + +{scrolledIndex} +
    + {#each items as item, i} +
    + {item} +
    + {/each} +
    diff --git a/sites/docs/src/examples/components/scroll/only-if-needed.svelte b/sites/docs/src/examples/components/scroll/only-if-needed.svelte new file mode 100644 index 0000000..c77f5a1 --- /dev/null +++ b/sites/docs/src/examples/components/scroll/only-if-needed.svelte @@ -0,0 +1,21 @@ + + + +{scrolledIndex} +
    + {#each items as item, i} +
    + {item} +
    + {/each} +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte b/sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte new file mode 100644 index 0000000..3ee001a --- /dev/null +++ b/sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte @@ -0,0 +1,24 @@ + + +
    + {#each items as item, i (item)} +
    {item}
    + {/each} +
    + +
    + +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte b/sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte new file mode 100644 index 0000000..a361978 --- /dev/null +++ b/sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte @@ -0,0 +1,14 @@ + + +
    +
    + {#each items as item, i} +
    {item}
    + {/each} +
    +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-fade.svelte b/sites/docs/src/examples/components/scroll/scroll-fade.svelte new file mode 100644 index 0000000..0276a96 --- /dev/null +++ b/sites/docs/src/examples/components/scroll/scroll-fade.svelte @@ -0,0 +1,12 @@ + + +
    + {#each items as item, i (item)} +
    {item}
    + {/each} +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte new file mode 100644 index 0000000..c75ff16 --- /dev/null +++ b/sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte @@ -0,0 +1,17 @@ + + +
    + {#each items as item, i} +
    {item}
    + {/each} +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte new file mode 100644 index 0000000..341d0a1 --- /dev/null +++ b/sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte @@ -0,0 +1,24 @@ + + +
    + {#each items as item, i (item)} +
    {item}
    + {/each} +
    + +
    + +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte new file mode 100644 index 0000000..9b43d17 --- /dev/null +++ b/sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte @@ -0,0 +1,14 @@ + + +
    +
    + {#each items as item, i} +
    {item}
    + {/each} +
    +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte new file mode 100644 index 0000000..68fc200 --- /dev/null +++ b/sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte @@ -0,0 +1,12 @@ + + +
    + {#each items as item, i} +
    {item} with a really long description
    + {/each} +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow.svelte new file mode 100644 index 0000000..10d899c --- /dev/null +++ b/sites/docs/src/examples/components/scroll/scroll-shadow.svelte @@ -0,0 +1,12 @@ + + +
    + {#each items as item, i (item)} +
    {item}
    + {/each} +
    diff --git a/sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte b/sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte new file mode 100644 index 0000000..6724043 --- /dev/null +++ b/sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte @@ -0,0 +1,35 @@ + + + { + const body = window.document.body; + body.style.setProperty('--x', e.clientX + 'px'); + body.style.setProperty('--y', e.clientY + 'px'); + }} +/> + +
    + {#each items as item, i} +
    + {item} +
    + {/each} +
    diff --git a/sites/docs/src/examples/components/spotlight/global-context-and-options.svelte b/sites/docs/src/examples/components/spotlight/global-context-and-options.svelte new file mode 100644 index 0000000..dd8c5e5 --- /dev/null +++ b/sites/docs/src/examples/components/spotlight/global-context-and-options.svelte @@ -0,0 +1,45 @@ + + + { + const body = window.document.body; + body.style.setProperty('--x', e.clientX + 'px'); + body.style.setProperty('--y', e.clientY + 'px'); + }} +/> + +
    + {#each items as item, i} +
    + {item} +
    + {/each} +
    diff --git a/sites/docs/src/examples/components/spotlight/line.svelte b/sites/docs/src/examples/components/spotlight/line.svelte new file mode 100644 index 0000000..827ef9e --- /dev/null +++ b/sites/docs/src/examples/components/spotlight/line.svelte @@ -0,0 +1,36 @@ + + + { + const body = window.document.body; + body.style.setProperty('--x', e.clientX + 'px'); + body.style.setProperty('--y', e.clientY + 'px'); + }} +/> + +
    + {#each items as item, i} +
    + {item} +
    + {/each} +
    diff --git a/sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte b/sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte new file mode 100644 index 0000000..db32599 --- /dev/null +++ b/sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte @@ -0,0 +1,7 @@ + + +
    {truncate(str, 20, 10)}
    diff --git a/sites/docs/src/examples/components/string/truncate-playground.svelte b/sites/docs/src/examples/components/string/truncate-playground.svelte new file mode 100644 index 0000000..adc6363 --- /dev/null +++ b/sites/docs/src/examples/components/string/truncate-playground.svelte @@ -0,0 +1,14 @@ + + +
    + + +
    +
    {truncate(str, totalChars, endChars)}
    diff --git a/sites/docs/src/examples/components/string/truncate-total-only.svelte b/sites/docs/src/examples/components/string/truncate-total-only.svelte new file mode 100644 index 0000000..db535f3 --- /dev/null +++ b/sites/docs/src/examples/components/string/truncate-total-only.svelte @@ -0,0 +1,7 @@ + + +
    {truncate(str, 20)}
    diff --git a/sites/docs/src/examples/components/string/unique-basic.svelte b/sites/docs/src/examples/components/string/unique-basic.svelte new file mode 100644 index 0000000..8ea76f8 --- /dev/null +++ b/sites/docs/src/examples/components/string/unique-basic.svelte @@ -0,0 +1,8 @@ + + +
    {uniqueId('checkbox-')}
    +
    {uniqueId('checkbox-')}
    +
    {uniqueId('checkbox-')}
    +
    {uniqueId('radio-')}
    diff --git a/sites/docs/src/examples/components/styles/computed-styles.svelte b/sites/docs/src/examples/components/styles/computed-styles.svelte new file mode 100644 index 0000000..f4611c2 --- /dev/null +++ b/sites/docs/src/examples/components/styles/computed-styles.svelte @@ -0,0 +1,47 @@ + + +
    +
    (_styles = styles)} + class={cls('size-10 rounded-sm outline-offset-2', backgroundClass)} + style:outline-style={outlineStyle} + >
    + +
    + + + primary + secondary + + + + + + solid + dashed + dotted + + +
    + + + + + + + + +
    diff --git a/sites/docs/src/examples/components/styles/style-props.svelte b/sites/docs/src/examples/components/styles/style-props.svelte new file mode 100644 index 0000000..8d2d40c --- /dev/null +++ b/sites/docs/src/examples/components/styles/style-props.svelte @@ -0,0 +1,21 @@ + + +
    +
    +
    + + +
    +
    diff --git a/sites/docs/src/lib/plugins/svelte.js b/sites/docs/src/lib/plugins/svelte.js deleted file mode 100644 index bac6911..0000000 --- a/sites/docs/src/lib/plugins/svelte.js +++ /dev/null @@ -1,46 +0,0 @@ -import { format } from 'prettier'; -import typescriptPlugin from 'prettier/plugins/typescript'; -import sveltePlugin from 'prettier-plugin-svelte'; -import Prism from 'prismjs'; -import 'prism-svelte'; - -/** - * Add `code` and `highlightedCode` props to from slot contents - */ -export function codePreview() { - return { - /** - * @param {Object} options - * @param {string} options.content - * @param {string} options.filename - */ - async markup({ content, filename }) { - let code = content; - - // Process ... to `... - const previewMatches = content.match(//g) ?? []; - - for await (const previewMatch of previewMatches) { - const previewContent = previewMatch.match(/([^]*)<\/Preview>/)?.[1] ?? ''; - - const formattedCode = await format(previewContent, { - parser: 'svelte', - plugins: [typescriptPlugin, sveltePlugin], - }); - const highlightedCode = Prism.highlight(formattedCode, Prism.languages.svelte, 'svelte'); - - if (!previewMatch.includes('code=')) { - code = code.replace( - previewMatch, - previewMatch.replace( - ' import { onMount } from 'svelte'; import posthog from 'posthog-js'; - import 'prism-themes/themes/prism-vsc-dark-plus.css'; import { mdiArrowTopRight, mdiDotsVertical, mdiGithub, mdiTwitter } from '@mdi/js'; import { diff --git a/sites/docs/src/routes/docs/+layout.svelte b/sites/docs/src/routes/docs/+layout.svelte index bdad874..d32d464 100644 --- a/sites/docs/src/routes/docs/+layout.svelte +++ b/sites/docs/src/routes/docs/+layout.svelte @@ -1,311 +1,11 @@ -{#if page.data.metadata} - - -{:else} -
    - {#if title} -
    -
    Docs
    - -
    - {packageName} -
    -
    - -
    - {title} - {#if status} - - {status} - - {/if} -
    - - {#if description} -
    - {description} -
    - {/if} - -
    - - - - - {#if !hideTableOfContents} - - {/if} -
    - {/if} -
    - -
    - {#if !$xlScreen} - {#key page.route.id} - -
    On this page
    -
    - {/key} - {/if} - -
    -
    - {#if features} - {#key page.route.id} -

    Features

    -
      - {#each features as feature} -
    • - - {@html feature} -
    • - {/each} -
    - {/key} - {/if} - - - - {#if related} -

    Related

    - - {/if} - - {#if api} -

    API

    - - {/if} -
    - - {#if showTableOfContents && $xlScreen} -
    -
    - - On this page -
    - - {#key page.route.id} - - {/key} -
    - {/if} -
    -
    -{/if} + diff --git a/sites/docs/src/routes/docs/svelte-actions/dataBackground/+page.ts b/sites/docs/src/routes/docs/svelte-actions/dataBackground/+page.ts deleted file mode 100644 index 3a65836..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/dataBackground/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-actions/dataBackground.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Set background gradient based on data, similar to Excel. Typically used within a table', - related: ['components/Table', 'svelte-table/actions/table'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/input/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/input/+page.svelte deleted file mode 100644 index 107c303..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/input/+page.svelte +++ /dev/null @@ -1,60 +0,0 @@ - - -

    Usage

    - - - -

    autoFocus Auto focus node when rendered

    - - - - - -

    selectOnFocus Selects the text inside a text node when the node is focused

    - - - - - -

    blurOnEscape Blurs the node when Escape is pressed

    - - - - - -

    autoHeight Automatically resize textarea based on content

    - - - - - -

    debounceEvent Debounce any event (input, change, etc)

    - - - { - // @ts-expect-error - console.log(e.target.value); - }, - timeout: 1000, - }} - class="border" - /> - diff --git a/sites/docs/src/routes/docs/svelte-actions/input/+page.ts b/sites/docs/src/routes/docs/svelte-actions/input/+page.ts deleted file mode 100644 index 0c214a2..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/input/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$svelte-actions/input.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - related: ['components/TextField', 'components/Input'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/layout/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/layout/+page.svelte deleted file mode 100644 index 4b4c86d..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/layout/+page.svelte +++ /dev/null @@ -1,70 +0,0 @@ - - -

    Usage

    - - - -

    - remainingViewportHeight Set `height` or `max-height` to viewport height excluding node's current viewport top -

    - -
    TODO
    - -

    - remainingViewportWidth Set `width` or `max-width` to viewport width excluding node's current viewport left -

    - -
    TODO
    - -

    - overflow Watch for overflow changes (x or y) and dispatch `overflow` event with amount -

    - - -
    - - -
    -
    { - overflowX = e.detail.overflowX; - overflowY = e.detail.overflowY; - }} - > - {#each { length: overflowItems } as _} -
    Resize the window to see text truncate and watch values
    - {/each} -
    -
    overflowX: {overflowX}
    -
    overflowY: {overflowY}
    -
    diff --git a/sites/docs/src/routes/docs/svelte-actions/layout/+page.ts b/sites/docs/src/routes/docs/svelte-actions/layout/+page.ts deleted file mode 100644 index db71858..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/layout/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$svelte-actions/layout.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - related: ['components/Overflow'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/mouse/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/mouse/+page.svelte deleted file mode 100644 index b04f558..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/mouse/+page.svelte +++ /dev/null @@ -1,150 +0,0 @@ - - -

    Usage

    - - - -

    - longpress Dispatch event after element has been pressed for a duration of time -

    - - - - {#if longpressed} - Success! Repeat to hide - {/if} - - -

    movable Track mouse position changes from mouse down on node to mouse up

    - - -
    -
    { - coords.stiffness = 1; - coords.damping = 1; - }} - on:move={(e) => { - $coords.x += e.detail.dx; - $coords.y += e.detail.dy; - }} - on:moveend={() => { - coords.stiffness = 0.2; - coords.damping = 0.4; - coords.set({ x: 0, y: 0 }); - }} - style="transform: - translate({$coords.x}px,{$coords.y}px) - rotate({$coords.x * 0.2}deg)" - >
    -
    -
    - -

    With pixel steps / snapping

    - - -
    -
    { - coords.stiffness = 1; - coords.damping = 1; - }} - on:move={(e) => { - $coords.x += e.detail.dx; - $coords.y += e.detail.dy; - }} - on:moveend={() => { - coords.stiffness = 0.2; - coords.damping = 0.4; - coords.set({ x: 0, y: 0 }); - }} - style="transform: - translate({$coords.x}px,{$coords.y}px) - rotate({$coords.x * 0.2}deg)" - >
    -
    -
    - -

    With percentage of parent steps / snapping

    - - -
    -
    { - coords.stiffness = 1; - coords.damping = 1; - }} - on:move={(e) => { - $coords.x += e.detail.dx; - $coords.y += e.detail.dy; - }} - on:moveend={() => { - coords.stiffness = 0.2; - coords.damping = 0.4; - coords.set({ x: 0, y: 0 }); - }} - style="transform: - translate({$coords.x}px,{$coords.y}px) - rotate({$coords.x * 0.2}deg)" - >
    -
    -
    - -

    x-axis only

    - - -
    -
    { - coords.stiffness = 1; - coords.damping = 1; - }} - on:move={(e) => { - $coords.x += e.detail.dx; - $coords.y += e.detail.dy; - }} - on:moveend={() => { - coords.stiffness = 0.2; - coords.damping = 0.4; - coords.set({ x: 0, y: 0 }); - }} - style="transform: - translate({$coords.x}px,{$coords.y}px) - rotate({$coords.x * 0.2}deg) - " - >
    -
    -
    diff --git a/sites/docs/src/routes/docs/svelte-actions/mouse/+page.ts b/sites/docs/src/routes/docs/svelte-actions/mouse/+page.ts deleted file mode 100644 index a4bc974..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/mouse/+page.ts +++ /dev/null @@ -1,11 +0,0 @@ -import source from '$svelte-actions/mouse.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/multi/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/multi/+page.svelte deleted file mode 100644 index c9687aa..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/multi/+page.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - -

    Usage

    - - diff --git a/sites/docs/src/routes/docs/svelte-actions/multi/+page.ts b/sites/docs/src/routes/docs/svelte-actions/multi/+page.ts deleted file mode 100644 index 23a0414..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/multi/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-actions/multi.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Helper action to handle multiple actions as a single action. Useful for adding actions for custom components', - related: ['components/Button', 'components/Input', 'components/TextField'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/observer/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/observer/+page.svelte deleted file mode 100644 index a2566e7..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/observer/+page.svelte +++ /dev/null @@ -1,138 +0,0 @@ - - -

    Usage

    - - - -

    use:resize

    - -

    Basic

    - - -
    { - console.log(e.detail); - // @ts-expect-error - e.target.innerText = JSON.stringify(e.detail.contentRect, null, 2); - }} - class="resize overflow-auto whitespace-pre outline rounded-sm" - >
    -
    - -

    Full coordinates (using `getBoundingClientRect()`)

    - - -
    { - // @ts-expect-error - e.target.innerText = JSON.stringify(e.target.getBoundingClientRect(), null, 2); - }} - class="resize overflow-auto whitespace-pre outline rounded-sm" - >
    -
    - -

    Setting CSS variable

    - - -
    { - // @ts-expect-error - e.target.style.setProperty('--color', e.detail.contentRect.width % 255); - }} - style:background-color="hsl(var(--color), 100%, 70%)" - class="resize overflow-auto p-2 rounded-sm" - > - Resize and watch me change colors -
    -
    - -

    use:intersection

    - -

    Adding class when fully visible

    - - -
    - {#each { length: 10 } as _} -
    Scroll down
    - {/each} -
    { - if (e.detail.isIntersecting) { - // @ts-expect-error - e.target.classList.add('bg-danger'); - } else { - // @ts-expect-error - e.target.classList.remove('bg-danger'); - } - }} - class="transition-colors duration-500" - > - Watch me scroll away -
    - {#each { length: 10 } as _} -
    Scroll up
    - {/each} -
    -
    - -

    Show header on scroll away

    - - - -
    - {#if showHeader} -
    - Header -
    - {/if} -
    - {#each { length: 10 } as _} -
    Scroll down
    - {/each} -
    { - if (e.detail.isIntersecting) { - // Visible - toggleOff(); - } else { - if (e.detail.boundingClientRect.top < (e.detail.rootBounds?.top ?? 0)) { - // Scrolled off top - toggleOn(); - } else { - // Scrolled off bottom - } - } - }} - > - Watch me scroll away -
    - {#each { length: 10 } as _} -
    Scroll up
    - {/each} -
    -
    -
    -
    - -

    use:mutate

    - -
    TODO
    diff --git a/sites/docs/src/routes/docs/svelte-actions/observer/+page.ts b/sites/docs/src/routes/docs/svelte-actions/observer/+page.ts deleted file mode 100644 index 3278b0c..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/observer/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-actions/observer.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Actions for ResizeObserver, IntersectionObserver, and MutationObserver', - related: ['components/InfiniteScroll', 'components/Lazy'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/popover/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/popover/+page.svelte deleted file mode 100644 index 7be49c1..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/popover/+page.svelte +++ /dev/null @@ -1,11 +0,0 @@ - - -

    Usage

    - - diff --git a/sites/docs/src/routes/docs/svelte-actions/popover/+page.ts b/sites/docs/src/routes/docs/svelte-actions/popover/+page.ts deleted file mode 100644 index f403135..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/popover/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-actions/popover.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Svelte action for floating-ui with simplier setup, especially for middlware', - related: ['components/Popover'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/portal/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/portal/+page.svelte deleted file mode 100644 index 277447a..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/portal/+page.svelte +++ /dev/null @@ -1,125 +0,0 @@ - - -

    Usage

    - - - -

    Examples

    - -

    basic

    - - -
    - - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    -
    - -

    first/sibling .PortalTarget

    - - - -
    - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    -
    -
    - -

    anscestor .PortalTarget

    - - - - -
    -
    - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    -
    -
    - -

    custom target

    - - - -
    - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    -
    -
    - -

    Destroyable

    - - - - - {#if !destroyed} -
    -
    - - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    -
    - {:else} - - {/if} -
    -
    -
    - - diff --git a/sites/docs/src/routes/docs/svelte-actions/portal/+page.ts b/sites/docs/src/routes/docs/svelte-actions/portal/+page.ts deleted file mode 100644 index 2b3da59..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/portal/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-actions/portal.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Render component outside current DOM hierarchy', - related: ['components/Dialog', 'components/Drawer', 'components/Backdrop'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/scroll/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/scroll/+page.svelte deleted file mode 100644 index 845770c..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/scroll/+page.svelte +++ /dev/null @@ -1,155 +0,0 @@ - - -

    Usage

    - - - -

    scrollIntoView Smootly scroll element into center of view

    - - - - {scrolledIndex} -
    - {#each items as item, i} -
    - {item} -
    - {/each} -
    -
    - -
    - Only if needed -
    - - - - {scrolledIndex} -
    - {#each items as item, i} -
    - {item} -
    - {/each} -
    -
    - -

    scrollShadow Add shadows to indicate scrolling available

    - - -
    - {#each items as item, i (item)} -
    {item}
    - {/each} -
    -
    - -

    with flip'd children

    - - -
    - {#each items as item, i (item)} -
    {item}
    - {/each} -
    -
    - -

    Horizontal scroll

    - - -
    -
    - {#each items as item, i} -
    {item}
    - {/each} -
    -
    -
    - -

    Surface shadow on bottom (fade content)

    - - -
    - {#each items as item, i} -
    {item}
    - {/each} -
    -
    - -

    with truncation

    - - -
    - {#each items as item, i} -
    {item} with a really long description
    - {/each} -
    -
    - -

    scrollFade Add shadows to indicate scrolling available

    - - -
    - {#each items as item, i (item)} -
    {item}
    - {/each} -
    -
    - -

    with flip'd children

    - - -
    - {#each items as item, i (item)} -
    {item}
    - {/each} -
    -
    - -

    Horizontal scroll

    - - -
    -
    - {#each items as item, i} -
    {item}
    - {/each} -
    -
    -
    - -
    - -
    diff --git a/sites/docs/src/routes/docs/svelte-actions/scroll/+page.ts b/sites/docs/src/routes/docs/svelte-actions/scroll/+page.ts deleted file mode 100644 index 73c179a..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/scroll/+page.ts +++ /dev/null @@ -1,11 +0,0 @@ -import source from '$svelte-actions/scroll.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/spotlight/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/spotlight/+page.svelte deleted file mode 100644 index 3f3ae43..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/spotlight/+page.svelte +++ /dev/null @@ -1,105 +0,0 @@ - - -

    Usage

    - - - - { - const body = window.document.body; - body.style.setProperty('--x', e.clientX + 'px'); - body.style.setProperty('--y', e.clientY + 'px'); - }} -/> - -

    Using global context and options

    - - -
    - {#each items as item, i} -
    - {item} -
    - {/each} -
    -
    - -

    Using global context and CSS variables

    - - -
    - {#each items as item, i} -
    - {item} -
    - {/each} -
    -
    - -

    Line example

    - - -
    - {#each items as item, i} -
    - {item} -
    - {/each} -
    -
    diff --git a/sites/docs/src/routes/docs/svelte-actions/spotlight/+page.ts b/sites/docs/src/routes/docs/svelte-actions/spotlight/+page.ts deleted file mode 100644 index 482b7d3..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/spotlight/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$svelte-actions/spotlight.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - related: ['components/Shine'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/sticky/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/sticky/+page.svelte deleted file mode 100644 index 998aa20..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/sticky/+page.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - -

    Usage

    - - - -

    sticky

    - -
    TODO
    - -

    stickyContext

    - -
    TODO
    diff --git a/sites/docs/src/routes/docs/svelte-actions/sticky/+page.ts b/sites/docs/src/routes/docs/svelte-actions/sticky/+page.ts deleted file mode 100644 index 028313a..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/sticky/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$svelte-actions/sticky.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - related: ['components/Table', 'svelte-table/actions/table'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-actions/styles/+page.svelte b/sites/docs/src/routes/docs/svelte-actions/styles/+page.svelte deleted file mode 100644 index f2f5b45..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/styles/+page.svelte +++ /dev/null @@ -1,86 +0,0 @@ - - -

    Usage

    - - - -

    - computedStyles - Retrieve all computed styles for element. Useful to resolve CSS variable values or working with - `canvas`. - -

    - - -
    -
    (_styles = styles)} - class={cls('size-10 rounded-sm outline-offset-2', backgroundClass)} - style:outline-style={outlineStyle} - >
    - -
    - - - primary - secondary - - - - - - solid - dashed - dotted - - -
    - - - - - - - - -
    -
    - -

    styleProps Reactively set style properties using a single object.

    - - - {@const styles = { '--background': background, '--border': border }} -
    -
    -
    - - -
    -
    -
    diff --git a/sites/docs/src/routes/docs/svelte-actions/styles/+page.ts b/sites/docs/src/routes/docs/svelte-actions/styles/+page.ts deleted file mode 100644 index d455715..0000000 --- a/sites/docs/src/routes/docs/svelte-actions/styles/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$svelte-actions/styles.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Actions to conveniently work with CSS styles', - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-state/MediaQueryPresets/+page.svelte b/sites/docs/src/routes/docs/svelte-state/MediaQueryPresets/+page.svelte deleted file mode 100644 index cca3abc..0000000 --- a/sites/docs/src/routes/docs/svelte-state/MediaQueryPresets/+page.svelte +++ /dev/null @@ -1,126 +0,0 @@ - - -

    Usage

    - - - import { MediaQueryPresets } from '@layerstack/svelte-state'; - const { mdScreen, print } = new MediaQueryPresets(); - - -{#if mdScreen.current} -
    Only visible on 768px+ screens
    -{/if} - -{#if print.current} -
    Only visable when printing
    -{/if}`} - language="svelte" -/> - -

    Examples

    - - -
    - {#if smScreen.current} - - {:else} - - {/if} - smScreen (640px) - - {#if mdScreen.current} - - {:else} - - {/if} - mdScreen (768px) - - {#if lgScreen.current} - - {:else} - - {/if} - lgScreen (1024px) - - {#if xlScreen.current} - - {:else} - - {/if} - xlScreen (1280px) - - {#if xxlScreen.current} - - {:else} - - {/if} - xxlScreen (1536px) - - {#if screen.current} - - {:else} - - {/if} - screen - - {#if print.current} - - {:else} - - {/if} - print - - {#if dark.current} - - {:else} - - {/if} - dark - - {#if motion.current} - - {:else} - - {/if} - motion - - {#if motionReduce.current} - - {:else} - - {/if} - motionReduce -
    - -
    - current width: {innerWidth}px -
    -
    - - diff --git a/sites/docs/src/routes/docs/svelte-state/MediaQueryPresets/+page.ts b/sites/docs/src/routes/docs/svelte-state/MediaQueryPresets/+page.ts deleted file mode 100644 index 57a5f73..0000000 --- a/sites/docs/src/routes/docs/svelte-state/MediaQueryPresets/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-state/mediaQueryPresets.svelte.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Presets to monitor media query matching, including screen width/height, orientation, print media, prefers dark/light scheme, and prefers reduced motion', - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-state/PaginationState/+page.svelte b/sites/docs/src/routes/docs/svelte-state/PaginationState/+page.svelte deleted file mode 100644 index d65d7ca..0000000 --- a/sites/docs/src/routes/docs/svelte-state/PaginationState/+page.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - -

    Usage

    - - diff --git a/sites/docs/src/routes/docs/svelte-state/PaginationState/+page.ts b/sites/docs/src/routes/docs/svelte-state/PaginationState/+page.ts deleted file mode 100644 index c081072..0000000 --- a/sites/docs/src/routes/docs/svelte-state/PaginationState/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-state/paginationState.svelte.js?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Manage pagination state including current page and page navigation (next/previous/first/last). See related Paginate/Pagination components', - related: ['components/Paginate', 'components/Pagination'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-state/SelectionState/+page.svelte b/sites/docs/src/routes/docs/svelte-state/SelectionState/+page.svelte deleted file mode 100644 index b445b8b..0000000 --- a/sites/docs/src/routes/docs/svelte-state/SelectionState/+page.svelte +++ /dev/null @@ -1,156 +0,0 @@ - - -

    Usage

    - - - -

    Examples

    - -

    Basic

    - - - - - {#each data as d} -
    - selection.toggle(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify(selection.current)} -
    - -

    Initial selection

    - - - - - - - {#each data as d} -
    - selectionInitial.toggle(d.id)} - > - {d.id} - -
    - {/each} - selected: {JSON.stringify(selectionInitial.current)} -
    - -

    Max

    - - - - - {#each data as d} -
    - selectionSet.toggle(d.id)} - disabled={selectionSet.isDisabled(d.id)} - > - {d.id} - -
    - {/each} - selected: {JSON.stringify(selectionSet.current)} -
    - -

    Select all

    - - d.id) });`} - language="javascript" -/> - - - selectionAll.toggleAll()} - > - Select all - - {#each data as d} -
    - selectionAll.toggle(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify(selectionAll.current)} -
    - -

    Single

    - - - - - {#each data as d} -
    - selectionSingle.toggle(d.id)} - > - {d.id} - -
    - {/each} - selected: {JSON.stringify(selectionSingle.current)} -
    - -

    Set selection

    - - - - - - - - {#each data as d} -
    - selectionSet.toggle(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify(selectionSet.current)} -
    diff --git a/sites/docs/src/routes/docs/svelte-state/SelectionState/+page.ts b/sites/docs/src/routes/docs/svelte-state/SelectionState/+page.ts deleted file mode 100644 index 0158feb..0000000 --- a/sites/docs/src/routes/docs/svelte-state/SelectionState/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-state/selectionState.svelte.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Manage item selection state including toggling values, selecting all, and clear or reset selection', - related: ['svelte-state/UniqueState', 'components/MultiSelect', 'components/Selection'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-state/TimerState/+page.svelte b/sites/docs/src/routes/docs/svelte-state/TimerState/+page.svelte deleted file mode 100644 index 046d528..0000000 --- a/sites/docs/src/routes/docs/svelte-state/TimerState/+page.svelte +++ /dev/null @@ -1,54 +0,0 @@ - - -

    Usage

    - - - -({ initial?: T, tick?: (value: T) => {...}, delay?: number, disabled?: boolean })`} - language="javascript" -/> - -

    Examples

    - -

    Default

    - - - - -
    {dateTimer.current}
    - { - // @ts-expect-error - e.target?.checked ? dateTimer.start() : dateTimer.stop(); - }} - /> -
    - -

    Tick count

    - - value + 1 });`} - language="javascript" -/> - - -
    {tickTimer.current}
    - { - // @ts-expect-error - e.target?.checked ? tickTimer.start() : tickTimer.stop(); - }} - /> -
    diff --git a/sites/docs/src/routes/docs/svelte-state/TimerState/+page.ts b/sites/docs/src/routes/docs/svelte-state/TimerState/+page.ts deleted file mode 100644 index 43030ae..0000000 --- a/sites/docs/src/routes/docs/svelte-state/TimerState/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$svelte-state/timerState.svelte.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Manage interval ticks, useful for timely updates and countdowns', - related: ['components/Duration', 'components/ScrollingValue'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-state/UniqueState/+page.svelte b/sites/docs/src/routes/docs/svelte-state/UniqueState/+page.svelte deleted file mode 100644 index 3820017..0000000 --- a/sites/docs/src/routes/docs/svelte-state/UniqueState/+page.svelte +++ /dev/null @@ -1,49 +0,0 @@ - - -

    Usage

    - - - -

    Examples

    - -

    Basic

    - - - {#each data as d} -
    - state.toggle(d.id)}> - {d.id} - -
    - {/each} - selected: {JSON.stringify([...state.current])} -
    diff --git a/sites/docs/src/routes/docs/svelte-state/UniqueState/+page.ts b/sites/docs/src/routes/docs/svelte-state/UniqueState/+page.ts deleted file mode 100644 index b55a2ee..0000000 --- a/sites/docs/src/routes/docs/svelte-state/UniqueState/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-state/uniqueState.svelte.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'State to manage unique values using `Set` with improves ergonomics and better control of updates', - related: ['svelte-state/SelectionState'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/svelte-table/actions/+page.svelte b/sites/docs/src/routes/docs/svelte-table/actions/+page.svelte deleted file mode 100644 index cc3e655..0000000 --- a/sites/docs/src/routes/docs/svelte-table/actions/+page.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - -

    Usage

    - - diff --git a/sites/docs/src/routes/docs/svelte-table/actions/+page.ts b/sites/docs/src/routes/docs/svelte-table/actions/+page.ts deleted file mode 100644 index b3b135c..0000000 --- a/sites/docs/src/routes/docs/svelte-table/actions/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import source from '$svelte-table/actions.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Apply ColumnDef to a table cell . Includes order by, dataBackground, and sticky support', - related: ['components/Table', 'svelte-actions/dataBackground'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/utils/duration/+page.svelte b/sites/docs/src/routes/docs/utils/duration/+page.svelte deleted file mode 100644 index 27184da..0000000 --- a/sites/docs/src/routes/docs/utils/duration/+page.svelte +++ /dev/null @@ -1,60 +0,0 @@ - - -

    Examples

    - -

    new Duration()

    - -

    Date range

    - - -
    - {JSON.stringify(new Duration({ start: intervalOffset('day', new Date(), 3) }), null, 2)} -
    -
    - -

    Date range

    - - -
    {JSON.stringify(new Duration({ start: '2021-01-01', end: '2021-01-07' }), null, 2)}
    -
    - -

    duration.format()

    - -

    Date range

    - - -
    {new Duration({ start: intervalOffset('day', new Date(), 3) }).format()}
    -
    {new Duration({ start: intervalOffset('month', new Date(), 3) }).format()}
    -
    - {new Duration({ start: intervalOffset('month', new Date(), 3) }).format({ variant: 'long' })} -
    -
    - -

    string range

    - - -
    {new Duration({ start: '1982-03-30' }).format()}
    -
    {new Duration({ start: '2021-01-01', end: '2021-01-07' }).format()}
    -
    {new Duration({ start: '1982-03-30' }).format({ totalUnits: 2 })}
    -
    {new Duration({ start: '1982-03-30' }).format({ minUnits: DurationUnits.Hour })}
    -
    - -

    duration object

    - - -
    {new Duration({ duration: { milliseconds: 300 } }).format()}
    -
    {new Duration({ duration: { hours: 1, minutes: 30 } }).format()}
    -
    {new Duration({ duration: { days: 5, hours: 26 } }).format()}
    -
    - -

    Leap year comparison

    - - -
    {new Duration({ start: new Date('2023-02-28'), end: new Date('2023-03-01') }).format()}
    -
    {new Duration({ start: new Date('2024-02-28'), end: new Date('2024-03-01') }).format()}
    -
    diff --git a/sites/docs/src/routes/docs/utils/duration/+page.ts b/sites/docs/src/routes/docs/utils/duration/+page.ts deleted file mode 100644 index 4d8e015..0000000 --- a/sites/docs/src/routes/docs/utils/duration/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$utils/duration.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - related: ['components/Duration'], - }, - }; -} diff --git a/sites/docs/src/routes/docs/utils/format/+page.svelte b/sites/docs/src/routes/docs/utils/format/+page.svelte deleted file mode 100644 index b8d12a6..0000000 --- a/sites/docs/src/routes/docs/utils/format/+page.svelte +++ /dev/null @@ -1,250 +0,0 @@ - - -

    Usage

    - - - -

    Playgrounds

    -

    Playground numbers

    - -
    - - - ({ label: value, value }))} - stepper - /> - - ({ - label: value ?? 'None', - value, - }))} - stepper - disabled={numberType !== 'currency' && numberType !== 'currencyRound'} - /> - - ({ label: value, value }))} - stepper - /> - - ({ - label: value, - value, - }))} - stepper - /> -
    - - -
    {format(value, { type: numberType, locale, options: { currency, notation } })}
    -
    - -

    Playground dates

    - -
    - - - ({ label: value, value }))} - stepper - /> - - ({ label: value, value }))} - stepper - /> -
    - - -
    {format(myDate, { type: periodType, locale })}
    -
    - -

    Numbers

    - -

    format (default settings)

    - - -
    {format(1234.56, 'integer')}
    -
    {format(1234.56, 'decimal')}
    -
    {format(1234.56, 'currency')}
    -
    {format(0.5678, 'percent')}
    -
    {format(0.5678, 'percentRound')}
    -
    {format(1_234_567, 'metric')}
    -
    {format(1_200_000, 'metric')}
    -
    {format(0.5678, 'percent')}
    -
    - -

    format (additional options)

    - - - You can customize numbers with the 3rd arg that is an enhanced `Intl.NumberFormatOptions` type. - - - -
    {format(1234.56, 'integer', { maximumSignificantDigits: 2 })}
    -
    {format(1234.56, 'decimal', { maximumSignificantDigits: 5 })}
    -
    {format(1234.56, 'currency', { currency: 'EUR' })}
    -
    - {format(123_456_789.99, 'currency', { notation: 'compact', maximumSignificantDigits: 3 })} -
    -
    {format(0.5678, 'percent', { signDisplay: 'always' })}
    -
    {format(0.5678, 'percentRound', { signDisplay: 'always' })}
    -
    {format(1_234_567, 'metric', { minimumSignificantDigits: 12 })}
    -
    {format(0.5678, 'percent', { fractionDigits: 1 })}
    -
    - -

    config

    - - You can customize numbers with a config option. - - -
    {format(1234.56, { type: 'integer', options: { maximumSignificantDigits: 2 } })}
    -
    {format(1234.56, { type: 'decimal', options: { maximumSignificantDigits: 5 } })}
    -
    {format(1234.56, { type: 'currency', options: { currency: 'EUR' } })}
    -
    - {format(123_456_789.99, { - type: 'currency', - options: { notation: 'compact', maximumSignificantDigits: 3 }, - })} -
    -
    {format(0.5678, { type: 'percent', options: { signDisplay: 'always' } })}
    -
    {format(0.5678, { type: 'percentRound', options: { signDisplay: 'always' } })}
    -
    {format(1_234_567, { type: 'metric', options: { minimumSignificantDigits: 12 } })}
    -
    {format(0.5678, { type: 'percent', options: { fractionDigits: 1 } })}
    -
    - -

    Dates

    - -

    Custom format

    - -
    -
    -

    With format string

    - - {format(myDate, 'custom', { - custom: 'eee, MMMM do', - })} - -
    -
    -

    With descriptive tokens

    - - {format(myDate, 'custom', { - custom: [DateToken.DayOfWeek_short, DateToken.Month_long, DateToken.DayOfMonth_withOrdinal], - })} - -
    -
    -

    With full intl

    - - {format(myDate, 'custom', { - custom: { weekday: 'short', month: 'long', day: 'numeric', withOrdinal: true }, - })} - -
    -
    - -{#each periodTypeCodes as periodType} -

    {periodType}

    - - {#if periodType === 'week' || periodType === 'biweek1'} - - It will take your default weekStartsOn - settings, if you want to be specific, you can also use - {periodType === 'week' ? 'PeriodType.WeekSun' : 'PeriodType.BiWeek1Sun'} - - {/if} - -
    -
    -

    short

    - - {format(myDate, periodType, { - variant: 'short', - })} - -
    -
    -

    default

    - - {format(myDate, periodType, { - // variant: 'default', - })} - -
    -
    -

    long

    - - {format(myDate, periodType, { - variant: 'long', - })} - -
    -
    -{/each} diff --git a/sites/docs/src/routes/docs/utils/format/+page.ts b/sites/docs/src/routes/docs/utils/format/+page.ts deleted file mode 100644 index 7f5a9ff..0000000 --- a/sites/docs/src/routes/docs/utils/format/+page.ts +++ /dev/null @@ -1,17 +0,0 @@ -import source from '$utils/format.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'Easily format numbers and dates to a variety of formats and locales', - features: [ - 'Number: Pass `style` for quick formatting', - 'Date: Pass `periodType` along with `variant` for quick formatting', - 'Date: Pass `custom` for greater control', - ], - }, - }; -} diff --git a/sites/docs/src/routes/docs/utils/string/+page.svelte b/sites/docs/src/routes/docs/utils/string/+page.svelte deleted file mode 100644 index 20ed024..0000000 --- a/sites/docs/src/routes/docs/utils/string/+page.svelte +++ /dev/null @@ -1,55 +0,0 @@ - - -

    Usage

    - - - -

    Examples

    - -

    truncate()

    - - - -

    Playground

    -
    - - -
    - -
    {truncate(str, totalChars, endChars)}
    -
    - -

    Total only

    - -
    {truncate(str, 20)}
    -
    - -

    Middle ellipsis

    - -
    {truncate(str, 20, 10)}
    -
    - -

    unique()

    - - - -

    Basic

    - -
    {uniqueId('checkbox-')}
    -
    {uniqueId('checkbox-')}
    -
    {uniqueId('checkbox-')}
    -
    {uniqueId('radio-')}
    -
    diff --git a/sites/docs/src/routes/docs/utils/string/+page.ts b/sites/docs/src/routes/docs/utils/string/+page.ts deleted file mode 100644 index 11f1622..0000000 --- a/sites/docs/src/routes/docs/utils/string/+page.ts +++ /dev/null @@ -1,12 +0,0 @@ -import source from '$utils/string.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: 'String utilities', - }, - }; -} diff --git a/sites/docs/src/vite-plugin-sveld.d.ts b/sites/docs/src/vite-plugin-sveld.d.ts deleted file mode 100644 index 7cfeace..0000000 --- a/sites/docs/src/vite-plugin-sveld.d.ts +++ /dev/null @@ -1,82 +0,0 @@ -// Copied from: https://github.com/mattjennings/vite-plugin-sveld/blob/main/types.d.ts - -declare module 'vite-plugin-sveld' { - export default function sveld(): { - name: string; - transform: ( - src: string, - id: string - ) => Promise<{ - code: string; - map: any; - }>; - }; -} - -declare module '*.svelte?raw&sveld' { - interface SveldProp { - name: string; - kind: 'let' | 'const' | 'function'; - constant: boolean; - type?: string; - value?: any; - description?: string; - isFunction: boolean; - isFunctionDeclaration: boolean; - isRequired: boolean; - reactive: boolean; - } - - interface SveldSlot { - name?: string; - default: boolean; - fallback?: string; - slot_props?: string; - description?: string; - } - - interface ForwardedEvent { - type: 'forwarded'; - name: string; - element: ComponentInlineElement | ComponentElement; - } - - interface DispatchedEvent { - type: 'dispatched'; - name: string; - detail?: any; - description?: string; - } - - type SvelteEvent = ForwardedEvent | DispatchedEvent; - - interface SveldRestProps { - type: 'InlineComponent' | 'Element'; - name: string; - } - - interface SveldTypedefs { - type: string; - name: string; - description?: string; - ts: string; - } - - interface SveldJson { - props: SveldProp[]; - slots: SveldSlot[]; - events: SveldEvent[]; - typedefs: SveldTypedefs[]; - rest_props: SveldRestProps; - moduleExports: SveldProp[]; - componentComment?: string; - extends?: { - interface: string; - import: string; - }; - } - - const json: SveldJson; - - export default json; -} diff --git a/sites/docs/svelte.config.js b/sites/docs/svelte.config.js index 1e4df3e..efa7700 100644 --- a/sites/docs/svelte.config.js +++ b/sites/docs/svelte.config.js @@ -3,13 +3,11 @@ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import { mdsx } from 'mdsx'; import { mdsxConfig } from './mdsx.config.js'; -import { codePreview } from './src/lib/plugins/svelte.js'; /** @type {import('@sveltejs/kit').Config} */ const config = { extensions: ['.svelte', '.md'], - // `codePreview` retained during migration for legacy ``-based pages; harmless otherwise. - preprocess: [mdsx(mdsxConfig), vitePreprocess(), codePreview()], + preprocess: [mdsx(mdsxConfig), vitePreprocess()], vitePlugin: { inspector: { @@ -21,7 +19,6 @@ const config = { kit: { adapter: adapter(), alias: { - $docs: 'src/docs', $examples: 'src/examples', 'content-collections': './.content-collections/generated', // Resolve workspace libraries to their *source* during dev/build so Vite compiles From 773c6e9e8a33279b312dd68590987f509f4d42b9 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 13:32:56 -0400 Subject: [PATCH 06/21] setup search and llms.txt --- packages/docs/package.json | 10 + .../docs/src/lib/components/Search.svelte | 328 ++++++++++++++++++ packages/docs/src/lib/components/index.js | 1 + packages/docs/src/lib/llms.ts | 177 ++++++++++ packages/docs/src/lib/search.ts | 113 ++++++ pnpm-lock.yaml | 11 + sites/docs/src/content/guides/LLMs.md | 49 +++ .../src/lib/components/OpenWithButton.svelte | 16 + sites/docs/src/lib/llms.ts | 123 +++++++ sites/docs/src/lib/searchContent.ts | 133 +++++++ sites/docs/src/routes/+layout.svelte | 29 +- sites/docs/src/routes/_NavMenu.svelte | 103 ++---- .../src/routes/api/search.json/+server.ts | 8 + .../docs/[packageName]/[name]/+page.svelte | 12 +- .../[packageName]/[name]/llms.txt/+server.ts | 12 +- .../routes/docs/guides/[name]/+page.svelte | 69 ++++ .../src/routes/docs/guides/[name]/+page.ts | 8 + .../docs/guides/[name]/llms.txt/+server.ts | 12 + .../docs/src/routes/docs/llms.txt/+server.ts | 7 + sites/docs/src/routes/llms.txt/+server.ts | 7 + 20 files changed, 1116 insertions(+), 112 deletions(-) create mode 100644 packages/docs/src/lib/components/Search.svelte create mode 100644 packages/docs/src/lib/llms.ts create mode 100644 packages/docs/src/lib/search.ts create mode 100644 sites/docs/src/content/guides/LLMs.md create mode 100644 sites/docs/src/lib/components/OpenWithButton.svelte create mode 100644 sites/docs/src/lib/llms.ts create mode 100644 sites/docs/src/lib/searchContent.ts create mode 100644 sites/docs/src/routes/api/search.json/+server.ts create mode 100644 sites/docs/src/routes/docs/guides/[name]/+page.svelte create mode 100644 sites/docs/src/routes/docs/guides/[name]/+page.ts create mode 100644 sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts create mode 100644 sites/docs/src/routes/docs/llms.txt/+server.ts create mode 100644 sites/docs/src/routes/llms.txt/+server.ts diff --git a/packages/docs/package.json b/packages/docs/package.json index 28a9740..d745df1 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -23,10 +23,12 @@ "dependencies": { "@content-collections/core": "^0.14.3", "@content-collections/markdown": "^0.1.4", + "@iconify-json/lucide": "^1.2.53", "@iconify-json/simple-icons": "^1.2.84", "@layerstack/tailwind": "workspace:*", "@layerstack/utils": "workspace:*", "@shikijs/transformers": "^4.1.0", + "flexsearch": "^0.8.212", "@sveltejs/svelte-json-tree": "^2.2.1", "@webcontainer/api": "^1.6.4", "github-slugger": "^2.0.0", @@ -110,6 +112,14 @@ "types": "./dist/project-stats.d.ts", "default": "./dist/project-stats.js" }, + "./llms": { + "types": "./dist/llms.d.ts", + "default": "./dist/llms.js" + }, + "./search": { + "types": "./dist/search.d.ts", + "default": "./dist/search.js" + }, "./components": { "types": "./dist/components/index.d.ts", "svelte": "./dist/components/index.js", diff --git a/packages/docs/src/lib/components/Search.svelte b/packages/docs/src/lib/components/Search.svelte new file mode 100644 index 0000000..04364f5 --- /dev/null +++ b/packages/docs/src/lib/components/Search.svelte @@ -0,0 +1,328 @@ + + + + + + +{#if !hideInput} + +{/if} + + + options} + classes={{ + root: 'w-150 max-w-[95vw]', + field: { + container: 'border-none hover:shadow-none group-focus-within:shadow-none' + }, + options: 'overflow-auto max-h-[min(70dvh,400px)] [scrollbar-width:thin] p-2!' + }} + > + {#snippet prepend()} + + {/snippet} + + {#snippet option({ + option, + index, + highlightIndex + }: { + option: SearchOption; + index: number; + highlightIndex: number; + })} + {@const result = option.result} + {@const isHighlighted = highlightIndex === index} + {@const isHeading = result.type === 'heading'} + +
    + {#if showExampleScreenshots && result.type === 'example' && result.component && result.example} + + {:else} + {@const Icon = typeIcons[result.type] ?? LucideHash} +
    + +
    + {/if} +
    +

    + {#if isHeading && result.parent} + {result.parent} + + {/if} + {@html result.title} +

    +

    + {@html result.content ?? ''} +

    +
    +
    +
    + {/snippet} + + {#snippet empty()} + {#if searchQuery && !searchResults.length} +
    +

    No results found.

    +
    + {/if} + {/snippet} +
    +
    diff --git a/packages/docs/src/lib/components/index.js b/packages/docs/src/lib/components/index.js index 94c2e6c..7e33316 100644 --- a/packages/docs/src/lib/components/index.js +++ b/packages/docs/src/lib/components/index.js @@ -9,6 +9,7 @@ export { default as Json } from './Json.svelte'; export { default as LoadingPlaceholder } from './LoadingPlaceholder.svelte'; export { default as OpenWithButton } from './OpenWithButton.svelte'; export { default as RelatedLink } from './RelatedLink.svelte'; +export { default as Search } from './Search.svelte'; export { default as Step } from './Step.svelte'; export { default as Steps } from './Steps.svelte'; export { default as TableOfContents } from './TableOfContents.svelte'; diff --git a/packages/docs/src/lib/llms.ts b/packages/docs/src/lib/llms.ts new file mode 100644 index 0000000..5735fc6 --- /dev/null +++ b/packages/docs/src/lib/llms.ts @@ -0,0 +1,177 @@ +/** + * Helpers for generating LLM-optimized (`llms.txt`) markdown from docs content. + * + * These are pure/string utilities — the consuming docs app supplies the data + * (via `content-collections` + `import.meta.glob`) and assembles the endpoints. + */ +import type { ComponentAPI } from './api-types.js'; + +/** Create a `text/markdown` response for an llms.txt endpoint. */ +export function markdownResponse(content: string, filename: string): Response { + return new Response(content, { + headers: { + 'Content-Type': 'text/markdown; charset=utf-8', + 'Content-Disposition': `inline; filename="${filename}"` + } + }); +} + +/** Strip `') + .trim(); +} + +function escapeMarkdown(text: string): string { + return text + .replace(/\|/g, '\\|') + .replace(/\n/g, ' ') + .replace(//g, '>'); +} + +/** Generate a markdown API table from a component's `ComponentAPI` properties. */ +export function generateApiTable(api: ComponentAPI): string { + if (!api.properties || api.properties.length === 0) return ''; + + const rows = api.properties.map((prop) => { + const name = prop.required ? `**${prop.name}** (required)` : prop.name; + const type = `\`${escapeMarkdown(prop.type)}\``; + const defaultVal = prop.default ? `\`${escapeMarkdown(prop.default)}\`` : '-'; + const description = prop.description ? escapeMarkdown(prop.description) : '-'; + return `| ${name} | ${type} | ${defaultVal} | ${description} |`; + }); + + return `| Property | Type | Default | Description | +|----------|------|---------|-------------| +${rows.join('\n')}`; +} + +/** Resolve the raw source for an example, by component (optional) + name. */ +export type ExampleSourceResolver = (component: string | undefined, name: string) => string | undefined; + +/** + * Replace `:example{...}` directives with inlined fenced code blocks, using a + * caller-provided source resolver. Run this BEFORE `processMarkdownContent`. + */ +export function inlineExampleDirectives( + content: string, + resolveSource: ExampleSourceResolver, + defaultComponent?: string +): string { + // Strip HTML comments first so commented-out examples aren't inlined + content = content.replace(//g, ''); + + // Cross-component examples: :example{ component="X" name="Y" ... } (run first) + content = content.replace( + /:example\{\s*component="([^"]+)"\s+name="([^"]+)"[^}]*\}/g, + (_match, component: string, name: string) => { + const raw = resolveSource(component, name); + return raw ? '```svelte\n' + trimCode(raw) + '\n```' : `See example: ${component}/${name}`; + } + ); + + // Same-component examples: :example{ name="Y" ... } + content = content.replace(/:example\{\s*name="([^"]+)"[^}]*\}/g, (_match, name: string) => { + const raw = resolveSource(defaultComponent, name); + return raw ? '```svelte\n' + trimCode(raw) + '\n```' : `See example: ${name}`; + }); + + return content; +} + +/** + * Convert docs markdown (with Svelte + MDC directive syntax) to vanilla markdown + * suitable for LLM consumption. + */ +export function processMarkdownContent(content: string): string { + // Remove frontmatter + content = content.replace(/^---\n[\s\S]*?\n---\n*/, ''); + + // Remove HTML comments + content = content.replace(//g, ''); + + // Remove Svelte script blocks and components ONLY outside of code blocks + content = content + .split(/(```[\s\S]*?```)/g) + .map((part, index) => { + if (index % 2 === 1) return part; // code block — leave as-is + part = part.replace(/]*>[\s\S]*?<\/script>\n*/g, ''); + part = part.replace(/<[A-Z][a-zA-Z]*[^>]*\/>\n*/g, ''); + part = part.replace(/<[A-Z][a-zA-Z]*[^>]*>[\s\S]*?<\/[A-Z][a-zA-Z]*>\n*/g, ''); + return part; + }) + .join(''); + + // Surface code-block `title="..."` meta as a "File:" line + content = content.replace(/(```\w*)\s+([^\n]*title="[^"]+")[^\n]*$/gm, (_, lang, meta) => { + const titleMatch = meta.match(/title="([^"]+)"/); + return titleMatch ? `File: ${titleMatch[1]} ${lang}` : lang; + }); + + // :::tabs → markdown table + content = content.replace( + /:::tabs\{key="([^"]+)"\}\s*([\s\S]*?)(?=\n:::(?:\s*$|\s*\n))\n:::/gm, + (_, key, tabsContent) => { + const tabs: { label: string; content: string }[] = []; + const tabRegex = + /::tab\{label="([^"]+)"[^}]*\}\s*([\s\S]*?)\s*(?=\n\s*::(?:\s*$|\s+))\n\s*::/gm; + let match; + while ((match = tabRegex.exec(tabsContent)) !== null) { + tabs.push({ label: match[1], content: match[2].trim() }); + } + if (tabs.length === 0) return ''; + + const header = key.charAt(0).toUpperCase() + key.slice(1); + let table = `| ${header} | Details |\n|-----------|---------|`; + for (const tab of tabs) { + const cleanContent = tab.content + .replace(/:button\{label="([^"]+)"\s+href="([^"]+)"[^}]*\}/g, '[$1]($2)') + .replace(/```\w*\n([\s\S]*?)```/g, '$1') + .replace(/\n/g, ' ') + .trim(); + table += `\n| ${tab.label} | ${cleanContent} |`; + } + return table; + } + ); + + // ::note / ::tip / ::warning / ::caution → blockquote + content = content.replace( + /:{2,3}(note|tip|warning|caution)\s*([\s\S]*?)(?=\n:{2,3}(?:\s*$|\s*\n))\n:{2,3}/gm, + (_, variant, noteContent) => `> ${variant}: ${noteContent.trim()}\n` + ); + + // ::steps → numbered list (## headings become numbered items) + content = content.replace( + /::steps\s*([\s\S]*?)(?=\n::(?:\s*$|\s*\n))\n::/gm, + (_, stepsContent: string) => { + let stepNum = 0; + return stepsContent.replace(/^## (.+)$/gm, (_match: string, heading: string) => { + stepNum++; + return `**${stepNum}. ${heading}**`; + }); + } + ); + + // Remove any remaining standalone :: + content = content.replace(/^::\s*$/gm, ''); + + // :icon syntax — keep bracketed label text, otherwise drop + content = content.replace(/\[:icon\{[^}]+\}\s*([^\]]+)\]/g, '$1'); + content = content.replace(/:icon\{[^}]+\}\s*/g, ''); + + // Any remaining :example directives → plain text + content = content.replace( + /:example\{\s*component="([^"]+)"\s+name="([^"]+)"[^}]*\}/g, + 'See example: $1/$2' + ); + content = content.replace(/:example\{\s*name="([^"]+)"[^}]*\}/g, 'See example: $1'); + + // Collapse blank lines + content = content.replace(/\n{3,}/g, '\n\n'); + + return content.trim(); +} diff --git a/packages/docs/src/lib/search.ts b/packages/docs/src/lib/search.ts new file mode 100644 index 0000000..565d638 --- /dev/null +++ b/packages/docs/src/lib/search.ts @@ -0,0 +1,113 @@ +import FlexSearch, { type Index as FlexSearchIndex } from 'flexsearch'; + +/** + * A single searchable entry. `type` is intentionally a free string so each docs app + * can define its own taxonomy (`page`, `guide`, `component`, `util`, `example`, + * `reference`, `heading`, …). Build these in a docs-local `searchContent` module and + * serve them from `/api/search.json`. + */ +export type SearchEntry = { + title: string; + slug: string; + content: string; + type: string; + category?: string; + /** For examples, the component/item name */ + component?: string; + /** For examples, the example name */ + example?: string; + /** For examples, optional author-curated search keywords */ + tags?: string[]; + /** For headings, the parent page title */ + parent?: string; + /** For headings, the parent page slug (without hash) */ + parentSlug?: string; + /** For headings, the parent entry type (used for grouping) */ + parentType?: string; +}; + +let searchIndex: FlexSearchIndex; +let searchData: SearchEntry[] = []; +let initialized = false; + +/** + * Initialize the search index with data fetched from the API (default `/api/search.json`). + */ +export async function initSearch(endpoint = '/api/search.json'): Promise { + if (initialized) return; + + const response = await fetch(endpoint); + searchData = await response.json(); + + searchIndex = new FlexSearch.Index({ + tokenize: 'forward' + }); + + searchData.forEach((entry, i) => { + const text = `${entry.title} ${entry.content}`; + searchIndex.add(i, text); + }); + + initialized = true; +} + +function escapeRegex(str: string): string { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +function queryTokens(query: string): string[] { + return query.toLowerCase().trim().split(/\s+/).filter(Boolean); +} + +function highlightMatch(text: string, query: string): string { + const tokens = queryTokens(query).map(escapeRegex); + if (!tokens.length) return text; + const regex = new RegExp(tokens.join('|'), 'gi'); + return text.replace(regex, (match) => `${match}`); +} + +function getSnippet(text: string, query: string, contextLength = 80): string { + const lowerText = text.toLowerCase(); + const tokens = queryTokens(query); + + // Anchor the snippet on the earliest-occurring token + let anchorIndex = -1; + let anchorLength = 0; + for (const token of tokens) { + const idx = lowerText.indexOf(token); + if (idx !== -1 && (anchorIndex === -1 || idx < anchorIndex)) { + anchorIndex = idx; + anchorLength = token.length; + } + } + + if (anchorIndex === -1) { + return text.substring(0, contextLength) + (text.length > contextLength ? '...' : ''); + } + + const start = Math.max(0, anchorIndex - 20); + const end = Math.min(text.length, anchorIndex + anchorLength + contextLength); + const snippet = text.substring(start, end).trim(); + + return ( + (start > 0 ? '...' : '') + highlightMatch(snippet, query) + (end < text.length ? '...' : '') + ); +} + +/** + * Search the index and return matching entries (with highlighted snippets). + */ +export function search(query: string): SearchEntry[] { + if (!initialized || !query.trim()) return []; + + const searchTerm = query.trim(); + + const results = searchIndex.search(searchTerm) as number[]; + + return results + .map((idx) => searchData[idx]) + .map((entry) => ({ + ...entry, + content: entry.type === 'example' ? entry.content : getSnippet(entry.content, searchTerm) + })); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b1089a..5b5e174 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: '@content-collections/markdown': specifier: ^0.1.4 version: 0.1.4(@content-collections/core@0.14.3(typescript@5.8.3)) + '@iconify-json/lucide': + specifier: ^1.2.53 + version: 1.2.53 '@iconify-json/simple-icons': specifier: ^1.2.84 version: 1.2.84 @@ -47,6 +50,9 @@ importers: '@webcontainer/api': specifier: ^1.6.4 version: 1.6.4 + flexsearch: + specifier: ^0.8.212 + version: 0.8.212 github-slugger: specifier: ^2.0.0 version: 2.0.0 @@ -2392,6 +2398,9 @@ packages: engines: {node: '>=18'} hasBin: true + flexsearch@0.8.212: + resolution: {integrity: sha512-wSyJr1GUWoOOIISRu+X2IXiOcVfg9qqBRyCPRUdLMIGJqPzMo+jMRlvE83t14v1j0dRMEaBbER/adQjp6Du2pw==} + foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -5398,6 +5407,8 @@ snapshots: flat@6.0.1: {} + flexsearch@0.8.212: {} + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.6 diff --git a/sites/docs/src/content/guides/LLMs.md b/sites/docs/src/content/guides/LLMs.md new file mode 100644 index 0000000..cacec19 --- /dev/null +++ b/sites/docs/src/content/guides/LLMs.md @@ -0,0 +1,49 @@ +--- +title: LLMs +description: Using the LayerStack documentation with LLMs +order: 99 +--- + + + +The LayerStack documentation is designed to be useful both for human developers working alongside LLMs and for large language models ingesting the docs directly. + +## :icon{name="lucide:user" class="relative -top-1"} For the humans + + + +At the top of each documentation page — and demonstrated above — you'll find a button that copies the page's documentation as Markdown to your clipboard. The dropdown also offers handy options such as viewing the source or opening the page in a chat assistant. + +::note +The `View Component source` option is only shown for pages with a linked source file. +:: + +## :icon{name="lucide:bot" class="relative -top-1"} For the bots + +LayerStack adopts the [llms.txt](https://llmstxt.org/) proposal — a structured, machine-readable format optimized for LLMs — so tools and AI systems can efficiently parse the documentation. + +## LLM-friendly documentation + +::steps + +### Per page + +Append `/llms.txt` to any documentation page's URL to get its content as plain-text, LLM-optimized Markdown — the same text the `Copy Page` button copies. + +:::tip +**Standard page**: [/docs/svelte-stores/debounceStore](/docs/svelte-stores/debounceStore) + +**LLM-friendly version**: [/docs/svelte-stores/debounceStore/llms.txt](/docs/svelte-stores/debounceStore/llms.txt) +::: + +### Root index + +To explore every page in LLM-friendly format, visit the root index at [llms.txt](/llms.txt). + +### Complete documentation + +For a single, consolidated document containing all of the documentation, see [/docs/llms.txt](/docs/llms.txt). + +:: diff --git a/sites/docs/src/lib/components/OpenWithButton.svelte b/sites/docs/src/lib/components/OpenWithButton.svelte new file mode 100644 index 0000000..cfbab16 --- /dev/null +++ b/sites/docs/src/lib/components/OpenWithButton.svelte @@ -0,0 +1,16 @@ + + + diff --git a/sites/docs/src/lib/llms.ts b/sites/docs/src/lib/llms.ts new file mode 100644 index 0000000..bfccfd2 --- /dev/null +++ b/sites/docs/src/lib/llms.ts @@ -0,0 +1,123 @@ +import { allReferences, allGuides, type Reference } from 'content-collections'; +import { sortCollection } from '@layerstack/docs/collections'; +import { + inlineExampleDirectives, + processMarkdownContent, + type ExampleSourceResolver +} from '@layerstack/docs/llms'; + +const exampleSources = import.meta.glob('/src/examples/**/*.svelte', { + eager: true, + query: '?raw', + import: 'default' +}); + +const guideSources = import.meta.glob('/src/content/guides/**/*.md', { + eager: true, + query: '?raw', + import: 'default' +}); + +const resolveExampleSource: ExampleSourceResolver = (component, name) => { + if (!component) return undefined; + return exampleSources[`/src/examples/components/${component}/${name}.svelte`]; +}; + +/** Group reference docs by their package (first slug segment), sorted within each group. */ +function referencesByPackage(): [string, Reference[]][] { + const byPackage = new Map(); + for (const doc of allReferences) { + const pkg = doc.slug.split('/')[0]; + if (!byPackage.has(pkg)) byPackage.set(pkg, []); + byPackage.get(pkg)!.push(doc); + } + return [...byPackage.entries()] + .sort(([a], [b]) => a.localeCompare(b)) + .map(([pkg, docs]) => [pkg, sortCollection(docs)]); +} + +/** LLM-optimized markdown for a single reference doc (examples inlined). */ +export function generateReferenceMarkdown(doc: Reference): string { + const sections: string[] = [`# ${doc.name}`]; + if (doc.description) sections.push(doc.description); + + const item = doc.slug.split('/').pop(); + const inlined = inlineExampleDirectives(doc.content, resolveExampleSource, item); + const processed = processMarkdownContent(inlined); + if (processed) sections.push(processed); + + if (doc.related?.length) { + sections.push('## Related'); + sections.push(doc.related.map((r) => `- ${r}`).join('\n')); + } + + return sections.join('\n\n'); +} + +/** LLM-optimized markdown for a guide. */ +export function generateGuideMarkdown(name: string): string { + const raw = guideSources[`/src/content/guides/${name}.md`]; + if (!raw) throw new Error(`Guide "${name}" not found`); + + let title = name; + const frontmatter = raw.match(/^---\n([\s\S]*?)\n---/); + const titleMatch = frontmatter?.[1].match(/^title:\s*(.+)$/m); + if (titleMatch) title = titleMatch[1].trim().replace(/^["']|["']$/g, ''); + + return `# ${title}\n\n${processMarkdownContent(raw)}`; +} + +/** Root `/llms.txt` index — links to each page's `/llms.txt`. */ +export function generateLlmsTxt(baseUrl: string): string { + const sections: string[] = [ + `# LayerStack Documentation for LLMs + +> LayerStack is a collection of Svelte actions, stores, state, table utilities, and general utils for Svelte. + +This file links to LLM-optimized documentation in markdown format. Append \`/llms.txt\` to any page URL for its markdown, or see [/docs/llms.txt](${baseUrl}/docs/llms.txt) for everything in one file.` + ]; + + const guides = sortCollection(allGuides.filter((g) => !g.draft)); + if (guides.length) { + const items = guides + .map( + (g) => + `- [${g.name}](${baseUrl}/docs/guides/${g.slug}/llms.txt)${g.description ? `: ${g.description}` : ''}` + ) + .join('\n'); + sections.push(`## Guides\n\n${items}`); + } + + for (const [pkg, docs] of referencesByPackage()) { + const items = docs + .map( + (d) => + `- [${d.name}](${baseUrl}/docs/${d.slug}/llms.txt)${d.description ? `: ${d.description}` : ''}` + ) + .join('\n'); + sections.push(`## ${pkg}\n\n${items}`); + } + + return sections.join('\n\n'); +} + +/** `/docs/llms.txt` — the full documentation inlined into one file. */ +export function generateFullLlmsTxt(baseUrl: string): string { + const sections: string[] = [ + `# LayerStack Full Documentation for LLMs + +> LayerStack is a collection of Svelte actions, stores, state, table utilities, and general utils for Svelte. + +This file contains the complete LLM-optimized documentation. Index: [/llms.txt](${baseUrl}/llms.txt).` + ]; + + for (const [pkg, docs] of referencesByPackage()) { + sections.push('---'); + sections.push(`# ${pkg}`); + for (const doc of docs) { + sections.push(generateReferenceMarkdown(doc)); + } + } + + return sections.join('\n\n'); +} diff --git a/sites/docs/src/lib/searchContent.ts b/sites/docs/src/lib/searchContent.ts new file mode 100644 index 0000000..b0dffee --- /dev/null +++ b/sites/docs/src/lib/searchContent.ts @@ -0,0 +1,133 @@ +import { allReferences, allGuides, type Reference, type Guide } from 'content-collections'; +import { stripMarkdown } from '@layerstack/docs/markdown'; +import type { SearchEntry } from '@layerstack/docs/search'; + +type TocEntry = { id: string; text: string; level: number }; + +function escapeRegexChars(str: string): string { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +/** + * Extract the content under each heading from markdown, keyed by heading text. + */ +function extractHeadingContents(markdown: string, toc: TocEntry[]): Map { + const result = new Map(); + const headingPositions: { text: string; start: number; end: number }[] = []; + + for (const heading of toc) { + const headingPattern = new RegExp( + `^#{1,6}\\s+${escapeRegexChars(heading.text)}(?:\\s*:[a-zA-Z][\\w-]*\\{[^}]*\\})*\\s*$`, + 'gm' + ); + const match = headingPattern.exec(markdown); + if (match) { + headingPositions.push({ + text: heading.text, + start: match.index + match[0].length, + end: markdown.length + }); + } + } + + headingPositions.sort((a, b) => a.start - b.start); + for (let i = 0; i < headingPositions.length - 1; i++) { + const nextHeadingMatch = markdown.slice(headingPositions[i].start).match(/^#{1,6}\s+/m); + if (nextHeadingMatch) { + headingPositions[i].end = headingPositions[i].start + (nextHeadingMatch.index ?? 0); + } + } + + for (const pos of headingPositions) { + const rawContent = markdown.slice(pos.start, pos.end).trim(); + result.set(pos.text, stripMarkdown(rawContent).slice(0, 200)); + } + + return result; +} + +function referenceToEntry(doc: Reference): SearchEntry { + const description = doc.description ?? ''; + const content = stripMarkdown(doc.content); + return { + title: doc.name, + slug: `docs/${doc.slug}`, + content: description ? `${description} ${content}` : content, + type: 'reference', + category: doc.slug.split('/')[0] + }; +} + +function referenceHeadingsToEntries(doc: Reference): SearchEntry[] { + const seen = new Set(); + const parentSlug = `docs/${doc.slug}`; + const headingContents = extractHeadingContents(doc.content, doc.toc); + + return doc.toc + .filter((heading) => { + if (seen.has(heading.id)) return false; + seen.add(heading.id); + return true; + }) + .map((heading) => ({ + title: heading.text, + slug: `${parentSlug}#${heading.id}`, + content: headingContents.get(heading.text) || doc.name, + type: 'heading' as const, + parent: doc.name, + parentSlug, + parentType: 'reference' + })); +} + +function guideToEntry(doc: Guide): SearchEntry { + const description = doc.description ?? ''; + const content = stripMarkdown(doc.content); + return { + title: doc.name, + slug: `docs/guides/${doc.slug}`, + content: description ? `${description} ${content}` : content, + type: 'guide' + }; +} + +function guideHeadingsToEntries(doc: Guide): SearchEntry[] { + const seen = new Set(); + const parentSlug = `docs/guides/${doc.slug}`; + const headingContents = extractHeadingContents(doc.content, doc.toc); + + return doc.toc + .filter((heading) => { + if (seen.has(heading.id)) return false; + seen.add(heading.id); + return true; + }) + .map((heading) => ({ + title: heading.text, + slug: `${parentSlug}#${heading.id}`, + content: headingContents.get(heading.text) || doc.name, + type: 'heading' as const, + parent: doc.name, + parentSlug, + parentType: 'guide' + })); +} + +const topLevelPages: SearchEntry[] = [ + { + title: 'Introduction', + slug: '', + content: 'LayerStack — a collection of Svelte actions, stores, state, table utilities, and general utils', + type: 'page' + } +]; + +const guides = allGuides.filter((g) => !g.draft); + +export const searchContent: SearchEntry[] = [ + ...topLevelPages, + ...guides.map(guideToEntry), + ...guides.flatMap(guideHeadingsToEntries), + ...allReferences.map(referenceToEntry), + ...allReferences.flatMap(referenceHeadingsToEntries) +]; diff --git a/sites/docs/src/routes/+layout.svelte b/sites/docs/src/routes/+layout.svelte index 92b89fa..ea3967a 100644 --- a/sites/docs/src/routes/+layout.svelte +++ b/sites/docs/src/routes/+layout.svelte @@ -9,7 +9,6 @@ Button, Icon, MenuButton, - QuickSearch, ThemeInit, ThemeSelect, ThemeSwitch, @@ -18,13 +17,13 @@ settings, } from 'svelte-ux'; - import { entries } from '@layerstack/utils'; import { lgScreen } from '@layerstack/svelte-stores'; + import { Search } from '@layerstack/docs/components'; import NavMenu from './_NavMenu.svelte'; import { dev } from '$app/environment'; - import { afterNavigate, goto } from '$app/navigation'; + import { afterNavigate } from '$app/navigation'; import { page } from '$app/stores'; import './app.css'; @@ -64,21 +63,6 @@ mainEl.scrollTo({ top: 0, behavior: 'instant' }); }); - const groups = ['components', 'actions', 'stores', 'utils']; - const quickSearchOptions = entries( - import.meta.glob('./docs/**/+page.(md|svelte)', { query: '?raw', eager: true }) - ) - .flatMap(([file, source]) => { - const url = file.replace('.', '').replace(/\/\+page.(md|svelte)/, ''); - const [_, docs, group, name] = url.split('/'); - return { - label: name, - value: url, - group: group, - }; - }) - .sort((a, b) => groups.indexOf(a.group) - groups.indexOf(b.group)); - let currentPath = ''; onMount(() => { // Delay adding `scroll-smooth` to `` as provides better refresh experience @@ -155,14 +139,7 @@ LayerChart - { - // @ts-expect-error - goto(e.detail.value); - }} - classes={{ button: 'max-sm:-mr-3' }} - /> +
    diff --git a/sites/docs/src/routes/_NavMenu.svelte b/sites/docs/src/routes/_NavMenu.svelte index 9c21390..1c4d356 100644 --- a/sites/docs/src/routes/_NavMenu.svelte +++ b/sites/docs/src/routes/_NavMenu.svelte @@ -1,54 +1,27 @@ @@ -61,32 +34,16 @@ target="_blank" /> -

    svelte-actions

    -{#each actions as item} - -{/each} - -

    svelte-state

    -{#each state as item} - -{/each} - -

    svelte-stores

    -{#each stores as item} - -{/each} - -

    svelte-table

    -{#each table as item} - -{/each} - -

    tailwind

    -{#each tailwind as item} - -{/each} - -

    utils

    -{#each utils as item} - +{#if guides.length} +

    Guides

    + {#each guides as guide} + + {/each} +{/if} + +{#each packages as [pkg, refs]} +

    {pkg}

    + {#each refs as ref} + + {/each} {/each} diff --git a/sites/docs/src/routes/api/search.json/+server.ts b/sites/docs/src/routes/api/search.json/+server.ts new file mode 100644 index 0000000..70069cf --- /dev/null +++ b/sites/docs/src/routes/api/search.json/+server.ts @@ -0,0 +1,8 @@ +import { json } from '@sveltejs/kit'; +import { searchContent } from '$lib/searchContent'; + +export const prerender = true; + +export const GET = async () => { + return json(searchContent); +}; diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte index b386ddd..9499c0d 100644 --- a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte +++ b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte @@ -1,18 +1,14 @@ + +
    +
    +
    + Docs + + Guides +
    + +
    {metadata.name}
    + + {#if metadata.description} +
    + {metadata.description} +
    + {/if} + +
    + +
    +
    + +
    +
    + {#key page.url.pathname} + + {/key} +
    + + {#if metadata.toc?.length} + + {/if} +
    +
    diff --git a/sites/docs/src/routes/docs/guides/[name]/+page.ts b/sites/docs/src/routes/docs/guides/[name]/+page.ts new file mode 100644 index 0000000..7dca271 --- /dev/null +++ b/sites/docs/src/routes/docs/guides/[name]/+page.ts @@ -0,0 +1,8 @@ +import { getMarkdownComponent, loadExamplesFromMarkdown } from '$lib/content.js'; + +export const load = async ({ params }) => { + const { PageComponent, metadata } = await getMarkdownComponent(params.name, 'guides'); + const examples = await loadExamplesFromMarkdown(metadata.content, undefined, 'guides'); + + return { PageComponent, metadata, examples }; +}; diff --git a/sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts b/sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts new file mode 100644 index 0000000..d2072f9 --- /dev/null +++ b/sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts @@ -0,0 +1,12 @@ +import { error } from '@sveltejs/kit'; +import type { RequestHandler } from './$types'; +import { generateGuideMarkdown } from '$lib/llms'; +import { markdownResponse } from '@layerstack/docs/llms'; + +export const GET: RequestHandler = async ({ params }) => { + try { + return markdownResponse(generateGuideMarkdown(params.name), `${params.name}.md`); + } catch { + error(404, 'Not found'); + } +}; diff --git a/sites/docs/src/routes/docs/llms.txt/+server.ts b/sites/docs/src/routes/docs/llms.txt/+server.ts new file mode 100644 index 0000000..9547319 --- /dev/null +++ b/sites/docs/src/routes/docs/llms.txt/+server.ts @@ -0,0 +1,7 @@ +import type { RequestHandler } from './$types'; +import { generateFullLlmsTxt } from '$lib/llms'; +import { markdownResponse } from '@layerstack/docs/llms'; + +export const GET: RequestHandler = async ({ url }) => { + return markdownResponse(generateFullLlmsTxt(url.origin), 'llms-full.md'); +}; diff --git a/sites/docs/src/routes/llms.txt/+server.ts b/sites/docs/src/routes/llms.txt/+server.ts new file mode 100644 index 0000000..ae940a4 --- /dev/null +++ b/sites/docs/src/routes/llms.txt/+server.ts @@ -0,0 +1,7 @@ +import type { RequestHandler } from './$types'; +import { generateLlmsTxt } from '$lib/llms'; +import { markdownResponse } from '@layerstack/docs/llms'; + +export const GET: RequestHandler = async ({ url }) => { + return markdownResponse(generateLlmsTxt(url.origin), 'llms.md'); +}; From 23c786ba57d9a16c6c6add52a9c5959a47a8c05a Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 14:22:17 -0400 Subject: [PATCH 07/21] Fix Code height by due to whitespace --- packages/docs/src/lib/components/Code.svelte | 295 +++++++++---------- 1 file changed, 142 insertions(+), 153 deletions(-) diff --git a/packages/docs/src/lib/components/Code.svelte b/packages/docs/src/lib/components/Code.svelte index a1d90e7..7144fbb 100644 --- a/packages/docs/src/lib/components/Code.svelte +++ b/packages/docs/src/lib/components/Code.svelte @@ -1,175 +1,164 @@
    - {#if title} -
    - {#if language === 'css'} - - {:else if language === 'javascript'} - - {:else if language === 'ts'} - - {:else if language === 'json'} - - {:else if language === 'sh' || language === 'bash'} - - {:else if language === 'svelte'} - - {:else if language === 'html'} - - {:else} - Icon ERROR: {language} - {/if} - {title} -
    - {/if} -
    - {#if source} -
    -				
    -					{#if highlighter}
    -						
    -						{@html highlighter.codeToHtml(
    -							sourceStr,
    -							{
    -								lang: language,
    -								themes: {
    -									light: 'github-light-default',
    -									dark: 'github-dark-default'
    -								},
    -								meta: highlight ? { __raw: `{${highlight}}` } : undefined,
    -								transformers: highlight ? [transformerMetaHighlight()] : undefined
    -							}
    -						)}
    -					{:else}
    -						
    Loading...
    - {/if} -
    -
    + {#if title} +
    + {#if language === 'css'} + + {:else if language === 'javascript'} + + {:else if language === 'ts'} + + {:else if language === 'json'} + + {:else if language === 'sh' || language === 'bash'} + + {:else if language === 'svelte'} + + {:else if language === 'html'} + + {:else} + Icon ERROR: {language} + {/if} + {title} +
    + {/if} +
    + {#if source} + + + +
    {#if highlighter}{@html highlighter.codeToHtml(sourceStr, {
    +						lang: language,
    +						themes: { light: 'github-light-default', dark: 'github-dark-default' },
    +						meta: highlight ? { __raw: `{${highlight}}` } : undefined,
    +						transformers: highlight ? [transformerMetaHighlight()] : undefined
    +					})}{:else}Loading...{/if}
    - {#if copyButton !== false} -
    - -
    - {/if} - {/if} -
    + {#if copyButton !== false} +
    + +
    + {/if} + {/if} +
    From f674e429525ac3898660e52a292682d5c9f121e8 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 15:13:38 -0400 Subject: [PATCH 08/21] Extract reusable llms.txt generation into @layerstack/docs Move the llms.txt markdown-generation logic out of the docs-site and into the framework so any consuming app (LayerStack, LayerChart) shares it: - Add generateReferenceMarkdown, generateGuideMarkdown, linkListSection, groupBySlugSegment, and extractFrontmatterTitle to @layerstack/docs/llms - Add an optional exampleUrl resolver to processMarkdownContent / inlineExampleDirectives so non-inlined :example references render as links instead of plain text - Rewire sites/docs/llms.ts onto the shared helpers, leaving only app-specific glue (import.meta.glob, content-collections, and copy) --- packages/docs/src/lib/llms.ts | 173 +++++++++++++++++++++++++++++++++- sites/docs/src/lib/llms.ts | 73 ++++++-------- 2 files changed, 197 insertions(+), 49 deletions(-) diff --git a/packages/docs/src/lib/llms.ts b/packages/docs/src/lib/llms.ts index 5735fc6..63ebc75 100644 --- a/packages/docs/src/lib/llms.ts +++ b/packages/docs/src/lib/llms.ts @@ -52,14 +52,21 @@ ${rows.join('\n')}`; /** Resolve the raw source for an example, by component (optional) + name. */ export type ExampleSourceResolver = (component: string | undefined, name: string) => string | undefined; +/** Build a docs URL for a (cross-component) example reference. */ +export type ExampleUrlResolver = (component: string, name: string) => string; + /** * Replace `:example{...}` directives with inlined fenced code blocks, using a * caller-provided source resolver. Run this BEFORE `processMarkdownContent`. + * + * When an example's source can't be resolved, the directive becomes a "See example" + * reference — a markdown link if `exampleUrl` is provided, otherwise plain text. */ export function inlineExampleDirectives( content: string, resolveSource: ExampleSourceResolver, - defaultComponent?: string + defaultComponent?: string, + exampleUrl?: ExampleUrlResolver ): string { // Strip HTML comments first so commented-out examples aren't inlined content = content.replace(//g, ''); @@ -69,7 +76,10 @@ export function inlineExampleDirectives( /:example\{\s*component="([^"]+)"\s+name="([^"]+)"[^}]*\}/g, (_match, component: string, name: string) => { const raw = resolveSource(component, name); - return raw ? '```svelte\n' + trimCode(raw) + '\n```' : `See example: ${component}/${name}`; + if (raw) return '```svelte\n' + trimCode(raw) + '\n```'; + return exampleUrl + ? `See example: [${component}/${name}](${exampleUrl(component, name)})` + : `See example: ${component}/${name}`; } ); @@ -86,7 +96,10 @@ export function inlineExampleDirectives( * Convert docs markdown (with Svelte + MDC directive syntax) to vanilla markdown * suitable for LLM consumption. */ -export function processMarkdownContent(content: string): string { +export function processMarkdownContent( + content: string, + options?: { exampleUrl?: ExampleUrlResolver } +): string { // Remove frontmatter content = content.replace(/^---\n[\s\S]*?\n---\n*/, ''); @@ -163,10 +176,13 @@ export function processMarkdownContent(content: string): string { content = content.replace(/\[:icon\{[^}]+\}\s*([^\]]+)\]/g, '$1'); content = content.replace(/:icon\{[^}]+\}\s*/g, ''); - // Any remaining :example directives → plain text + // Any remaining :example directives → "See example" reference (link if a URL resolver is provided) content = content.replace( /:example\{\s*component="([^"]+)"\s+name="([^"]+)"[^}]*\}/g, - 'See example: $1/$2' + (_match, component: string, name: string) => + options?.exampleUrl + ? `See example: [${component}/${name}](${options.exampleUrl(component, name)})` + : `See example: ${component}/${name}` ); content = content.replace(/:example\{\s*name="([^"]+)"[^}]*\}/g, 'See example: $1'); @@ -175,3 +191,150 @@ export function processMarkdownContent(content: string): string { return content.trim(); } + +/** + * Extract a `title` from a markdown file's frontmatter, falling back to `fallback` + * (e.g. a title-cased filename) when absent. + */ +export function extractFrontmatterTitle(raw: string, fallback = ''): string { + const frontmatter = raw.match(/^---\n([\s\S]*?)\n---/); + const titleMatch = frontmatter?.[1].match(/^title:\s*(.+)$/m); + if (titleMatch) return titleMatch[1].trim().replace(/^["']|["']$/g, ''); + return fallback; +} + +/** + * Generate LLM-optimized markdown for a guide from its raw source. + * + * The consuming app resolves the raw markdown (via `import.meta.glob`); this handles + * the title (explicit → frontmatter → `fallbackTitle`) and content processing. + */ +export function generateGuideMarkdown( + raw: string, + options: { title?: string; fallbackTitle?: string } = {} +): string { + const title = options.title ?? extractFrontmatterTitle(raw, options.fallbackTitle ?? ''); + const body = processMarkdownContent(raw); + return title ? `# ${title}\n\n${body}` : body; +} + +/** Minimal shape a doc needs to render reference markdown. */ +export interface ReferenceDoc { + name: string; + slug: string; + description?: string | null; + content?: string | null; + related?: string[] | null; +} + +export interface ReferenceMarkdownOptions { + /** Heading level for the title (1 = `#`). Related/extra sections use `headingLevel + 1`. Default: 1 */ + headingLevel?: number; + /** Inline `:example` directives as fenced code blocks (requires `resolveSource`). Default: false */ + inlineExamples?: boolean; + /** Resolver for example source (used when `inlineExamples`). */ + resolveSource?: ExampleSourceResolver; + /** URL resolver for non-inlined cross-component `:example` references. */ + exampleUrl?: ExampleUrlResolver; + /** Default component for same-component `:example{name}` directives (e.g. the doc's slug). */ + defaultComponent?: string; + /** Sections inserted after the description, before the processed content (e.g. metadata). */ + leadingSections?: (string | null | undefined)[]; + /** Sections inserted after the processed content, before Related (e.g. API, Examples). */ + extraSections?: (string | null | undefined)[]; + /** Render Related items as links via this URL builder; omit for a plain `- name` list. */ + relatedUrl?: (name: string) => string; +} + +/** + * Generate LLM-optimized markdown for a reference doc (component/util/etc.): + * `title → description → [leading] → content → [extra] → Related`. + * + * App-specific sections (metadata, API tables, example listings) are passed via + * `leadingSections` / `extraSections` so the orchestration stays shared. + */ +export function generateReferenceMarkdown( + doc: ReferenceDoc, + options: ReferenceMarkdownOptions = {} +): string { + const { + headingLevel = 1, + inlineExamples = false, + resolveSource, + exampleUrl, + defaultComponent, + leadingSections = [], + extraSections = [], + relatedUrl + } = options; + const h = (level: number) => '#'.repeat(level); + + const sections: string[] = [`${h(headingLevel)} ${doc.name}`]; + if (doc.description) sections.push(doc.description); + + for (const section of leadingSections) { + if (section) sections.push(section); + } + + if (doc.content) { + let content = doc.content; + if (inlineExamples && resolveSource) { + content = inlineExampleDirectives(content, resolveSource, defaultComponent, exampleUrl); + } + const processed = processMarkdownContent(content, { exampleUrl }); + if (processed) sections.push(processed); + } + + for (const section of extraSections) { + if (section) sections.push(section); + } + + if (doc.related?.length) { + sections.push(`${h(headingLevel + 1)} Related`); + sections.push( + doc.related.map((r) => (relatedUrl ? `- [${r}](${relatedUrl(r)})` : `- ${r}`)).join('\n') + ); + } + + return sections.join('\n\n'); +} + +/** An item in a markdown link list. */ +export interface LinkListItem { + name: string; + url: string; + description?: string | null; +} + +/** Render a `## Title` section with a bulleted list of links: `- [name](url): description`. */ +export function linkListSection( + title: string, + items: LinkListItem[], + options: { headingLevel?: number } = {} +): string { + const h = '#'.repeat(options.headingLevel ?? 2); + const lines = items.map( + (item) => `- [${item.name}](${item.url})${item.description ? `: ${item.description}` : ''}` + ); + return `${h} ${title}\n\n${lines.join('\n')}`; +} + +/** + * Group docs by a segment of their slug (default: the first, i.e. the package), + * sorted by key. Pass `sort` (e.g. `sortCollection`) to order within each group. + */ +export function groupBySlugSegment( + docs: T[], + options: { segment?: number; sort?: (group: T[]) => T[] } = {} +): [string, T[]][] { + const segment = options.segment ?? 0; + const byKey = new Map(); + for (const doc of docs) { + const key = doc.slug.split('/')[segment]; + if (!byKey.has(key)) byKey.set(key, []); + byKey.get(key)!.push(doc); + } + return [...byKey.entries()] + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, group]) => [key, options.sort ? options.sort(group) : group]); +} diff --git a/sites/docs/src/lib/llms.ts b/sites/docs/src/lib/llms.ts index bfccfd2..b5e87c4 100644 --- a/sites/docs/src/lib/llms.ts +++ b/sites/docs/src/lib/llms.ts @@ -1,8 +1,10 @@ import { allReferences, allGuides, type Reference } from 'content-collections'; import { sortCollection } from '@layerstack/docs/collections'; import { - inlineExampleDirectives, - processMarkdownContent, + generateGuideMarkdown as generateGuideMarkdownContent, + generateReferenceMarkdown as generateReferenceMarkdownDoc, + groupBySlugSegment, + linkListSection, type ExampleSourceResolver } from '@layerstack/docs/llms'; @@ -25,46 +27,23 @@ const resolveExampleSource: ExampleSourceResolver = (component, name) => { /** Group reference docs by their package (first slug segment), sorted within each group. */ function referencesByPackage(): [string, Reference[]][] { - const byPackage = new Map(); - for (const doc of allReferences) { - const pkg = doc.slug.split('/')[0]; - if (!byPackage.has(pkg)) byPackage.set(pkg, []); - byPackage.get(pkg)!.push(doc); - } - return [...byPackage.entries()] - .sort(([a], [b]) => a.localeCompare(b)) - .map(([pkg, docs]) => [pkg, sortCollection(docs)]); + return groupBySlugSegment(allReferences, { sort: sortCollection }); } /** LLM-optimized markdown for a single reference doc (examples inlined). */ export function generateReferenceMarkdown(doc: Reference): string { - const sections: string[] = [`# ${doc.name}`]; - if (doc.description) sections.push(doc.description); - - const item = doc.slug.split('/').pop(); - const inlined = inlineExampleDirectives(doc.content, resolveExampleSource, item); - const processed = processMarkdownContent(inlined); - if (processed) sections.push(processed); - - if (doc.related?.length) { - sections.push('## Related'); - sections.push(doc.related.map((r) => `- ${r}`).join('\n')); - } - - return sections.join('\n\n'); + return generateReferenceMarkdownDoc(doc, { + inlineExamples: true, + resolveSource: resolveExampleSource, + defaultComponent: doc.slug.split('/').pop() + }); } /** LLM-optimized markdown for a guide. */ export function generateGuideMarkdown(name: string): string { const raw = guideSources[`/src/content/guides/${name}.md`]; if (!raw) throw new Error(`Guide "${name}" not found`); - - let title = name; - const frontmatter = raw.match(/^---\n([\s\S]*?)\n---/); - const titleMatch = frontmatter?.[1].match(/^title:\s*(.+)$/m); - if (titleMatch) title = titleMatch[1].trim().replace(/^["']|["']$/g, ''); - - return `# ${title}\n\n${processMarkdownContent(raw)}`; + return generateGuideMarkdownContent(raw, { fallbackTitle: name }); } /** Root `/llms.txt` index — links to each page's `/llms.txt`. */ @@ -79,23 +58,29 @@ This file links to LLM-optimized documentation in markdown format. Append \`/llm const guides = sortCollection(allGuides.filter((g) => !g.draft)); if (guides.length) { - const items = guides - .map( - (g) => - `- [${g.name}](${baseUrl}/docs/guides/${g.slug}/llms.txt)${g.description ? `: ${g.description}` : ''}` + sections.push( + linkListSection( + 'Guides', + guides.map((g) => ({ + name: g.name, + url: `${baseUrl}/docs/guides/${g.slug}/llms.txt`, + description: g.description + })) ) - .join('\n'); - sections.push(`## Guides\n\n${items}`); + ); } for (const [pkg, docs] of referencesByPackage()) { - const items = docs - .map( - (d) => - `- [${d.name}](${baseUrl}/docs/${d.slug}/llms.txt)${d.description ? `: ${d.description}` : ''}` + sections.push( + linkListSection( + pkg, + docs.map((d) => ({ + name: d.name, + url: `${baseUrl}/docs/${d.slug}/llms.txt`, + description: d.description + })) ) - .join('\n'); - sections.push(`## ${pkg}\n\n${items}`); + ); } return sections.join('\n\n'); From c4d396aca6d37f6bebb342c9e2489c7de7647028 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 15:53:13 -0400 Subject: [PATCH 09/21] Fix background of ImageLink --- .../docs/src/lib/components/ImageLink.svelte | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/packages/docs/src/lib/components/ImageLink.svelte b/packages/docs/src/lib/components/ImageLink.svelte index 2f060b0..054f6d2 100644 --- a/packages/docs/src/lib/components/ImageLink.svelte +++ b/packages/docs/src/lib/components/ImageLink.svelte @@ -1,61 +1,61 @@ - {#if image} -
    - {@render image()} -
    - {/if} + {#if image} +
    + {@render image()} +
    + {/if} - {#if label && variant !== 'screenshot-only'} -

    - - {@render label()} - + {#if label && variant !== 'screenshot-only'} +

    + + {@render label()} + - -

    - {/if} + +

    + {/if}
    From edad7464b27aa1bc4b9eada366a2624e7a16aea9 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 29 May 2026 16:08:51 -0400 Subject: [PATCH 10/21] Re-add related links --- .../src/routes/docs/[packageName]/[name]/+page.svelte | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte index 9499c0d..aece8c8 100644 --- a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte +++ b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte @@ -1,6 +1,6 @@ - {#if $page.url.origin.includes('https')} - - - - {/if} + {title} + + {#if page.url.origin.includes('https')} + + + + {/if} - - - - -
    -
    - - -
    - - - - -
    - -
    - - {#if $lgScreen} - -
    -
    - -
    - -
    -
    +
    +
    + +
    + + +
    + +
    + + + + { + window.open(e.detail.value, '_blank'); + }} + class="inline-block md:hidden" + > + + +
    + + +
    + + + + (showDrawer = false)} /> + + +
    + {@render children()} +
    + + + {#if !page.data.metadata?.hideTableOfContents && page.data.metadata?.toc?.length} + + {/if} +
    diff --git a/sites/docs/src/routes/_NavMenu.svelte b/sites/docs/src/routes/_NavMenu.svelte index 1c4d356..80464e4 100644 --- a/sites/docs/src/routes/_NavMenu.svelte +++ b/sites/docs/src/routes/_NavMenu.svelte @@ -1,49 +1,127 @@ - - - - -{#if guides.length} -

    Guides

    - {#each guides as guide} - - {/each} -{/if} - -{#each packages as [pkg, refs]} -

    {pkg}

    - {#each refs as ref} - - {/each} -{/each} + + +{#snippet navItem({ label, path, icon }: { label: string; path: string; icon?: IconProp })} + onItemClick?.()} + /> +{/snippet} diff --git a/sites/docs/src/routes/app.css b/sites/docs/src/routes/app.css index a212c93..da4f5a5 100644 --- a/sites/docs/src/routes/app.css +++ b/sites/docs/src/routes/app.css @@ -10,6 +10,44 @@ @source '../../node_modules/@layerstack/docs/dist'; @plugin '@tailwindcss/typography'; +@theme { + --font-sans: 'Inter Variable', sans-serif; + --font-pixel: 'Departure Mono', monospace; +} + +@font-face { + font-family: 'Departure Mono'; + src: url('/fonts/DepartureMono-Regular.woff2') format('woff2'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +/* Match LayerChart: inline code uses the Departure Mono pixel font */ +code:not(pre > code):not(.custom) { + @apply font-pixel px-2; +} + +@layer utilities { + .background-gradient { + background: radial-gradient( + 49.63% 57.02% at 58.99% -7.2%, + color-mix(in oklab, var(--color-primary) 5%, transparent) 39.4%, + transparent 100% + ); + } + + .background-grid { + --size: 50px; + --_g: #0000 90deg, color-mix(in srgb, var(--color-primary) 5%, transparent) 0; + + background: + conic-gradient(from 90deg at 2px 2px, var(--_g)) 0 0 / var(--size) var(--size), + conic-gradient(from 90deg at 1px 1px, var(--_g)) 0 0 / calc(var(--size) / 5) + calc(var(--size) / 5); + } +} + /* Useful with `basic.css` */ /* :root { --color-primary: light-dark(var(--color-emerald-600), var(--color-indigo-700)); @@ -39,17 +77,8 @@ */ html { @apply bg-surface-200 accent-primary scroll-smooth; - /* background-image: - radial-gradient(at 0% 0%, hsl(var(--color-secondary) / 0.33) 0px, transparent 50%), - radial-gradient(at 98% 1%, hsl(var(--color-primary) / 0.33) 0px, transparent 50%); */ -} - -nav h1 { - @apply py-2 pl-4 mt-4 text-sm text-surface-content font-bold bg-surface-200 border-t border-b; -} - -nav h2 { - @apply pt-4 pb-2 pl-4 text-xs text-surface-content font-bold; + /* App header height (was provided by svelte-ux AppLayout; now a custom shell) */ + --headerHeight: 4rem; } .prose { diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte index aece8c8..fe92835 100644 --- a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte +++ b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte @@ -1,13 +1,13 @@ -
    -
    -
    - Docs - - {page.params.packageName} -
    - -
    - {metadata.name} - {#if metadata.status} - - {metadata.status} - - {/if} -
    +
    +
    + Docs + + {page.params.packageName} +
    - {#if metadata.description} -
    - {metadata.description} -
    +
    + {metadata.name} + {#if metadata.status} + + {metadata.status} + {/if} +
    -
    - + {#if metadata.description} +
    + {metadata.description}
    + {/if} + +
    +
    +
    -
    -
    - {#if metadata.features?.length} -

    Features

    -
      - {#each metadata.features as feature} -
    • {@html feature}
    • - {/each} -
    - {/if} +
    + {#if metadata.features?.length} +

    Features

    +
      + {#each metadata.features as feature (feature)} +
    • {@html feature}
    • + {/each} +
    + {/if} - {#key page.url.pathname} - - {/key} + {#key page.url.pathname} + + {/key} - {#if metadata.related?.length} - -
    - {#each metadata.related as related} - - {/each} -
    - {/if} -
    + {#if metadata.related?.length} + +
    + {#each metadata.related as related (related)} + + {/each} +
    + {/if} - {#if !metadata.hideTableOfContents && metadata.toc?.length} - - {/if} +
    diff --git a/sites/docs/src/routes/docs/guides/[name]/+page.svelte b/sites/docs/src/routes/docs/guides/[name]/+page.svelte index bc441bd..7eac958 100644 --- a/sites/docs/src/routes/docs/guides/[name]/+page.svelte +++ b/sites/docs/src/routes/docs/guides/[name]/+page.svelte @@ -1,12 +1,11 @@ -
    -
    -
    - Docs - - Guides -
    - -
    {metadata.name}
    +
    +
    + Docs + + Guides +
    - {#if metadata.description} -
    - {metadata.description} -
    - {/if} +
    {metadata.name}
    -
    - + {#if metadata.description} +
    + {metadata.description}
    -
    + {/if} -
    -
    - {#key page.url.pathname} - - {/key} -
    +
    + +
    +
    - {#if metadata.toc?.length} - - {/if} +
    + {#key page.url.pathname} + + {/key} + +
    diff --git a/sites/docs/static/fonts/DepartureMono-Regular.woff2 b/sites/docs/static/fonts/DepartureMono-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..b4a23dc1dad1c934005d0862e62c0294636afb08 GIT binary patch literal 22496 zcmV)CK*GOwPew9NR8&s@09W7u3;+NC0ZIS>09TLz0RR9100000000000000000000 z0000DgW3=pg<>0&ZXA{r24Dc{ZUHs|BmCrObD{ZH=hZA*&!MH+zI zVgQwY&Xv7oaDi>piFnp|L%N=YblB`*3>zna;rXqz|NsC0|NsA$%a_OIlC<^Z{4FiW z5Mlt1+f*Rat075p$4JQ#bNd8rcH26dxfJf!f+<%oEMz zWCgC9uTrU$ItyD;yOMObCg-bfw%u*mK7!m2%)d)VRdOn3#+A|-Mt04Ut=LICW2s;* zA|kjunV{LHI~RKYoW#P3Pt@LQT4+s0e=T}E+&xIyQo1A03H+%fHu;|>Y$AJil-e?cEWRiLUXmj*mfu(sZxSrLgc z3UQ4_M8v{EL_{UqAloiX%(DwK`pOJ?kg?Z$B~@2Flv6;G6oRIB0!M0@T;_;4eoB$- zF93o0*DXJR1UWUCyY+QghEC^#Tf~46#1cdapi}R6(v789DI^^mXcHEc%m33a``
    S&Y$B6bQNVy_}t=+?^%B}Y(` zNCCwE@5h>pC(WFJEMDWk(h z0X67Sb6(6EtCT&Vwn80{$v~ZP@ZgB)!QZuCdD}H4(`IyE&2RO(7Gh;$zgYVt-NsBTI^N4h(NG7te^*kqdQ z+I|K|gaZvowVZLc$FgaWs{;RtLp2{dP`hCv`CL_!1<(5~=!Z+RlmNCk$8 zs6ZT?*z9)8vaDDL3krr~%AeriqPR?gf&@X-GA^wZ7aW1M;94*H-dwN$8*tf|t6d zf0Da>ZLFUz1{Uccf8-zsGgX;|#P0b_md5C4X%Lo*@RCc4@TuhiGVIg>ki;TQB$a=5 z&(t~4M~J?4F(%-EtA$qq0)Dl(c1KA4h<`}gnb}nf3MYR}_lDZ(jnl;WcUcjl&F}OWrvZjoo#rZI<{Ccqm>}IyBZx=h9M<;!5v2Wg8E$g^|EpTIz>u2)ooa9A z)D)cHm`?Ae6aIhT9g+ZPiKKKajG zi7Z0u5ZI1)k2Ha)?`}qcr3IF8{PSy%Y3IUQ5!f2JV&KSnlm1pDOvHy$IJSJSZ*3to zli;F6lhe-p0igLy%U19F+3OO4P={ZHJxuWw}Hi*$a`YhDaRfBUzk z^N+CoN3TuxpSf+nss?Lny^aKg(pXWRy;>S`)rN<2UF9gita0>qI~s6en#W5f;)M;wt-hr$`k7;H|(Q|;6`jgRYT zb39Jh6L7*$+(|qcC-3w-BhQ30z}5q8Oq;8j((vj>twLmo7CSl2`13JH*Mk zLY?)Qon$B`bU{hT>05`0xU@l8MOC9F4I4LY-m-Puf})bLipuKR`u6x=k70S!YE~p# zsx|2pm611P-rB;=*SwqPA~<^$@|B5J{-wQjNRoC!VWz zP^M@2|J)%irIvA{&*<>e;bg8V2j0*95y-R_M-P7~MGYVVPhlIe^NA8=<<&4PgC@*d zv+KmQqNHlpS>H;vrnas=maViATGG9#E0{=v66)<5>^_Q1WcNreyLQi&*V=H4?RQHS z>HyBk*3jmS2pPRfn*-x>t2@V6+W|I;$Qu_v{BWowFv(D+1q_9VhRXyeK0?HiQP3$; z17p(W2Q^wO*l^+lgCzt{41uaDZ=F&K#w=R5BP1?kPgO(Lq5pIlG;CB+*|eG^t5QuZ zztm_IGj1_upO}PV6)RK^2#cwo*`R-UiX@aRUoEq4#vEYJGHO5+iDkkqLX=ZRwdpw#IC81EkfiEr>*(s~D^b2$-LTmDnGO1%r*M4fv?`IT z)R}UI#>AH@pID6-t;u9^V2b*v{N8YAFJKz_WC6i)B!j$%aDy%gdjy#hBfpt za`2;tCFN9C4pv%$GPPQC)I;Ayz6KJ!Vvp>;sF=;ySZi=%er@;Ux+p2r=__ii^RaBD zjnIUZu@}@wwHV zufm;(<80}dpC0t%o8 zD6qgUFaR6yf`YRtHM57Qn8H)veV@rHJoSAf^<7{Ig!BYHATWAUCct8qYflsz3q%B4 zB=!gUo|^O7ham(CZw=jnQ0IXfuZB=TE(4nw!{v-I_uW!SgJf?F2n_|%6q1&!O^i4U zBLU=HmHsV43K52BthyZnIW=>Mlr=6NkYcr14Oz3o^Z68F8U@Ey{=33VlT)r)?}w^Z z@RQPwpNgeK)T@Yz0Wvns1wUF_@+nPXq<4S-rbjZ5Jp61wiD;WBG1A z4EOYj^=kb_*}?1^fxYhgy}uvQasNg-Lb^qZ|R0$ps<%Qlyp(9h27%#*a>(?#nA=%yU}IB(@38FIt~NO1K)%SIEmmNmXL=%W_KyLBu z&VF#yY97mWa$5+KA-sn%;2TU1jfrQOsn1l81QRwJA#^B0PRos~iw&IWQn}4?x{0tK z{6eHnrmdVFB8+cG820#>TAy1?K`4{mn+W4pP9GwSOKm-<`|${qKURNW0(o3dBBzxw zi5|>%ENDO}0Hu^($WWk^Qpy-(z!+nU0b>jRfB^t7c7cLW#>Er_C}X>rf-u5%2ZV8{ ztv$dLgzaJqLK)k|6qJprJzyN~6;;Cq+{Zt>>$vwTEjyI#9cpVX+j@05*{R9+kCocL zM{wPnMgDM=eC`+igv$+ppO_VHl-*+6l@<4Uzn51EONFZihf8^uqem8WvMw-+Kxb{r z^3Fw*!bNea1+-@Fr>@ufL-mmOPkCDn*$xT7R^O_E12TBc8HpOll+s2KKe$B z2jW358*lA5?+t%E@CiSM@8muDX5t@;HhK-#iZghvllF=MaPSbfh@X+wn_-+UVNN`96 z0Gi+l0O|$F1mAGC0?w)&6b8T%NE8}$gfCGN7y^X>a0HSn#zRm=Q-H`BAP@)yLZetd zv1wFsl1o_r*%K70>u)~^uFkdj^XEitk8C>}#~4BaXu$kPV75jW_7po3I?y#4(7Su`Ivj}@t$OR!<37l3gj1`-ugE`e}v{H^Q?Vt zQ#k6{k}M1PK3?`+w`bbk*lb@Y;?w&XC&S;vS{ceO-+QJCiTC}4Qw9Z~JfR9I!F>aF zRjIQf0fs=gv4?b5@fP-2!;@l41BZ}4eA%94NdO#zC~JMCE5p^p=l7?ZKL$NtKYqCq ztehc`C^QBO8>hOT=uuZk_>$z~IV;~@OWQA)7Iw_@)xKX?Geb{@nj`rhD&N{D5VX_c z>NF6NzM*h81Yk;P6gC>H3s4Zj!3EHQrI0W>C3Fj8C$}w8IoblVNCE>$%(kFwF`1zP zN0-<|(s5KeCGs?gt$1dvhVV2h`r2T`ltA{XbSX(6W7D(FZsc|lCE>P}^G3i5HLZ!j zrX<qzyGiobHOE*zY?EVj;GEDR5=s&Da^n>p)NQs^y-ERqP5 zT*o>;n73py4-FS)(6%|Qqw>EdO8$8N|HS@&h4NdUe33)_3na`!iZ1>Kr5}u;6*$Q; zO2fQ)u^w-q=rjnL)p*zc35#56d(QIVD_!`5%1NBdzcp{n^WVb|tjYe+k{Y9^g9PO* z>lxdWQ;fhDfB8<`CH}E;WUP`|;?42XJE=S&B_ohiP*PF10^VbY_yOW(Zp>!y@a3o2 z)AL6ShPSqj7u72(`C=^{1WlqAnH;sr)Yz=z zs6%Fa%%v{2XkKhh7Q}WfI_i-XQJ<{(Xh1f;G$dPNhqlMgWM}Nw?$L)T`;yBzpetjNZr~u3X-aNl0WS5wHC)L(93uCR=H%(o0*A@# zha<^9I7a?GT9OaeihM3w*Y7y_4kyTuXd|PkfMJvn5BFMg;e{h>R!H04$;g9-?^|7E{CDp$P9& z3;!<*Kg71zhdw7BU(-KhA%3R+)DZW}U{aAa)Q7f#{xIB%PIv*2<4M%T;4lo(2q!TZ z(EvjYJc9QaYKA*%3o*DEC*ov=IyZ%pif3>dYQg<@77v7mdvTXEdZ7kt!V|a~f8ker zi60qSjadAEN5u_~Nt>HqxCa%6jt_c^cO*#nVFAD44}6af48G`y_6&YwK0^R*!RI)I zA@GR_JTFmyFcPoh#TbK^@h)D&n|LKg;~k~kUNCANu2-mJHH&gK zC#*7+U9=GTNH6taw|eQ=ITjt0qjqczc-*5rsIeT?F+9=^Th;J@4L7EI-m@`Rr!i-i zWc@8})t0etucy7c*X&b!shaApdO3BfW@@9wDfipbZ5rJcD!$}_86(pNZL6AK&Ez4xId0@-mGRvIdw!5eE?D7@7fCixqq(PUV6Lw>Sv$LDLbf{_$=LjgbHO>z zX**9i2c3ee$CY<^u4}FhcfUL8-svv8&pa!hrJggMOYeYpymyy(22mgxL`BXb*XTGp z3q6T$V!arNHLwLX=u`MipX^G$xiPw-ixT`&b% zxFqb0?P6I3#F3a42gQISk*rcuLZod{Q^IAH9F-Ty8)PQ0DjkZUOjR~2gQ`T;)J5tx zwO=i0liEaWruFNcdPiUCSU)m4jf64PSZ7#9BH9&|qsyWB?#)EM)-ib@`?eToP8AlTh z30ESKn3b3(Qe1Qae+5YC5%_%FmeTbh?(d(p%C) z>D6>1)109*^^B5vo0Vmm?Ck80>_bkO%j7z_L9R2mm^;ZO^4)nVKQVtePtCDHdm&h; z74X8S5GmloTA{Y-i|yiuqES34fp$u<(wx$k5-S~*TgztoK>4uJSE*I(%I*rRtW~nr zcy&v4Q`M}V*LG^1npN9h>#K=%s&3Tp);AhRgKAV8a^qNIuQ}YTG|lG!t%=sO*7}y! z%CueWc6(DB$$qD?Q}1}4E8T{!(VfxV*q!P=0V*H?%mz&005A<413cIcir^G*8@La3 zLsdwGPC+;D5L|)ha38z^d*QOcAu2Kp=^@9Ee`p^%8I{p(s6uy894*lr=Ee+c8aBij zwvTt<9Nxwa{4hR_iv&TG2$Oh4Hj^n*BTtZR5~ZXRpvF_%C_v57FkPiddP$e*MFwU> zrofzJR#~uku^Et+`Uk*+v9rsd#Jb36Z&Ys*ysA2`=$PDpOax(kxjWL@0WL!1|^|vQ1&YwC8YMK zEp?MxRnN2@t)}VP4eeB)(M?^@XL?QF)T;(%%s18>z?d|pCSk_S>E_%VHM3UO>RPsS z+1j?-?T$_TxqaZsor!Jr zl=FfyqVUzGy1P4q!B#uck$t%r~_DNkS zClAS4xh3zDLHAQxIwozVaLT49(&f~dCbH42lWopUvsgZzm-Bkg<;U~oJX7=);bM9* zEoO_W@}xXku9vB*wbH67)mkO1Q&^>5;gqq8r5sfHl!%g1DnJe(;081hKpYf75wrmg zBw&LX@B<#G0D>kk0WaV{NmZ#%l~!YFP5V;&6O|m4DXGb!qsclTy`8wWPQ9lSrp3@EYU&0uqL~vP2mL;rXx7a~DZnvz* zhOD3-31Arug3r#4Cm(QP6x1T0B-Mq>)K*<|*H8RNW*K?vb8Y?}vEZUBCarnu)tm9# zNte?WA&E4Dq?ciqT=U2`T&fj^9gu}NScd{!KoM49Kg3}iLCAt|#G?uVk&32>LpmBn zILZtmhWq%Ao0!2i-idW=;UKON$dKGgg9K%^i_Rbr5dgOSs-@OR9jyy0Pbd*>DpOR}|e{h4s;HqK=$=m7(0Ej#oV@`poi zAY806Ya9cnmYU;reLYoK-8LpU&+V$EO*I^f5mk@9DRN7oj~j1W=~dV4gpWdFAHBPq zleGFGLim*esfbt3S1m9*C=a1(WR5}fj~w~wdLaytuAL8)o==5OG94UVBRwC~F zcgpCR>rx3ZgnlAVG?}E>cVH8UPg~$qb-Wa6-#zEz^iE3;ygdPWbosA~AGbWAUK0jA zK+}`iV9|~Uy8H_fIjbJlN*q2jRqi$K@wp*8OZk|LMPl{Be#;TMpDYudGHrfkVXi@7 z31@UNBo^LQePKZew+mh_%=!G*_VV1J_ksf#+K{xAOjw1ZkauAri2YO#xR?EP-%s=8BMdEe9()Tdo(Iy)y zVOngMUGdq3Z_D4p9F`cFBN5a0iCqilJ2Jy+-g*cZ41K*aYtt@XPv7d0`q6$LzHnWN zhoA=lq7=WgVh+&?E4K>mX_tALr`lyQ`hdYXj7bKL0>lihdCWb+a2`;DI?*@_pm>W` zrZT6%G#H$T{gGX+#)~IP%40mv`|_HMyrz>AqlxQYv^V-b@{-Z-?OzH7tK+#al)w+y zg>*cP?9~=CLUXE=)d}p=45TCk z8o=!mq`D{E!C^q~9jl7&_u2S-IZx{{nt+DP1?gnfM?cFVTZMwhCYQ)p!6xdtz>DNs~sY)Q>xlsKt zFo`2jM$>(^MMiyPYLw2Fct`O@B>^K0j(Jxjsi>-ODUZ7=W-)6tv3_LzBBN_Gv#M1p zWgiMlJVu9oG|VoS7)AM83n4Uf>BBKl7K+OF)==Sl9xgCOoPJdFd4B~?0ML$fX}VPE zy8ltH9|KdI`{4$dB+EM>mPiYV3j=f_$vgqgxJ^u5J|{_Dj#I2S4Q1Mws9(Hd-5BVw z-R&$Jwhr>s8j_xeesv4783v0iTZnLfa}hZuAiq;7N0GYm;?j<$O;7BzYMn)H)J+j> zbX@zr2=wM_y_(hFCL}fM54;^7zR{$Xn?7+z=7@W~>w}3vD5Z`PSYNze)mXEpz_(~z z>NP^fZ=4_qUiEJ4WYp-_VNt}n6@vrpQu1lit;`-11rH%9CW}H_R;qX==4H+gIcG{L zuZ!2O$hNyG6gnza3Jim03{yaeB3Zej8tZC(Gr90#8nWo6L+&Fk zAK_{n)o8DMr2B`EF6`Sz--?_2rv~sJtn{P;!UyQ)KP=J zWT-cZ<_!V4fahz!RgL_E9VUX83WF!iKmscA+hG%4wq37m9gVRZs=bw$6+`bT1=h`k zdJt60OsDHfmqc;y5)QJDDxxlcob8-A(ah>~au<7KX_NBBh@CSyXF)J)-4y0EbB;(a zi8Qf^@_BoE@p|&TMb?W(a%$t9Z-c`L-p)3*m!<8%80`o8YNTBKBFLpuxF4X{=Gb`* zC^Nj^DxY^v!j65Ruee8gL7FMbuUYde0z<%2|6yW7m2t)tEfg$&jL6p$^7)xQbt1!* zEn9K$xQfHk+elRux?+V&OlaKcAva?0mVDE8m3?2~k9T{J3qT;w(L4&ZDNEn4XZ-XTQDuo#@6 zWOjsp53nYUif9!8=2B1GleaXa8bnGog;fjnMo$G&{+|yj&&o~FqCsT zCB&wMflCs$afN|<`nx!wLHe~4<_oLg5=tU5QW3bFtCpHJXsdP;AS_BHYif$`l%j0F z`&W|t_4l39PH2vx9M+Of2XSBK@nxG%%Z zxC-lHn9t?Af$SM+_6Wl7 zecE>a9dV&R zI>_dv+3}4f(^{IBwRm7k%epdTpe?S?W5?ZA_%V}{-jdz0g_9P&#dTJjW$LGhc$yr~ zZ?V7dJ7w=AnY@HF?+A7^mA6Xl8`I%3m9WDAH{zu$tF&m0%0t5yVW4$P+VE`qguCcY zI1XC&dy(`e2k6{#E4;?`UFL{1O^2$CdERC8q30tV#YKInARg4?1WKa0v+#>^CcgGP zJ#Dh%s=Zj+2-u7k!0uifjG`yCH#;si*B)S(-V7IQZ6-?$)Io_`i(<~&r}#9QDPG@% z1cyjm#Qp&)7#kukxsJ?saZ!80@(5hOEp`;nY0e3ho5LWTJ%wy@b*R*scG!LJ;Bz9+ zxl!JEvxr!l@jAf=?1B0&U+I{FE#*iTYb+Mo8HOZNm`0Om=~$YymzVqOx5BI;90w%+ zU8tbufycAio&~wGQ32$4Q|)M-4_$^Qa2<^*B6f>H zfmDS8M|QE|;PA!4849H2as7uea%yTbAJ1U3K&0E5$g#b>sTIC#Vy*ZV9m_b-B-kn?o}To-hH0Q#JH`Aw_vpB91%Sj zDGQJo&6qSVNyJ$J?LjvkK_00&+6P`B+#l~wLvKoel#1WYi_Hm>KWjyIJWLuWgZ{a! zw3H!j`3{1WMr_|$M%9(4?@@E|M^^2CXAATTXT&%bS+rSmggHROTj1Hf#D zBFfDJfq;2l-rbohe~rTgLLsp?RU!>J9O+?N=dCq*+FES}3(@}^iMoSY&VKP7wDuzd zJNx@I^ICH{@J_4(S?8U;dnQn3#6n_?z$al6gMZptO$<$q+5#As18?;%ON;^x!VRr1 z1Dlwgg?4G0>JYV!?t7WSOfVeJ9{*FqtnI?8n zp~YRNDY!}%WbI@I*jYKx5vBRjbiOpRO-qJho0)+1!VA0=r+jC#Z{u{= zT- z)RgVX5P(iQBx`pUVpW(&=7{VQA)Vp~KO=J4fMg=b1?dX*NZ|;+g-i&`^I*GfuF&Hk zrsXif85bd+1jOm0c%vr&6rpO*Y%Ta>ppoJE+-U-{MT@nYg6)jylsi}-8A`rb)CYmSE#_DNd7jV5w9v31R^5e;&0;_qu;SB}(%t2mMrLnXEF ze+<1npgv?NfU+Ax2hA8~zO+0~D_)nRSDVqT>b_p3M`tr1txv%)g*C%F*{?-xGrAuQ zg6!ob?%>|2_JP>aD*=C(kZzDHu|4NZd7xw}Ma)skq@;y5Y{he(_nH<6YI=$J>jtB2 zporVzOj&PV1f3C>7poehMFfyWLjK*+B&omi`x6j`kC?4S*9zIFHKvO;jyI>c@~%C^ zKS;UW?IfFvgViss|KNhNo7&3GinIU0Yz7JqQcw13O)>H4@5@@jpl7!g&Ep<}+{^q0 zoY2(~OxD$GnYfLZEy#kLTsPRsuZN0>V--7)K|^c0CaI+LyNv!}@XfmZo9vm?YFDRO zGIi0!E+hrVgbE$hIx$?^l$WgVPObFR z#CeqFQYlvfDNT*&J%LNw9vVr+&G63VC_t91p;1%WcB9@G3BQPb<+S;2`)|p+u_P8%t$9JbX z-VyCQ5cw#CX*gEtR0l(-JiiPyr1^mWn^9cwaOQ!f3>2v5oEr5ld%Y7c{M{UU5~<1F zUcc}0_xin$Pf_I~RbI<8**F|WMNQaZE4q0r)neN}R(1499U`UX*m2~VNQ?(}Zz>%l z7yd6pDXa9T_Y7%n`V$xyCK{JnsIA|V+mz)jPJHb~UoW^vse#o~)}8Fc6lv#D6iaM^ z%B|SEp)RPVU^egRp)}Qdfr##k3|7JudT4OwIzjf!M0ijA?o*EaazWt=c3Z)VJHDT~ zwj0URGS}>dF2sEh`awcrgus`sB?*OX5+?3nH9PPuD}Jbbu+HjCGiyFW9+6CbH>VkBA&cK)_wigp|f+qE?XhXn7gYN ze5k^?yK`*^J4YF>HQUYH=M%j8P?d_r!bScSPBbYfW@TKqsPS{6Pto!*QU+z#;ya*E<_u?76dY z+gf*8nKwgx9|1#~-;+IHHUos9`RTly*V;!X!Tg9j)~W6MI86?Wk}@Ka+IFoIbyBU; z-*%;L|JHydqc)IN0}nx6IT`I95+p*njUaX&;qc<1QjbZ!`Yo|2!r7yo5r%S|h#bIU zhoT*1!_PnNdV&_h_Qo@$gLl|)FYn!-ezQCwkJlH%jH_AIW6uYP{~HLPv-pS8INlE| z@b3vW|0h2U*fJz_5IT8g#)ez5+8WzFY~Po-kceXEj@_Jx7MMF}<@_36%H|n}Gx_yt z30%4C{EwkO4CKZYxi05Nmyh1NAs?&)D%VW@sqMsh9p_vsyk}nh8QcMyw^KRRE*OVB zr)3ls?Oa@-oAM4GZI;Qa`#EGwgZTG^yXXz@YD*}`cnX&( zGv@-3$ao%_eqTX&%?HH4ypB~ew=+1}QU69QXxAGm4#zQIw{bSDCVL(kXy=LsPjGxg zpic^W;Iv+#11u8;&SNfR&|tzE$QGKmLh(*j>!c&>hmldr=G^uEb#yKZJ5ndT#67t9 zTe?7d#1#e(JXNa5plyo? zT5DK*ONz-(YE`jHDY`qpvV?RM$~^tfUq8=~Nv2RGSTwArXo6aE`>4&rT%VquS&md~ z+|-*k0_o*=x=fL`cl&rS6DVttKWS}9^-LRd=(BOxmcp1M5B9#Ywf@Tfg5t{s=Y zklJ$_%Lo3?Ut!_jI8M+RKgACukTD){^Jlk_6E(xU;?n0A1B%4_|99pwMUBM7v`)5om!`B&$R8z2j@*888^Q&18VSbQ5QB4*bTxUMa)5z z>37T%L+ZF8wf{1StQINtuEQ~E@DZY!$~x2xoG-pphy{oa{Al4q`OBM0u zXYw|YrCs}HWdD{1r<5$t$peR$W3Ov1SOJ=jZB74lChZ4wUUI*K&q8h^;`Pk2^A8Kq z_+kq2>WHUqaP<=6on=ULuf!Z>0+&W8hT-*E#aq@w(pG;x|x zMhYvHTxTFQybdYzcrTQhu>h#fXl|A-(tN{`iW&HJ19*{}fP@`9)}@!aPR50dBM!3g zsFK$`fV`O)OO1u@prSZ4WZ={6!#Bg5TKw*)^~+}aAMod0{P0Qrp8x+v{{Pr0+OtX9 zFyFMlLbE|RWHM8->#&mJQr4tui^{v0l&m*b;^CepJj5bbV7SgKa-FR-W+FDDqow}M z8NhrM5?g`G`_=1fapTOl&FMR$;ZI7xW}3+9!!)tyd4lZ0vTw4}dMJ=%>6b|j!tu<& zn)(&5C%h9~Ak<%AfC5-(sleYGQ>gY=Yj`Vumw*=sUcLw+U^?K8;uVt!#Nv@Bu|tZh z%G6iz;#VY<9Yu0_5+dchW~VdT_WP?leV>?OV3kt&fdEyph8;ut4{=i3l{Z>^ktI6C zktCd{T~AWvj0RmSClw5+Ak(#56*HSJP%Mu8&$=Iy!0|SwC$|Lx3`pMM4-e%Gt z*Csw|%QwM};UX(q89Cg8Kf^NIy?7BJF#g%^ZcVUETv1Ur!E2-IMiYQviV&%o-)bU>Vy6M2w($lgGWv?I-i+gq zPfEmL;BeZhUFqRt_h-T0`;qO&^Y;3SF49eZCjz>qcLHN+6CH~uGlL_Ovs;TJdz}+x zz7g2l#NuTv>BY{@e9}}C_$jFEu&!mem~-1`z2bz_u?gN2R6-;@*3r(IX4h8`D^)+b_PN*DuTqB8adFaonOwu&HR;)0uP!~QCWiV;SpR1EMcZ9fcUKxB} z9LW7uPZMg#m%xnQuAAaY#T(m%vO6f)rOa7>KrT$#K-y0(u8&ViK$%~Nj&rDFjFI9# z4f*=8zRVAu>O&iqdvAcLCQDBSJE}KA=)ibopl;HW=4=#+q#i;+;^{a=TQ$lfY-!XIdP-;}HH(a4LUSzJCM)#0C=6KVk@xm?HZZI+mVgQ7K#qh&@;>3c zPJx-F5g!}4IDwbCj~WtvLk!hTgXrok8jl8ZETY`-%xFIF=* zshVV{X2vvy=3^wWa6TZ4%Ckfw#Q$oDrGj;D&%-EIBVsSUm?3m>8R+lf_1oIceF5LB zMlyQ;i}P)!Ca+ju84M?xe=-Z6)6SPdZ!(Fx*(sMGtMrMtqzW2bC!9Y`GC>Gh*QlRg zOmE!`ojbvjpxATtL;SctOFsV{>O0ie^dXJh#yjkH1mBTLV1-5RoN39R43HtNNA!7p_yic7TgGJwIy`m zLFmkn5GarkESL}~j1Vc35G|SzBZeYYETN}fgm}q>RH=jv1%!V369ySX80Lf+?Ub0} zw3z9PnC+}s=z>_{vRLW5SnZD3=&{)5nb_&I*zYUhgj0kw&JfNyN4V%J;f5Q8TW%8` zctLpWHQ`_X65jeq_~HxUyWd0*Gej)J0ugJmM#MIVNQLY~D%D4%at=zWj+GB87-sI+6CJhT5+Xk8-VO(qi8G$Os4NhGm3M3P%bB(oJn@>@-$ zPaB9VYLR4Rt0e2%AStOtvb)`qGo2xFwW~z#b&traUJ?1fw}`ygpNM4lKJTmKdmv@5 z%n@Z*S)wXdnW(B&C8|z!h-zL7qB_)pDDS*Ug%m<6x)@S%^(5811X4+5kSc0AQ5)Jt z3`r+hF{GbyG=c^ifllB+3S~$?*+}l`t3ogs`knq~;2F#q>bewbe#UDWhMaM%5TFi0 zo@dW*eL`rE@pC~IO*n%tN_F}o#K`fKd&i5GK8^FtvvFVgejDuDCxW_%bo8GaJfayc zd}Kbb11Law#wlnFl)?ln$=lcGkmrThmKgwHipXc18;kk3tyKnl%C}cOBGn1)J08W;kV3I|QNk;X>-(XoVa`H_JJoZ-ZiwQ^VL(sQ#+) zttdlzVcT~95fU-S6tzN)%***v4_Y}Q_ZbPg9)NRLp4Hl#(wij8 zXVaou08#=sGlCujHdkpSP-G2|WWKN;3+0SlIinsWBtxl3#8_7bpTK!()vqY66R|!f zSgb3x(1&Y-wXT~wwkf2Otec!iTi;Y# zQntE;$C2G94DLuyBZI*Mdf;A6{AldhE@p^WV6k&0&IhI=12hR&5=uZY!^Y{U;?i;G z{eWWDnTpk<&<8Se+?r)UMNe*-|MQ(ap7_ql?&E;j>{Z25q5j@DTYan>sPd&-g9pLm zV=cm}?l$Y>aTtLE<4$y3aw>%h7HPl{j2fzY(Cn9Z)-!Wm`mi6hSS9Xy~+}brHWbt5ky7IGqn3cqveO-JG zZ~yGU;XcQmgZlkX@xx? zb1Fc%1FoWNFwn%%^!B#wx#dbH;fy(R=_EoyVS-wwAUUfS=Tcwf7tkJZPR$B9?R zuTDJcO^r|2r_Xc1vzUgXq^P&{SkM2%Q>rL2`HD!0mDptunzpc9By1xC$J&m??9Xtl6^X z$eAlDIwrP2!9sC`;}iSbm%jF`@BQd!zxsW-UahXQ(_am2C@iQA3LxwV&ID*h5Ps(} zRoa|bzE{QW5-+Z>!oYab@?IceV63TmEud(2CdiIr=>Hb)k`5GRlq0`*XC{a+hy_Y4 z5folQ4PvBTN(YZ{?Q*6F0$R_bq2j_3o#t~9D1U}+s9V{I1Dq&8H=b0J zR%NDkh7YtEtN!FdD?u&zJAq2pZpV>e2W{so6#INM_G~M=JEF@wr`JH@z^x@YpR39m z>=P&Dx<``a$SE)ZEhA)(#-Tgcb-@HneipT$QHXao65>mv{MfRBdO_u9~amsyf$0 z!*+#5^$i%X+gPW~X#!V!q#nvvJs!nxvGiU{q;?rx`F<=#MCChFKJ~l$PBBAfZdTCH zojqJ{e}99-ZK_h3O3J!{USnM!#K9~WY6HNJ)F1Qp2LJ$9tqS*}KjVMjy8qt~*EMS! zS_F{erh-m15TF3vK%kzVf=m-MW`BBO(GW@+)FjCvS{su0hHm)AY{F*juPxZ7ZQIc~ zhAp(nYOY%Kn$brfKcqQ(@i_5{Y4gQ*6Xvm*<@4<>^SieQPYCpI3_#-5(F~BG-}ti z!sb+Ikdo$UldkD5y{7-k#bV=Ps#;%IOPjlCgP*7!#ZVFrqfI(YWGV*;5Tl-V*uYNg zjRDMq1+YSd!s6n{%IbAR$ zwRrvuyz35)f54>Q#XWJjr~w7J$@79pFXj^BB&+Fj-fg|p5jr(Iwh|Y*;DyZp|9{w* zKLz$asixTZQvmFlSvl+9wEhEk_{WtDTzhs)4fG z$1g5doIM0A{7s{@+0Ob&zh?3H)%el_=xzX5@F;Cb{Q$6Vi26OvOVa@s98CpO5akN< zcaouixr<=#f*bvYhq<$E{4jUs4SMqj{(^mnX>6E#f38jdvlbuIfFubTk(rJHltb6& zWkR`h*)G?GqP)8JD|!_V1_b~IMwGW+QFc}aliVtP$9u%oU;~Id;%#38i08>VIVbPT zIB#knfA9ziCoUs#~P3%^TXf3SuqF9JdwP-rBa*mU7yaLtckl zS$aP>UA6ISVSUi>x^o|8(3oIFX)Lg&qDE?~r#@e2JJ0#LNcFe}J>of!4o}n9H)i_F zTpJCpyFvClQq^_U+~nwmIv#4^sm5Na>yhni<-Hc(a`RDZA9VCnd*1{$0>6gR zrT+LgjPCyMY$U<`L1;a}BD0IGPgK2Pa)`?%K2%~p31QNr6~xOdAV1E4RKsd-MDB*y z!RS1VtBbLD8B=Fd3os>rlk>B*-WJuv?7}UnmxaYyTu*CCQBsyoUew3#`q@?ADrzut z)|3<1;Yr$9ZoTlV78GlRC*^g%zna}#qa3un0b~_4rwA>*QoO{%GPH2e(vro4p&F`Bz(CSY{84eP?TS zVymKO4tiBxQd;2#r5jmC6Y8p{Zi)*syw+-98OGXu!P3>QzA$z6qfbhE3lpF`HzE9#)j@CmebuAi zLRHpYFTQ;i*H6JJaa2{uzW0$Q2PR(Zc?ja8v+C@$Q%xs5b?=*4HFQyhdw&#oF{-Em z?O^EJzf}KTk$$}tsayYu(6zrMis`Kc(fyB7y%5g3H{wP0pIU0Ft&aNYsmobQt{O43 zvNE}~Vs2;7_I;;zawm3t$98l_c6!%$V>fqr5B6ve_hi1St+dLDE8E)u761*V13+g0 zW4MWAYM`A!O>`uvg>DIIqlZBq^eU)}P6PEe9R=$D-T=B2Xoz+NjnGrT5#10pMz;Y@ z=mwz4rdt8$)p}FA!ELocHv(0rN!H$Wh zh3*1k(5*o%+8e~77eEiR2k5Dx2zpUsU%j0z-h~oeE7ARu{8O_3O7XQ+zbB1_h$WDY z*nkYAJjg_lv@&|oziqFzHaY?zh} zcR(X_yOG;O&l?RFHOAS-8t1&m>(T`GHPPcu@?eua(iG1%)uS_QmuX-+&osj~&Ge~R zX8W=^{%fw6X5LnJFrPs!(5Hp^x5)4o8_*I%TWZ8CTTB4UAIhzOxmMn)R^MtYnE-2k zvCq8g5`F89*|UM)hw6ci$Qf)x4Z&vA7;Hf;!B*r1wo!_~cGMi~KrvwFrckhJ?M9Jc z56T34Q5&%Dq3i+bfCL6Z3Ifv57cxLyP$?J!nLu->G>n5xp%qjHCPHS=8Zw7TkOj1W zEMYuk1#KZ~m;%{Ad&m~1L3VH;R2G&(<)AxM9_B$6U_YoLEP^V*K~QB_233I`P*s@k zh(YY36{H%xhd4kBNOgD%F@hVU27H9ngw~K+@BvaAIzsBePe@&852**=AoV2>(m-a@ zQ2Zc`RC*kx3#74RoWvi}M5f~m-62ik55z@0A$sx@6C0phKi(@oMK z-Bo{l{vH$lA(!!!Oo+c4O@QP>0@ZYaWB?>sttLca3oS4CQ3#l z(ej)a8HdEG%f!i8q=&qwr;I^*sq^%fsYtv6CPAhkiSnN$nT#aMZ&F|>l6vu;G{_<( zT|Fj4W+RyjpDbB|WUJTY$U-Dnag!&Dk$m->0$GC;DrNde3DQ?t(+@Tw{b46E;Ho(T z0lSew7tUb7E@a5X`5B6QW;m3EjDbFo@lXRYVZ#WSyrzINWGXm8rhzM@7#$6n4s9Sa zU^y}y0w8lF9P*dS%>qb)l*j^PlVWEJtU$KLFWFXJhdzf}e2$>mUq_oe=b;qH1vrRY z6mQ5Ssktm!kSlVWt1<`Sf8v@V=02>1UcfQXOV|Ltk*A=))oi}XJ;R|2)nOOx0{_F!P(IueS%E#_GdLK= zz#+&L4ue^6ILw42VHF$=%i*4|1&)Vxa0)5|&O>$KLC6ChkHX+0lmO3wt?*tl8{YSh z^iI4^rY4_ThD?QTlL_!0G7Y{gDM?2$ zBLyhtBpbzo|xLMzywe6}P^PZLg$~HngctZE16-n{mznZ$vqZH=~@xTT#yA zO(+*OZ$nsuRw4>rL^N827|=Rn-|{L{xz$yvN*k+Mtu|G=2JJZwfsP`L&=JHD9Yz}8I)$8S()pZMvxiIPTJvmb zQR~X(mRnV7Q>X0ntZQ{oH{d2nckG1t;KqpWW>>^-`EPEG1gt=8hXmm^NH8{sgy3dK z=xrAiRz%HB1dotaumHrj^R+`IC_Jez+uQq^fz(}ha;!aKgbyz zft*GEBIj@P1Zp#vMiuP)GQGXlyM&}T~m zWP2F21K~+`7_uYbO-~rNGl6FqOd3w;83j{D6DfPbw7rO;y^Ye5JQ2xfu;6oIlJ8-|55x+;!nWUt)m1ikZp8w42+Znl zHa08zIFtZDj*DA?hesX)p+KQD7|f4Iq_0sZzhJRW;t3=gU9DLlrRA$X7+0d3!?+PW z8RPD^miK3g>&T{!FdluKwAr027Ci#vEp!pa+vu?v@1loeypNuM@hN&F#+T^v7+;~s zV0?`ph4CGFG{z6;!Kg8DYcf=@6+1fv1|uMm4hjp?H8gyzsp$)C9q;Ly=p&O%^@#%x zc-L{qU2wt)r<`=s8K<0b&KYN1a@JWFopa7<=bd-f1s9z6+?%=l8Gwajh8W_IKm6ga z9zBkLKsIu4SPuY>igGYmXf#@6Yiq8DhZ#OT=Jbmwv(a@OWgxn4q6|QHmnIMdWkgY1 zNm4^AMx4-nPWeUm1?3Cfm&6phulPSJ zY4xyg5PJg?oR!>cRAZ-tUZUzF7Y9`U%5f5zi~QU)$U}Kv_5q@Kn%h979zGV1x45wmc8OAf+rq^C@8gyS9*qETWdh?A{U*Te>B(Y%M2=6{N6|)mL(hdpZdyae0#iXD2#j(lXNKC=T~*s&k%#BX-yPqyXnZJW>F z*AO(&^rkm-;faQu)7(Z{(BjqEE_tcOTHKPdEp2J3mbI)*%UfQu6|E@UfBnDY|KDCP z|5wEM`6g}{Y5@KCweWB6H$dhPK*QAh4I0~{sqJ41t?B|6uYG)u*YCT(xZG7WQE*J~ z^;>foAkGliw&&f$3+p@lmVz~LD26!LV%19U&({FFO7(0uG)vxoZQO(3x7F9(Kezvr zeqD7!ZOG;!kFN5@;z_P^&{n_OfA=rRvuNd=&3oVZ@9y@gkmEc(Ipg6H*khNUmuwD` z&^F`@B@wewPC*Rv#$7ptQ2I>k$9fRw;5K6GSqa-owbIM=A7qi zpXF$1bV`Y3hAnU2iLtpeZw&QkIHjmSDo14HYS(<0njy|76p3Vel@wjcV2=GIGz7D= zxU*|yj;tamm&?#7sW*4>bN$b_^kazsOCu*}#83t}73sPN_S~VcA_f|F_rrjrwJ3#$ zsW72osDv_93LdasGhCYp3!FL%OR3psSkYqWUuBeS+BexgNTBAh6`}m%vQDz)=r2#I zWGM<5xo}?MX!^vHbloY*WN#-e0j$ZN!De%{g=SSBC07&(G%9!c{az@g`M9|M)P8^5jb`O&Z(&@Gdg+mm@_!qh_2!yJ>3F z*R1V|X*G}}s}k$jE;xIAm)GQV*r@v>!VLNBNA_69gm!;o(30=ix-R~0Y{ zesGckef83ZinnJ-6>r-4@%{;n3T4T;J&#dA6I1#4u6!8z%b_vWNuTP_QBv53#3)K= z2_g6IrH@`x)f@MgksbGyD!~*?%jJ#&Q#23Va#b1Ui|^NVjvME5641`D&mP(GBx}N- v7oUo5C)>^E>&CZV$&|CqZZE~UofZ=oq Date: Tue, 2 Jun 2026 10:07:22 -0400 Subject: [PATCH 12/21] fix ci --- .github/workflows/ci.yml | 6 ++++-- sites/docs/package.json | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 134ca19..e45aebc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,10 @@ jobs: - run: pnpm --filter "./packages/*" build + # Build sites before `pnpm check`: the docs site generates the `content-collections` + # module at build time, which the type-check then consumes. + - run: pnpm --filter "./sites/*" build + - run: pnpm check - run: pnpm lint @@ -36,5 +40,3 @@ jobs: - run: pnpm test:unit env: CI: true - - - run: pnpm --filter "./sites/*" build diff --git a/sites/docs/package.json b/sites/docs/package.json index 4e6d032..0da8a6a 100644 --- a/sites/docs/package.json +++ b/sites/docs/package.json @@ -12,11 +12,10 @@ "preview": "vite preview", "package": "svelte-package", "prepublishOnly": "svelte-package", - "check": "svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --check .", - "format": "prettier --write .", - "prepare": "svelte-kit sync" + "format": "prettier --write ." }, "devDependencies": { "@changesets/cli": "^2.29.4", From 5918a97e0f3fba831b0787124b86056451001564 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 10:39:19 -0400 Subject: [PATCH 13/21] fix `pnpm check` --- packages/utils/src/lib/date.ts | 4 +- packages/utils/src/lib/date_types.ts | 2 +- .../components/timerStore/default.svelte | 12 +- .../components/timerStore/tick-count.svelte | 12 +- sites/docs/src/lib/searchContent.ts | 199 +++++++++--------- sites/docs/src/routes/+layout.ts | 1 - sites/docs/tsconfig.json | 4 +- 7 files changed, 116 insertions(+), 118 deletions(-) diff --git a/packages/utils/src/lib/date.ts b/packages/utils/src/lib/date.ts index 6fda1d5..eef78c1 100644 --- a/packages/utils/src/lib/date.ts +++ b/packages/utils/src/lib/date.ts @@ -1,5 +1,5 @@ import { - CountableTimeInterval, + type CountableTimeInterval, timeDay, timeHour, timeMillisecond, @@ -32,7 +32,7 @@ import { type FormatDateOptions, type DateFormatVariantPreset, periodTypeMappings, - PeriodTypeCode, + type PeriodTypeCode, type TimeIntervalType, } from './date_types.js'; import { defaultLocale, type LocaleSettings } from './locale.js'; diff --git a/packages/utils/src/lib/date_types.ts b/packages/utils/src/lib/date_types.ts index 3b2885e..037125f 100644 --- a/packages/utils/src/lib/date_types.ts +++ b/packages/utils/src/lib/date_types.ts @@ -1,5 +1,5 @@ import type { DateRange } from './dateRange.js'; -import { ValueOf } from './typeHelpers.js'; +import type { ValueOf } from './typeHelpers.js'; export type SelectedDate = Date | Date[] | DateRange | null | undefined; diff --git a/sites/docs/src/examples/components/timerStore/default.svelte b/sites/docs/src/examples/components/timerStore/default.svelte index 5829178..94358ac 100644 --- a/sites/docs/src/examples/components/timerStore/default.svelte +++ b/sites/docs/src/examples/components/timerStore/default.svelte @@ -1,13 +1,13 @@
    {$dateTimer}
    (e.target.checked ? dateTimer.start() : dateTimer.stop())} + checked={$isDateRunning} + on:change={(e) => ((e.target as HTMLInputElement).checked ? dateTimer.start() : dateTimer.stop())} /> diff --git a/sites/docs/src/examples/components/timerStore/tick-count.svelte b/sites/docs/src/examples/components/timerStore/tick-count.svelte index 36be262..2af4c9f 100644 --- a/sites/docs/src/examples/components/timerStore/tick-count.svelte +++ b/sites/docs/src/examples/components/timerStore/tick-count.svelte @@ -1,13 +1,13 @@
    {$tickTimer}
    (e.target.checked ? tickTimer.start() : tickTimer.stop())} + checked={$isTickRunning} + on:change={(e) => ((e.target as HTMLInputElement).checked ? tickTimer.start() : tickTimer.stop())} /> diff --git a/sites/docs/src/lib/searchContent.ts b/sites/docs/src/lib/searchContent.ts index b0dffee..e8ba4f4 100644 --- a/sites/docs/src/lib/searchContent.ts +++ b/sites/docs/src/lib/searchContent.ts @@ -5,129 +5,130 @@ import type { SearchEntry } from '@layerstack/docs/search'; type TocEntry = { id: string; text: string; level: number }; function escapeRegexChars(str: string): string { - return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } /** * Extract the content under each heading from markdown, keyed by heading text. */ function extractHeadingContents(markdown: string, toc: TocEntry[]): Map { - const result = new Map(); - const headingPositions: { text: string; start: number; end: number }[] = []; - - for (const heading of toc) { - const headingPattern = new RegExp( - `^#{1,6}\\s+${escapeRegexChars(heading.text)}(?:\\s*:[a-zA-Z][\\w-]*\\{[^}]*\\})*\\s*$`, - 'gm' - ); - const match = headingPattern.exec(markdown); - if (match) { - headingPositions.push({ - text: heading.text, - start: match.index + match[0].length, - end: markdown.length - }); - } - } - - headingPositions.sort((a, b) => a.start - b.start); - for (let i = 0; i < headingPositions.length - 1; i++) { - const nextHeadingMatch = markdown.slice(headingPositions[i].start).match(/^#{1,6}\s+/m); - if (nextHeadingMatch) { - headingPositions[i].end = headingPositions[i].start + (nextHeadingMatch.index ?? 0); - } - } - - for (const pos of headingPositions) { - const rawContent = markdown.slice(pos.start, pos.end).trim(); - result.set(pos.text, stripMarkdown(rawContent).slice(0, 200)); - } - - return result; + const result = new Map(); + const headingPositions: { text: string; start: number; end: number }[] = []; + + for (const heading of toc) { + const headingPattern = new RegExp( + `^#{1,6}\\s+${escapeRegexChars(heading.text)}(?:\\s*:[a-zA-Z][\\w-]*\\{[^}]*\\})*\\s*$`, + 'gm' + ); + const match = headingPattern.exec(markdown); + if (match) { + headingPositions.push({ + text: heading.text, + start: match.index + match[0].length, + end: markdown.length, + }); + } + } + + headingPositions.sort((a, b) => a.start - b.start); + for (let i = 0; i < headingPositions.length - 1; i++) { + const nextHeadingMatch = markdown.slice(headingPositions[i].start).match(/^#{1,6}\s+/m); + if (nextHeadingMatch) { + headingPositions[i].end = headingPositions[i].start + (nextHeadingMatch.index ?? 0); + } + } + + for (const pos of headingPositions) { + const rawContent = markdown.slice(pos.start, pos.end).trim(); + result.set(pos.text, stripMarkdown(rawContent).slice(0, 200)); + } + + return result; } function referenceToEntry(doc: Reference): SearchEntry { - const description = doc.description ?? ''; - const content = stripMarkdown(doc.content); - return { - title: doc.name, - slug: `docs/${doc.slug}`, - content: description ? `${description} ${content}` : content, - type: 'reference', - category: doc.slug.split('/')[0] - }; + const description = doc.description ?? ''; + const content = stripMarkdown(doc.content); + return { + title: doc.name, + slug: `docs/${doc.slug}`, + content: description ? `${description} ${content}` : content, + type: 'reference', + category: doc.slug.split('/')[0], + }; } function referenceHeadingsToEntries(doc: Reference): SearchEntry[] { - const seen = new Set(); - const parentSlug = `docs/${doc.slug}`; - const headingContents = extractHeadingContents(doc.content, doc.toc); - - return doc.toc - .filter((heading) => { - if (seen.has(heading.id)) return false; - seen.add(heading.id); - return true; - }) - .map((heading) => ({ - title: heading.text, - slug: `${parentSlug}#${heading.id}`, - content: headingContents.get(heading.text) || doc.name, - type: 'heading' as const, - parent: doc.name, - parentSlug, - parentType: 'reference' - })); + const seen = new Set(); + const parentSlug = `docs/${doc.slug}`; + const headingContents = extractHeadingContents(doc.content, doc.toc); + + return doc.toc + .filter((heading: TocEntry) => { + if (seen.has(heading.id)) return false; + seen.add(heading.id); + return true; + }) + .map((heading: TocEntry) => ({ + title: heading.text, + slug: `${parentSlug}#${heading.id}`, + content: headingContents.get(heading.text) || doc.name, + type: 'heading' as const, + parent: doc.name, + parentSlug, + parentType: 'reference', + })); } function guideToEntry(doc: Guide): SearchEntry { - const description = doc.description ?? ''; - const content = stripMarkdown(doc.content); - return { - title: doc.name, - slug: `docs/guides/${doc.slug}`, - content: description ? `${description} ${content}` : content, - type: 'guide' - }; + const description = doc.description ?? ''; + const content = stripMarkdown(doc.content); + return { + title: doc.name, + slug: `docs/guides/${doc.slug}`, + content: description ? `${description} ${content}` : content, + type: 'guide', + }; } function guideHeadingsToEntries(doc: Guide): SearchEntry[] { - const seen = new Set(); - const parentSlug = `docs/guides/${doc.slug}`; - const headingContents = extractHeadingContents(doc.content, doc.toc); - - return doc.toc - .filter((heading) => { - if (seen.has(heading.id)) return false; - seen.add(heading.id); - return true; - }) - .map((heading) => ({ - title: heading.text, - slug: `${parentSlug}#${heading.id}`, - content: headingContents.get(heading.text) || doc.name, - type: 'heading' as const, - parent: doc.name, - parentSlug, - parentType: 'guide' - })); + const seen = new Set(); + const parentSlug = `docs/guides/${doc.slug}`; + const headingContents = extractHeadingContents(doc.content, doc.toc); + + return doc.toc + .filter((heading: TocEntry) => { + if (seen.has(heading.id)) return false; + seen.add(heading.id); + return true; + }) + .map((heading: TocEntry) => ({ + title: heading.text, + slug: `${parentSlug}#${heading.id}`, + content: headingContents.get(heading.text) || doc.name, + type: 'heading' as const, + parent: doc.name, + parentSlug, + parentType: 'guide', + })); } const topLevelPages: SearchEntry[] = [ - { - title: 'Introduction', - slug: '', - content: 'LayerStack — a collection of Svelte actions, stores, state, table utilities, and general utils', - type: 'page' - } + { + title: 'Introduction', + slug: '', + content: + 'LayerStack — a collection of Svelte actions, stores, state, table utilities, and general utils', + type: 'page', + }, ]; const guides = allGuides.filter((g) => !g.draft); export const searchContent: SearchEntry[] = [ - ...topLevelPages, - ...guides.map(guideToEntry), - ...guides.flatMap(guideHeadingsToEntries), - ...allReferences.map(referenceToEntry), - ...allReferences.flatMap(referenceHeadingsToEntries) + ...topLevelPages, + ...guides.map(guideToEntry), + ...guides.flatMap(guideHeadingsToEntries), + ...allReferences.map(referenceToEntry), + ...allReferences.flatMap(referenceHeadingsToEntries), ]; diff --git a/sites/docs/src/routes/+layout.ts b/sites/docs/src/routes/+layout.ts index 9502b08..bf67ffe 100644 --- a/sites/docs/src/routes/+layout.ts +++ b/sites/docs/src/routes/+layout.ts @@ -8,7 +8,6 @@ export const ssr = false; export const load = async ({ data }) => { // Setup Posthog if (browser && !dev) { - // @ts-expect-error: `posthog.init()` is valid - https://posthog.com/docs/product-analytics/installation posthog.init('phc_F78mUWQpKPpsXS1mamJFzDWM8bivZrwIx4Nm1cI8BSb', { api_host: 'https://app.posthog.com', capture_pageview: false, diff --git a/sites/docs/tsconfig.json b/sites/docs/tsconfig.json index 4b06227..794b95b 100644 --- a/sites/docs/tsconfig.json +++ b/sites/docs/tsconfig.json @@ -8,9 +8,7 @@ "resolveJsonModule": true, "skipLibCheck": true, "sourceMap": true, - "strict": true, - "module": "NodeNext", - "moduleResolution": "NodeNext" + "strict": true } // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // From 7691d358f9862a6047645c340cf32be1b3a5d3ea Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 10:39:40 -0400 Subject: [PATCH 14/21] format --- packages/docs/README.md | 20 +- packages/docs/bin/layerstack-docs.js | 2 +- packages/docs/src/app.d.ts | 2 +- packages/docs/src/cli.ts | 251 ++++--- packages/docs/src/lib/api-types.ts | 42 +- packages/docs/src/lib/catalog.ts | 72 +- packages/docs/src/lib/collections.ts | 12 +- .../docs/src/lib/components/Blockquote.svelte | 18 +- .../src/lib/components/ComponentLink.svelte | 126 ++-- .../src/lib/components/ExampleLink.svelte | 106 +-- .../src/lib/components/ExampleListing.svelte | 336 ++++----- .../lib/components/ExampleScreenshot.svelte | 120 ++-- packages/docs/src/lib/components/Json.svelte | 60 +- .../lib/components/LoadingPlaceholder.svelte | 6 +- .../src/lib/components/OpenWithButton.svelte | 416 +++++------ .../src/lib/components/RelatedLink.svelte | 111 +-- .../docs/src/lib/components/Search.svelte | 628 ++++++++--------- packages/docs/src/lib/components/Step.svelte | 44 +- packages/docs/src/lib/components/Steps.svelte | 6 +- .../src/lib/components/TableOfContents.svelte | 126 ++-- packages/docs/src/lib/components/Tabs.svelte | 106 +-- .../lib/components/ViewSourceButton.svelte | 84 +-- .../docs/src/lib/content-collections/index.js | 569 +++++++-------- packages/docs/src/lib/content.ts | 238 +++---- packages/docs/src/lib/examples-glob.ts | 36 +- packages/docs/src/lib/examples.ts | 164 ++--- packages/docs/src/lib/llms.ts | 475 +++++++------ .../blueprints/default/blueprint.svelte | 44 +- .../src/lib/markdown/components/Button.svelte | 58 +- .../lib/markdown/components/LiveCode.svelte | 26 +- .../src/lib/markdown/components/Note.svelte | 56 +- .../src/lib/markdown/components/Steps.svelte | 6 +- .../src/lib/markdown/components/Tab.svelte | 48 +- .../src/lib/markdown/components/Tabs.svelte | 182 ++--- .../docs/src/lib/markdown/components/a.svelte | 36 +- .../lib/markdown/components/blockquote.svelte | 20 +- .../src/lib/markdown/components/code.svelte | 8 +- .../src/lib/markdown/components/h-base.svelte | 32 +- .../src/lib/markdown/components/h1.svelte | 8 +- .../src/lib/markdown/components/h2.svelte | 14 +- .../src/lib/markdown/components/h3.svelte | 14 +- .../src/lib/markdown/components/h4.svelte | 14 +- .../src/lib/markdown/components/img.svelte | 6 +- .../src/lib/markdown/components/li.svelte | 8 +- .../src/lib/markdown/components/ol.svelte | 8 +- .../docs/src/lib/markdown/components/p.svelte | 8 +- .../src/lib/markdown/components/pre.svelte | 144 ++-- .../src/lib/markdown/components/strong.svelte | 2 +- .../src/lib/markdown/components/table.svelte | 12 +- .../src/lib/markdown/components/td.svelte | 18 +- .../src/lib/markdown/components/th.svelte | 18 +- .../src/lib/markdown/components/tr.svelte | 8 +- .../src/lib/markdown/components/ul.svelte | 8 +- .../docs/src/lib/markdown/config/index.js | 87 ++- .../src/lib/markdown/config/pretty-code.js | 20 +- .../lib/markdown/rehype/component-example.js | 142 ++-- .../lib/markdown/rehype/handle-code-blocks.js | 114 +-- .../docs/src/lib/markdown/rehype/live-code.js | 284 ++++---- .../src/lib/markdown/remark/components.js | 437 ++++++------ packages/docs/src/lib/markdown/toc.ts | 46 +- .../lib/markdown/transformers/shiki-diff.js | 78 +- packages/docs/src/lib/markdown/utils.ts | 60 +- packages/docs/src/lib/node/component-api.js | 667 +++++++++--------- packages/docs/src/lib/node/example-catalog.js | 373 +++++----- packages/docs/src/lib/node/releases.js | 158 +++-- packages/docs/src/lib/node/screenshots.js | 635 +++++++++-------- packages/docs/src/lib/node/stackblitz.js | 159 +++-- packages/docs/src/lib/page-transitions.ts | 22 +- packages/docs/src/lib/project-stats.ts | 174 ++--- packages/docs/src/lib/search.ts | 136 ++-- packages/docs/src/lib/styles.css | 96 +-- packages/docs/src/lib/utils/string.ts | 24 +- packages/docs/svelte.config.js | 8 +- .../stackblitz-template/package.json | 66 +- .../stackblitz-template/src/app.html | 102 +-- .../src/routes/+layout.svelte | 6 +- .../stackblitz-template/svelte.config.js | 28 +- .../stackblitz-template/vite.config.js | 14 +- packages/docs/tsconfig.json | 26 +- sites/docs/content-collections.ts | 14 +- sites/docs/mdsx.config.js | 6 +- .../content/reference/svelte-actions/input.md | 8 +- .../reference/svelte-actions/layout.md | 6 +- .../reference/svelte-state/PaginationState.md | 22 +- .../reference/svelte-state/SelectionState.md | 4 +- .../reference/svelte-state/UniqueState.md | 4 +- .../Duration/format-date-range.svelte | 6 +- .../Duration/format-duration-object.svelte | 2 +- .../format-leap-year-comparison.svelte | 2 +- .../Duration/format-string-range.svelte | 2 +- .../Duration/new-duration-date-range.svelte | 6 +- .../Duration/new-duration-string-range.svelte | 4 +- .../components/MediaQueryPresets/basic.svelte | 154 ++-- .../components/SelectionState/basic.svelte | 26 +- .../SelectionState/initial-selection.svelte | 26 +- .../components/SelectionState/max.svelte | 34 +- .../SelectionState/select-all.svelte | 34 +- .../SelectionState/set-selection.svelte | 26 +- .../components/SelectionState/single.svelte | 26 +- .../components/TimerState/basic.svelte | 16 +- .../components/TimerState/tick-count.svelte | 16 +- .../components/UniqueState/basic.svelte | 26 +- .../components/changeStore/basic.svelte | 10 +- .../components/changeStore/pagination.svelte | 12 +- .../components/dataBackground/basic.svelte | 3 +- .../dataBackground/tailwind-gradient.svelte | 3 +- .../components/debounceStore/basic.svelte | 10 +- .../components/dirtyStore/basic.svelte | 10 +- .../components/format/dates-custom.svelte | 40 +- .../format/dates-period-types.svelte | 92 +-- .../components/format/numbers-config.svelte | 10 +- .../components/format/numbers-default.svelte | 2 +- .../components/format/numbers-options.svelte | 4 +- .../components/format/playground-dates.svelte | 62 +- .../format/playground-numbers.svelte | 104 +-- .../components/matchMedia/basic.svelte | 138 ++-- .../components/mouse/longpress.svelte | 14 +- .../mouse/movable-step-percent.svelte | 42 +- .../components/mouse/movable-step.svelte | 42 +- .../components/mouse/movable-x-axis.svelte | 42 +- .../examples/components/mouse/movable.svelte | 42 +- .../adding-class-when-fully-visible.svelte | 44 +- .../examples/components/observer/basic.svelte | 16 +- .../observer/full-coordinates.svelte | 14 +- .../observer/setting-css-variable.svelte | 18 +- .../show-header-on-scroll-away.svelte | 78 +- .../portal/ancestor-portal-target.svelte | 36 +- .../examples/components/portal/basic.svelte | 28 +- .../components/portal/custom-target.svelte | 34 +- .../components/portal/destroyable.svelte | 48 +- .../portal/first-sibling-portal-target.svelte | 34 +- .../examples/components/scroll/basic.svelte | 26 +- .../components/scroll/only-if-needed.svelte | 26 +- .../components/scroll/scroll-fade-flip.svelte | 28 +- .../scroll/scroll-fade-horizontal.svelte | 16 +- .../components/scroll/scroll-fade.svelte | 12 +- .../scroll-shadow-bottom-surface.svelte | 20 +- .../scroll/scroll-shadow-flip.svelte | 28 +- .../scroll/scroll-shadow-horizontal.svelte | 16 +- .../scroll/scroll-shadow-truncation.svelte | 12 +- .../components/scroll/scroll-shadow.svelte | 12 +- .../components/selectionStore/basic.svelte | 24 +- .../selectionStore/initial-selection.svelte | 24 +- .../components/selectionStore/max.svelte | 26 +- .../selectionStore/select-all.svelte | 32 +- .../components/selectionStore/single.svelte | 26 +- .../global-context-and-css-variables.svelte | 52 +- .../global-context-and-options.svelte | 72 +- .../examples/components/spotlight/line.svelte | 54 +- .../string/truncate-middle-ellipsis.svelte | 4 +- .../string/truncate-playground.svelte | 14 +- .../string/truncate-total-only.svelte | 4 +- .../components/string/unique-basic.svelte | 2 +- .../components/styles/computed-styles.svelte | 72 +- .../components/styles/style-props.svelte | 28 +- .../components/uniqueStore/basic.svelte | 18 +- sites/docs/src/lib/components/Example.svelte | 132 ++-- .../src/lib/components/OpenWithButton.svelte | 20 +- sites/docs/src/lib/content.ts | 28 +- sites/docs/src/lib/examples.ts | 30 +- sites/docs/src/lib/llms.ts | 134 ++-- sites/docs/src/routes/+layout.svelte | 425 ++++++----- sites/docs/src/routes/_NavMenu.svelte | 222 +++--- .../src/routes/api/search.json/+server.ts | 2 +- .../docs/[packageName]/[name]/+page.svelte | 146 ++-- .../routes/docs/[packageName]/[name]/+page.ts | 12 +- .../[packageName]/[name]/llms.txt/+server.ts | 12 +- .../routes/docs/guides/[name]/+page.svelte | 90 +-- .../src/routes/docs/guides/[name]/+page.ts | 6 +- .../docs/guides/[name]/llms.txt/+server.ts | 10 +- .../docs/src/routes/docs/llms.txt/+server.ts | 2 +- sites/docs/src/routes/llms.txt/+server.ts | 2 +- 172 files changed, 6195 insertions(+), 6172 deletions(-) diff --git a/packages/docs/README.md b/packages/docs/README.md index d95d3e5..f870df1 100644 --- a/packages/docs/README.md +++ b/packages/docs/README.md @@ -33,7 +33,7 @@ docs-app/ import { createMdsxConfig } from '@layerstack/docs/markdown/config'; export const mdsxConfig = createMdsxConfig({ - exampleComponentPath: '$lib/components' + exampleComponentPath: '$lib/components', }); ``` @@ -48,8 +48,8 @@ Add a `sourceFile:` frontmatter (relative to `packages/`) only to override the i import { createContentConfig } from '@layerstack/docs/content-collections'; export default createContentConfig({ - packageName: 'layerstack', - repo: 'techniq/layerstack' + packageName: 'layerstack', + repo: 'techniq/layerstack', }); ``` @@ -67,13 +67,13 @@ export default createContentConfig({ ```jsonc { - "scripts": { - "generate:api": "layerstack-docs generate-api ../packages//src/lib/components generated/api", - "generate:catalog": "layerstack-docs generate-catalog ../packages//src/lib/components src/examples/components src/examples/catalog", - "generate:screenshots": "layerstack-docs generate-screenshots src/examples/components static/screenshots", - "generate:stackblitz": "layerstack-docs generate-stackblitz src static/stackblitz-files.json [remote-sources.json]", - "generate:releases": "layerstack-docs generate-releases techniq/ generated/releases" - } + "scripts": { + "generate:api": "layerstack-docs generate-api ../packages//src/lib/components generated/api", + "generate:catalog": "layerstack-docs generate-catalog ../packages//src/lib/components src/examples/components src/examples/catalog", + "generate:screenshots": "layerstack-docs generate-screenshots src/examples/components static/screenshots", + "generate:stackblitz": "layerstack-docs generate-stackblitz src static/stackblitz-files.json [remote-sources.json]", + "generate:releases": "layerstack-docs generate-releases techniq/ generated/releases", + }, } ``` diff --git a/packages/docs/bin/layerstack-docs.js b/packages/docs/bin/layerstack-docs.js index cddfb5f..74fa279 100755 --- a/packages/docs/bin/layerstack-docs.js +++ b/packages/docs/bin/layerstack-docs.js @@ -18,6 +18,6 @@ const binRel = typeof tsxPkg.bin === 'string' ? tsxPkg.bin : tsxPkg.bin.tsx; const tsxBin = join(dirname(tsxPkgPath), binRel); const child = spawn(process.execPath, [tsxBin, cliPath, ...process.argv.slice(2)], { - stdio: 'inherit' + stdio: 'inherit', }); child.on('exit', (code) => process.exit(code ?? 0)); diff --git a/packages/docs/src/app.d.ts b/packages/docs/src/app.d.ts index 777ed40..1209879 100644 --- a/packages/docs/src/app.d.ts +++ b/packages/docs/src/app.d.ts @@ -4,7 +4,7 @@ // See https://svelte.dev/docs/kit/types#app.d.ts declare global { - namespace App {} + namespace App {} } export {}; diff --git a/packages/docs/src/cli.ts b/packages/docs/src/cli.ts index e3bfff5..842531e 100644 --- a/packages/docs/src/cli.ts +++ b/packages/docs/src/cli.ts @@ -11,67 +11,64 @@ import { writeComponentAPIs } from './lib/node/component-api.js'; import { writeExampleCatalogs } from './lib/node/example-catalog.js'; import { generateScreenshots } from './lib/node/screenshots.js'; -import { - generateStackBlitzFiles, - getDefaultStackBlitzTemplateDir -} from './lib/node/stackblitz.js'; +import { generateStackBlitzFiles, getDefaultStackBlitzTemplateDir } from './lib/node/stackblitz.js'; import { generateReleases } from './lib/node/releases.js'; type ParsedArgs = { - positionals: string[]; - options: Record; - multi: Record; + positionals: string[]; + options: Record; + multi: Record; }; /** Flags that may be repeated and collected into a list (e.g. `--source a=b --source c=d`). */ const MULTI_FLAGS = new Set(['source', 'remote']); function parseArgs(argv: string[]): ParsedArgs { - const positionals: string[] = []; - const options: Record = {}; - const multi: Record = {}; - - for (let i = 0; i < argv.length; i++) { - const arg = argv[i]; - if (arg.startsWith('--')) { - let key = arg.slice(2); - let value: string | boolean; - const eq = key.indexOf('='); - if (eq !== -1) { - value = key.slice(eq + 1); - key = key.slice(0, eq); - } else if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) { - value = argv[++i]; - } else { - value = true; - } - if (MULTI_FLAGS.has(key) && typeof value === 'string') { - (multi[key] ??= []).push(value); - } else { - options[key] = value; - } - } else { - positionals.push(arg); - } - } - - return { positionals, options, multi }; + const positionals: string[] = []; + const options: Record = {}; + const multi: Record = {}; + + for (let i = 0; i < argv.length; i++) { + const arg = argv[i]; + if (arg.startsWith('--')) { + let key = arg.slice(2); + let value: string | boolean; + const eq = key.indexOf('='); + if (eq !== -1) { + value = key.slice(eq + 1); + key = key.slice(0, eq); + } else if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) { + value = argv[++i]; + } else { + value = true; + } + if (MULTI_FLAGS.has(key) && typeof value === 'string') { + (multi[key] ??= []).push(value); + } else { + options[key] = value; + } + } else { + positionals.push(arg); + } + } + + return { positionals, options, multi }; } /** Parse `output=source` pairs into a `{ [output]: source }` record. */ function parseKeyValueList(items: string[] = []): Record { - const result: Record = {}; - for (const item of items) { - const eq = item.indexOf('='); - if (eq === -1) continue; - result[item.slice(0, eq)] = item.slice(eq + 1); - } - return result; + const result: Record = {}; + for (const item of items) { + const eq = item.indexOf('='); + if (eq === -1) continue; + result[item.slice(0, eq)] = item.slice(eq + 1); + } + return result; } function optString(options: Record, key: string): string | undefined { - const value = options[key]; - return typeof value === 'string' ? value : undefined; + const value = options[key]; + return typeof value === 'string' ? value : undefined; } const HELP = `layerstack-docs [...args] @@ -86,89 +83,89 @@ Commands: `; async function main() { - const [command, ...rest] = process.argv.slice(2); - const { positionals, options, multi } = parseArgs(rest); - - switch (command) { - case 'generate-api': { - const [componentsDir, outputDir] = positionals; - if (!componentsDir || !outputDir) { - throw new Error('Usage: layerstack-docs generate-api '); - } - writeComponentAPIs({ componentsDir, outputDir }); - break; - } - - case 'generate-catalog': { - const [componentsDir, examplesDir, catalogDir] = positionals; - if (!componentsDir || !examplesDir || !catalogDir) { - throw new Error( - 'Usage: layerstack-docs generate-catalog ' - ); - } - await writeExampleCatalogs({ componentsDir, examplesDir, catalogDir }); - break; - } - - case 'generate-screenshots': { - const [examplesDir, screenshotsDir] = positionals; - if (!examplesDir || !screenshotsDir) { - throw new Error( - 'Usage: layerstack-docs generate-screenshots ' - ); - } - await generateScreenshots({ - examplesDir, - screenshotsDir, - baseUrl: optString(options, 'base-url'), - routeBase: optString(options, 'route-base'), - forceAll: options['all'] === true - }); - break; - } - - case 'generate-stackblitz': { - const [sourceDir, outputFile, remoteSourcesFile] = positionals; - if (!sourceDir || !outputFile) { - throw new Error( - 'Usage: layerstack-docs generate-stackblitz [remote-sources-file]' - ); - } - const templateDir = optString(options, 'template-dir') ?? getDefaultStackBlitzTemplateDir(); - generateStackBlitzFiles({ - templateDir, - sourceDir, - outputFile, - remoteSourcesFile, - sources: parseKeyValueList(multi['source']), - remoteSources: parseKeyValueList(multi['remote']) - }); - break; - } - - case 'generate-releases': { - const [repo, outputDir] = positionals; - if (!repo || !outputDir) { - throw new Error('Usage: layerstack-docs generate-releases '); - } - await generateReleases({ repo, outputDir }); - break; - } - - case undefined: - case '--help': - case '-h': - console.log(HELP); - break; - - default: - console.error(`Unknown command: ${command}\n`); - console.log(HELP); - process.exit(1); - } + const [command, ...rest] = process.argv.slice(2); + const { positionals, options, multi } = parseArgs(rest); + + switch (command) { + case 'generate-api': { + const [componentsDir, outputDir] = positionals; + if (!componentsDir || !outputDir) { + throw new Error('Usage: layerstack-docs generate-api '); + } + writeComponentAPIs({ componentsDir, outputDir }); + break; + } + + case 'generate-catalog': { + const [componentsDir, examplesDir, catalogDir] = positionals; + if (!componentsDir || !examplesDir || !catalogDir) { + throw new Error( + 'Usage: layerstack-docs generate-catalog ' + ); + } + await writeExampleCatalogs({ componentsDir, examplesDir, catalogDir }); + break; + } + + case 'generate-screenshots': { + const [examplesDir, screenshotsDir] = positionals; + if (!examplesDir || !screenshotsDir) { + throw new Error( + 'Usage: layerstack-docs generate-screenshots ' + ); + } + await generateScreenshots({ + examplesDir, + screenshotsDir, + baseUrl: optString(options, 'base-url'), + routeBase: optString(options, 'route-base'), + forceAll: options['all'] === true, + }); + break; + } + + case 'generate-stackblitz': { + const [sourceDir, outputFile, remoteSourcesFile] = positionals; + if (!sourceDir || !outputFile) { + throw new Error( + 'Usage: layerstack-docs generate-stackblitz [remote-sources-file]' + ); + } + const templateDir = optString(options, 'template-dir') ?? getDefaultStackBlitzTemplateDir(); + generateStackBlitzFiles({ + templateDir, + sourceDir, + outputFile, + remoteSourcesFile, + sources: parseKeyValueList(multi['source']), + remoteSources: parseKeyValueList(multi['remote']), + }); + break; + } + + case 'generate-releases': { + const [repo, outputDir] = positionals; + if (!repo || !outputDir) { + throw new Error('Usage: layerstack-docs generate-releases '); + } + await generateReleases({ repo, outputDir }); + break; + } + + case undefined: + case '--help': + case '-h': + console.log(HELP); + break; + + default: + console.error(`Unknown command: ${command}\n`); + console.log(HELP); + process.exit(1); + } } main().catch((err) => { - console.error(err); - process.exit(1); + console.error(err); + process.exit(1); }); diff --git a/packages/docs/src/lib/api-types.ts b/packages/docs/src/lib/api-types.ts index 8b5f1cf..6f66007 100644 --- a/packages/docs/src/lib/api-types.ts +++ b/packages/docs/src/lib/api-types.ts @@ -2,31 +2,31 @@ * Shared types for component API documentation */ export interface PropertyInfo { - name: string; - type: string; - required: boolean; - description?: string; - descriptionHtml?: string; - default?: string; - tags?: Record; - properties?: PropertyInfo[]; + name: string; + type: string; + required: boolean; + description?: string; + descriptionHtml?: string; + default?: string; + tags?: Record; + properties?: PropertyInfo[]; } export interface ExtendedType { - name: string; - /** The full type expression, e.g., "SVGAttributes" */ - fullType: string; - /** For HTML/SVG element types, the element name, e.g., "SVGRectElement" */ - elementType?: string; - /** Whether this is a known library type that should be documented separately */ - isLibraryType?: boolean; + name: string; + /** The full type expression, e.g., "SVGAttributes" */ + fullType: string; + /** For HTML/SVG element types, the element name, e.g., "SVGRectElement" */ + elementType?: string; + /** Whether this is a known library type that should be documented separately */ + isLibraryType?: boolean; } export interface ComponentAPI { - generatedAt: string; - component: string; - propsType: string; - properties: PropertyInfo[]; - /** Types that are extended/intersected (e.g., CommonEvents, SVGAttributes) */ - extends?: ExtendedType[]; + generatedAt: string; + component: string; + propsType: string; + properties: PropertyInfo[]; + /** Types that are extended/intersected (e.g., CommonEvents, SVGAttributes) */ + extends?: ExtendedType[]; } diff --git a/packages/docs/src/lib/catalog.ts b/packages/docs/src/lib/catalog.ts index a4d6a8c..03f68d2 100644 --- a/packages/docs/src/lib/catalog.ts +++ b/packages/docs/src/lib/catalog.ts @@ -9,58 +9,58 @@ * Information about a component usage within an example */ export interface ComponentUsageInExample { - /** The component name */ - component: string; - /** The line number where the component is used */ - lineNumber: number; - /** The trimmed line of code containing the component usage */ - line: string; + /** The component name */ + component: string; + /** The line number where the component is used */ + lineNumber: number; + /** The trimmed line of code containing the component usage */ + line: string; } /** * Information about a specific example for a component */ export interface ExampleInfo { - /** The name of the example (filename without .svelte extension) */ - name: string; - /** Human-readable title (from
    a]:font-medium [&>a]:underline [&>a]:decoration-dashed [&>a]:decoration-primary/50 [&>a]:underline-offset-2' - )} + class={cls( + 'bg-primary/10 border border-l-[6px] border-primary/30 border-l-primary text-primary px-4 py-2 my-4 rounded-sm flex items-center gap-2 text-sm', + '[&>a]:font-medium [&>a]:underline [&>a]:decoration-dashed [&>a]:decoration-primary/50 [&>a]:underline-offset-2' + )} > - - {@render children()} + + {@render children()}
    diff --git a/packages/docs/src/lib/components/ComponentLink.svelte b/packages/docs/src/lib/components/ComponentLink.svelte index db3238f..dd1c319 100644 --- a/packages/docs/src/lib/components/ComponentLink.svelte +++ b/packages/docs/src/lib/components/ComponentLink.svelte @@ -1,75 +1,75 @@ - {#snippet image()} - - {/snippet} + {#snippet image()} + + {/snippet} - {#snippet label()} - + {#snippet label()} + - {component} + {component} -
    - {#each supportedLayers ?? [] as layer} -
    - {layer} -
    - {/each} -
    - {/snippet} +
    + {#each supportedLayers ?? [] as layer} +
    + {layer} +
    + {/each} +
    + {/snippet}
    diff --git a/packages/docs/src/lib/components/ExampleLink.svelte b/packages/docs/src/lib/components/ExampleLink.svelte index 4e7f10e..afe95a6 100644 --- a/packages/docs/src/lib/components/ExampleLink.svelte +++ b/packages/docs/src/lib/components/ExampleLink.svelte @@ -1,63 +1,63 @@ - {#snippet image()} - - {/snippet} + {#snippet image()} + + {/snippet} - {#snippet label()} - + {#snippet label()} + - {#if showComponent} - {component} - - {/if} - {title ?? example.replaceAll('-', ' ')} - {/snippet} + {#if showComponent} + {component} + + {/if} + {title ?? example.replaceAll('-', ' ')} + {/snippet} diff --git a/packages/docs/src/lib/components/ExampleListing.svelte b/packages/docs/src/lib/components/ExampleListing.svelte index cce26e1..2ebf27c 100644 --- a/packages/docs/src/lib/components/ExampleListing.svelte +++ b/packages/docs/src/lib/components/ExampleListing.svelte @@ -1,173 +1,173 @@ {#if hasContent} -
    -

    {title}

    -
    - {#if viewAllHref && catalog.examples?.length} - - {/if} - - - {#snippet prepend()} - - {/snippet} - - -
    -
    -
    -
    - - {#if examples.length} -
    - {#each examples as example (example.name)} - - {/each} -
    - {:else if catalog.examples?.length} -

    No examples match your filter.

    - {/if} - - {#if uniqueUsage.length} - {#if examples.length} - - {showDetails ? 'show less' : 'show more'}... -
    -
    - {#each uniqueUsage as usage (`${usage.component}::${usage.example}`)} - - {/each} -
    -
    -
    - {:else if catalog.examples?.length === 0} -
    - {#each uniqueUsage as usage (`${usage.component}::${usage.example}`)} - - {/each} -
    - {:else if catalog.usage?.length} -

    - No additional usage examples match your filter. -

    - {/if} - {/if} +
    +

    {title}

    +
    + {#if viewAllHref && catalog.examples?.length} + + {/if} + + + {#snippet prepend()} + + {/snippet} + + +
    +
    +
    +
    + + {#if examples.length} +
    + {#each examples as example (example.name)} + + {/each} +
    + {:else if catalog.examples?.length} +

    No examples match your filter.

    + {/if} + + {#if uniqueUsage.length} + {#if examples.length} + + {showDetails ? 'show less' : 'show more'}... +
    +
    + {#each uniqueUsage as usage (`${usage.component}::${usage.example}`)} + + {/each} +
    +
    +
    + {:else if catalog.examples?.length === 0} +
    + {#each uniqueUsage as usage (`${usage.component}::${usage.example}`)} + + {/each} +
    + {:else if catalog.usage?.length} +

    + No additional usage examples match your filter. +

    + {/if} + {/if} {/if} diff --git a/packages/docs/src/lib/components/ExampleScreenshot.svelte b/packages/docs/src/lib/components/ExampleScreenshot.svelte index 3c8b90a..2d12d41 100644 --- a/packages/docs/src/lib/components/ExampleScreenshot.svelte +++ b/packages/docs/src/lib/components/ExampleScreenshot.svelte @@ -1,70 +1,70 @@
    - {#if hasError && fallbackIcon} - {@const FallbackIcon = fallbackIcon} -
    - -
    - {:else if !hasError} - {#each ['light', 'dark'] as mode (mode)} - {#each sizes as size (size.width)} - {component} - {example} (hasError = true)} - /> - {/each} - {/each} - {/if} + {#if hasError && fallbackIcon} + {@const FallbackIcon = fallbackIcon} +
    + +
    + {:else if !hasError} + {#each ['light', 'dark'] as mode (mode)} + {#each sizes as size (size.width)} + {component} - {example} (hasError = true)} + /> + {/each} + {/each} + {/if}
    diff --git a/packages/docs/src/lib/components/Json.svelte b/packages/docs/src/lib/components/Json.svelte index 7d6335c..fb92fb5 100644 --- a/packages/docs/src/lib/components/Json.svelte +++ b/packages/docs/src/lib/components/Json.svelte @@ -1,36 +1,36 @@
    - +
    diff --git a/packages/docs/src/lib/components/LoadingPlaceholder.svelte b/packages/docs/src/lib/components/LoadingPlaceholder.svelte index fb31a55..1ce147d 100644 --- a/packages/docs/src/lib/components/LoadingPlaceholder.svelte +++ b/packages/docs/src/lib/components/LoadingPlaceholder.svelte @@ -1,8 +1,8 @@
    - - Loading... + + Loading...
    diff --git a/packages/docs/src/lib/components/OpenWithButton.svelte b/packages/docs/src/lib/components/OpenWithButton.svelte index 97e92e4..238ace2 100644 --- a/packages/docs/src/lib/components/OpenWithButton.svelte +++ b/packages/docs/src/lib/components/OpenWithButton.svelte @@ -1,221 +1,221 @@ - - - - + + + + (openSourceModal = false)} - class="max-h-[98dvh] md:max-h-[90dvh] max-w-[98vw] md:max-w-[90vw] grid grid-rows-[auto_1fr_auto]" + bind:open={openSourceModal} + on:close={() => (openSourceModal = false)} + class="max-h-[98dvh] md:max-h-[90dvh] max-w-[98vw] md:max-w-[90vw] grid grid-rows-[auto_1fr_auto]" > -
    -
    -
    Source
    -
    {sourceUrl}
    -
    - - {#if sourceUrl} - - {/if} -
    - -
    - -
    - -
    - -
    +
    +
    +
    Source
    +
    {sourceUrl}
    +
    + + {#if sourceUrl} + + {/if} +
    + +
    + +
    + +
    + +
    (openMarkdownModal = false)} - class="max-h-[98dvh] md:max-h-[90dvh] max-w-[98vw] md:max-w-[90vw] grid grid-rows-[auto_1fr_auto]" + bind:open={openMarkdownModal} + on:close={() => (openMarkdownModal = false)} + class="max-h-[98dvh] md:max-h-[90dvh] max-w-[98vw] md:max-w-[90vw] grid grid-rows-[auto_1fr_auto]" > -
    -
    -
    Page Markdown
    -
    {pageUrl}/llms.txt
    -
    - - -
    - -
    - -
    - -
    - -
    +
    +
    +
    Page Markdown
    +
    {pageUrl}/llms.txt
    +
    + + +
    + +
    + +
    + +
    + +
    diff --git a/packages/docs/src/lib/components/RelatedLink.svelte b/packages/docs/src/lib/components/RelatedLink.svelte index 3039bdd..4c8c85e 100644 --- a/packages/docs/src/lib/components/RelatedLink.svelte +++ b/packages/docs/src/lib/components/RelatedLink.svelte @@ -1,59 +1,64 @@ {#if type === 'component'} - + {:else} - + {/if} diff --git a/packages/docs/src/lib/components/Search.svelte b/packages/docs/src/lib/components/Search.svelte index 04364f5..83ebe47 100644 --- a/packages/docs/src/lib/components/Search.svelte +++ b/packages/docs/src/lib/components/Search.svelte @@ -1,328 +1,328 @@ {#if !hideInput} - + {/if} - options} - classes={{ - root: 'w-150 max-w-[95vw]', - field: { - container: 'border-none hover:shadow-none group-focus-within:shadow-none' - }, - options: 'overflow-auto max-h-[min(70dvh,400px)] [scrollbar-width:thin] p-2!' - }} - > - {#snippet prepend()} - - {/snippet} - - {#snippet option({ - option, - index, - highlightIndex - }: { - option: SearchOption; - index: number; - highlightIndex: number; - })} - {@const result = option.result} - {@const isHighlighted = highlightIndex === index} - {@const isHeading = result.type === 'heading'} - -
    - {#if showExampleScreenshots && result.type === 'example' && result.component && result.example} - - {:else} - {@const Icon = typeIcons[result.type] ?? LucideHash} -
    - -
    - {/if} -
    -

    - {#if isHeading && result.parent} - {result.parent} - - {/if} - {@html result.title} -

    -

    - {@html result.content ?? ''} -

    -
    -
    -
    - {/snippet} - - {#snippet empty()} - {#if searchQuery && !searchResults.length} -
    -

    No results found.

    -
    - {/if} - {/snippet} -
    + options} + classes={{ + root: 'w-150 max-w-[95vw]', + field: { + container: 'border-none hover:shadow-none group-focus-within:shadow-none', + }, + options: 'overflow-auto max-h-[min(70dvh,400px)] [scrollbar-width:thin] p-2!', + }} + > + {#snippet prepend()} + + {/snippet} + + {#snippet option({ + option, + index, + highlightIndex, + }: { + option: SearchOption; + index: number; + highlightIndex: number; + })} + {@const result = option.result} + {@const isHighlighted = highlightIndex === index} + {@const isHeading = result.type === 'heading'} + +
    + {#if showExampleScreenshots && result.type === 'example' && result.component && result.example} + + {:else} + {@const Icon = typeIcons[result.type] ?? LucideHash} +
    + +
    + {/if} +
    +

    + {#if isHeading && result.parent} + {result.parent} + + {/if} + {@html result.title} +

    +

    + {@html result.content ?? ''} +

    +
    +
    +
    + {/snippet} + + {#snippet empty()} + {#if searchQuery && !searchResults.length} +
    +

    No results found.

    +
    + {/if} + {/snippet} +
    diff --git a/packages/docs/src/lib/components/Step.svelte b/packages/docs/src/lib/components/Step.svelte index 51a1696..e20d4d8 100644 --- a/packages/docs/src/lib/components/Step.svelte +++ b/packages/docs/src/lib/components/Step.svelte @@ -1,36 +1,36 @@
    -
    -
    +
    +
    -

    - {@html title} -

    - {@render children?.()} +

    + {@html title} +

    + {@render children?.()}
    diff --git a/packages/docs/src/lib/components/Steps.svelte b/packages/docs/src/lib/components/Steps.svelte index 162915b..2d0c2b0 100644 --- a/packages/docs/src/lib/components/Steps.svelte +++ b/packages/docs/src/lib/components/Steps.svelte @@ -1,9 +1,9 @@
    - {@render children?.()} + {@render children?.()}
    diff --git a/packages/docs/src/lib/components/TableOfContents.svelte b/packages/docs/src/lib/components/TableOfContents.svelte index 30d6a87..e9af56e 100644 --- a/packages/docs/src/lib/components/TableOfContents.svelte +++ b/packages/docs/src/lib/components/TableOfContents.svelte @@ -1,78 +1,78 @@ {#if items.length} - + {/if} diff --git a/packages/docs/src/lib/components/Tabs.svelte b/packages/docs/src/lib/components/Tabs.svelte index 071a9e5..0bd7ddc 100644 --- a/packages/docs/src/lib/components/Tabs.svelte +++ b/packages/docs/src/lib/components/Tabs.svelte @@ -1,62 +1,62 @@ - {#each keys as key, v} - {@const isActive = value === v} - {@const Icon = icons?.[v] ?? null} - (value = v)} - selected={isActive} - >{#if Icon}{:else}{/if}{key} - {/each} - -
    - {@render content?.(value)} -
    -
    + {#each keys as key, v} + {@const isActive = value === v} + {@const Icon = icons?.[v] ?? null} + (value = v)} + selected={isActive} + >{#if Icon}{:else}{/if}{key} + {/each} + +
    + {@render content?.(value)} +
    +
    diff --git a/packages/docs/src/lib/components/ViewSourceButton.svelte b/packages/docs/src/lib/components/ViewSourceButton.svelte index 140c788..4cc05e0 100644 --- a/packages/docs/src/lib/components/ViewSourceButton.svelte +++ b/packages/docs/src/lib/components/ViewSourceButton.svelte @@ -1,53 +1,53 @@ {#if source} - - - -
    -
    -
    {label}
    -
    {href}
    -
    + + + +
    +
    +
    {label}
    +
    {href}
    +
    - {#if href} - - {/if} -
    + {#if href} + + {/if} +
    -
    - -
    +
    + +
    -
    - -
    -
    -
    +
    + +
    + + {:else if href} - - - + + + {/if} diff --git a/packages/docs/src/lib/content-collections/index.js b/packages/docs/src/lib/content-collections/index.js index 0dcf171..45484e6 100644 --- a/packages/docs/src/lib/content-collections/index.js +++ b/packages/docs/src/lib/content-collections/index.js @@ -10,309 +10,314 @@ import { extractTocFromMarkdown } from '../markdown/index.js'; import { prettyCodeOptions } from '../markdown/config/pretty-code.js'; import { getFirstExampleName } from '../content.js'; export const componentSchema = z.object({ - name: z.string().optional(), - description: z.string().optional(), - category: z.string().optional(), - layers: z.array(z.string()).default([]), - /** - * Whether the component renders inside an `` layer. - */ - withinLayer: z.boolean().default(true), - related: z.array(z.string()).default([]), - resize: z.boolean().optional(), - tableOfContents: z.boolean().default(true), - order: z.number().optional(), - content: z.string() + name: z.string().optional(), + description: z.string().optional(), + category: z.string().optional(), + layers: z.array(z.string()).default([]), + /** + * Whether the component renders inside an `` layer. + */ + withinLayer: z.boolean().default(true), + related: z.array(z.string()).default([]), + resize: z.boolean().optional(), + tableOfContents: z.boolean().default(true), + order: z.number().optional(), + content: z.string(), }); export const utilSchema = z.object({ - name: z.string().optional(), - description: z.string().optional(), - category: z.string().optional(), - layers: z.array(z.string()).default([]), - related: z.array(z.string()).default([]), - resize: z.boolean().optional(), - tableOfContents: z.boolean().default(true), - order: z.number().optional(), - content: z.string() + name: z.string().optional(), + description: z.string().optional(), + category: z.string().optional(), + layers: z.array(z.string()).default([]), + related: z.array(z.string()).default([]), + resize: z.boolean().optional(), + tableOfContents: z.boolean().default(true), + order: z.number().optional(), + content: z.string(), }); export const guideSchema = z.object({ - title: z.string(), - description: z.string().optional(), - category: z.string().optional(), - order: z.number().optional(), - draft: z.boolean().default(false), - content: z.string() + title: z.string(), + description: z.string().optional(), + category: z.string().optional(), + order: z.number().optional(), + draft: z.boolean().default(false), + content: z.string(), }); export const referenceSchema = z.object({ - title: z.string(), - description: z.string().optional(), - category: z.string().optional(), - packageName: z.string().optional(), - kind: z.string().optional(), - sourceFile: z.string().optional(), - related: z.array(z.string()).default([]), - features: z.array(z.string()).optional(), - hideUsage: z.boolean().optional(), - hideTableOfContents: z.boolean().optional(), - tableOfContents: z.boolean().default(true), - status: z.string().optional(), - order: z.number().optional(), - draft: z.boolean().default(false), - content: z.string() + title: z.string(), + description: z.string().optional(), + category: z.string().optional(), + packageName: z.string().optional(), + kind: z.string().optional(), + sourceFile: z.string().optional(), + related: z.array(z.string()).default([]), + features: z.array(z.string()).optional(), + hideUsage: z.boolean().optional(), + hideTableOfContents: z.boolean().optional(), + tableOfContents: z.boolean().default(true), + status: z.string().optional(), + order: z.number().optional(), + draft: z.boolean().default(false), + content: z.string(), }); export const releaseSchema = z.object({ - title: z.string(), - tag: z.string(), - date: z.coerce.date(), - url: z.string(), - draft: z.boolean().default(false), - prerelease: z.boolean().default(false), - author: z.string(), - content: z.string() + title: z.string(), + tag: z.string(), + date: z.coerce.date(), + url: z.string(), + draft: z.boolean().default(false), + prerelease: z.boolean().default(false), + author: z.string(), + content: z.string(), }); function sourceBase(options) { - return `https://github.com/${options.repo}/blob/${options.branch}/packages/${options.packageName}/src/lib`; + return `https://github.com/${options.repo}/blob/${options.branch}/packages/${options.packageName}/src/lib`; } function readSource(root, sourceUrlBase, rel) { - const full = join(root, rel); - if (!existsSync(full)) - return null; - try { - return { - source: readFileSync(full, 'utf-8'), - url: `${sourceUrlBase}/${rel}` - }; - } - catch { - return null; - } -} -function normalizeOptions(options) { + const full = join(root, rel); + if (!existsSync(full)) return null; + try { return { - packageName: options.packageName, - repo: options.repo ?? `techniq/${options.packageName}`, - branch: options.branch ?? 'next', - packagesRoot: options.packagesRoot ?? '../packages', - referenceDirectory: options.referenceDirectory ?? 'src/content/reference' + source: readFileSync(full, 'utf-8'), + url: `${sourceUrlBase}/${rel}`, }; + } catch { + return null; + } +} +function normalizeOptions(options) { + return { + packageName: options.packageName, + repo: options.repo ?? `techniq/${options.packageName}`, + branch: options.branch ?? 'next', + packagesRoot: options.packagesRoot ?? '../packages', + referenceDirectory: options.referenceDirectory ?? 'src/content/reference', + }; } export function createContentConfig(options) { - const normalized = normalizeOptions(options); - const packagesRoot = join(process.cwd(), normalized.packagesRoot); - const packageRoot = join(packagesRoot, `${normalized.packageName}/src/lib`); - const githubBase = sourceBase(normalized); - const components = defineCollection({ - name: 'components', - directory: 'src/content/components', - include: '**/*.md', - schema: componentSchema, - transform: async (doc, context) => { - const { fileName, path } = doc._meta; - const name = doc.name ?? toPascalCase(fileName.replace('.md', '')); - const componentsRoot = join(packageRoot, 'components'); - const componentsSourceBase = `${githubBase}/components`; - const subdirs = existsSync(componentsRoot) - ? readdirSync(componentsRoot).filter((entry) => !entry.startsWith('.') && statSync(join(componentsRoot, entry)).isDirectory()) - : []; - const searchDirs = ['', ...subdirs.map((d) => `${d}/`)]; - const sources = {}; - const sourceUrls = {}; - let primary = null; - let splitDir = ''; - for (const dir of searchDirs) { - const hit = readSource(componentsRoot, componentsSourceBase, `${dir}${path}/${path}.base.svelte`) ?? - readSource(componentsRoot, componentsSourceBase, `${dir}${path}/${path}.svelte`) ?? - readSource(componentsRoot, componentsSourceBase, `${dir}${path}.svelte`); - if (hit) { - primary = hit; - splitDir = `${dir}${path}/`; - break; - } - } - if (primary && !primary.url.endsWith('.base.svelte')) { - for (const layer of ['svg', 'canvas', 'html']) { - const variant = readSource(componentsRoot, componentsSourceBase, `${splitDir}${path}.${layer}.svelte`); - if (variant) { - sources[layer] = variant.source; - sourceUrls[layer] = variant.url; - } - } - } - const toc = extractTocFromMarkdown(doc.content); - const catalogPath = join(process.cwd(), `src/examples/catalog/${path}.json`); - let catalogFirstExample; - if (existsSync(catalogPath)) { - if (!toc.some((t) => t.id === 'examples')) { - toc.push({ id: 'examples', text: 'Examples', level: 2 }); - } - try { - const catalog = JSON.parse(readFileSync(catalogPath, 'utf-8')); - catalogFirstExample = catalog.examples?.[0]?.name; - } - catch { - // ignore malformed generated catalog files - } - } - const apiPath = join(process.cwd(), `generated/api/${path}.json`); - let api = null; - if (existsSync(apiPath)) { - try { - api = JSON.parse(readFileSync(apiPath, 'utf-8')); - const renderInline = async (text) => { - const html = await compileMarkdown(context, { ...doc, content: text }, { - remarkPlugins: [remarkGfm] - }); - return html - .replace(/^

    /, '') - .replace(/<\/p>\s*$/, '') - .trim(); - }; - const walk = async (props = []) => { - for (const p of props) { - if (p.description) - p.descriptionHtml = await renderInline(p.description); - if (p.properties) - await walk(p.properties); - } - }; - await walk(api.properties); - if (api.properties?.length) { - toc.push({ id: 'api-reference', text: 'API Reference', level: 2 }); - } - } - catch { - // ignore malformed generated API files - } - } - if (doc.related.length) { - toc.push({ id: 'related', text: 'Related', level: 2 }); - } - return { - ...doc, - name, - slug: path, - source: primary?.source ?? '', - sourceUrl: primary?.url ?? '', - sources, - sourceUrls, - defaultExample: getFirstExampleName(doc.content) ?? catalogFirstExample, - toc, - api - }; + const normalized = normalizeOptions(options); + const packagesRoot = join(process.cwd(), normalized.packagesRoot); + const packageRoot = join(packagesRoot, `${normalized.packageName}/src/lib`); + const githubBase = sourceBase(normalized); + const components = defineCollection({ + name: 'components', + directory: 'src/content/components', + include: '**/*.md', + schema: componentSchema, + transform: async (doc, context) => { + const { fileName, path } = doc._meta; + const name = doc.name ?? toPascalCase(fileName.replace('.md', '')); + const componentsRoot = join(packageRoot, 'components'); + const componentsSourceBase = `${githubBase}/components`; + const subdirs = existsSync(componentsRoot) + ? readdirSync(componentsRoot).filter( + (entry) => !entry.startsWith('.') && statSync(join(componentsRoot, entry)).isDirectory() + ) + : []; + const searchDirs = ['', ...subdirs.map((d) => `${d}/`)]; + const sources = {}; + const sourceUrls = {}; + let primary = null; + let splitDir = ''; + for (const dir of searchDirs) { + const hit = + readSource(componentsRoot, componentsSourceBase, `${dir}${path}/${path}.base.svelte`) ?? + readSource(componentsRoot, componentsSourceBase, `${dir}${path}/${path}.svelte`) ?? + readSource(componentsRoot, componentsSourceBase, `${dir}${path}.svelte`); + if (hit) { + primary = hit; + splitDir = `${dir}${path}/`; + break; } - }); - const utils = defineCollection({ - name: 'utils', - directory: 'src/content/utils', - include: '**/*.md', - schema: utilSchema, - transform: async (doc) => { - const { fileName, path } = doc._meta; - const source = readSource(join(packageRoot, 'utils'), `${githubBase}/utils`, `${path}.ts`); - return { - ...doc, - name: doc.name ?? fileName.replace('.md', ''), - slug: fileName.replace('.md', '').toLowerCase(), - source: source?.source ?? '', - sourceUrl: source?.url ?? '', - toc: extractTocFromMarkdown(doc.content) - }; + } + if (primary && !primary.url.endsWith('.base.svelte')) { + for (const layer of ['svg', 'canvas', 'html']) { + const variant = readSource( + componentsRoot, + componentsSourceBase, + `${splitDir}${path}.${layer}.svelte` + ); + if (variant) { + sources[layer] = variant.source; + sourceUrls[layer] = variant.url; + } } - }); - const guides = defineCollection({ - name: 'guides', - directory: 'src/content/guides', - include: '**/*.md', - schema: guideSchema, - transform: async (doc) => { - const { path } = doc._meta; - return { - ...doc, - name: doc.title, - slug: path, - toc: extractTocFromMarkdown(doc.content) - }; + } + const toc = extractTocFromMarkdown(doc.content); + const catalogPath = join(process.cwd(), `src/examples/catalog/${path}.json`); + let catalogFirstExample; + if (existsSync(catalogPath)) { + if (!toc.some((t) => t.id === 'examples')) { + toc.push({ id: 'examples', text: 'Examples', level: 2 }); } - }); - const references = defineCollection({ - name: 'references', - directory: normalized.referenceDirectory, - include: '**/*.md', - schema: referenceSchema, - transform: async (doc) => { - const { path } = doc._meta; - const referenceSourceBase = `https://github.com/${normalized.repo}/blob/${normalized.branch}/packages`; - - // Explicit `sourceFile` (relative to `packages/`) always wins. Otherwise infer - // the source from the conventional `/src/lib/.{ts,svelte.ts}` location - // derived from the doc path (e.g. `svelte-stores/debounceStore`). A camelCase fallback - // covers PascalCase items (`utils/Duration` -> `duration.ts`, - // `svelte-state/SelectionState` -> `selectionState.svelte.ts`). - const explicit = doc.sourceFile?.replace(/^\/?packages\//, '').replace(/^\//, ''); - let source = null; - let sourceFile = explicit; - - if (explicit) { - source = readSource(packagesRoot, referenceSourceBase, explicit); - } else { - const segments = path.split('/'); - const pkg = segments[0]; - const rest = segments.slice(1); - if (pkg && rest.length) { - const dir = rest.slice(0, -1).join('/'); - const item = rest[rest.length - 1]; - const camelItem = item.charAt(0).toLowerCase() + item.slice(1); - const prefix = `${pkg}/src/lib/${dir ? `${dir}/` : ''}`; - const candidates = [ - `${prefix}${item}.ts`, - `${prefix}${item}.svelte.ts`, - `${prefix}${camelItem}.ts`, - `${prefix}${camelItem}.svelte.ts` - ]; - for (const candidate of candidates) { - const hit = readSource(packagesRoot, referenceSourceBase, candidate); - if (hit) { - source = hit; - sourceFile = candidate; - break; - } - } - } + try { + const catalog = JSON.parse(readFileSync(catalogPath, 'utf-8')); + catalogFirstExample = catalog.examples?.[0]?.name; + } catch { + // ignore malformed generated catalog files + } + } + const apiPath = join(process.cwd(), `generated/api/${path}.json`); + let api = null; + if (existsSync(apiPath)) { + try { + api = JSON.parse(readFileSync(apiPath, 'utf-8')); + const renderInline = async (text) => { + const html = await compileMarkdown( + context, + { ...doc, content: text }, + { + remarkPlugins: [remarkGfm], + } + ); + return html + .replace(/^

    /, '') + .replace(/<\/p>\s*$/, '') + .trim(); + }; + const walk = async (props = []) => { + for (const p of props) { + if (p.description) p.descriptionHtml = await renderInline(p.description); + if (p.properties) await walk(p.properties); } + }; + await walk(api.properties); + if (api.properties?.length) { + toc.push({ id: 'api-reference', text: 'API Reference', level: 2 }); + } + } catch { + // ignore malformed generated API files + } + } + if (doc.related.length) { + toc.push({ id: 'related', text: 'Related', level: 2 }); + } + return { + ...doc, + name, + slug: path, + source: primary?.source ?? '', + sourceUrl: primary?.url ?? '', + sources, + sourceUrls, + defaultExample: getFirstExampleName(doc.content) ?? catalogFirstExample, + toc, + api, + }; + }, + }); + const utils = defineCollection({ + name: 'utils', + directory: 'src/content/utils', + include: '**/*.md', + schema: utilSchema, + transform: async (doc) => { + const { fileName, path } = doc._meta; + const source = readSource(join(packageRoot, 'utils'), `${githubBase}/utils`, `${path}.ts`); + return { + ...doc, + name: doc.name ?? fileName.replace('.md', ''), + slug: fileName.replace('.md', '').toLowerCase(), + source: source?.source ?? '', + sourceUrl: source?.url ?? '', + toc: extractTocFromMarkdown(doc.content), + }; + }, + }); + const guides = defineCollection({ + name: 'guides', + directory: 'src/content/guides', + include: '**/*.md', + schema: guideSchema, + transform: async (doc) => { + const { path } = doc._meta; + return { + ...doc, + name: doc.title, + slug: path, + toc: extractTocFromMarkdown(doc.content), + }; + }, + }); + const references = defineCollection({ + name: 'references', + directory: normalized.referenceDirectory, + include: '**/*.md', + schema: referenceSchema, + transform: async (doc) => { + const { path } = doc._meta; + const referenceSourceBase = `https://github.com/${normalized.repo}/blob/${normalized.branch}/packages`; + + // Explicit `sourceFile` (relative to `packages/`) always wins. Otherwise infer + // the source from the conventional `/src/lib/.{ts,svelte.ts}` location + // derived from the doc path (e.g. `svelte-stores/debounceStore`). A camelCase fallback + // covers PascalCase items (`utils/Duration` -> `duration.ts`, + // `svelte-state/SelectionState` -> `selectionState.svelte.ts`). + const explicit = doc.sourceFile?.replace(/^\/?packages\//, '').replace(/^\//, ''); + let source = null; + let sourceFile = explicit; - const toc = extractTocFromMarkdown(doc.content); - if (doc.related.length) { - toc.push({ id: 'related', text: 'Related', level: 2 }); + if (explicit) { + source = readSource(packagesRoot, referenceSourceBase, explicit); + } else { + const segments = path.split('/'); + const pkg = segments[0]; + const rest = segments.slice(1); + if (pkg && rest.length) { + const dir = rest.slice(0, -1).join('/'); + const item = rest[rest.length - 1]; + const camelItem = item.charAt(0).toLowerCase() + item.slice(1); + const prefix = `${pkg}/src/lib/${dir ? `${dir}/` : ''}`; + const candidates = [ + `${prefix}${item}.ts`, + `${prefix}${item}.svelte.ts`, + `${prefix}${camelItem}.ts`, + `${prefix}${camelItem}.svelte.ts`, + ]; + for (const candidate of candidates) { + const hit = readSource(packagesRoot, referenceSourceBase, candidate); + if (hit) { + source = hit; + sourceFile = candidate; + break; } - return { - ...doc, - name: doc.title, - slug: path, - sourceFile, - source: source?.source ?? '', - sourceUrl: source?.url ?? '', - toc - }; + } } - }); - const releases = defineCollection({ - name: 'releases', - directory: 'generated/releases', - include: '**/*.md', - schema: releaseSchema, - transform: async (doc, context) => { - const { fileName } = doc._meta; - return { - ...doc, - slug: fileName.replace('.md', ''), - html: await compileMarkdown(context, doc, { - remarkPlugins: [remarkGfm], - rehypePlugins: [[rehypePrettyCode, prettyCodeOptions]] - }) - }; - } - }); - return defineConfig({ - content: [components, utils, guides, references, releases] - }); + } + + const toc = extractTocFromMarkdown(doc.content); + if (doc.related.length) { + toc.push({ id: 'related', text: 'Related', level: 2 }); + } + return { + ...doc, + name: doc.title, + slug: path, + sourceFile, + source: source?.source ?? '', + sourceUrl: source?.url ?? '', + toc, + }; + }, + }); + const releases = defineCollection({ + name: 'releases', + directory: 'generated/releases', + include: '**/*.md', + schema: releaseSchema, + transform: async (doc, context) => { + const { fileName } = doc._meta; + return { + ...doc, + slug: fileName.replace('.md', ''), + html: await compileMarkdown(context, doc, { + remarkPlugins: [remarkGfm], + rehypePlugins: [[rehypePrettyCode, prettyCodeOptions]], + }), + }; + }, + }); + return defineConfig({ + content: [components, utils, guides, references, releases], + }); } diff --git a/packages/docs/src/lib/content.ts b/packages/docs/src/lib/content.ts index 19f28c4..9adda2b 100644 --- a/packages/docs/src/lib/content.ts +++ b/packages/docs/src/lib/content.ts @@ -6,154 +6,154 @@ export type ContentPaths = Partial>; export type { Examples } from './examples.js'; export type ExampleReference = - | { kind: 'component'; component?: string; name: string } - | { kind: 'path'; path: string }; + | { kind: 'component'; component?: string; name: string } + | { kind: 'path'; path: string }; const defaultContentPaths: Record = { - components: '/src/content/components', - utils: '/src/content/utils', - guides: '/src/content/guides', - reference: '/src/content/reference' + components: '/src/content/components', + utils: '/src/content/utils', + guides: '/src/content/guides', + reference: '/src/content/reference', }; function getContentPath(type: ContentType, contentPaths?: ContentPaths): string { - return contentPaths?.[type] ?? defaultContentPaths[type]; + return contentPaths?.[type] ?? defaultContentPaths[type]; } /** * Resolve a relative or absolute example path to the conventional Vite `/src/...` key. */ export function resolveExamplePath( - path: string, - currentPath: string, - type: ContentType = 'components', - contentPaths?: ContentPaths + path: string, + currentPath: string, + type: ContentType = 'components', + contentPaths?: ContentPaths ): string { - if ( - (type === 'guides' || type === 'reference') && - (path.startsWith('./') || !path.startsWith('/')) - ) { - const relativePath = path.startsWith('./') ? path.slice(2) : path; - return `${getContentPath(type, contentPaths)}/${relativePath}`; - } - if (path.startsWith('./')) { - return `/src/routes${currentPath}/${path.slice(2)}`; - } - if (path.startsWith('/')) { - return `/src${path}`; - } - return `/src/routes${currentPath}/${path}`; + if ( + (type === 'guides' || type === 'reference') && + (path.startsWith('./') || !path.startsWith('/')) + ) { + const relativePath = path.startsWith('./') ? path.slice(2) : path; + return `${getContentPath(type, contentPaths)}/${relativePath}`; + } + if (path.startsWith('./')) { + return `/src/routes${currentPath}/${path.slice(2)}`; + } + if (path.startsWith('/')) { + return `/src${path}`; + } + return `/src/routes${currentPath}/${path}`; } /** * Extract examples referenced by `` or `:example{...}` markdown syntax. */ export function extractExampleReferences(markdownContent: string): ExampleReference[] { - const componentRegex = /]*?)\/>/g; - const mdcRegex = /:example\{([^}]*?)\}/g; - const matches = [ - ...markdownContent.matchAll(componentRegex), - ...markdownContent.matchAll(mdcRegex) - ]; - return matches.flatMap((match): ExampleReference[] => { - const attrs = match[1]; - const path = attrs.match(/path="([^"]*?)"/)?.[1]; - if (path) return [{ kind: 'path', path }]; - const component = attrs.match(/component="([^"]*?)"/)?.[1]; - const name = attrs.match(/name="([^"]*?)"/)?.[1]; - if (!name) return []; - return [{ kind: 'component', component, name }]; - }); + const componentRegex = /]*?)\/>/g; + const mdcRegex = /:example\{([^}]*?)\}/g; + const matches = [ + ...markdownContent.matchAll(componentRegex), + ...markdownContent.matchAll(mdcRegex), + ]; + return matches.flatMap((match): ExampleReference[] => { + const attrs = match[1]; + const path = attrs.match(/path="([^"]*?)"/)?.[1]; + if (path) return [{ kind: 'path', path }]; + const component = attrs.match(/component="([^"]*?)"/)?.[1]; + const name = attrs.match(/name="([^"]*?)"/)?.[1]; + if (!name) return []; + return [{ kind: 'component', component, name }]; + }); } export function getFirstExampleName(markdownContent: string): string | undefined { - return ( - markdownContent.match(/]*name=["']([^"']+)["'][^>]*>/)?.[1] || - markdownContent.match(/:example\{[^}]*name=["']([^"']+)["'][^}]*\}/)?.[1] - ); + return ( + markdownContent.match(/]*name=["']([^"']+)["'][^>]*>/)?.[1] || + markdownContent.match(/:example\{[^}]*name=["']([^"']+)["'][^}]*\}/)?.[1] + ); } export type MarkdownModule = { - default: Component; - metadata: Metadata; + default: Component; + metadata: Metadata; }; export function createContentLoaders(options: { - modules: Record Promise>>; - contentPaths?: ContentPaths; - getMetadata: (slug: string, type: ContentType) => Metadata | undefined; - loadExample: ( - component: string, - name: string, - type?: ExampleType - ) => Promise; - loadExampleByPath: (path: string) => Promise; - notFound: () => never; + modules: Record Promise>>; + contentPaths?: ContentPaths; + getMetadata: (slug: string, type: ContentType) => Metadata | undefined; + loadExample: ( + component: string, + name: string, + type?: ExampleType + ) => Promise; + loadExampleByPath: (path: string) => Promise; + notFound: () => never; }) { - async function getMarkdownComponent( - slug: string = 'index', - type: ContentType = 'components' - ): Promise<{ PageComponent: Component; metadata: Metadata }> { - const resolver = options.modules[`${getContentPath(type, options.contentPaths)}/${slug}.md`]; - const [doc, metadata] = await Promise.all([resolver?.(), options.getMetadata(slug, type)]); - if (!doc || !metadata) { - options.notFound(); - } - return { - PageComponent: doc.default, - metadata - }; - } + async function getMarkdownComponent( + slug: string = 'index', + type: ContentType = 'components' + ): Promise<{ PageComponent: Component; metadata: Metadata }> { + const resolver = options.modules[`${getContentPath(type, options.contentPaths)}/${slug}.md`]; + const [doc, metadata] = await Promise.all([resolver?.(), options.getMetadata(slug, type)]); + if (!doc || !metadata) { + options.notFound(); + } + return { + PageComponent: doc.default, + metadata, + }; + } - async function loadExamplesFromMarkdown( - markdownContent: string, - defaultComponent?: string, - type: ContentType = 'components', - currentPath?: string - ): Promise>> { - const refs = extractExampleReferences(markdownContent); - const componentExamples = refs.flatMap((ref) => { - if (ref.kind !== 'component') return []; - const component = ref.component ?? defaultComponent; - if (!component) return []; - return [{ component, name: ref.name }]; - }); - const pathExamples = refs.flatMap((ref) => { - if (ref.kind !== 'path' || !currentPath) return []; - return [ - { - path: ref.path, - resolvedPath: resolveExamplePath(ref.path, currentPath, type, options.contentPaths) - } - ]; - }); + async function loadExamplesFromMarkdown( + markdownContent: string, + defaultComponent?: string, + type: ContentType = 'components', + currentPath?: string + ): Promise>> { + const refs = extractExampleReferences(markdownContent); + const componentExamples = refs.flatMap((ref) => { + if (ref.kind !== 'component') return []; + const component = ref.component ?? defaultComponent; + if (!component) return []; + return [{ component, name: ref.name }]; + }); + const pathExamples = refs.flatMap((ref) => { + if (ref.kind !== 'path' || !currentPath) return []; + return [ + { + path: ref.path, + resolvedPath: resolveExamplePath(ref.path, currentPath, type, options.contentPaths), + }, + ]; + }); - const examples: Record> = {}; - await Promise.all( - componentExamples.map(async (ex) => { - const exampleType: ExampleType = type === 'utils' ? 'utils' : 'components'; - const loaded = await options.loadExample(ex.component, ex.name, exampleType); - if (loaded) { - if (!examples[ex.component]) { - examples[ex.component] = {}; - } - examples[ex.component][ex.name] = loaded; - } - }) - ); - if (pathExamples.length > 0) { - examples['__path__'] = {}; - await Promise.all( - pathExamples.map(async (ex) => { - const loaded = await options.loadExampleByPath(ex.resolvedPath); - if (loaded) { - examples['__path__'][ex.resolvedPath] = loaded; - } - }) - ); - } - return examples; - } + const examples: Record> = {}; + await Promise.all( + componentExamples.map(async (ex) => { + const exampleType: ExampleType = type === 'utils' ? 'utils' : 'components'; + const loaded = await options.loadExample(ex.component, ex.name, exampleType); + if (loaded) { + if (!examples[ex.component]) { + examples[ex.component] = {}; + } + examples[ex.component][ex.name] = loaded; + } + }) + ); + if (pathExamples.length > 0) { + examples['__path__'] = {}; + await Promise.all( + pathExamples.map(async (ex) => { + const loaded = await options.loadExampleByPath(ex.resolvedPath); + if (loaded) { + examples['__path__'][ex.resolvedPath] = loaded; + } + }) + ); + } + return examples; + } - return { getMarkdownComponent, loadExamplesFromMarkdown }; + return { getMarkdownComponent, loadExamplesFromMarkdown }; } diff --git a/packages/docs/src/lib/examples-glob.ts b/packages/docs/src/lib/examples-glob.ts index 62b5399..c139e64 100644 --- a/packages/docs/src/lib/examples-glob.ts +++ b/packages/docs/src/lib/examples-glob.ts @@ -8,28 +8,28 @@ * Using import.meta.glob causes Vite to pre-transform all matched files during development. */ export const componentExamples: Record Promise> = import.meta.glob( - '/src/examples/components/**/*.svelte', - { - import: 'default' - } + '/src/examples/components/**/*.svelte', + { + import: 'default', + } ); export const componentSources: Record Promise> = import.meta.glob( - '/src/examples/components/**/*.svelte', - { - import: 'default', - query: '?raw' - } + '/src/examples/components/**/*.svelte', + { + import: 'default', + query: '?raw', + } ); export const utilExamples: Record Promise> = import.meta.glob( - '/src/examples/utils/**/*.svelte', - { - import: 'default' - } + '/src/examples/utils/**/*.svelte', + { + import: 'default', + } ); export const utilSources: Record Promise> = import.meta.glob( - '/src/examples/utils/**/*.svelte', - { - import: 'default', - query: '?raw' - } + '/src/examples/utils/**/*.svelte', + { + import: 'default', + query: '?raw', + } ); diff --git a/packages/docs/src/lib/examples.ts b/packages/docs/src/lib/examples.ts index 2951d23..5d0d8d3 100644 --- a/packages/docs/src/lib/examples.ts +++ b/packages/docs/src/lib/examples.ts @@ -1,109 +1,109 @@ import type { Component } from 'svelte'; export type LoadedExample = { - component: Component; - source: string; - module?: { - title?: string; - description?: string; - layers?: string[]; - }; + component: Component; + source: string; + module?: { + title?: string; + description?: string; + layers?: string[]; + }; }; export type Examples = Record>; export type ExampleType = 'components' | 'utils'; export type ComponentExampleImporter = ( - type: ExampleType, - component: string, - name: string + type: ExampleType, + component: string, + name: string ) => Promise<{ default: Component; title?: string; description?: string; layers?: string[] }>; export type RawExampleImporter = ( - type: ExampleType, - component: string, - name: string + type: ExampleType, + component: string, + name: string ) => Promise; export type PathExampleImporter = (path: string) => Promise<{ default: Component } | undefined>; export type RawPathExampleImporter = (path: string) => Promise; export function cleanExampleSource(source: string): string { - return source - .replace(/[\s\S]*?<\/script>\n*/g, '') - .replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n'); + return source + .replace(/[\s\S]*?<\/script>\n*/g, '') + .replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n'); } export function cleanPathExampleSource(source: string): string { - return source.replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n'); + return source.replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n'); } export function createExampleLoaders(options: { - loadComponentExample: ComponentExampleImporter; - loadRawExample: RawExampleImporter; - loadPathExample: PathExampleImporter; - loadRawPathExample: RawPathExampleImporter; - warn?: typeof console.warn; + loadComponentExample: ComponentExampleImporter; + loadRawExample: RawExampleImporter; + loadPathExample: PathExampleImporter; + loadRawPathExample: RawPathExampleImporter; + warn?: typeof console.warn; }) { - const warn = options.warn ?? console.warn; + const warn = options.warn ?? console.warn; - async function loadExample( - component: string, - name: string, - type: ExampleType = 'components' - ): Promise { - try { - const [componentModule, rawSource] = await Promise.all([ - options.loadComponentExample(type, component, name), - options.loadRawExample(type, component, name) - ]); - const { default: comp, ...module } = componentModule; - return { - component: comp, - source: cleanExampleSource(rawSource), - module - }; - } catch (e) { - warn(`Failed to load example: ${type}/${component}/${name}`, e); - return null; - } - } + async function loadExample( + component: string, + name: string, + type: ExampleType = 'components' + ): Promise { + try { + const [componentModule, rawSource] = await Promise.all([ + options.loadComponentExample(type, component, name), + options.loadRawExample(type, component, name), + ]); + const { default: comp, ...module } = componentModule; + return { + component: comp, + source: cleanExampleSource(rawSource), + module, + }; + } catch (e) { + warn(`Failed to load example: ${type}/${component}/${name}`, e); + return null; + } + } - async function loadExamples( - items: Array<{ component: string; name: string }>, - type: ExampleType = 'components' - ): Promise { - const results: Examples = {}; - await Promise.all( - items.map(async ({ component, name }) => { - const example = await loadExample(component, name, type); - if (example) { - if (!results[component]) { - results[component] = {}; - } - results[component][name] = example; - } - }) - ); - return results; - } + async function loadExamples( + items: Array<{ component: string; name: string }>, + type: ExampleType = 'components' + ): Promise { + const results: Examples = {}; + await Promise.all( + items.map(async ({ component, name }) => { + const example = await loadExample(component, name, type); + if (example) { + if (!results[component]) { + results[component] = {}; + } + results[component][name] = example; + } + }) + ); + return results; + } - async function loadExampleByPath(resolvedPath: string): Promise { - try { - const [componentModule, rawSource] = await Promise.all([ - options.loadPathExample(resolvedPath), - options.loadRawPathExample(resolvedPath) - ]); - if (!componentModule || rawSource === undefined) { - warn(`Failed to load example by path: ${resolvedPath}`); - return null; - } - return { - component: componentModule.default, - source: cleanPathExampleSource(rawSource) - }; - } catch (e) { - warn(`Failed to load example by path: ${resolvedPath}`, e); - return null; - } - } + async function loadExampleByPath(resolvedPath: string): Promise { + try { + const [componentModule, rawSource] = await Promise.all([ + options.loadPathExample(resolvedPath), + options.loadRawPathExample(resolvedPath), + ]); + if (!componentModule || rawSource === undefined) { + warn(`Failed to load example by path: ${resolvedPath}`); + return null; + } + return { + component: componentModule.default, + source: cleanPathExampleSource(rawSource), + }; + } catch (e) { + warn(`Failed to load example by path: ${resolvedPath}`, e); + return null; + } + } - return { loadExample, loadExamples, loadExampleByPath }; + return { loadExample, loadExamples, loadExampleByPath }; } diff --git a/packages/docs/src/lib/llms.ts b/packages/docs/src/lib/llms.ts index 63ebc75..c1d9519 100644 --- a/packages/docs/src/lib/llms.ts +++ b/packages/docs/src/lib/llms.ts @@ -8,49 +8,48 @@ import type { ComponentAPI } from './api-types.js'; /** Create a `text/markdown` response for an llms.txt endpoint. */ export function markdownResponse(content: string, filename: string): Response { - return new Response(content, { - headers: { - 'Content-Type': 'text/markdown; charset=utf-8', - 'Content-Disposition': `inline; filename="${filename}"` - } - }); + return new Response(content, { + headers: { + 'Content-Type': 'text/markdown; charset=utf-8', + 'Content-Disposition': `inline; filename="${filename}"`, + }, + }); } /** Strip `') - .trim(); + return code + .replace(/[\s\S]*?<\/script>\n*/g, '') + .replace(/\n*\s*export \{ data \};\s*\n*\s*<\/script>/gm, '\n') + .trim(); } function escapeMarkdown(text: string): string { - return text - .replace(/\|/g, '\\|') - .replace(/\n/g, ' ') - .replace(//g, '>'); + return text.replace(/\|/g, '\\|').replace(/\n/g, ' ').replace(//g, '>'); } /** Generate a markdown API table from a component's `ComponentAPI` properties. */ export function generateApiTable(api: ComponentAPI): string { - if (!api.properties || api.properties.length === 0) return ''; + if (!api.properties || api.properties.length === 0) return ''; - const rows = api.properties.map((prop) => { - const name = prop.required ? `**${prop.name}** (required)` : prop.name; - const type = `\`${escapeMarkdown(prop.type)}\``; - const defaultVal = prop.default ? `\`${escapeMarkdown(prop.default)}\`` : '-'; - const description = prop.description ? escapeMarkdown(prop.description) : '-'; - return `| ${name} | ${type} | ${defaultVal} | ${description} |`; - }); + const rows = api.properties.map((prop) => { + const name = prop.required ? `**${prop.name}** (required)` : prop.name; + const type = `\`${escapeMarkdown(prop.type)}\``; + const defaultVal = prop.default ? `\`${escapeMarkdown(prop.default)}\`` : '-'; + const description = prop.description ? escapeMarkdown(prop.description) : '-'; + return `| ${name} | ${type} | ${defaultVal} | ${description} |`; + }); - return `| Property | Type | Default | Description | + return `| Property | Type | Default | Description | |----------|------|---------|-------------| ${rows.join('\n')}`; } /** Resolve the raw source for an example, by component (optional) + name. */ -export type ExampleSourceResolver = (component: string | undefined, name: string) => string | undefined; +export type ExampleSourceResolver = ( + component: string | undefined, + name: string +) => string | undefined; /** Build a docs URL for a (cross-component) example reference. */ export type ExampleUrlResolver = (component: string, name: string) => string; @@ -63,33 +62,33 @@ export type ExampleUrlResolver = (component: string, name: string) => string; * reference — a markdown link if `exampleUrl` is provided, otherwise plain text. */ export function inlineExampleDirectives( - content: string, - resolveSource: ExampleSourceResolver, - defaultComponent?: string, - exampleUrl?: ExampleUrlResolver + content: string, + resolveSource: ExampleSourceResolver, + defaultComponent?: string, + exampleUrl?: ExampleUrlResolver ): string { - // Strip HTML comments first so commented-out examples aren't inlined - content = content.replace(//g, ''); - - // Cross-component examples: :example{ component="X" name="Y" ... } (run first) - content = content.replace( - /:example\{\s*component="([^"]+)"\s+name="([^"]+)"[^}]*\}/g, - (_match, component: string, name: string) => { - const raw = resolveSource(component, name); - if (raw) return '```svelte\n' + trimCode(raw) + '\n```'; - return exampleUrl - ? `See example: [${component}/${name}](${exampleUrl(component, name)})` - : `See example: ${component}/${name}`; - } - ); - - // Same-component examples: :example{ name="Y" ... } - content = content.replace(/:example\{\s*name="([^"]+)"[^}]*\}/g, (_match, name: string) => { - const raw = resolveSource(defaultComponent, name); - return raw ? '```svelte\n' + trimCode(raw) + '\n```' : `See example: ${name}`; - }); - - return content; + // Strip HTML comments first so commented-out examples aren't inlined + content = content.replace(//g, ''); + + // Cross-component examples: :example{ component="X" name="Y" ... } (run first) + content = content.replace( + /:example\{\s*component="([^"]+)"\s+name="([^"]+)"[^}]*\}/g, + (_match, component: string, name: string) => { + const raw = resolveSource(component, name); + if (raw) return '```svelte\n' + trimCode(raw) + '\n```'; + return exampleUrl + ? `See example: [${component}/${name}](${exampleUrl(component, name)})` + : `See example: ${component}/${name}`; + } + ); + + // Same-component examples: :example{ name="Y" ... } + content = content.replace(/:example\{\s*name="([^"]+)"[^}]*\}/g, (_match, name: string) => { + const raw = resolveSource(defaultComponent, name); + return raw ? '```svelte\n' + trimCode(raw) + '\n```' : `See example: ${name}`; + }); + + return content; } /** @@ -97,99 +96,99 @@ export function inlineExampleDirectives( * suitable for LLM consumption. */ export function processMarkdownContent( - content: string, - options?: { exampleUrl?: ExampleUrlResolver } + content: string, + options?: { exampleUrl?: ExampleUrlResolver } ): string { - // Remove frontmatter - content = content.replace(/^---\n[\s\S]*?\n---\n*/, ''); - - // Remove HTML comments - content = content.replace(//g, ''); - - // Remove Svelte script blocks and components ONLY outside of code blocks - content = content - .split(/(```[\s\S]*?```)/g) - .map((part, index) => { - if (index % 2 === 1) return part; // code block — leave as-is - part = part.replace(/]*>[\s\S]*?<\/script>\n*/g, ''); - part = part.replace(/<[A-Z][a-zA-Z]*[^>]*\/>\n*/g, ''); - part = part.replace(/<[A-Z][a-zA-Z]*[^>]*>[\s\S]*?<\/[A-Z][a-zA-Z]*>\n*/g, ''); - return part; - }) - .join(''); - - // Surface code-block `title="..."` meta as a "File:" line - content = content.replace(/(```\w*)\s+([^\n]*title="[^"]+")[^\n]*$/gm, (_, lang, meta) => { - const titleMatch = meta.match(/title="([^"]+)"/); - return titleMatch ? `File: ${titleMatch[1]} ${lang}` : lang; - }); - - // :::tabs → markdown table - content = content.replace( - /:::tabs\{key="([^"]+)"\}\s*([\s\S]*?)(?=\n:::(?:\s*$|\s*\n))\n:::/gm, - (_, key, tabsContent) => { - const tabs: { label: string; content: string }[] = []; - const tabRegex = - /::tab\{label="([^"]+)"[^}]*\}\s*([\s\S]*?)\s*(?=\n\s*::(?:\s*$|\s+))\n\s*::/gm; - let match; - while ((match = tabRegex.exec(tabsContent)) !== null) { - tabs.push({ label: match[1], content: match[2].trim() }); - } - if (tabs.length === 0) return ''; - - const header = key.charAt(0).toUpperCase() + key.slice(1); - let table = `| ${header} | Details |\n|-----------|---------|`; - for (const tab of tabs) { - const cleanContent = tab.content - .replace(/:button\{label="([^"]+)"\s+href="([^"]+)"[^}]*\}/g, '[$1]($2)') - .replace(/```\w*\n([\s\S]*?)```/g, '$1') - .replace(/\n/g, ' ') - .trim(); - table += `\n| ${tab.label} | ${cleanContent} |`; - } - return table; - } - ); - - // ::note / ::tip / ::warning / ::caution → blockquote - content = content.replace( - /:{2,3}(note|tip|warning|caution)\s*([\s\S]*?)(?=\n:{2,3}(?:\s*$|\s*\n))\n:{2,3}/gm, - (_, variant, noteContent) => `> ${variant}: ${noteContent.trim()}\n` - ); - - // ::steps → numbered list (## headings become numbered items) - content = content.replace( - /::steps\s*([\s\S]*?)(?=\n::(?:\s*$|\s*\n))\n::/gm, - (_, stepsContent: string) => { - let stepNum = 0; - return stepsContent.replace(/^## (.+)$/gm, (_match: string, heading: string) => { - stepNum++; - return `**${stepNum}. ${heading}**`; - }); - } - ); - - // Remove any remaining standalone :: - content = content.replace(/^::\s*$/gm, ''); - - // :icon syntax — keep bracketed label text, otherwise drop - content = content.replace(/\[:icon\{[^}]+\}\s*([^\]]+)\]/g, '$1'); - content = content.replace(/:icon\{[^}]+\}\s*/g, ''); - - // Any remaining :example directives → "See example" reference (link if a URL resolver is provided) - content = content.replace( - /:example\{\s*component="([^"]+)"\s+name="([^"]+)"[^}]*\}/g, - (_match, component: string, name: string) => - options?.exampleUrl - ? `See example: [${component}/${name}](${options.exampleUrl(component, name)})` - : `See example: ${component}/${name}` - ); - content = content.replace(/:example\{\s*name="([^"]+)"[^}]*\}/g, 'See example: $1'); - - // Collapse blank lines - content = content.replace(/\n{3,}/g, '\n\n'); - - return content.trim(); + // Remove frontmatter + content = content.replace(/^---\n[\s\S]*?\n---\n*/, ''); + + // Remove HTML comments + content = content.replace(//g, ''); + + // Remove Svelte script blocks and components ONLY outside of code blocks + content = content + .split(/(```[\s\S]*?```)/g) + .map((part, index) => { + if (index % 2 === 1) return part; // code block — leave as-is + part = part.replace(/]*>[\s\S]*?<\/script>\n*/g, ''); + part = part.replace(/<[A-Z][a-zA-Z]*[^>]*\/>\n*/g, ''); + part = part.replace(/<[A-Z][a-zA-Z]*[^>]*>[\s\S]*?<\/[A-Z][a-zA-Z]*>\n*/g, ''); + return part; + }) + .join(''); + + // Surface code-block `title="..."` meta as a "File:" line + content = content.replace(/(```\w*)\s+([^\n]*title="[^"]+")[^\n]*$/gm, (_, lang, meta) => { + const titleMatch = meta.match(/title="([^"]+)"/); + return titleMatch ? `File: ${titleMatch[1]} ${lang}` : lang; + }); + + // :::tabs → markdown table + content = content.replace( + /:::tabs\{key="([^"]+)"\}\s*([\s\S]*?)(?=\n:::(?:\s*$|\s*\n))\n:::/gm, + (_, key, tabsContent) => { + const tabs: { label: string; content: string }[] = []; + const tabRegex = + /::tab\{label="([^"]+)"[^}]*\}\s*([\s\S]*?)\s*(?=\n\s*::(?:\s*$|\s+))\n\s*::/gm; + let match; + while ((match = tabRegex.exec(tabsContent)) !== null) { + tabs.push({ label: match[1], content: match[2].trim() }); + } + if (tabs.length === 0) return ''; + + const header = key.charAt(0).toUpperCase() + key.slice(1); + let table = `| ${header} | Details |\n|-----------|---------|`; + for (const tab of tabs) { + const cleanContent = tab.content + .replace(/:button\{label="([^"]+)"\s+href="([^"]+)"[^}]*\}/g, '[$1]($2)') + .replace(/```\w*\n([\s\S]*?)```/g, '$1') + .replace(/\n/g, ' ') + .trim(); + table += `\n| ${tab.label} | ${cleanContent} |`; + } + return table; + } + ); + + // ::note / ::tip / ::warning / ::caution → blockquote + content = content.replace( + /:{2,3}(note|tip|warning|caution)\s*([\s\S]*?)(?=\n:{2,3}(?:\s*$|\s*\n))\n:{2,3}/gm, + (_, variant, noteContent) => `> ${variant}: ${noteContent.trim()}\n` + ); + + // ::steps → numbered list (## headings become numbered items) + content = content.replace( + /::steps\s*([\s\S]*?)(?=\n::(?:\s*$|\s*\n))\n::/gm, + (_, stepsContent: string) => { + let stepNum = 0; + return stepsContent.replace(/^## (.+)$/gm, (_match: string, heading: string) => { + stepNum++; + return `**${stepNum}. ${heading}**`; + }); + } + ); + + // Remove any remaining standalone :: + content = content.replace(/^::\s*$/gm, ''); + + // :icon syntax — keep bracketed label text, otherwise drop + content = content.replace(/\[:icon\{[^}]+\}\s*([^\]]+)\]/g, '$1'); + content = content.replace(/:icon\{[^}]+\}\s*/g, ''); + + // Any remaining :example directives → "See example" reference (link if a URL resolver is provided) + content = content.replace( + /:example\{\s*component="([^"]+)"\s+name="([^"]+)"[^}]*\}/g, + (_match, component: string, name: string) => + options?.exampleUrl + ? `See example: [${component}/${name}](${options.exampleUrl(component, name)})` + : `See example: ${component}/${name}` + ); + content = content.replace(/:example\{\s*name="([^"]+)"[^}]*\}/g, 'See example: $1'); + + // Collapse blank lines + content = content.replace(/\n{3,}/g, '\n\n'); + + return content.trim(); } /** @@ -197,10 +196,10 @@ export function processMarkdownContent( * (e.g. a title-cased filename) when absent. */ export function extractFrontmatterTitle(raw: string, fallback = ''): string { - const frontmatter = raw.match(/^---\n([\s\S]*?)\n---/); - const titleMatch = frontmatter?.[1].match(/^title:\s*(.+)$/m); - if (titleMatch) return titleMatch[1].trim().replace(/^["']|["']$/g, ''); - return fallback; + const frontmatter = raw.match(/^---\n([\s\S]*?)\n---/); + const titleMatch = frontmatter?.[1].match(/^title:\s*(.+)$/m); + if (titleMatch) return titleMatch[1].trim().replace(/^["']|["']$/g, ''); + return fallback; } /** @@ -210,40 +209,40 @@ export function extractFrontmatterTitle(raw: string, fallback = ''): string { * the title (explicit → frontmatter → `fallbackTitle`) and content processing. */ export function generateGuideMarkdown( - raw: string, - options: { title?: string; fallbackTitle?: string } = {} + raw: string, + options: { title?: string; fallbackTitle?: string } = {} ): string { - const title = options.title ?? extractFrontmatterTitle(raw, options.fallbackTitle ?? ''); - const body = processMarkdownContent(raw); - return title ? `# ${title}\n\n${body}` : body; + const title = options.title ?? extractFrontmatterTitle(raw, options.fallbackTitle ?? ''); + const body = processMarkdownContent(raw); + return title ? `# ${title}\n\n${body}` : body; } /** Minimal shape a doc needs to render reference markdown. */ export interface ReferenceDoc { - name: string; - slug: string; - description?: string | null; - content?: string | null; - related?: string[] | null; + name: string; + slug: string; + description?: string | null; + content?: string | null; + related?: string[] | null; } export interface ReferenceMarkdownOptions { - /** Heading level for the title (1 = `#`). Related/extra sections use `headingLevel + 1`. Default: 1 */ - headingLevel?: number; - /** Inline `:example` directives as fenced code blocks (requires `resolveSource`). Default: false */ - inlineExamples?: boolean; - /** Resolver for example source (used when `inlineExamples`). */ - resolveSource?: ExampleSourceResolver; - /** URL resolver for non-inlined cross-component `:example` references. */ - exampleUrl?: ExampleUrlResolver; - /** Default component for same-component `:example{name}` directives (e.g. the doc's slug). */ - defaultComponent?: string; - /** Sections inserted after the description, before the processed content (e.g. metadata). */ - leadingSections?: (string | null | undefined)[]; - /** Sections inserted after the processed content, before Related (e.g. API, Examples). */ - extraSections?: (string | null | undefined)[]; - /** Render Related items as links via this URL builder; omit for a plain `- name` list. */ - relatedUrl?: (name: string) => string; + /** Heading level for the title (1 = `#`). Related/extra sections use `headingLevel + 1`. Default: 1 */ + headingLevel?: number; + /** Inline `:example` directives as fenced code blocks (requires `resolveSource`). Default: false */ + inlineExamples?: boolean; + /** Resolver for example source (used when `inlineExamples`). */ + resolveSource?: ExampleSourceResolver; + /** URL resolver for non-inlined cross-component `:example` references. */ + exampleUrl?: ExampleUrlResolver; + /** Default component for same-component `:example{name}` directives (e.g. the doc's slug). */ + defaultComponent?: string; + /** Sections inserted after the description, before the processed content (e.g. metadata). */ + leadingSections?: (string | null | undefined)[]; + /** Sections inserted after the processed content, before Related (e.g. API, Examples). */ + extraSections?: (string | null | undefined)[]; + /** Render Related items as links via this URL builder; omit for a plain `- name` list. */ + relatedUrl?: (name: string) => string; } /** @@ -254,69 +253,69 @@ export interface ReferenceMarkdownOptions { * `leadingSections` / `extraSections` so the orchestration stays shared. */ export function generateReferenceMarkdown( - doc: ReferenceDoc, - options: ReferenceMarkdownOptions = {} + doc: ReferenceDoc, + options: ReferenceMarkdownOptions = {} ): string { - const { - headingLevel = 1, - inlineExamples = false, - resolveSource, - exampleUrl, - defaultComponent, - leadingSections = [], - extraSections = [], - relatedUrl - } = options; - const h = (level: number) => '#'.repeat(level); - - const sections: string[] = [`${h(headingLevel)} ${doc.name}`]; - if (doc.description) sections.push(doc.description); - - for (const section of leadingSections) { - if (section) sections.push(section); - } - - if (doc.content) { - let content = doc.content; - if (inlineExamples && resolveSource) { - content = inlineExampleDirectives(content, resolveSource, defaultComponent, exampleUrl); - } - const processed = processMarkdownContent(content, { exampleUrl }); - if (processed) sections.push(processed); - } - - for (const section of extraSections) { - if (section) sections.push(section); - } - - if (doc.related?.length) { - sections.push(`${h(headingLevel + 1)} Related`); - sections.push( - doc.related.map((r) => (relatedUrl ? `- [${r}](${relatedUrl(r)})` : `- ${r}`)).join('\n') - ); - } - - return sections.join('\n\n'); + const { + headingLevel = 1, + inlineExamples = false, + resolveSource, + exampleUrl, + defaultComponent, + leadingSections = [], + extraSections = [], + relatedUrl, + } = options; + const h = (level: number) => '#'.repeat(level); + + const sections: string[] = [`${h(headingLevel)} ${doc.name}`]; + if (doc.description) sections.push(doc.description); + + for (const section of leadingSections) { + if (section) sections.push(section); + } + + if (doc.content) { + let content = doc.content; + if (inlineExamples && resolveSource) { + content = inlineExampleDirectives(content, resolveSource, defaultComponent, exampleUrl); + } + const processed = processMarkdownContent(content, { exampleUrl }); + if (processed) sections.push(processed); + } + + for (const section of extraSections) { + if (section) sections.push(section); + } + + if (doc.related?.length) { + sections.push(`${h(headingLevel + 1)} Related`); + sections.push( + doc.related.map((r) => (relatedUrl ? `- [${r}](${relatedUrl(r)})` : `- ${r}`)).join('\n') + ); + } + + return sections.join('\n\n'); } /** An item in a markdown link list. */ export interface LinkListItem { - name: string; - url: string; - description?: string | null; + name: string; + url: string; + description?: string | null; } /** Render a `## Title` section with a bulleted list of links: `- [name](url): description`. */ export function linkListSection( - title: string, - items: LinkListItem[], - options: { headingLevel?: number } = {} + title: string, + items: LinkListItem[], + options: { headingLevel?: number } = {} ): string { - const h = '#'.repeat(options.headingLevel ?? 2); - const lines = items.map( - (item) => `- [${item.name}](${item.url})${item.description ? `: ${item.description}` : ''}` - ); - return `${h} ${title}\n\n${lines.join('\n')}`; + const h = '#'.repeat(options.headingLevel ?? 2); + const lines = items.map( + (item) => `- [${item.name}](${item.url})${item.description ? `: ${item.description}` : ''}` + ); + return `${h} ${title}\n\n${lines.join('\n')}`; } /** @@ -324,17 +323,17 @@ export function linkListSection( * sorted by key. Pass `sort` (e.g. `sortCollection`) to order within each group. */ export function groupBySlugSegment( - docs: T[], - options: { segment?: number; sort?: (group: T[]) => T[] } = {} + docs: T[], + options: { segment?: number; sort?: (group: T[]) => T[] } = {} ): [string, T[]][] { - const segment = options.segment ?? 0; - const byKey = new Map(); - for (const doc of docs) { - const key = doc.slug.split('/')[segment]; - if (!byKey.has(key)) byKey.set(key, []); - byKey.get(key)!.push(doc); - } - return [...byKey.entries()] - .sort(([a], [b]) => a.localeCompare(b)) - .map(([key, group]) => [key, options.sort ? options.sort(group) : group]); + const segment = options.segment ?? 0; + const byKey = new Map(); + for (const doc of docs) { + const key = doc.slug.split('/')[segment]; + if (!byKey.has(key)) byKey.set(key, []); + byKey.get(key)!.push(doc); + } + return [...byKey.entries()] + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, group]) => [key, options.sort ? options.sort(group) : group]); } diff --git a/packages/docs/src/lib/markdown/blueprints/default/blueprint.svelte b/packages/docs/src/lib/markdown/blueprints/default/blueprint.svelte index 52715c1..0849c24 100644 --- a/packages/docs/src/lib/markdown/blueprints/default/blueprint.svelte +++ b/packages/docs/src/lib/markdown/blueprints/default/blueprint.svelte @@ -1,30 +1,30 @@ {@render children?.()} diff --git a/packages/docs/src/lib/markdown/components/Button.svelte b/packages/docs/src/lib/markdown/components/Button.svelte index c3252fc..94eca2c 100644 --- a/packages/docs/src/lib/markdown/components/Button.svelte +++ b/packages/docs/src/lib/markdown/components/Button.svelte @@ -1,38 +1,38 @@ diff --git a/packages/docs/src/lib/markdown/components/LiveCode.svelte b/packages/docs/src/lib/markdown/components/LiveCode.svelte index 7560cb7..3fd7943 100644 --- a/packages/docs/src/lib/markdown/components/LiveCode.svelte +++ b/packages/docs/src/lib/markdown/components/LiveCode.svelte @@ -1,20 +1,20 @@

    -
    - {@render preview()} -
    - {#if showCode} - {@render children()} - {/if} +
    + {@render preview()} +
    + {#if showCode} + {@render children()} + {/if}
    diff --git a/packages/docs/src/lib/markdown/components/Note.svelte b/packages/docs/src/lib/markdown/components/Note.svelte index 29ea7da..4db5e41 100644 --- a/packages/docs/src/lib/markdown/components/Note.svelte +++ b/packages/docs/src/lib/markdown/components/Note.svelte @@ -1,39 +1,39 @@
    - -
    - {@render children?.()} -
    + +
    + {@render children?.()} +
    diff --git a/packages/docs/src/lib/markdown/components/Steps.svelte b/packages/docs/src/lib/markdown/components/Steps.svelte index a327f80..e31ffa8 100644 --- a/packages/docs/src/lib/markdown/components/Steps.svelte +++ b/packages/docs/src/lib/markdown/components/Steps.svelte @@ -1,9 +1,9 @@
    - {@render children?.()} + {@render children?.()}
    diff --git a/packages/docs/src/lib/markdown/components/Tab.svelte b/packages/docs/src/lib/markdown/components/Tab.svelte index 8eec7cf..2e6d2ab 100644 --- a/packages/docs/src/lib/markdown/components/Tab.svelte +++ b/packages/docs/src/lib/markdown/components/Tab.svelte @@ -1,34 +1,34 @@
    - {@render children?.()} + {@render children?.()}
    diff --git a/packages/docs/src/lib/markdown/components/Tabs.svelte b/packages/docs/src/lib/markdown/components/Tabs.svelte index 44838dd..b7f8cdd 100644 --- a/packages/docs/src/lib/markdown/components/Tabs.svelte +++ b/packages/docs/src/lib/markdown/components/Tabs.svelte @@ -1,109 +1,109 @@
    - -
    - {#each tabs as tab, index} - {@const isActive = activeTab === index} - - {/each} -
    + +
    + {#each tabs as tab, index} + {@const isActive = activeTab === index} + + {/each} +
    - -
    - {@render children?.()} -
    + +
    + {@render children?.()} +
    diff --git a/packages/docs/src/lib/markdown/components/a.svelte b/packages/docs/src/lib/markdown/components/a.svelte index 728b2aa..c1230ec 100644 --- a/packages/docs/src/lib/markdown/components/a.svelte +++ b/packages/docs/src/lib/markdown/components/a.svelte @@ -1,26 +1,26 @@ - {@render children?.()}{#if !internal} - - {/if} + {@render children?.()}{#if !internal} + + {/if} diff --git a/packages/docs/src/lib/markdown/components/blockquote.svelte b/packages/docs/src/lib/markdown/components/blockquote.svelte index 8361807..9404246 100644 --- a/packages/docs/src/lib/markdown/components/blockquote.svelte +++ b/packages/docs/src/lib/markdown/components/blockquote.svelte @@ -1,17 +1,17 @@
    a]:font-medium [&>a]:underline [&>a]:decoration-dashed [&>a]:decoration-primary/50 [&>a]:underline-offset-2', - className - )} - {...restProps} + class={cls( + 'bg-surface-content/5 border-l-4 px-4 py-2 my-4 text-sm rounded-r', + '[&>a]:font-medium [&>a]:underline [&>a]:decoration-dashed [&>a]:decoration-primary/50 [&>a]:underline-offset-2', + className + )} + {...restProps} > - {@render children?.()} + {@render children?.()}
    diff --git a/packages/docs/src/lib/markdown/components/code.svelte b/packages/docs/src/lib/markdown/components/code.svelte index 47ee310..8f218a1 100644 --- a/packages/docs/src/lib/markdown/components/code.svelte +++ b/packages/docs/src/lib/markdown/components/code.svelte @@ -1,10 +1,10 @@ - {@render children?.()} + {@render children?.()} diff --git a/packages/docs/src/lib/markdown/components/h-base.svelte b/packages/docs/src/lib/markdown/components/h-base.svelte index 9ca08dd..315a220 100644 --- a/packages/docs/src/lib/markdown/components/h-base.svelte +++ b/packages/docs/src/lib/markdown/components/h-base.svelte @@ -1,23 +1,23 @@ - - - {@render children?.()} - + + + {@render children?.()} + diff --git a/packages/docs/src/lib/markdown/components/h1.svelte b/packages/docs/src/lib/markdown/components/h1.svelte index 1671972..19564c5 100644 --- a/packages/docs/src/lib/markdown/components/h1.svelte +++ b/packages/docs/src/lib/markdown/components/h1.svelte @@ -1,9 +1,9 @@ diff --git a/packages/docs/src/lib/markdown/components/h2.svelte b/packages/docs/src/lib/markdown/components/h2.svelte index ac20663..4d3c0b6 100644 --- a/packages/docs/src/lib/markdown/components/h2.svelte +++ b/packages/docs/src/lib/markdown/components/h2.svelte @@ -1,13 +1,13 @@ diff --git a/packages/docs/src/lib/markdown/components/h3.svelte b/packages/docs/src/lib/markdown/components/h3.svelte index 93b7fc6..b420911 100644 --- a/packages/docs/src/lib/markdown/components/h3.svelte +++ b/packages/docs/src/lib/markdown/components/h3.svelte @@ -1,13 +1,13 @@ diff --git a/packages/docs/src/lib/markdown/components/h4.svelte b/packages/docs/src/lib/markdown/components/h4.svelte index 28ae065..9f37186 100644 --- a/packages/docs/src/lib/markdown/components/h4.svelte +++ b/packages/docs/src/lib/markdown/components/h4.svelte @@ -1,13 +1,13 @@ diff --git a/packages/docs/src/lib/markdown/components/img.svelte b/packages/docs/src/lib/markdown/components/img.svelte index 153b391..a28c61a 100644 --- a/packages/docs/src/lib/markdown/components/img.svelte +++ b/packages/docs/src/lib/markdown/components/img.svelte @@ -1,8 +1,8 @@ diff --git a/packages/docs/src/lib/markdown/components/li.svelte b/packages/docs/src/lib/markdown/components/li.svelte index e5c5da0..db23246 100644 --- a/packages/docs/src/lib/markdown/components/li.svelte +++ b/packages/docs/src/lib/markdown/components/li.svelte @@ -1,10 +1,10 @@
  • - {@render children?.()} + {@render children?.()}
  • diff --git a/packages/docs/src/lib/markdown/components/ol.svelte b/packages/docs/src/lib/markdown/components/ol.svelte index b229521..19264ba 100644 --- a/packages/docs/src/lib/markdown/components/ol.svelte +++ b/packages/docs/src/lib/markdown/components/ol.svelte @@ -1,10 +1,10 @@
      - {@render children?.()} + {@render children?.()}
    diff --git a/packages/docs/src/lib/markdown/components/p.svelte b/packages/docs/src/lib/markdown/components/p.svelte index a23bd14..badd61b 100644 --- a/packages/docs/src/lib/markdown/components/p.svelte +++ b/packages/docs/src/lib/markdown/components/p.svelte @@ -1,10 +1,10 @@

    &]:my-5 leading-relaxed', className)} {...restProps}> - {@render children?.()} + {@render children?.()}

    diff --git a/packages/docs/src/lib/markdown/components/pre.svelte b/packages/docs/src/lib/markdown/components/pre.svelte index 068e6f6..6dcd07d 100644 --- a/packages/docs/src/lib/markdown/components/pre.svelte +++ b/packages/docs/src/lib/markdown/components/pre.svelte @@ -1,84 +1,84 @@
    - {#if dataTitle} -
    - - {dataTitle} -
    - {/if} + {#if dataTitle} +
    + + {dataTitle} +
    + {/if} -
    {@render children?.()}
    +
    {@render children?.()}
    -
    - -
    +
    + +
    diff --git a/packages/docs/src/lib/markdown/components/strong.svelte b/packages/docs/src/lib/markdown/components/strong.svelte index 28b0f41..ba540c7 100644 --- a/packages/docs/src/lib/markdown/components/strong.svelte +++ b/packages/docs/src/lib/markdown/components/strong.svelte @@ -1,5 +1,5 @@ {@render children?.()} diff --git a/packages/docs/src/lib/markdown/components/table.svelte b/packages/docs/src/lib/markdown/components/table.svelte index d218982..212481f 100644 --- a/packages/docs/src/lib/markdown/components/table.svelte +++ b/packages/docs/src/lib/markdown/components/table.svelte @@ -1,12 +1,12 @@
    - - {@render children?.()} -
    + + {@render children?.()} +
    diff --git a/packages/docs/src/lib/markdown/components/td.svelte b/packages/docs/src/lib/markdown/components/td.svelte index bae6bb2..b60f62b 100644 --- a/packages/docs/src/lib/markdown/components/td.svelte +++ b/packages/docs/src/lib/markdown/components/td.svelte @@ -1,16 +1,16 @@ - {@render children?.()} + {@render children?.()} diff --git a/packages/docs/src/lib/markdown/components/th.svelte b/packages/docs/src/lib/markdown/components/th.svelte index c3e1493..f8c6842 100644 --- a/packages/docs/src/lib/markdown/components/th.svelte +++ b/packages/docs/src/lib/markdown/components/th.svelte @@ -1,16 +1,16 @@ - {@render children?.()} + {@render children?.()} diff --git a/packages/docs/src/lib/markdown/components/tr.svelte b/packages/docs/src/lib/markdown/components/tr.svelte index 2ac46d0..f18f769 100644 --- a/packages/docs/src/lib/markdown/components/tr.svelte +++ b/packages/docs/src/lib/markdown/components/tr.svelte @@ -1,10 +1,10 @@ - {@render children?.()} + {@render children?.()} diff --git a/packages/docs/src/lib/markdown/components/ul.svelte b/packages/docs/src/lib/markdown/components/ul.svelte index 4a92b64..ea86d22 100644 --- a/packages/docs/src/lib/markdown/components/ul.svelte +++ b/packages/docs/src/lib/markdown/components/ul.svelte @@ -1,10 +1,10 @@
      - {@render children?.()} + {@render children?.()}
    diff --git a/packages/docs/src/lib/markdown/config/index.js b/packages/docs/src/lib/markdown/config/index.js index 10710ab..f61c036 100644 --- a/packages/docs/src/lib/markdown/config/index.js +++ b/packages/docs/src/lib/markdown/config/index.js @@ -30,17 +30,17 @@ const __dirname = dirname(fileURLToPath(import.meta.url)); /** Strip leading/trailing dashes from heading IDs produced by rehype-slug. */ export function rehypeCleanSlugIds() { - return (tree) => { - visit(tree, 'element', (node) => { - if (/^h[1-6]$/.test(node.tagName) && node.properties?.id) { - node.properties.id = node.properties.id.replace(/^-+|-+$/g, ''); - } - }); - }; + return (tree) => { + visit(tree, 'element', (node) => { + if (/^h[1-6]$/.test(node.tagName) && node.properties?.id) { + node.properties.id = node.properties.id.replace(/^-+|-+$/g, ''); + } + }); + }; } export function getDefaultBlueprintPath() { - return join(__dirname, '../blueprints/default/blueprint.svelte'); + return join(__dirname, '../blueprints/default/blueprint.svelte'); } /** @@ -56,40 +56,39 @@ export function getDefaultBlueprintPath() { * }} [options] */ export function createMdsxConfig(options = {}) { - return defineConfig({ - extensions: ['.md'], - remarkPlugins: [ - remarkGfm, - remarkMDC, - [ - remarkComponents, - { - markdownComponentsPath: - options.markdownComponentsPath ?? '@layerstack/docs/markdown/components', - exampleComponentPath: options.exampleComponentPath ?? '$lib/components' - } - ], - [ - remarkLiveCode, - { - outputDir: options.liveCodeOutputDir, - importPrefix: options.liveCodeImportPrefix, - liveCodeComponent: - options.liveCodeComponent ?? - '@layerstack/docs/markdown/components/LiveCode.svelte' - } - ] - ], - rehypePlugins: [ - rehypeSlug, - rehypeCleanSlugIds, - [rehypePrettyCode, prettyCodeOptions], - rehypeCodeBlocks - ], - blueprints: { - default: { - path: options.blueprintPath ?? getDefaultBlueprintPath() - } - } - }); + return defineConfig({ + extensions: ['.md'], + remarkPlugins: [ + remarkGfm, + remarkMDC, + [ + remarkComponents, + { + markdownComponentsPath: + options.markdownComponentsPath ?? '@layerstack/docs/markdown/components', + exampleComponentPath: options.exampleComponentPath ?? '$lib/components', + }, + ], + [ + remarkLiveCode, + { + outputDir: options.liveCodeOutputDir, + importPrefix: options.liveCodeImportPrefix, + liveCodeComponent: + options.liveCodeComponent ?? '@layerstack/docs/markdown/components/LiveCode.svelte', + }, + ], + ], + rehypePlugins: [ + rehypeSlug, + rehypeCleanSlugIds, + [rehypePrettyCode, prettyCodeOptions], + rehypeCodeBlocks, + ], + blueprints: { + default: { + path: options.blueprintPath ?? getDefaultBlueprintPath(), + }, + }, + }); } diff --git a/packages/docs/src/lib/markdown/config/pretty-code.js b/packages/docs/src/lib/markdown/config/pretty-code.js index df2e8c9..fbd41aa 100644 --- a/packages/docs/src/lib/markdown/config/pretty-code.js +++ b/packages/docs/src/lib/markdown/config/pretty-code.js @@ -5,14 +5,14 @@ import { shikiDiffTransformer } from '../transformers/shiki-diff.js'; * @type {import('rehype-pretty-code').Options} */ export const prettyCodeOptions = { - theme: { - light: 'github-light-default', - dark: 'github-dark-default' - }, - keepBackground: false, - defaultLang: { - block: 'plaintext' - // inline: "plaintext", - }, - transformers: [shikiDiffTransformer(), transformerMetaHighlight()] + theme: { + light: 'github-light-default', + dark: 'github-dark-default', + }, + keepBackground: false, + defaultLang: { + block: 'plaintext', + // inline: "plaintext", + }, + transformers: [shikiDiffTransformer(), transformerMetaHighlight()], }; diff --git a/packages/docs/src/lib/markdown/rehype/component-example.js b/packages/docs/src/lib/markdown/rehype/component-example.js index 9df93cf..fbfd74a 100644 --- a/packages/docs/src/lib/markdown/rehype/component-example.js +++ b/packages/docs/src/lib/markdown/rehype/component-example.js @@ -9,71 +9,71 @@ import { visit } from 'unist-util-visit'; * @returns {(tree: import('unist').Node) => Promise} */ export function rehypeComponentExample() { - return async (tree) => { - const componentRegex = /component="([^"]+)"/; - const nameRegex = /name="([^"]+)"/; + return async (tree) => { + const componentRegex = /component="([^"]+)"/; + const nameRegex = /name="([^"]+)"/; - visit(tree, (node, index, parent) => { - // Use type narrowing - node can have custom properties - if ( - !node || - typeof node !== 'object' || - !('type' in node) || - !('value' in node) || - node.type !== 'raw' || - typeof node.value !== 'string' || - !node.value.startsWith(' { + // Use type narrowing - node can have custom properties + if ( + !node || + typeof node !== 'object' || + !('type' in node) || + !('value' in node) || + node.type !== 'raw' || + typeof node.value !== 'string' || + !node.value.startsWith(' void} */ export function rehypeCodeBlocks() { - return (tree) => { - visit(tree, 'element', (node) => { - if (node.tagName === 'pre') { - node.properties.className = node.properties.className || []; + return (tree) => { + visit(tree, 'element', (node) => { + if (node.tagName === 'pre') { + node.properties.className = node.properties.className || []; - // Check if the code element has a data-meta attribute from rehype-pretty-code - const codeNode = node.children?.find( - (child) => child.type === 'element' && child.tagName === 'code' - ); + // Check if the code element has a data-meta attribute from rehype-pretty-code + const codeNode = node.children?.find( + (child) => child.type === 'element' && child.tagName === 'code' + ); - if (!codeNode || codeNode.type !== 'element') return; + if (!codeNode || codeNode.type !== 'element') return; - // @ts-expect-error - rehype-pretty-code adds custom meta property - const meta = codeNode.data?.meta || codeNode.properties?.metastring; + // @ts-expect-error - rehype-pretty-code adds custom meta property + const meta = codeNode.data?.meta || codeNode.properties?.metastring; - if (meta) { - // Check for 'frame' keyword - if (meta.includes('frame')) { - node.properties['data-frame'] = ''; - } + if (meta) { + // Check for 'frame' keyword + if (meta.includes('frame')) { + node.properties['data-frame'] = ''; + } - // Extract title="..." if present - const titleMatch = meta.match(/title="([^"]+)"/); - if (titleMatch) { - node.properties['data-title'] = titleMatch[1]; - } + // Extract title="..." if present + const titleMatch = meta.match(/title="([^"]+)"/); + if (titleMatch) { + node.properties['data-title'] = titleMatch[1]; + } - // Check for line numbers flag in meta - if (meta.includes('showLineNumbers') || meta.includes('ln')) { - node.properties['data-line-numbers'] = ''; - } - } + // Check for line numbers flag in meta + if (meta.includes('showLineNumbers') || meta.includes('ln')) { + node.properties['data-line-numbers'] = ''; + } + } - // Check recursively for [data-line] attribute in nested children - /** - * @param {import('hast').Element} element - * @returns {boolean} - */ - function hasDataLine(element) { - if (element.properties?.['data-line'] !== undefined) { - return true; - } - if (element.children) { - return element.children.some((child) => child.type === 'element' && hasDataLine(child)); - } - return false; - } + // Check recursively for [data-line] attribute in nested children + /** + * @param {import('hast').Element} element + * @returns {boolean} + */ + function hasDataLine(element) { + if (element.properties?.['data-line'] !== undefined) { + return true; + } + if (element.children) { + return element.children.some((child) => child.type === 'element' && hasDataLine(child)); + } + return false; + } - if (hasDataLine(codeNode)) { - node.properties['data-line-numbers'] = ''; - } + if (hasDataLine(codeNode)) { + node.properties['data-line-numbers'] = ''; + } - // Extract language from code element - const codeClassName = codeNode.properties?.className; - if (Array.isArray(codeClassName)) { - const langClass = codeClassName.find( - (cls) => typeof cls === 'string' && cls.startsWith('language-') - ); - if (typeof langClass === 'string') { - const language = langClass.replace('language-', ''); - node.properties['data-language'] = language; - } - } - } - }); - }; + // Extract language from code element + const codeClassName = codeNode.properties?.className; + if (Array.isArray(codeClassName)) { + const langClass = codeClassName.find( + (cls) => typeof cls === 'string' && cls.startsWith('language-') + ); + if (typeof langClass === 'string') { + const language = langClass.replace('language-', ''); + node.properties['data-language'] = language; + } + } + } + }); + }; } diff --git a/packages/docs/src/lib/markdown/rehype/live-code.js b/packages/docs/src/lib/markdown/rehype/live-code.js index ac09dab..0a370e4 100644 --- a/packages/docs/src/lib/markdown/rehype/live-code.js +++ b/packages/docs/src/lib/markdown/rehype/live-code.js @@ -13,146 +13,146 @@ import { visit } from 'unist-util-visit'; * @returns {(tree: import('mdast').Root, vFile: import('vfile').VFile) => void} */ export function remarkLiveCode(options = {}) { - const basePath = resolve(process.cwd(), options.outputDir ?? '.live-code'); - const liveCodeMap = resolve(basePath, 'live-code-map.json'); - const importPrefix = options.importPrefix ?? '/.live-code'; - const liveCodeComponent = - options.liveCodeComponent ?? '@layerstack/docs/markdown/components/LiveCode.svelte'; - - // Ensure directory exists - if (!existsSync(basePath)) { - mkdirSync(basePath, { recursive: true }); - } - - // Initialize or load the map file - if (!existsSync(liveCodeMap)) { - writeFileSync(liveCodeMap, '{}'); - } - - return (tree, vFile) => { - const liveCodeImports = new Map(); // Use Map to dedupe identical code blocks - let hasScript = false; - - visit(tree, 'code', (node, index, parent) => { - if (index === null || !parent) return; - const { meta, lang, value } = node; - const metaArray = (meta || '').split(' ').filter(Boolean); - - // Check if this is a live code block - if (lang !== 'svelte' || !metaArray.includes('live')) return; - - // Parse all key=value props from meta string - /** @type {Record} */ - const props = {}; - const propsRegex = /(\w+)=(?:"([^"]*)"|(\w+))/g; - let match; - while ((match = propsRegex.exec(meta || '')) !== null) { - const key = match[1]; - const value = match[2] || match[3]; // quoted or unquoted value - // Convert boolean strings to actual booleans - if (value === 'true') { - props[key] = true; - } else if (value === 'false') { - props[key] = false; - } else { - props[key] = value; - } - } - - // Convert props object to Svelte props string - const propsString = Object.entries(props) - .map(([key, value]) => { - if (typeof value === 'boolean') { - return `${key}={${value}}`; - } else { - return `${key}="${value}"`; - } - }) - .join(' '); - const propsWithSpace = propsString ? ' ' + propsString : ''; - - // Use the raw code value - const rawCode = value || ''; - - // Generate unique ID for this code block based on file path and content hash - const contentHash = createHash('md5').update(rawCode).digest('hex').substring(0, 8); - const blockId = `${vFile.path}-${contentHash}`; - const idMap = JSON.parse(readFileSync(liveCodeMap, 'utf-8')); - - let componentFileName = idMap[blockId]; - if (!componentFileName) { - // Generate unique filename - const hash = Math.random().toString(36).substring(2, 11); - componentFileName = `LiveCode${hash}.svelte`; - idMap[blockId] = componentFileName; - writeFileSync(liveCodeMap, JSON.stringify(idMap, null, 2)); - } - - // Write the live code to a .svelte file - const componentPath = resolve(basePath, componentFileName); - writeFileSync(componentPath, rawCode); - - // Generate component name (remove .svelte extension) - const componentName = componentFileName.replace(/\.svelte$/, ''); - - // Track import for later injection (Map dedupes identical code blocks) - liveCodeImports.set(componentName, `${importPrefix}/${componentFileName}`); - - // Create the live code container structure wrapped in LiveCodeWrapper - const liveCodeContainer = { - type: 'paragraph', - data: { - hName: 'div', - hProperties: {} - }, - children: [ - { - type: 'html', - value: `{#snippet preview()}<${componentName} />{/snippet}
    ` - } - ] - }; - - // Add code section with original code block (title will be handled by rehype-code-block-title) - liveCodeContainer.children.push(node); - - liveCodeContainer.children.push({ - type: 'html', - value: '
    ' // Close live-code-source and LiveCode - }); - - // Replace the code node with the container - parent.children[index] = liveCodeContainer; - }); - - // Inject imports at the beginning of the file - if (liveCodeImports.size > 0) { - const importStatements = [ - `import LiveCode from '${liveCodeComponent}';`, - ...[...liveCodeImports.entries()].map( - ([componentName, path]) => `import ${componentName} from '${path}';` - ) - ].join('\n'); - - // Find existing script tag or create new one - visit(tree, 'html', (node, idx, parent) => { - if (node.value.startsWith(']*>/, - (match) => `${match}\n${importStatements}` - ); - return visit.EXIT; - } - }); - - if (!hasScript) { - // Create new script tag at the beginning - tree.children.unshift({ - type: 'html', - value: `` - }); - } - } - }; + const basePath = resolve(process.cwd(), options.outputDir ?? '.live-code'); + const liveCodeMap = resolve(basePath, 'live-code-map.json'); + const importPrefix = options.importPrefix ?? '/.live-code'; + const liveCodeComponent = + options.liveCodeComponent ?? '@layerstack/docs/markdown/components/LiveCode.svelte'; + + // Ensure directory exists + if (!existsSync(basePath)) { + mkdirSync(basePath, { recursive: true }); + } + + // Initialize or load the map file + if (!existsSync(liveCodeMap)) { + writeFileSync(liveCodeMap, '{}'); + } + + return (tree, vFile) => { + const liveCodeImports = new Map(); // Use Map to dedupe identical code blocks + let hasScript = false; + + visit(tree, 'code', (node, index, parent) => { + if (index === null || !parent) return; + const { meta, lang, value } = node; + const metaArray = (meta || '').split(' ').filter(Boolean); + + // Check if this is a live code block + if (lang !== 'svelte' || !metaArray.includes('live')) return; + + // Parse all key=value props from meta string + /** @type {Record} */ + const props = {}; + const propsRegex = /(\w+)=(?:"([^"]*)"|(\w+))/g; + let match; + while ((match = propsRegex.exec(meta || '')) !== null) { + const key = match[1]; + const value = match[2] || match[3]; // quoted or unquoted value + // Convert boolean strings to actual booleans + if (value === 'true') { + props[key] = true; + } else if (value === 'false') { + props[key] = false; + } else { + props[key] = value; + } + } + + // Convert props object to Svelte props string + const propsString = Object.entries(props) + .map(([key, value]) => { + if (typeof value === 'boolean') { + return `${key}={${value}}`; + } else { + return `${key}="${value}"`; + } + }) + .join(' '); + const propsWithSpace = propsString ? ' ' + propsString : ''; + + // Use the raw code value + const rawCode = value || ''; + + // Generate unique ID for this code block based on file path and content hash + const contentHash = createHash('md5').update(rawCode).digest('hex').substring(0, 8); + const blockId = `${vFile.path}-${contentHash}`; + const idMap = JSON.parse(readFileSync(liveCodeMap, 'utf-8')); + + let componentFileName = idMap[blockId]; + if (!componentFileName) { + // Generate unique filename + const hash = Math.random().toString(36).substring(2, 11); + componentFileName = `LiveCode${hash}.svelte`; + idMap[blockId] = componentFileName; + writeFileSync(liveCodeMap, JSON.stringify(idMap, null, 2)); + } + + // Write the live code to a .svelte file + const componentPath = resolve(basePath, componentFileName); + writeFileSync(componentPath, rawCode); + + // Generate component name (remove .svelte extension) + const componentName = componentFileName.replace(/\.svelte$/, ''); + + // Track import for later injection (Map dedupes identical code blocks) + liveCodeImports.set(componentName, `${importPrefix}/${componentFileName}`); + + // Create the live code container structure wrapped in LiveCodeWrapper + const liveCodeContainer = { + type: 'paragraph', + data: { + hName: 'div', + hProperties: {}, + }, + children: [ + { + type: 'html', + value: `{#snippet preview()}<${componentName} />{/snippet}
    `, + }, + ], + }; + + // Add code section with original code block (title will be handled by rehype-code-block-title) + liveCodeContainer.children.push(node); + + liveCodeContainer.children.push({ + type: 'html', + value: '
    ', // Close live-code-source and LiveCode + }); + + // Replace the code node with the container + parent.children[index] = liveCodeContainer; + }); + + // Inject imports at the beginning of the file + if (liveCodeImports.size > 0) { + const importStatements = [ + `import LiveCode from '${liveCodeComponent}';`, + ...[...liveCodeImports.entries()].map( + ([componentName, path]) => `import ${componentName} from '${path}';` + ), + ].join('\n'); + + // Find existing script tag or create new one + visit(tree, 'html', (node, idx, parent) => { + if (node.value.startsWith(']*>/, + (match) => `${match}\n${importStatements}` + ); + return visit.EXIT; + } + }); + + if (!hasScript) { + // Create new script tag at the beginning + tree.children.unshift({ + type: 'html', + value: ``, + }); + } + } + }; } diff --git a/packages/docs/src/lib/markdown/remark/components.js b/packages/docs/src/lib/markdown/remark/components.js index adfe31c..dba066c 100644 --- a/packages/docs/src/lib/markdown/remark/components.js +++ b/packages/docs/src/lib/markdown/remark/components.js @@ -27,14 +27,14 @@ import { visit, EXIT } from 'unist-util-visit'; * @returns {Record} - Attributes object with camelCase keys */ function kebabToCamelCase(attributes) { - /** @type {Record} */ - const camelCaseAttributes = {}; - for (const [key, value] of Object.entries(attributes)) { - // Convert kebab-case to camelCase - const camelKey = toCamelCase(key); - camelCaseAttributes[camelKey] = value; - } - return camelCaseAttributes; + /** @type {Record} */ + const camelCaseAttributes = {}; + for (const [key, value] of Object.entries(attributes)) { + // Convert kebab-case to camelCase + const camelKey = toCamelCase(key); + camelCaseAttributes[camelKey] = value; + } + return camelCaseAttributes; } /** @@ -43,220 +43,221 @@ function kebabToCamelCase(attributes) { * @returns {{importPath: string, componentName: string}} - Import path and PascalCase component name */ function convertIconName(name) { - // Remove i- prefix if present - let iconName = name; - if (iconName.startsWith('i-')) { - iconName = iconName.slice(2); - } - - // Split by colon to get collection and icon name - let collection, icon; - if (iconName.includes(':')) { - [collection, icon] = iconName.split(':'); - } else { - // For i-collection-icon format without colon, we need to parse differently - // This is tricky because collections can have hyphens (e.g., vscode-icons) - // For now, assume everything after first hyphen is the icon name - const parts = iconName.split('-'); - collection = parts[0]; - icon = parts.slice(1).join('-'); - } - - // Create PascalCase component name by converting both collection and icon parts - /** @param {string} str */ - const toPascalCase = (str) => - str - .split('-') - .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) - .join(''); - - const componentName = toPascalCase(collection) + toPascalCase(icon); - const importPath = `~icons/${collection}/${icon}`; - - return { importPath, componentName }; + // Remove i- prefix if present + let iconName = name; + if (iconName.startsWith('i-')) { + iconName = iconName.slice(2); + } + + // Split by colon to get collection and icon name + let collection, icon; + if (iconName.includes(':')) { + [collection, icon] = iconName.split(':'); + } else { + // For i-collection-icon format without colon, we need to parse differently + // This is tricky because collections can have hyphens (e.g., vscode-icons) + // For now, assume everything after first hyphen is the icon name + const parts = iconName.split('-'); + collection = parts[0]; + icon = parts.slice(1).join('-'); + } + + // Create PascalCase component name by converting both collection and icon parts + /** @param {string} str */ + const toPascalCase = (str) => + str + .split('-') + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(''); + + const componentName = toPascalCase(collection) + toPascalCase(icon); + const importPath = `~icons/${collection}/${icon}`; + + return { importPath, componentName }; } /** * @param {{ markdownComponentsPath?: string; exampleComponentPath?: string }} [options] */ export function remarkComponents(options = {}) { - const markdownComponentsPath = options.markdownComponentsPath ?? '@layerstack/docs/markdown/components'; - const exampleComponentPath = options.exampleComponentPath ?? '$lib/components'; - - return (tree) => { - const componentsToImport = new Set(); - const iconImports = new Map(); // Map of componentName -> importPath - - // Process MDC components (remark-mdc creates leafComponent and containerComponent nodes) - visit(tree, (node) => { - // Handle both leafComponent (::component) and containerComponent (::component...::) - if (node.type === 'leafComponent' || node.type === 'containerComponent') { - const componentName = node.name; - - // Alert variants all use the Note component - const alertVariants = ['tip', 'note', 'warning', 'caution']; - - // Map component names to Svelte component names and variants - let svelteComponent; - let variant; - - if (alertVariants.includes(componentName)) { - svelteComponent = 'Note'; - variant = componentName; - } else if (componentName === 'steps') { - svelteComponent = 'Steps'; - } else if (componentName === 'tabs') { - svelteComponent = 'Tabs'; - } else if (componentName === 'tab') { - svelteComponent = 'Tab'; - } else { - // Unknown component, skip transformation - return; - } - - // Track which components we need to import - componentsToImport.add(svelteComponent); - - // Get component attributes from MDC - const attributes = node.attributes || {}; - - // Convert kebab-case to camelCase for Svelte props - let processedAttributes = kebabToCamelCase(attributes); - - // Handle icon attribute on tab components (e.g., ::tab{label="pnpm" icon="vscode-icons:file-type-pnpm"}) - if (componentName === 'tab' && processedAttributes.icon) { - const { importPath, componentName: iconCompName } = convertIconName( - processedAttributes.icon - ); - iconImports.set(iconCompName, importPath); - - // Replace icon string with component reference expression - // Remove quotes so it becomes {ComponentName} instead of "ComponentName" - processedAttributes = { - ...processedAttributes, - icon: `{${iconCompName}}` - }; - } - - // Convert the MDC component into a component that rehype can handle - // We set data.hName to tell rehype to convert this to the component - const data = node.data || (node.data = {}); - data.hName = svelteComponent; - data.hProperties = { - ...processedAttributes, - // Pass variant for alert components - ...(variant && { variant }) - }; - } - - // Handle inline text components (:component) - if (node.type === 'textComponent') { - const componentName = node.name; - - // Support :icon{name="logos:tailwindcss-icon"} or :icon{name="i-lucide-code"} syntax - if (componentName === 'icon') { - const iconName = node.attributes?.name; - if (iconName) { - const { importPath, componentName: iconComponentName } = convertIconName(iconName); - - // Track this icon import - iconImports.set(iconComponentName, importPath); - - // Get other attributes (excluding 'name') - const { name: _, class: className, ...otherAttributes } = node.attributes || {}; - - // Convert to the icon component - const data = node.data || (node.data = {}); - data.hName = iconComponentName; - data.hProperties = { - ...otherAttributes, - class: cls('inline-block', className) - }; - } - } else if (componentName === 'button') { - componentsToImport.add('Button'); - - const attributes = node.attributes || {}; - - // Convert kebab-case to camelCase for Svelte props - let processedAttributes = kebabToCamelCase(attributes); - - // Handle icon attribute on button components (e.g., :button{icon="lucide:github"}) - if (processedAttributes.icon) { - const { importPath, componentName: iconCompName } = convertIconName( - processedAttributes.icon - ); - iconImports.set(iconCompName, importPath); - - // Replace icon string with component reference expression - processedAttributes = { - ...processedAttributes, - icon: `{${iconCompName}}` - }; - } - - const data = node.data || (node.data = {}); - data.hName = 'Button'; - data.hProperties = processedAttributes; - } else if (componentName === 'example') { - componentsToImport.add('Example'); - - const attributes = node.attributes || {}; - - // Convert kebab-case to camelCase for Svelte props - const processedAttributes = kebabToCamelCase(attributes); - - const data = node.data || (node.data = {}); - data.hName = 'Example'; - data.hProperties = processedAttributes; - } - } - }); - - // Inject component imports at the beginning of the file - if (componentsToImport.size > 0 || iconImports.size > 0) { - // Generate regular component imports - const componentArray = Array.from(componentsToImport); - const componentImportStatements = componentArray - .map((comp) => { - const path = comp === 'Example' ? exampleComponentPath : markdownComponentsPath; - return `import ${comp} from '${path}/${comp}.svelte';`; - }) - .join('\n'); - - // Generate icon imports from unplugin-icons - const iconImportStatements = Array.from(iconImports.entries()) - .map(([componentName, importPath]) => { - return `import ${componentName} from '${importPath}';`; - }) - .join('\n'); - - // Combine all imports - const importStatements = [componentImportStatements, iconImportStatements] - .filter(Boolean) - .join('\n'); - - // Check if there's already a script tag - let hasScript = false; - visit(tree, 'html', (node) => { - if (node.value.startsWith(']*>/, - /** @param {string} match */ - (match) => `${match}\n${importStatements}` - ); - return EXIT; - } - }); - - if (!hasScript) { - // Create new script tag at the beginning - tree.children.unshift({ - type: 'html', - value: `` - }); - } - } - }; + const markdownComponentsPath = + options.markdownComponentsPath ?? '@layerstack/docs/markdown/components'; + const exampleComponentPath = options.exampleComponentPath ?? '$lib/components'; + + return (tree) => { + const componentsToImport = new Set(); + const iconImports = new Map(); // Map of componentName -> importPath + + // Process MDC components (remark-mdc creates leafComponent and containerComponent nodes) + visit(tree, (node) => { + // Handle both leafComponent (::component) and containerComponent (::component...::) + if (node.type === 'leafComponent' || node.type === 'containerComponent') { + const componentName = node.name; + + // Alert variants all use the Note component + const alertVariants = ['tip', 'note', 'warning', 'caution']; + + // Map component names to Svelte component names and variants + let svelteComponent; + let variant; + + if (alertVariants.includes(componentName)) { + svelteComponent = 'Note'; + variant = componentName; + } else if (componentName === 'steps') { + svelteComponent = 'Steps'; + } else if (componentName === 'tabs') { + svelteComponent = 'Tabs'; + } else if (componentName === 'tab') { + svelteComponent = 'Tab'; + } else { + // Unknown component, skip transformation + return; + } + + // Track which components we need to import + componentsToImport.add(svelteComponent); + + // Get component attributes from MDC + const attributes = node.attributes || {}; + + // Convert kebab-case to camelCase for Svelte props + let processedAttributes = kebabToCamelCase(attributes); + + // Handle icon attribute on tab components (e.g., ::tab{label="pnpm" icon="vscode-icons:file-type-pnpm"}) + if (componentName === 'tab' && processedAttributes.icon) { + const { importPath, componentName: iconCompName } = convertIconName( + processedAttributes.icon + ); + iconImports.set(iconCompName, importPath); + + // Replace icon string with component reference expression + // Remove quotes so it becomes {ComponentName} instead of "ComponentName" + processedAttributes = { + ...processedAttributes, + icon: `{${iconCompName}}`, + }; + } + + // Convert the MDC component into a component that rehype can handle + // We set data.hName to tell rehype to convert this to the component + const data = node.data || (node.data = {}); + data.hName = svelteComponent; + data.hProperties = { + ...processedAttributes, + // Pass variant for alert components + ...(variant && { variant }), + }; + } + + // Handle inline text components (:component) + if (node.type === 'textComponent') { + const componentName = node.name; + + // Support :icon{name="logos:tailwindcss-icon"} or :icon{name="i-lucide-code"} syntax + if (componentName === 'icon') { + const iconName = node.attributes?.name; + if (iconName) { + const { importPath, componentName: iconComponentName } = convertIconName(iconName); + + // Track this icon import + iconImports.set(iconComponentName, importPath); + + // Get other attributes (excluding 'name') + const { name: _, class: className, ...otherAttributes } = node.attributes || {}; + + // Convert to the icon component + const data = node.data || (node.data = {}); + data.hName = iconComponentName; + data.hProperties = { + ...otherAttributes, + class: cls('inline-block', className), + }; + } + } else if (componentName === 'button') { + componentsToImport.add('Button'); + + const attributes = node.attributes || {}; + + // Convert kebab-case to camelCase for Svelte props + let processedAttributes = kebabToCamelCase(attributes); + + // Handle icon attribute on button components (e.g., :button{icon="lucide:github"}) + if (processedAttributes.icon) { + const { importPath, componentName: iconCompName } = convertIconName( + processedAttributes.icon + ); + iconImports.set(iconCompName, importPath); + + // Replace icon string with component reference expression + processedAttributes = { + ...processedAttributes, + icon: `{${iconCompName}}`, + }; + } + + const data = node.data || (node.data = {}); + data.hName = 'Button'; + data.hProperties = processedAttributes; + } else if (componentName === 'example') { + componentsToImport.add('Example'); + + const attributes = node.attributes || {}; + + // Convert kebab-case to camelCase for Svelte props + const processedAttributes = kebabToCamelCase(attributes); + + const data = node.data || (node.data = {}); + data.hName = 'Example'; + data.hProperties = processedAttributes; + } + } + }); + + // Inject component imports at the beginning of the file + if (componentsToImport.size > 0 || iconImports.size > 0) { + // Generate regular component imports + const componentArray = Array.from(componentsToImport); + const componentImportStatements = componentArray + .map((comp) => { + const path = comp === 'Example' ? exampleComponentPath : markdownComponentsPath; + return `import ${comp} from '${path}/${comp}.svelte';`; + }) + .join('\n'); + + // Generate icon imports from unplugin-icons + const iconImportStatements = Array.from(iconImports.entries()) + .map(([componentName, importPath]) => { + return `import ${componentName} from '${importPath}';`; + }) + .join('\n'); + + // Combine all imports + const importStatements = [componentImportStatements, iconImportStatements] + .filter(Boolean) + .join('\n'); + + // Check if there's already a script tag + let hasScript = false; + visit(tree, 'html', (node) => { + if (node.value.startsWith(']*>/, + /** @param {string} match */ + (match) => `${match}\n${importStatements}` + ); + return EXIT; + } + }); + + if (!hasScript) { + // Create new script tag at the beginning + tree.children.unshift({ + type: 'html', + value: ``, + }); + } + } + }; } diff --git a/packages/docs/src/lib/markdown/toc.ts b/packages/docs/src/lib/markdown/toc.ts index 961ab1b..2585123 100644 --- a/packages/docs/src/lib/markdown/toc.ts +++ b/packages/docs/src/lib/markdown/toc.ts @@ -4,32 +4,32 @@ import GithubSlugger from 'github-slugger'; * Extract table of contents from markdown content */ export function extractTocFromMarkdown( - content: string + content: string ): { id: string; text: string; level: number }[] { - const toc: { id: string; text: string; level: number }[] = []; + const toc: { id: string; text: string; level: number }[] = []; - // A fresh slugger per document de-duplicates repeated slugs (e.g. headings - // `string` and `string[]` both slugify to `string`), matching `rehype-slug`'s - // behavior so TOC ids stay unique and line up with the rendered heading ids. - const slugger = new GithubSlugger(); + // A fresh slugger per document de-duplicates repeated slugs (e.g. headings + // `string` and `string[]` both slugify to `string`), matching `rehype-slug`'s + // behavior so TOC ids stay unique and line up with the rendered heading ids. + const slugger = new GithubSlugger(); - // Strip HTML comments so commented-out headings are ignored - const stripped = content.replace(//g, ''); + // Strip HTML comments so commented-out headings are ignored + const stripped = content.replace(//g, ''); - const headingRegex = /^(#{1,6})\s+(.+)$/gm; - let match: RegExpExecArray | null; - while ((match = headingRegex.exec(stripped)) !== null) { - const level = match[1].length; - // Strip inline MDC directives (e.g. `:icon{name="lucide:user" class="..."}`) - // and markdown links (e.g. `[text](url)` → `text`) - const text = match[2] - .replace(/:[a-zA-Z][\w-]*\{[^}]*\}/g, '') - .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') - .trim(); - if (!text) continue; - const id = slugger.slug(text); - toc.push({ id, text, level }); - } + const headingRegex = /^(#{1,6})\s+(.+)$/gm; + let match: RegExpExecArray | null; + while ((match = headingRegex.exec(stripped)) !== null) { + const level = match[1].length; + // Strip inline MDC directives (e.g. `:icon{name="lucide:user" class="..."}`) + // and markdown links (e.g. `[text](url)` → `text`) + const text = match[2] + .replace(/:[a-zA-Z][\w-]*\{[^}]*\}/g, '') + .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') + .trim(); + if (!text) continue; + const id = slugger.slug(text); + toc.push({ id, text, level }); + } - return toc; + return toc; } diff --git a/packages/docs/src/lib/markdown/transformers/shiki-diff.js b/packages/docs/src/lib/markdown/transformers/shiki-diff.js index 18beaeb..237d39e 100644 --- a/packages/docs/src/lib/markdown/transformers/shiki-diff.js +++ b/packages/docs/src/lib/markdown/transformers/shiki-diff.js @@ -4,43 +4,43 @@ * @returns {import('shiki').ShikiTransformer} */ export function shikiDiffTransformer() { - return { - name: 'diff-transformer', - code(node) { - // Trigger on either ```diff (language) or ``` diff (meta string) - const metaString = this.options.meta?.__raw || ''; - const lang = this.options.lang || ''; - if (lang !== 'diff' && !metaString.includes('diff')) return; - - // Add class to the pre element - this.addClassToHast(this.pre, 'has-diff'); - - // Get all line elements - const lines = node.children.filter((child) => child.type === 'element'); - - for (const line of lines) { - // Get all text tokens in this line - const tokens = line.children.filter((child) => child.type === 'element'); - - if (tokens.length === 0) continue; - - // Check the first token's text content - const firstToken = tokens[0]; - const textNodes = firstToken.children?.filter((child) => child.type === 'text'); - - if (!textNodes || textNodes.length === 0) continue; - - const firstText = textNodes[0]; - const text = firstText.value; - - if (text.startsWith('+')) { - this.addClassToHast(line, 'diff-add'); - firstText.value = text.slice(1); - } else if (text.startsWith('-')) { - this.addClassToHast(line, 'diff-remove'); - firstText.value = text.slice(1); - } - } - } - }; + return { + name: 'diff-transformer', + code(node) { + // Trigger on either ```diff (language) or ``` diff (meta string) + const metaString = this.options.meta?.__raw || ''; + const lang = this.options.lang || ''; + if (lang !== 'diff' && !metaString.includes('diff')) return; + + // Add class to the pre element + this.addClassToHast(this.pre, 'has-diff'); + + // Get all line elements + const lines = node.children.filter((child) => child.type === 'element'); + + for (const line of lines) { + // Get all text tokens in this line + const tokens = line.children.filter((child) => child.type === 'element'); + + if (tokens.length === 0) continue; + + // Check the first token's text content + const firstToken = tokens[0]; + const textNodes = firstToken.children?.filter((child) => child.type === 'text'); + + if (!textNodes || textNodes.length === 0) continue; + + const firstText = textNodes[0]; + const text = firstText.value; + + if (text.startsWith('+')) { + this.addClassToHast(line, 'diff-add'); + firstText.value = text.slice(1); + } else if (text.startsWith('-')) { + this.addClassToHast(line, 'diff-remove'); + firstText.value = text.slice(1); + } + } + }, + }; } diff --git a/packages/docs/src/lib/markdown/utils.ts b/packages/docs/src/lib/markdown/utils.ts index ad83cb3..28d030f 100644 --- a/packages/docs/src/lib/markdown/utils.ts +++ b/packages/docs/src/lib/markdown/utils.ts @@ -3,34 +3,34 @@ * Useful for search indexing or generating plain text excerpts. */ export function stripMarkdown(content: string): string { - return ( - content - // Remove code blocks - .replace(/```[\s\S]*?```/g, '') - // Remove inline code - .replace(/`[^`]+`/g, '') - // Remove links but keep text - .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') - // Remove images - .replace(/!\[([^\]]*)\]\([^)]+\)/g, '') - // Remove HTML tags - .replace(/<[^>]+>/g, '') - // Remove headings markup - .replace(/^#{1,6}\s+/gm, '') - // Remove bold/italic - .replace(/\*{1,2}([^*]+)\*{1,2}/g, '$1') - .replace(/_{1,2}([^_]+)_{1,2}/g, '$1') - // Remove blockquotes - .replace(/^>\s+/gm, '') - // Remove horizontal rules - .replace(/^[-*_]{3,}\s*$/gm, '') - // Remove list markers - .replace(/^[\s]*[-*+]\s+/gm, '') - .replace(/^[\s]*\d+\.\s+/gm, '') - // Remove MDX/directives like :example{...} or ::directive - .replace(/:{1,2}\w+(\{[^}]*\})?/g, '') - // Collapse multiple whitespace/newlines - .replace(/\s+/g, ' ') - .trim() - ); + return ( + content + // Remove code blocks + .replace(/```[\s\S]*?```/g, '') + // Remove inline code + .replace(/`[^`]+`/g, '') + // Remove links but keep text + .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') + // Remove images + .replace(/!\[([^\]]*)\]\([^)]+\)/g, '') + // Remove HTML tags + .replace(/<[^>]+>/g, '') + // Remove headings markup + .replace(/^#{1,6}\s+/gm, '') + // Remove bold/italic + .replace(/\*{1,2}([^*]+)\*{1,2}/g, '$1') + .replace(/_{1,2}([^_]+)_{1,2}/g, '$1') + // Remove blockquotes + .replace(/^>\s+/gm, '') + // Remove horizontal rules + .replace(/^[-*_]{3,}\s*$/gm, '') + // Remove list markers + .replace(/^[\s]*[-*+]\s+/gm, '') + .replace(/^[\s]*\d+\.\s+/gm, '') + // Remove MDX/directives like :example{...} or ::directive + .replace(/:{1,2}\w+(\{[^}]*\})?/g, '') + // Collapse multiple whitespace/newlines + .replace(/\s+/g, ' ') + .trim() + ); } diff --git a/packages/docs/src/lib/node/component-api.js b/packages/docs/src/lib/node/component-api.js index 4ba31d4..4a377c3 100644 --- a/packages/docs/src/lib/node/component-api.js +++ b/packages/docs/src/lib/node/component-api.js @@ -51,236 +51,228 @@ import ts from 'typescript'; * delegator re-exports the public Props type, which is what docs reference. */ export function getSvelteFiles(dir) { - const files = []; - const entries = fs.readdirSync(dir, { withFileTypes: true }); - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - // Recursively scan subdirectories (charts, layers, tooltip) - files.push(...getSvelteFiles(fullPath)); - } - else if (entry.isFile() && entry.name.endsWith('.svelte')) { - if (/\.(svg|canvas|html|base)\.svelte$/.test(entry.name)) - continue; - files.push(fullPath); - } + const files = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + // Recursively scan subdirectories (charts, layers, tooltip) + files.push(...getSvelteFiles(fullPath)); + } else if (entry.isFile() && entry.name.endsWith('.svelte')) { + if (/\.(svg|canvas|html|base)\.svelte$/.test(entry.name)) continue; + files.push(fullPath); } - return files; + } + return files; } /** * Extract JSDoc comments from a node */ function extractJsDoc(node) { - const jsDocTags = ts.getJSDocTags(node); - const jsDocComments = node.jsDoc; - let description; - const tags = {}; - let defaultValue; - // Extract description from JSDoc comment - if (jsDocComments && jsDocComments.length > 0) { - const comment = jsDocComments[0].comment; - if (typeof comment === 'string') { - description = comment; - } - else if (Array.isArray(comment)) { - description = comment.map((c) => c.text).join(''); - } + const jsDocTags = ts.getJSDocTags(node); + const jsDocComments = node.jsDoc; + let description; + const tags = {}; + let defaultValue; + // Extract description from JSDoc comment + if (jsDocComments && jsDocComments.length > 0) { + const comment = jsDocComments[0].comment; + if (typeof comment === 'string') { + description = comment; + } else if (Array.isArray(comment)) { + description = comment.map((c) => c.text).join(''); } - // Extract tags - for (const tag of jsDocTags) { - const tagName = tag.tagName.text; - let tagValue = ''; - if (tag.comment) { - if (typeof tag.comment === 'string') { - tagValue = tag.comment; - } - else if (Array.isArray(tag.comment)) { - tagValue = tag.comment.map((c) => c.text).join(''); - } - } - if (tagName === 'default') { - defaultValue = tagValue; - } - else { - tags[tagName] = tagValue; - } + } + // Extract tags + for (const tag of jsDocTags) { + const tagName = tag.tagName.text; + let tagValue = ''; + if (tag.comment) { + if (typeof tag.comment === 'string') { + tagValue = tag.comment; + } else if (Array.isArray(tag.comment)) { + tagValue = tag.comment.map((c) => c.text).join(''); + } } - return { - description, - tags: Object.keys(tags).length > 0 ? tags : undefined, - default: defaultValue - }; + if (tagName === 'default') { + defaultValue = tagValue; + } else { + tags[tagName] = tagValue; + } + } + return { + description, + tags: Object.keys(tags).length > 0 ? tags : undefined, + default: defaultValue, + }; } /** * Get type as string */ function getTypeString(typeNode, checker) { - if (!typeNode) - return 'any'; - // Use the printer to get a string representation - const printer = ts.createPrinter({ removeComments: true }); - const typeString = printer.printNode(ts.EmitHint.Unspecified, typeNode, typeNode.getSourceFile()); - // Normalize whitespace - collapse multiple spaces/newlines into single spaces - return typeString.replace(/\s+/g, ' ').trim(); + if (!typeNode) return 'any'; + // Use the printer to get a string representation + const printer = ts.createPrinter({ removeComments: true }); + const typeString = printer.printNode(ts.EmitHint.Unspecified, typeNode, typeNode.getSourceFile()); + // Normalize whitespace - collapse multiple spaces/newlines into single spaces + return typeString.replace(/\s+/g, ' ').trim(); } /** * Extract properties from a type literal or interface */ function extractProperties(node, checker) { - const properties = []; - for (const member of node.members) { - if (ts.isPropertySignature(member) && member.name) { - const name = member.name.getText(); - const required = !member.questionToken; // Inverted: required = not optional - const type = getTypeString(member.type, checker); - const jsDoc = extractJsDoc(member); - // Check if this is a nested object type - let nestedProperties; - if (member.type && ts.isTypeLiteralNode(member.type)) { - nestedProperties = extractProperties(member.type, checker); - } - properties.push({ - name, - type, - required, - ...jsDoc, - ...(nestedProperties && nestedProperties.length > 0 ? { properties: nestedProperties } : {}) - }); - } + const properties = []; + for (const member of node.members) { + if (ts.isPropertySignature(member) && member.name) { + const name = member.name.getText(); + const required = !member.questionToken; // Inverted: required = not optional + const type = getTypeString(member.type, checker); + const jsDoc = extractJsDoc(member); + // Check if this is a nested object type + let nestedProperties; + if (member.type && ts.isTypeLiteralNode(member.type)) { + nestedProperties = extractProperties(member.type, checker); + } + properties.push({ + name, + type, + required, + ...jsDoc, + ...(nestedProperties && nestedProperties.length > 0 + ? { properties: nestedProperties } + : {}), + }); } - return properties; + } + return properties; } /** * Resolve intersection types and extract all properties */ function extractPropertiesFromType(typeNode, checker, sourceFile) { - let properties = []; - if (ts.isIntersectionTypeNode(typeNode)) { - // Handle intersection types (A & B & C) - for (const type of typeNode.types) { - properties = properties.concat(extractPropertiesFromType(type, checker, sourceFile)); - } - } - else if (ts.isTypeLiteralNode(typeNode)) { - // Handle inline type literals - properties = extractProperties(typeNode, checker); - } - else if (ts.isTypeReferenceNode(typeNode)) { - // Handle type references (e.g., CommonStyleProps) - const typeName = typeNode.typeName.getText(); - // Try to find the type definition in the same file - ts.forEachChild(sourceFile, (node) => { - if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) { - properties = properties.concat(extractPropertiesFromType(node.type, checker, sourceFile)); - } - else if (ts.isInterfaceDeclaration(node) && node.name.text === typeName) { - properties = properties.concat(extractProperties(node, checker)); - } - }); + let properties = []; + if (ts.isIntersectionTypeNode(typeNode)) { + // Handle intersection types (A & B & C) + for (const type of typeNode.types) { + properties = properties.concat(extractPropertiesFromType(type, checker, sourceFile)); } - return properties; + } else if (ts.isTypeLiteralNode(typeNode)) { + // Handle inline type literals + properties = extractProperties(typeNode, checker); + } else if (ts.isTypeReferenceNode(typeNode)) { + // Handle type references (e.g., CommonStyleProps) + const typeName = typeNode.typeName.getText(); + // Try to find the type definition in the same file + ts.forEachChild(sourceFile, (node) => { + if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) { + properties = properties.concat(extractPropertiesFromType(node.type, checker, sourceFile)); + } else if (ts.isInterfaceDeclaration(node) && node.name.text === typeName) { + properties = properties.concat(extractProperties(node, checker)); + } + }); + } + return properties; } /** * Extract element type from generic types like SVGAttributes */ function extractElementType(typeString) { - const match = typeString.match(/(?:SVG|HTML)Attributes<(\w+)>/); - return match?.[1]; + const match = typeString.match(/(?:SVG|HTML)Attributes<(\w+)>/); + return match?.[1]; } /** * Parse extended types from an intersection type */ function parseExtendedTypes(typeNode, sourceFile) { - const extendedTypes = []; - if (!ts.isIntersectionTypeNode(typeNode)) { - return extendedTypes; + const extendedTypes = []; + if (!ts.isIntersectionTypeNode(typeNode)) { + return extendedTypes; + } + for (const type of typeNode.types) { + const typeText = type.getText(sourceFile); + // Skip the base PropsWithoutHTML type (but not Without<> that contains PropsWithoutHTML) + if (!typeText.startsWith('Without<') && typeText.includes('PropsWithoutHTML')) { + continue; } - for (const type of typeNode.types) { - const typeText = type.getText(sourceFile); - // Skip the base PropsWithoutHTML type (but not Without<> that contains PropsWithoutHTML) - if (!typeText.startsWith('Without<') && typeText.includes('PropsWithoutHTML')) { - continue; - } - // Check if this is a Without<> wrapper (used to exclude props) - // Extract the element type from inside Without, ...> - const elementTypeFromWithout = extractElementType(typeText); - if (typeText.startsWith('Without<') && elementTypeFromWithout) { - extendedTypes.push({ - name: elementTypeFromWithout.replace(/Element$/, 'Attributes'), - fullType: typeText, - elementType: elementTypeFromWithout, - isLibraryType: true - }); - continue; - } - // Check if this is an SVG/HTML Attributes type - const elementType = extractElementType(typeText); - if (elementType) { - extendedTypes.push({ - name: elementType.replace(/Element$/, 'Attributes'), - fullType: typeText, - elementType, - isLibraryType: true - }); - continue; - } - // Check if this is a reference to another type (like CommonEvents) - if (ts.isTypeReferenceNode(type)) { - const typeName = type.typeName.getText(sourceFile); - extendedTypes.push({ - name: typeName, - fullType: typeText, - isLibraryType: false // We should extract these types - }); - } + // Check if this is a Without<> wrapper (used to exclude props) + // Extract the element type from inside Without, ...> + const elementTypeFromWithout = extractElementType(typeText); + if (typeText.startsWith('Without<') && elementTypeFromWithout) { + extendedTypes.push({ + name: elementTypeFromWithout.replace(/Element$/, 'Attributes'), + fullType: typeText, + elementType: elementTypeFromWithout, + isLibraryType: true, + }); + continue; } - return extendedTypes; + // Check if this is an SVG/HTML Attributes type + const elementType = extractElementType(typeText); + if (elementType) { + extendedTypes.push({ + name: elementType.replace(/Element$/, 'Attributes'), + fullType: typeText, + elementType, + isLibraryType: true, + }); + continue; + } + // Check if this is a reference to another type (like CommonEvents) + if (ts.isTypeReferenceNode(type)) { + const typeName = type.typeName.getText(sourceFile); + extendedTypes.push({ + name: typeName, + fullType: typeText, + isLibraryType: false, // We should extract these types + }); + } + } + return extendedTypes; } /** * Find the main Props type for a component * Looks for patterns like: ComponentPropsWithoutHTML, ComponentProps */ function findPropsTypeName(componentName, moduleScript) { - // Try different patterns in order of preference - const patterns = [ - // First try exported types with exact component name match - { pattern: `${componentName}PropsWithoutHTML`, requireExport: true }, - { pattern: `${componentName}Props`, requireExport: true }, - // Then try non-exported types with exact component name match - { pattern: `${componentName}PropsWithoutHTML`, requireExport: false }, - { pattern: `${componentName}Props`, requireExport: false }, - // Finally, try any exported Props type - { regex: new RegExp(`export type (\\w*PropsWithoutHTML)`, 'g') }, - { regex: new RegExp(`export type (\\w*Props)(?!WithoutHTML)`, 'g') }, - // Last resort: any Props type (exported or not) - { regex: new RegExp(`type (\\w*PropsWithoutHTML)`, 'g') }, - { regex: new RegExp(`type (\\w*Props)(?!WithoutHTML)`, 'g') } - ]; - for (const config of patterns) { - if ('regex' in config && config.regex) { - // For regex patterns, find all matches - const matches = [...moduleScript.matchAll(config.regex)]; - if (matches.length > 0) { - // Prefer types ending with "WithoutHTML" - const withoutHTMLMatch = matches.find((m) => m[1].endsWith('WithoutHTML')); - if (withoutHTMLMatch) { - return withoutHTMLMatch[1]; - } - // Otherwise return the first match - return matches[0][1]; - } - } - else if ('pattern' in config && config.pattern) { - // String pattern - const searchStr = config.requireExport - ? `export type ${config.pattern}` - : `type ${config.pattern}`; - if (moduleScript.includes(searchStr)) { - return config.pattern; - } + // Try different patterns in order of preference + const patterns = [ + // First try exported types with exact component name match + { pattern: `${componentName}PropsWithoutHTML`, requireExport: true }, + { pattern: `${componentName}Props`, requireExport: true }, + // Then try non-exported types with exact component name match + { pattern: `${componentName}PropsWithoutHTML`, requireExport: false }, + { pattern: `${componentName}Props`, requireExport: false }, + // Finally, try any exported Props type + { regex: new RegExp(`export type (\\w*PropsWithoutHTML)`, 'g') }, + { regex: new RegExp(`export type (\\w*Props)(?!WithoutHTML)`, 'g') }, + // Last resort: any Props type (exported or not) + { regex: new RegExp(`type (\\w*PropsWithoutHTML)`, 'g') }, + { regex: new RegExp(`type (\\w*Props)(?!WithoutHTML)`, 'g') }, + ]; + for (const config of patterns) { + if ('regex' in config && config.regex) { + // For regex patterns, find all matches + const matches = [...moduleScript.matchAll(config.regex)]; + if (matches.length > 0) { + // Prefer types ending with "WithoutHTML" + const withoutHTMLMatch = matches.find((m) => m[1].endsWith('WithoutHTML')); + if (withoutHTMLMatch) { + return withoutHTMLMatch[1]; } + // Otherwise return the first match + return matches[0][1]; + } + } else if ('pattern' in config && config.pattern) { + // String pattern + const searchStr = config.requireExport + ? `export type ${config.pattern}` + : `type ${config.pattern}`; + if (moduleScript.includes(searchStr)) { + return config.pattern; + } } - return null; + } + return null; } /** * Inline `export type { Foo } from './X.shared.svelte.js'` re-exports by @@ -289,40 +281,43 @@ function findPropsTypeName(componentName, moduleScript) { * `*.shared.svelte.ts`, so without this the TS parser sees no type definition. */ function resolveSharedReExports(filePath, moduleScript) { - const reExportRegex = /export\s+type\s*\{[^}]+\}\s*from\s+['"](\.\/[^'"]+\.shared\.svelte)\.js['"]\s*;?/g; - const dir = path.dirname(filePath); - let combined = moduleScript; - for (const match of moduleScript.matchAll(reExportRegex)) { - const sharedPath = path.join(dir, `${match[1].slice(2)}.ts`); - if (fs.existsSync(sharedPath)) { - combined += '\n' + fs.readFileSync(sharedPath, 'utf-8'); - } + const reExportRegex = + /export\s+type\s*\{[^}]+\}\s*from\s+['"](\.\/[^'"]+\.shared\.svelte)\.js['"]\s*;?/g; + const dir = path.dirname(filePath); + let combined = moduleScript; + for (const match of moduleScript.matchAll(reExportRegex)) { + const sharedPath = path.join(dir, `${match[1].slice(2)}.ts`); + if (fs.existsSync(sharedPath)) { + combined += '\n' + fs.readFileSync(sharedPath, 'utf-8'); } - return combined; + } + return combined; } /** * Extract component API from a Svelte file */ export function extractComponentAPI(filePath) { - const content = fs.readFileSync(filePath, 'utf-8'); - // Extract the module script content - const moduleScriptMatch = content.match(/]*lang="ts"[^>]*module[^>]*>([\s\S]*?)<\/script>/); - if (!moduleScriptMatch) { - return null; - } - const moduleScript = resolveSharedReExports(filePath, moduleScriptMatch[1]); - // Look for the main Props type - const componentName = path.basename(filePath, '.svelte'); - const propsTypeName = findPropsTypeName(componentName, moduleScript); - if (!propsTypeName) { - return null; - } - // Create a temporary TypeScript file for parsing - const tempFile = `temp-${componentName}.ts`; - const tempPath = path.join(path.dirname(filePath), tempFile); - // Write the module script to a temp file with necessary imports resolved - // We keep the original imports but add stub types for common ones that might not resolve - const tempContent = ` + const content = fs.readFileSync(filePath, 'utf-8'); + // Extract the module script content + const moduleScriptMatch = content.match( + /]*lang="ts"[^>]*module[^>]*>([\s\S]*?)<\/script>/ + ); + if (!moduleScriptMatch) { + return null; + } + const moduleScript = resolveSharedReExports(filePath, moduleScriptMatch[1]); + // Look for the main Props type + const componentName = path.basename(filePath, '.svelte'); + const propsTypeName = findPropsTypeName(componentName, moduleScript); + if (!propsTypeName) { + return null; + } + // Create a temporary TypeScript file for parsing + const tempFile = `temp-${componentName}.ts`; + const tempPath = path.join(path.dirname(filePath), tempFile); + // Write the module script to a temp file with necessary imports resolved + // We keep the original imports but add stub types for common ones that might not resolve + const tempContent = ` import type { SVGAttributes, HTMLAttributes, MouseEventHandler, PointerEventHandler } from 'svelte/elements'; import type { Snippet, Component } from 'svelte'; @@ -366,141 +361,143 @@ type Placement = 'top' | 'right' | 'bottom' | 'left'; ${moduleScript} `; - fs.writeFileSync(tempPath, tempContent); - try { - // Parse the TypeScript file - const program = ts.createProgram([tempPath], { - target: ts.ScriptTarget.ES2020, - module: ts.ModuleKind.ESNext - }); - const sourceFile = program.getSourceFile(tempPath); - if (!sourceFile) { - return null; - } - const checker = program.getTypeChecker(); - let properties = []; - const extendedTypes = []; - // Find the PropsWithoutHTML type for properties - ts.forEachChild(sourceFile, (node) => { - if (ts.isTypeAliasDeclaration(node) && node.name.text === propsTypeName) { - properties = extractPropertiesFromType(node.type, checker, sourceFile); + fs.writeFileSync(tempPath, tempContent); + try { + // Parse the TypeScript file + const program = ts.createProgram([tempPath], { + target: ts.ScriptTarget.ES2020, + module: ts.ModuleKind.ESNext, + }); + const sourceFile = program.getSourceFile(tempPath); + if (!sourceFile) { + return null; + } + const checker = program.getTypeChecker(); + let properties = []; + const extendedTypes = []; + // Find the PropsWithoutHTML type for properties + ts.forEachChild(sourceFile, (node) => { + if (ts.isTypeAliasDeclaration(node) && node.name.text === propsTypeName) { + properties = extractPropertiesFromType(node.type, checker, sourceFile); + } + }); + // Also look for the full Props type to extract extended types + // Try both removing "WithoutHTML" and looking for types that end with "Props" + const possibleFullPropsNames = [ + propsTypeName.replace('WithoutHTML', ''), + `${componentName}Props`, + ]; + for (const fullPropsTypeName of possibleFullPropsNames) { + ts.forEachChild(sourceFile, (node) => { + if (ts.isTypeAliasDeclaration(node) && node.name.text === fullPropsTypeName) { + const newExtendedTypes = parseExtendedTypes(node.type, sourceFile); + // Merge with existing, avoiding duplicates + for (const extType of newExtendedTypes) { + if (!extendedTypes.some((et) => et.name === extType.name)) { + extendedTypes.push(extType); } - }); - // Also look for the full Props type to extract extended types - // Try both removing "WithoutHTML" and looking for types that end with "Props" - const possibleFullPropsNames = [ - propsTypeName.replace('WithoutHTML', ''), - `${componentName}Props` - ]; - for (const fullPropsTypeName of possibleFullPropsNames) { - ts.forEachChild(sourceFile, (node) => { - if (ts.isTypeAliasDeclaration(node) && node.name.text === fullPropsTypeName) { - const newExtendedTypes = parseExtendedTypes(node.type, sourceFile); - // Merge with existing, avoiding duplicates - for (const extType of newExtendedTypes) { - if (!extendedTypes.some((et) => et.name === extType.name)) { - extendedTypes.push(extType); - } - } - // Extract properties from non-library extended types (like CommonEvents) - for (const extType of extendedTypes) { - if (!extType.isLibraryType) { - // Find this type definition and extract its properties - ts.forEachChild(sourceFile, (typeNode) => { - if (ts.isTypeAliasDeclaration(typeNode) && typeNode.name.text === extType.name) { - const extProperties = extractPropertiesFromType(typeNode.type, checker, sourceFile); - // Add these properties to the main list, avoiding duplicates - for (const prop of extProperties) { - if (!properties.some((p) => p.name === prop.name)) { - properties.push(prop); - } - } - } - }); - } + } + // Extract properties from non-library extended types (like CommonEvents) + for (const extType of extendedTypes) { + if (!extType.isLibraryType) { + // Find this type definition and extract its properties + ts.forEachChild(sourceFile, (typeNode) => { + if (ts.isTypeAliasDeclaration(typeNode) && typeNode.name.text === extType.name) { + const extProperties = extractPropertiesFromType( + typeNode.type, + checker, + sourceFile + ); + // Add these properties to the main list, avoiding duplicates + for (const prop of extProperties) { + if (!properties.some((p) => p.name === prop.name)) { + properties.push(prop); } + } } - }); - } - if (properties.length === 0) { - return null; - } - const result = { - generatedAt: new Date().toISOString(), - component: componentName, - propsType: propsTypeName, - properties - }; - // Only add extends if there are extended types - if (extendedTypes.length > 0) { - result.extends = extendedTypes; + }); + } + } } - return result; + }); } - finally { - // Clean up temp file - if (fs.existsSync(tempPath)) { - fs.unlinkSync(tempPath); - } + if (properties.length === 0) { + return null; + } + const result = { + generatedAt: new Date().toISOString(), + component: componentName, + propsType: propsTypeName, + properties, + }; + // Only add extends if there are extended types + if (extendedTypes.length > 0) { + result.extends = extendedTypes; + } + return result; + } finally { + // Clean up temp file + if (fs.existsSync(tempPath)) { + fs.unlinkSync(tempPath); } + } } /** * Extract APIs for all components in a directory */ export function extractAPIs(dir) { - const svelteFiles = getSvelteFiles(dir); - const apis = []; - for (const filePath of svelteFiles) { - const api = extractComponentAPI(filePath); - if (api) { - apis.push(api); - } + const svelteFiles = getSvelteFiles(dir); + const apis = []; + for (const filePath of svelteFiles) { + const api = extractComponentAPI(filePath); + if (api) { + apis.push(api); } - return apis.sort((a, b) => a.component.localeCompare(b.component)); + } + return apis.sort((a, b) => a.component.localeCompare(b.component)); } export function writeComponentAPIs({ componentsDir, outputDir, logger = console }) { - logger.log('Extracting component APIs...'); - const svelteFiles = getSvelteFiles(componentsDir); - logger.log(`Found ${svelteFiles.length} Svelte files`); - const apis = []; - for (const filePath of svelteFiles) { - const componentName = path.basename(filePath, '.svelte'); - logger.log(`Processing ${componentName}...`); - const api = extractComponentAPI(filePath); - if (api) { - apis.push(api); - logger.log(` ✓ Extracted ${api.properties.length} properties`); - } - else { - logger.log(` ⚠ No Props type found`); - } - } - // Sort by component name - apis.sort((a, b) => a.component.localeCompare(b.component)); - // Create output directory if it doesn't exist - if (!fs.existsSync(outputDir)) { - fs.mkdirSync(outputDir, { recursive: true }); - } - // Write individual component files - logger.log(`\nWriting individual component files...`); - for (const api of apis) { - const componentFile = path.join(outputDir, `${api.component}.json`); - fs.writeFileSync(componentFile, JSON.stringify(api, null, 2)); + logger.log('Extracting component APIs...'); + const svelteFiles = getSvelteFiles(componentsDir); + logger.log(`Found ${svelteFiles.length} Svelte files`); + const apis = []; + for (const filePath of svelteFiles) { + const componentName = path.basename(filePath, '.svelte'); + logger.log(`Processing ${componentName}...`); + const api = extractComponentAPI(filePath); + if (api) { + apis.push(api); + logger.log(` ✓ Extracted ${api.properties.length} properties`); + } else { + logger.log(` ⚠ No Props type found`); } - // Write index file with list of all components - const indexFile = path.join(outputDir, 'index.json'); - const indexOutput = { - generatedAt: new Date().toISOString(), - components: apis.map((api) => ({ - component: api.component, - propsType: api.propsType, - propertyCount: api.properties.length, - file: `${api.component}.json` - })) - }; - fs.writeFileSync(indexFile, JSON.stringify(indexOutput, null, 2)); - logger.log(`\n✅ Generated ${apis.length} component API files in ${outputDir}`); - logger.log(`✅ Generated index file: ${indexFile}`); - logger.log(` Extracted ${apis.length} component APIs`); - return apis; + } + // Sort by component name + apis.sort((a, b) => a.component.localeCompare(b.component)); + // Create output directory if it doesn't exist + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + // Write individual component files + logger.log(`\nWriting individual component files...`); + for (const api of apis) { + const componentFile = path.join(outputDir, `${api.component}.json`); + fs.writeFileSync(componentFile, JSON.stringify(api, null, 2)); + } + // Write index file with list of all components + const indexFile = path.join(outputDir, 'index.json'); + const indexOutput = { + generatedAt: new Date().toISOString(), + components: apis.map((api) => ({ + component: api.component, + propsType: api.propsType, + propertyCount: api.properties.length, + file: `${api.component}.json`, + })), + }; + fs.writeFileSync(indexFile, JSON.stringify(indexOutput, null, 2)); + logger.log(`\n✅ Generated ${apis.length} component API files in ${outputDir}`); + logger.log(`✅ Generated index file: ${indexFile}`); + logger.log(` Extracted ${apis.length} component APIs`); + return apis; } diff --git a/packages/docs/src/lib/node/example-catalog.js b/packages/docs/src/lib/node/example-catalog.js index 574e81d..573075a 100644 --- a/packages/docs/src/lib/node/example-catalog.js +++ b/packages/docs/src/lib/node/example-catalog.js @@ -31,228 +31,231 @@ let EXAMPLES_DIR = ''; * `.svelte` is treated as a public component. */ function getComponents(dir) { - const components = []; - const entries = fs.readdirSync(dir, { withFileTypes: true }); - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - if (entry.isFile() && entry.name.endsWith('.svelte')) { - if (/\.(svg|canvas|html|base)\.svelte$/.test(entry.name)) - continue; - // Remove .svelte extension to get component name - const componentName = entry.name.replace('.svelte', ''); - components.push(componentName); - } - else if (entry.isDirectory()) { - // Recursively scan subdirectories - components.push(...getComponents(fullPath)); - } + const components = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isFile() && entry.name.endsWith('.svelte')) { + if (/\.(svg|canvas|html|base)\.svelte$/.test(entry.name)) continue; + // Remove .svelte extension to get component name + const componentName = entry.name.replace('.svelte', ''); + components.push(componentName); + } else if (entry.isDirectory()) { + // Recursively scan subdirectories + components.push(...getComponents(fullPath)); } - return components.sort(); + } + return components.sort(); } /** * Extract all component usages from an example file */ function extractComponentsFromExample(filePath, allComponents) { - const components = []; - const content = fs.readFileSync(filePath, 'utf-8'); - const lines = content.split('\n'); - // Track which components we've found to avoid duplicates - const foundComponents = new Set(); - // Search for each known component in the file - for (const componentName of allComponents) { - // Use word boundary to avoid matching components with similar prefixes - // Match if followed by: whitespace, >, /, ., :, or end-of-line - const searchPattern = new RegExp(`<${componentName}(?:\\s|>|/|\\.|:|$)`, 'i'); - lines.forEach((line, index) => { - if (searchPattern.test(line) && !foundComponents.has(componentName)) { - foundComponents.add(componentName); - components.push({ - component: componentName, - lineNumber: index + 1, - line: line.trim() - }); - } + const components = []; + const content = fs.readFileSync(filePath, 'utf-8'); + const lines = content.split('\n'); + // Track which components we've found to avoid duplicates + const foundComponents = new Set(); + // Search for each known component in the file + for (const componentName of allComponents) { + // Use word boundary to avoid matching components with similar prefixes + // Match if followed by: whitespace, >, /, ., :, or end-of-line + const searchPattern = new RegExp(`<${componentName}(?:\\s|>|/|\\.|:|$)`, 'i'); + lines.forEach((line, index) => { + if (searchPattern.test(line) && !foundComponents.has(componentName)) { + foundComponents.add(componentName); + components.push({ + component: componentName, + lineNumber: index + 1, + line: line.trim(), }); - } - // Sort by line number - return components.sort((a, b) => a.lineNumber - b.lineNumber); + } + }); + } + // Sort by line number + return components.sort((a, b) => a.lineNumber - b.lineNumber); } /** * Extract module-level exports (title, description, tags) from a - - -
    %sveltekit.body%
    - + // Send to parent window if in iframe + if (window.parent !== window) { + try { + window.parent.postMessage( + { + type: 'console', + level: level, + args: args.map((arg) => { + // Handle objects/arrays + if (typeof arg === 'object' && arg !== null) { + try { + return JSON.parse(JSON.stringify(arg)); + } catch (e) { + return String(arg); + } + } + return arg; + }), + }, + '*' + ); + } catch (e) { + // Ignore errors posting message + } + } + }; + }); + })(); + + + +
    %sveltekit.body%
    + diff --git a/packages/docs/templates/stackblitz-template/src/routes/+layout.svelte b/packages/docs/templates/stackblitz-template/src/routes/+layout.svelte index c5cd34f..06476ac 100644 --- a/packages/docs/templates/stackblitz-template/src/routes/+layout.svelte +++ b/packages/docs/templates/stackblitz-template/src/routes/+layout.svelte @@ -1,9 +1,9 @@
    - {@render children?.()} + {@render children?.()}
    diff --git a/packages/docs/templates/stackblitz-template/svelte.config.js b/packages/docs/templates/stackblitz-template/svelte.config.js index f571400..ae56723 100644 --- a/packages/docs/templates/stackblitz-template/svelte.config.js +++ b/packages/docs/templates/stackblitz-template/svelte.config.js @@ -2,20 +2,20 @@ import adapter from '@sveltejs/adapter-auto'; /** @type {import('@sveltejs/kit').Config} */ const config = { - kit: { - adapter: adapter(), - alias: { - '$static/*': 'static/*' - }, - experimental: { - remoteFunctions: true - } - }, - compilerOptions: { - experimental: { - async: true - } - } + kit: { + adapter: adapter(), + alias: { + '$static/*': 'static/*', + }, + experimental: { + remoteFunctions: true, + }, + }, + compilerOptions: { + experimental: { + async: true, + }, + }, }; export default config; diff --git a/packages/docs/templates/stackblitz-template/vite.config.js b/packages/docs/templates/stackblitz-template/vite.config.js index 1ed35fe..867603e 100644 --- a/packages/docs/templates/stackblitz-template/vite.config.js +++ b/packages/docs/templates/stackblitz-template/vite.config.js @@ -4,11 +4,11 @@ import tailwindcss from '@tailwindcss/vite'; import Icons from 'unplugin-icons/vite'; export default defineConfig({ - plugins: [ - tailwindcss(), - sveltekit(), - Icons({ - compiler: 'svelte' - }) - ] + plugins: [ + tailwindcss(), + sveltekit(), + Icons({ + compiler: 'svelte', + }), + ], }); diff --git a/packages/docs/tsconfig.json b/packages/docs/tsconfig.json index e37c0e4..b0bc4ba 100644 --- a/packages/docs/tsconfig.json +++ b/packages/docs/tsconfig.json @@ -1,15 +1,15 @@ { - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": false, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "moduleResolution": "bundler" - }, - "exclude": ["node_modules", "dist", "templates"] + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + }, + "exclude": ["node_modules", "dist", "templates"] } diff --git a/sites/docs/content-collections.ts b/sites/docs/content-collections.ts index 28d14dd..ccb099d 100644 --- a/sites/docs/content-collections.ts +++ b/sites/docs/content-collections.ts @@ -1,11 +1,11 @@ import { createContentConfig } from '@layerstack/docs/content-collections'; export default createContentConfig({ - // LayerStack is a multi-package monorepo; docs are authored as `reference` content - // organized by package under `src/content/reference//.md`. - packageName: 'layerstack', - repo: 'techniq/layerstack', - branch: 'main', - // `sites/docs` -> repo root `packages` - packagesRoot: '../../packages' + // LayerStack is a multi-package monorepo; docs are authored as `reference` content + // organized by package under `src/content/reference//.md`. + packageName: 'layerstack', + repo: 'techniq/layerstack', + branch: 'main', + // `sites/docs` -> repo root `packages` + packagesRoot: '../../packages', }); diff --git a/sites/docs/mdsx.config.js b/sites/docs/mdsx.config.js index ef3a1df..b89cf6c 100644 --- a/sites/docs/mdsx.config.js +++ b/sites/docs/mdsx.config.js @@ -1,7 +1,7 @@ import { createMdsxConfig } from '@layerstack/docs/markdown/config'; export const mdsxConfig = createMdsxConfig({ - markdownComponentsPath: '@layerstack/docs/markdown/components', - exampleComponentPath: '$lib/components', - liveCodeComponent: '@layerstack/docs/markdown/components/LiveCode.svelte' + markdownComponentsPath: '@layerstack/docs/markdown/components', + exampleComponentPath: '$lib/components', + liveCodeComponent: '@layerstack/docs/markdown/components/LiveCode.svelte', }); diff --git a/sites/docs/src/content/reference/svelte-actions/input.md b/sites/docs/src/content/reference/svelte-actions/input.md index 31b17ac..ac73dec 100644 --- a/sites/docs/src/content/reference/svelte-actions/input.md +++ b/sites/docs/src/content/reference/svelte-actions/input.md @@ -7,7 +7,13 @@ related: [components/TextField, components/Input] ## Usage ```js -import { autoFocus, autoHeight, blurOnEscape, selectOnFocus, debounceEvent } from '@layerstack/svelte-actions'; +import { + autoFocus, + autoHeight, + blurOnEscape, + selectOnFocus, + debounceEvent, +} from '@layerstack/svelte-actions'; ``` ## autoFocus diff --git a/sites/docs/src/content/reference/svelte-actions/layout.md b/sites/docs/src/content/reference/svelte-actions/layout.md index 276491d..9a07891 100644 --- a/sites/docs/src/content/reference/svelte-actions/layout.md +++ b/sites/docs/src/content/reference/svelte-actions/layout.md @@ -7,7 +7,11 @@ related: [components/Overflow] ## Usage ```js -import { remainingViewportHeight, remainingViewportWidth, overflow } from '@layerstack/svelte-actions'; +import { + remainingViewportHeight, + remainingViewportWidth, + overflow, +} from '@layerstack/svelte-actions'; ``` ## remainingViewportHeight diff --git a/sites/docs/src/content/reference/svelte-state/PaginationState.md b/sites/docs/src/content/reference/svelte-state/PaginationState.md index a127fcb..5cac383 100644 --- a/sites/docs/src/content/reference/svelte-state/PaginationState.md +++ b/sites/docs/src/content/reference/svelte-state/PaginationState.md @@ -11,15 +11,15 @@ import { PaginationState } from '@layerstack/svelte-state'; const state = new PaginationState({ total: 100 }); -state.page -state.perPage -state.total -state.totalPages -state.from -state.to -state.isFirst -state.isLast -state.hasPrevious -state.hasNext -state.slice(data) +state.page; +state.perPage; +state.total; +state.totalPages; +state.from; +state.to; +state.isFirst; +state.isLast; +state.hasPrevious; +state.hasNext; +state.slice(data); ``` diff --git a/sites/docs/src/content/reference/svelte-state/SelectionState.md b/sites/docs/src/content/reference/svelte-state/SelectionState.md index 72c5b28..b86db8c 100644 --- a/sites/docs/src/content/reference/svelte-state/SelectionState.md +++ b/sites/docs/src/content/reference/svelte-state/SelectionState.md @@ -11,8 +11,8 @@ import { SelectionState } from '@layerstack/svelte-state'; const state = new SelectionState(); -state.current.has(value) -state.current.size +state.current.has(value); +state.current.size; state.add(value); state.delete(value); state.toggle(value); diff --git a/sites/docs/src/content/reference/svelte-state/UniqueState.md b/sites/docs/src/content/reference/svelte-state/UniqueState.md index eb7ba36..c3eac56 100644 --- a/sites/docs/src/content/reference/svelte-state/UniqueState.md +++ b/sites/docs/src/content/reference/svelte-state/UniqueState.md @@ -11,8 +11,8 @@ import { UniqueState } from '@layerstack/svelte-state'; const state = new UniqueState(); -state.current.has(value) -state.current.size +state.current.has(value); +state.current.size; state.add(value); state.addEach([value1, value2]); state.delete(value); diff --git a/sites/docs/src/examples/components/Duration/format-date-range.svelte b/sites/docs/src/examples/components/Duration/format-date-range.svelte index 8daff36..b434c08 100644 --- a/sites/docs/src/examples/components/Duration/format-date-range.svelte +++ b/sites/docs/src/examples/components/Duration/format-date-range.svelte @@ -1,10 +1,10 @@
    {new Duration({ start: intervalOffset('day', new Date(), 3) }).format()}
    {new Duration({ start: intervalOffset('month', new Date(), 3) }).format()}
    - {new Duration({ start: intervalOffset('month', new Date(), 3) }).format({ variant: 'long' })} + {new Duration({ start: intervalOffset('month', new Date(), 3) }).format({ variant: 'long' })}
    diff --git a/sites/docs/src/examples/components/Duration/format-duration-object.svelte b/sites/docs/src/examples/components/Duration/format-duration-object.svelte index 27e9937..a0330b2 100644 --- a/sites/docs/src/examples/components/Duration/format-duration-object.svelte +++ b/sites/docs/src/examples/components/Duration/format-duration-object.svelte @@ -1,5 +1,5 @@
    {new Duration({ duration: { milliseconds: 300 } }).format()}
    diff --git a/sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte b/sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte index d884617..f1b9d3b 100644 --- a/sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte +++ b/sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte @@ -1,5 +1,5 @@
    {new Duration({ start: new Date('2023-02-28'), end: new Date('2023-03-01') }).format()}
    diff --git a/sites/docs/src/examples/components/Duration/format-string-range.svelte b/sites/docs/src/examples/components/Duration/format-string-range.svelte index 8dab416..b3d6606 100644 --- a/sites/docs/src/examples/components/Duration/format-string-range.svelte +++ b/sites/docs/src/examples/components/Duration/format-string-range.svelte @@ -1,5 +1,5 @@
    {new Duration({ start: '1982-03-30' }).format()}
    diff --git a/sites/docs/src/examples/components/Duration/new-duration-date-range.svelte b/sites/docs/src/examples/components/Duration/new-duration-date-range.svelte index b2c3950..72ae75a 100644 --- a/sites/docs/src/examples/components/Duration/new-duration-date-range.svelte +++ b/sites/docs/src/examples/components/Duration/new-duration-date-range.svelte @@ -1,8 +1,8 @@
    - {JSON.stringify(new Duration({ start: intervalOffset('day', new Date(), 3) }), null, 2)} + {JSON.stringify(new Duration({ start: intervalOffset('day', new Date(), 3) }), null, 2)}
    diff --git a/sites/docs/src/examples/components/Duration/new-duration-string-range.svelte b/sites/docs/src/examples/components/Duration/new-duration-string-range.svelte index 09fb7df..6a37237 100644 --- a/sites/docs/src/examples/components/Duration/new-duration-string-range.svelte +++ b/sites/docs/src/examples/components/Duration/new-duration-string-range.svelte @@ -1,7 +1,7 @@
    - {JSON.stringify(new Duration({ start: '2021-01-01', end: '2021-01-07' }), null, 2)} + {JSON.stringify(new Duration({ start: '2021-01-01', end: '2021-01-07' }), null, 2)}
    diff --git a/sites/docs/src/examples/components/MediaQueryPresets/basic.svelte b/sites/docs/src/examples/components/MediaQueryPresets/basic.svelte index d7aeaf4..1205bab 100644 --- a/sites/docs/src/examples/components/MediaQueryPresets/basic.svelte +++ b/sites/docs/src/examples/components/MediaQueryPresets/basic.svelte @@ -1,98 +1,98 @@
    - {#if smScreen.current} - - {:else} - - {/if} - smScreen (640px) + {#if smScreen.current} + + {:else} + + {/if} + smScreen (640px) - {#if mdScreen.current} - - {:else} - - {/if} - mdScreen (768px) + {#if mdScreen.current} + + {:else} + + {/if} + mdScreen (768px) - {#if lgScreen.current} - - {:else} - - {/if} - lgScreen (1024px) + {#if lgScreen.current} + + {:else} + + {/if} + lgScreen (1024px) - {#if xlScreen.current} - - {:else} - - {/if} - xlScreen (1280px) + {#if xlScreen.current} + + {:else} + + {/if} + xlScreen (1280px) - {#if xxlScreen.current} - - {:else} - - {/if} - xxlScreen (1536px) + {#if xxlScreen.current} + + {:else} + + {/if} + xxlScreen (1536px) - {#if screen.current} - - {:else} - - {/if} - screen + {#if screen.current} + + {:else} + + {/if} + screen - {#if print.current} - - {:else} - - {/if} - print + {#if print.current} + + {:else} + + {/if} + print - {#if dark.current} - - {:else} - - {/if} - dark + {#if dark.current} + + {:else} + + {/if} + dark - {#if motion.current} - - {:else} - - {/if} - motion + {#if motion.current} + + {:else} + + {/if} + motion - {#if motionReduce.current} - - {:else} - - {/if} - motionReduce + {#if motionReduce.current} + + {:else} + + {/if} + motionReduce
    - current width: {innerWidth}px + current width: {innerWidth}px
    diff --git a/sites/docs/src/examples/components/SelectionState/basic.svelte b/sites/docs/src/examples/components/SelectionState/basic.svelte index 62a8e73..a961ae7 100644 --- a/sites/docs/src/examples/components/SelectionState/basic.svelte +++ b/sites/docs/src/examples/components/SelectionState/basic.svelte @@ -1,21 +1,21 @@ {#each data as d} -
    - selection.toggle(d.id)}> - {d.id} - -
    +
    + selection.toggle(d.id)}> + {d.id} + +
    {/each} selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/initial-selection.svelte b/sites/docs/src/examples/components/SelectionState/initial-selection.svelte index ec3e764..cd6ef59 100644 --- a/sites/docs/src/examples/components/SelectionState/initial-selection.svelte +++ b/sites/docs/src/examples/components/SelectionState/initial-selection.svelte @@ -1,23 +1,23 @@ {#each data as d} -
    - selection.toggle(d.id)}> - {d.id} - -
    +
    + selection.toggle(d.id)}> + {d.id} + +
    {/each} selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/max.svelte b/sites/docs/src/examples/components/SelectionState/max.svelte index d452c7b..554a62a 100644 --- a/sites/docs/src/examples/components/SelectionState/max.svelte +++ b/sites/docs/src/examples/components/SelectionState/max.svelte @@ -1,25 +1,25 @@ {#each data as d} -
    - selection.toggle(d.id)} - disabled={selection.isDisabled(d.id)} - > - {d.id} - -
    +
    + selection.toggle(d.id)} + disabled={selection.isDisabled(d.id)} + > + {d.id} + +
    {/each} selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/select-all.svelte b/sites/docs/src/examples/components/SelectionState/select-all.svelte index 1f0f375..c669068 100644 --- a/sites/docs/src/examples/components/SelectionState/select-all.svelte +++ b/sites/docs/src/examples/components/SelectionState/select-all.svelte @@ -1,28 +1,28 @@ selection.toggleAll()} + checked={selection.isAnySelected()} + indeterminate={!selection.isAllSelected()} + on:change={() => selection.toggleAll()} > - Select all + Select all {#each data as d} -
    - selection.toggle(d.id)}> - {d.id} - -
    +
    + selection.toggle(d.id)}> + {d.id} + +
    {/each} selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/set-selection.svelte b/sites/docs/src/examples/components/SelectionState/set-selection.svelte index 14cb24c..9e17bb2 100644 --- a/sites/docs/src/examples/components/SelectionState/set-selection.svelte +++ b/sites/docs/src/examples/components/SelectionState/set-selection.svelte @@ -1,24 +1,24 @@ {#each data as d} -
    - selection.toggle(d.id)}> - {d.id} - -
    +
    + selection.toggle(d.id)}> + {d.id} + +
    {/each} selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/SelectionState/single.svelte b/sites/docs/src/examples/components/SelectionState/single.svelte index b898e07..5dc608f 100644 --- a/sites/docs/src/examples/components/SelectionState/single.svelte +++ b/sites/docs/src/examples/components/SelectionState/single.svelte @@ -1,21 +1,21 @@ {#each data as d} -
    - selection.toggle(d.id)}> - {d.id} - -
    +
    + selection.toggle(d.id)}> + {d.id} + +
    {/each} selected: {JSON.stringify(selection.current)} diff --git a/sites/docs/src/examples/components/TimerState/basic.svelte b/sites/docs/src/examples/components/TimerState/basic.svelte index 7f73ddf..20e1582 100644 --- a/sites/docs/src/examples/components/TimerState/basic.svelte +++ b/sites/docs/src/examples/components/TimerState/basic.svelte @@ -1,15 +1,15 @@
    {dateTimer.current}
    { - // @ts-expect-error - e.target?.checked ? dateTimer.start() : dateTimer.stop(); - }} + checked={dateTimer.running} + on:change={(e) => { + // @ts-expect-error + e.target?.checked ? dateTimer.start() : dateTimer.stop(); + }} /> diff --git a/sites/docs/src/examples/components/TimerState/tick-count.svelte b/sites/docs/src/examples/components/TimerState/tick-count.svelte index 3302845..c99f3bc 100644 --- a/sites/docs/src/examples/components/TimerState/tick-count.svelte +++ b/sites/docs/src/examples/components/TimerState/tick-count.svelte @@ -1,15 +1,15 @@
    {tickTimer.current}
    { - // @ts-expect-error - e.target?.checked ? tickTimer.start() : tickTimer.stop(); - }} + checked={tickTimer.running} + on:change={(e) => { + // @ts-expect-error + e.target?.checked ? tickTimer.start() : tickTimer.stop(); + }} /> diff --git a/sites/docs/src/examples/components/UniqueState/basic.svelte b/sites/docs/src/examples/components/UniqueState/basic.svelte index b1f1e42..073ef5c 100644 --- a/sites/docs/src/examples/components/UniqueState/basic.svelte +++ b/sites/docs/src/examples/components/UniqueState/basic.svelte @@ -1,21 +1,21 @@ {#each data as d} -
    - state.toggle(d.id)}> - {d.id} - -
    +
    + state.toggle(d.id)}> + {d.id} + +
    {/each} selected: {JSON.stringify([...state.current])} diff --git a/sites/docs/src/examples/components/changeStore/basic.svelte b/sites/docs/src/examples/components/changeStore/basic.svelte index c081d76..0fa1e1f 100644 --- a/sites/docs/src/examples/components/changeStore/basic.svelte +++ b/sites/docs/src/examples/components/changeStore/basic.svelte @@ -1,10 +1,10 @@ diff --git a/sites/docs/src/examples/components/changeStore/pagination.svelte b/sites/docs/src/examples/components/changeStore/pagination.svelte index 9c6f6b9..67b2e1a 100644 --- a/sites/docs/src/examples/components/changeStore/pagination.svelte +++ b/sites/docs/src/examples/components/changeStore/pagination.svelte @@ -1,11 +1,11 @@ diff --git a/sites/docs/src/examples/components/dataBackground/basic.svelte b/sites/docs/src/examples/components/dataBackground/basic.svelte index 40fcef5..80dade0 100644 --- a/sites/docs/src/examples/components/dataBackground/basic.svelte +++ b/sites/docs/src/examples/components/dataBackground/basic.svelte @@ -86,7 +86,8 @@
    - +
    diff --git a/sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte b/sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte index c6eb227..1c8adbd 100644 --- a/sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte +++ b/sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte @@ -87,7 +87,8 @@ - +
    diff --git a/sites/docs/src/examples/components/debounceStore/basic.svelte b/sites/docs/src/examples/components/debounceStore/basic.svelte index 20b12ea..da84cfb 100644 --- a/sites/docs/src/examples/components/debounceStore/basic.svelte +++ b/sites/docs/src/examples/components/debounceStore/basic.svelte @@ -1,10 +1,10 @@ diff --git a/sites/docs/src/examples/components/dirtyStore/basic.svelte b/sites/docs/src/examples/components/dirtyStore/basic.svelte index 1ee7311..0cb9b50 100644 --- a/sites/docs/src/examples/components/dirtyStore/basic.svelte +++ b/sites/docs/src/examples/components/dirtyStore/basic.svelte @@ -1,10 +1,10 @@ diff --git a/sites/docs/src/examples/components/format/dates-custom.svelte b/sites/docs/src/examples/components/format/dates-custom.svelte index 3d07301..d66440d 100644 --- a/sites/docs/src/examples/components/format/dates-custom.svelte +++ b/sites/docs/src/examples/components/format/dates-custom.svelte @@ -1,26 +1,26 @@
    -
    -

    With format string

    - {format(myDate, 'custom', { - custom: 'eee, MMMM do' - })} -
    -
    -

    With descriptive tokens

    - {format(myDate, 'custom', { - custom: [DateToken.DayOfWeek_short, DateToken.Month_long, DateToken.DayOfMonth_withOrdinal] - })} -
    -
    -

    With full intl

    - {format(myDate, 'custom', { - custom: { weekday: 'short', month: 'long', day: 'numeric', withOrdinal: true } - })} -
    +
    +

    With format string

    + {format(myDate, 'custom', { + custom: 'eee, MMMM do', + })} +
    +
    +

    With descriptive tokens

    + {format(myDate, 'custom', { + custom: [DateToken.DayOfWeek_short, DateToken.Month_long, DateToken.DayOfMonth_withOrdinal], + })} +
    +
    +

    With full intl

    + {format(myDate, 'custom', { + custom: { weekday: 'short', month: 'long', day: 'numeric', withOrdinal: true }, + })} +
    diff --git a/sites/docs/src/examples/components/format/dates-period-types.svelte b/sites/docs/src/examples/components/format/dates-period-types.svelte index 53f903f..ddbb2b3 100644 --- a/sites/docs/src/examples/components/format/dates-period-types.svelte +++ b/sites/docs/src/examples/components/format/dates-period-types.svelte @@ -1,55 +1,55 @@ {#each periodTypeCodes as periodType} -

    {periodType}

    +

    {periodType}

    - {#if periodType === 'week' || periodType === 'biweek1'} - - It will take your default weekStartsOn - settings, if you want to be specific, you can also use - {periodType === 'week' ? 'PeriodType.WeekSun' : 'PeriodType.BiWeek1Sun'} - - {/if} + {#if periodType === 'week' || periodType === 'biweek1'} + + It will take your default weekStartsOn + settings, if you want to be specific, you can also use + {periodType === 'week' ? 'PeriodType.WeekSun' : 'PeriodType.BiWeek1Sun'} + + {/if} -
    -
    -

    short

    - {format(myDate, periodType, { - variant: 'short' - })} -
    -
    -

    default

    - {format(myDate, periodType, { - // variant: 'default', - })} -
    -
    -

    long

    - {format(myDate, periodType, { - variant: 'long' - })} -
    -
    +
    +
    +

    short

    + {format(myDate, periodType, { + variant: 'short', + })} +
    +
    +

    default

    + {format(myDate, periodType, { + // variant: 'default', + })} +
    +
    +

    long

    + {format(myDate, periodType, { + variant: 'long', + })} +
    +
    {/each} diff --git a/sites/docs/src/examples/components/format/numbers-config.svelte b/sites/docs/src/examples/components/format/numbers-config.svelte index 83980e0..fe93ce4 100644 --- a/sites/docs/src/examples/components/format/numbers-config.svelte +++ b/sites/docs/src/examples/components/format/numbers-config.svelte @@ -1,15 +1,15 @@
    {format(1234.56, { type: 'integer', options: { maximumSignificantDigits: 2 } })}
    {format(1234.56, { type: 'decimal', options: { maximumSignificantDigits: 5 } })}
    {format(1234.56, { type: 'currency', options: { currency: 'EUR' } })}
    - {format(123_456_789.99, { - type: 'currency', - options: { notation: 'compact', maximumSignificantDigits: 3 } - })} + {format(123_456_789.99, { + type: 'currency', + options: { notation: 'compact', maximumSignificantDigits: 3 }, + })}
    {format(0.5678, { type: 'percent', options: { signDisplay: 'always' } })}
    {format(0.5678, { type: 'percentRound', options: { signDisplay: 'always' } })}
    diff --git a/sites/docs/src/examples/components/format/numbers-default.svelte b/sites/docs/src/examples/components/format/numbers-default.svelte index 0707af2..2f4fc3b 100644 --- a/sites/docs/src/examples/components/format/numbers-default.svelte +++ b/sites/docs/src/examples/components/format/numbers-default.svelte @@ -1,5 +1,5 @@
    {format(1234.56, 'integer')}
    diff --git a/sites/docs/src/examples/components/format/numbers-options.svelte b/sites/docs/src/examples/components/format/numbers-options.svelte index c9f53bb..e4c60ba 100644 --- a/sites/docs/src/examples/components/format/numbers-options.svelte +++ b/sites/docs/src/examples/components/format/numbers-options.svelte @@ -1,12 +1,12 @@
    {format(1234.56, 'integer', { maximumSignificantDigits: 2 })}
    {format(1234.56, 'decimal', { maximumSignificantDigits: 5 })}
    {format(1234.56, 'currency', { currency: 'EUR' })}
    - {format(123_456_789.99, 'currency', { notation: 'compact', maximumSignificantDigits: 3 })} + {format(123_456_789.99, 'currency', { notation: 'compact', maximumSignificantDigits: 3 })}
    {format(0.5678, 'percent', { signDisplay: 'always' })}
    {format(0.5678, 'percentRound', { signDisplay: 'always' })}
    diff --git a/sites/docs/src/examples/components/format/playground-dates.svelte b/sites/docs/src/examples/components/format/playground-dates.svelte index ab11999..dec40f7 100644 --- a/sites/docs/src/examples/components/format/playground-dates.svelte +++ b/sites/docs/src/examples/components/format/playground-dates.svelte @@ -1,43 +1,43 @@
    - + - ({ label: value, value }))} - stepper - /> + ({ label: value, value }))} + stepper + /> - ({ label: value, value }))} - stepper - /> + ({ label: value, value }))} + stepper + />
    {format(myDate, { type: periodType, locale })}
    diff --git a/sites/docs/src/examples/components/format/playground-numbers.svelte b/sites/docs/src/examples/components/format/playground-numbers.svelte index 7358d83..1df5546 100644 --- a/sites/docs/src/examples/components/format/playground-numbers.svelte +++ b/sites/docs/src/examples/components/format/playground-numbers.svelte @@ -1,61 +1,61 @@
    - - - ({ label: value, value }))} - stepper - /> - - ({ - label: value ?? 'None', - value - }))} - stepper - disabled={numberType !== 'currency' && numberType !== 'currencyRound'} - /> - - ({ label: value, value }))} - stepper - /> - - ({ - label: value, - value - }))} - stepper - /> + + + ({ label: value, value }))} + stepper + /> + + ({ + label: value ?? 'None', + value, + }))} + stepper + disabled={numberType !== 'currency' && numberType !== 'currencyRound'} + /> + + ({ label: value, value }))} + stepper + /> + + ({ + label: value, + value, + }))} + stepper + />
    {format(value, { type: numberType, locale, options: { currency, notation } })}
    diff --git a/sites/docs/src/examples/components/matchMedia/basic.svelte b/sites/docs/src/examples/components/matchMedia/basic.svelte index 6f93182..c73f566 100644 --- a/sites/docs/src/examples/components/matchMedia/basic.svelte +++ b/sites/docs/src/examples/components/matchMedia/basic.svelte @@ -1,88 +1,88 @@
    - {#if $smScreen}{:else}{/if} - $smScreen (640px) + {#if $smScreen}{:else}{/if} + $smScreen (640px) - {#if $mdScreen}{:else}{/if} - $mdScreen (768px) + {#if $mdScreen}{:else}{/if} + $mdScreen (768px) - {#if $lgScreen}{:else}{/if} - $lgScreen (1024px) + {#if $lgScreen}{:else}{/if} + $lgScreen (1024px) - {#if $xlScreen}{:else}{/if} - $xlScreen (1280px) + {#if $xlScreen}{:else}{/if} + $xlScreen (1280px) - {#if $xxlScreen}{:else}{/if} - $xxlScreen (1536px) + {#if $xxlScreen}{:else}{/if} + $xxlScreen (1536px) - {#if $screen}{:else}{/if} - $screen + {#if $screen}{:else}{/if} + $screen - {#if $print}{:else}{/if} - $print + {#if $print}{:else}{/if} + $print - {#if $darkColorScheme}{:else}{/if} - $darkColorScheme + {#if $darkColorScheme}{:else}{/if} + $darkColorScheme - {#if $motionReduce}{:else}{/if} - $motionReduce + {#if $motionReduce}{:else}{/if} + $motionReduce
    - current width: {innerWidth}px + current width: {innerWidth}px
    diff --git a/sites/docs/src/examples/components/mouse/longpress.svelte b/sites/docs/src/examples/components/mouse/longpress.svelte index f239c47..5e6647d 100644 --- a/sites/docs/src/examples/components/mouse/longpress.svelte +++ b/sites/docs/src/examples/components/mouse/longpress.svelte @@ -1,16 +1,16 @@ {#if longpressed} - Success! Repeat to hide + Success! Repeat to hide {/if} diff --git a/sites/docs/src/examples/components/mouse/movable-step-percent.svelte b/sites/docs/src/examples/components/mouse/movable-step-percent.svelte index 79ceed5..c6efef5 100644 --- a/sites/docs/src/examples/components/mouse/movable-step-percent.svelte +++ b/sites/docs/src/examples/components/mouse/movable-step-percent.svelte @@ -1,27 +1,27 @@
    -
    { - coords.stiffness = 1; - coords.damping = 1; - }} - on:move={(e) => { - $coords.x += e.detail.dx; - $coords.y += e.detail.dy; - }} - on:moveend={() => { - coords.stiffness = 0.2; - coords.damping = 0.4; - coords.set({ x: 0, y: 0 }); - }} - style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" - >
    +
    { + coords.stiffness = 1; + coords.damping = 1; + }} + on:move={(e) => { + $coords.x += e.detail.dx; + $coords.y += e.detail.dy; + }} + on:moveend={() => { + coords.stiffness = 0.2; + coords.damping = 0.4; + coords.set({ x: 0, y: 0 }); + }} + style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" + >
    diff --git a/sites/docs/src/examples/components/mouse/movable-step.svelte b/sites/docs/src/examples/components/mouse/movable-step.svelte index 9097a07..a156ee0 100644 --- a/sites/docs/src/examples/components/mouse/movable-step.svelte +++ b/sites/docs/src/examples/components/mouse/movable-step.svelte @@ -1,27 +1,27 @@
    -
    { - coords.stiffness = 1; - coords.damping = 1; - }} - on:move={(e) => { - $coords.x += e.detail.dx; - $coords.y += e.detail.dy; - }} - on:moveend={() => { - coords.stiffness = 0.2; - coords.damping = 0.4; - coords.set({ x: 0, y: 0 }); - }} - style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" - >
    +
    { + coords.stiffness = 1; + coords.damping = 1; + }} + on:move={(e) => { + $coords.x += e.detail.dx; + $coords.y += e.detail.dy; + }} + on:moveend={() => { + coords.stiffness = 0.2; + coords.damping = 0.4; + coords.set({ x: 0, y: 0 }); + }} + style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" + >
    diff --git a/sites/docs/src/examples/components/mouse/movable-x-axis.svelte b/sites/docs/src/examples/components/mouse/movable-x-axis.svelte index a14f29b..3e8c4b2 100644 --- a/sites/docs/src/examples/components/mouse/movable-x-axis.svelte +++ b/sites/docs/src/examples/components/mouse/movable-x-axis.svelte @@ -1,27 +1,27 @@
    -
    { - coords.stiffness = 1; - coords.damping = 1; - }} - on:move={(e) => { - $coords.x += e.detail.dx; - $coords.y += e.detail.dy; - }} - on:moveend={() => { - coords.stiffness = 0.2; - coords.damping = 0.4; - coords.set({ x: 0, y: 0 }); - }} - style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" - >
    +
    { + coords.stiffness = 1; + coords.damping = 1; + }} + on:move={(e) => { + $coords.x += e.detail.dx; + $coords.y += e.detail.dy; + }} + on:moveend={() => { + coords.stiffness = 0.2; + coords.damping = 0.4; + coords.set({ x: 0, y: 0 }); + }} + style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" + >
    diff --git a/sites/docs/src/examples/components/mouse/movable.svelte b/sites/docs/src/examples/components/mouse/movable.svelte index 77c9a2c..ebd907c 100644 --- a/sites/docs/src/examples/components/mouse/movable.svelte +++ b/sites/docs/src/examples/components/mouse/movable.svelte @@ -1,27 +1,27 @@
    -
    { - coords.stiffness = 1; - coords.damping = 1; - }} - on:move={(e) => { - $coords.x += e.detail.dx; - $coords.y += e.detail.dy; - }} - on:moveend={() => { - coords.stiffness = 0.2; - coords.damping = 0.4; - coords.set({ x: 0, y: 0 }); - }} - style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" - >
    +
    { + coords.stiffness = 1; + coords.damping = 1; + }} + on:move={(e) => { + $coords.x += e.detail.dx; + $coords.y += e.detail.dy; + }} + on:moveend={() => { + coords.stiffness = 0.2; + coords.damping = 0.4; + coords.set({ x: 0, y: 0 }); + }} + style="transform: translate({$coords.x}px,{$coords.y}px) rotate({$coords.x * 0.2}deg)" + >
    diff --git a/sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte b/sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte index a6d11c4..415c82b 100644 --- a/sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte +++ b/sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte @@ -1,27 +1,27 @@
    - {#each { length: 10 } as _} -
    Scroll down
    - {/each} -
    { - if (e.detail.isIntersecting) { - // @ts-expect-error - e.target.classList.add('bg-danger'); - } else { - // @ts-expect-error - e.target.classList.remove('bg-danger'); - } - }} - class="transition-colors duration-500" - > - Watch me scroll away -
    - {#each { length: 10 } as _} -
    Scroll up
    - {/each} + {#each { length: 10 } as _} +
    Scroll down
    + {/each} +
    { + if (e.detail.isIntersecting) { + // @ts-expect-error + e.target.classList.add('bg-danger'); + } else { + // @ts-expect-error + e.target.classList.remove('bg-danger'); + } + }} + class="transition-colors duration-500" + > + Watch me scroll away +
    + {#each { length: 10 } as _} +
    Scroll up
    + {/each}
    diff --git a/sites/docs/src/examples/components/observer/basic.svelte b/sites/docs/src/examples/components/observer/basic.svelte index b991aa5..aebbae8 100644 --- a/sites/docs/src/examples/components/observer/basic.svelte +++ b/sites/docs/src/examples/components/observer/basic.svelte @@ -1,13 +1,13 @@
    { - console.log(e.detail); - // @ts-expect-error - e.target.innerText = JSON.stringify(e.detail.contentRect, null, 2); - }} - class="resize overflow-auto whitespace-pre outline rounded-sm" + use:resize + on:resize={(e) => { + console.log(e.detail); + // @ts-expect-error + e.target.innerText = JSON.stringify(e.detail.contentRect, null, 2); + }} + class="resize overflow-auto whitespace-pre outline rounded-sm" >
    diff --git a/sites/docs/src/examples/components/observer/full-coordinates.svelte b/sites/docs/src/examples/components/observer/full-coordinates.svelte index 91e57d4..3dddcf2 100644 --- a/sites/docs/src/examples/components/observer/full-coordinates.svelte +++ b/sites/docs/src/examples/components/observer/full-coordinates.svelte @@ -1,12 +1,12 @@
    { - // @ts-expect-error - e.target.innerText = JSON.stringify(e.target.getBoundingClientRect(), null, 2); - }} - class="resize overflow-auto whitespace-pre outline rounded-sm" + use:resize + on:resize={(e) => { + // @ts-expect-error + e.target.innerText = JSON.stringify(e.target.getBoundingClientRect(), null, 2); + }} + class="resize overflow-auto whitespace-pre outline rounded-sm" >
    diff --git a/sites/docs/src/examples/components/observer/setting-css-variable.svelte b/sites/docs/src/examples/components/observer/setting-css-variable.svelte index c34257e..11567ba 100644 --- a/sites/docs/src/examples/components/observer/setting-css-variable.svelte +++ b/sites/docs/src/examples/components/observer/setting-css-variable.svelte @@ -1,15 +1,15 @@
    { - // @ts-expect-error - e.target.style.setProperty('--color', e.detail.contentRect.width % 255); - }} - style:background-color="hsl(var(--color), 100%, 70%)" - class="resize overflow-auto p-2 rounded-sm" + use:resize + on:resize={(e) => { + // @ts-expect-error + e.target.style.setProperty('--color', e.detail.contentRect.width % 255); + }} + style:background-color="hsl(var(--color), 100%, 70%)" + class="resize overflow-auto p-2 rounded-sm" > - Resize and watch me change colors + Resize and watch me change colors
    diff --git a/sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte b/sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte index 34d849c..c0ac471 100644 --- a/sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte +++ b/sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte @@ -1,44 +1,44 @@ -
    - {#if showHeader} -
    - Header -
    - {/if} -
    - {#each { length: 10 } as _} -
    Scroll down
    - {/each} -
    { - if (e.detail.isIntersecting) { - // Visible - toggleOff(); - } else { - if (e.detail.boundingClientRect.top < (e.detail.rootBounds?.top ?? 0)) { - // Scrolled off top - toggleOn(); - } else { - // Scrolled off bottom - } - } - }} - > - Watch me scroll away -
    - {#each { length: 10 } as _} -
    Scroll up
    - {/each} -
    -
    +
    + {#if showHeader} +
    + Header +
    + {/if} +
    + {#each { length: 10 } as _} +
    Scroll down
    + {/each} +
    { + if (e.detail.isIntersecting) { + // Visible + toggleOff(); + } else { + if (e.detail.boundingClientRect.top < (e.detail.rootBounds?.top ?? 0)) { + // Scrolled off top + toggleOn(); + } else { + // Scrolled off bottom + } + } + }} + > + Watch me scroll away +
    + {#each { length: 10 } as _} +
    Scroll up
    + {/each} +
    +
    diff --git a/sites/docs/src/examples/components/portal/ancestor-portal-target.svelte b/sites/docs/src/examples/components/portal/ancestor-portal-target.svelte index d46cd12..323dfaa 100644 --- a/sites/docs/src/examples/components/portal/ancestor-portal-target.svelte +++ b/sites/docs/src/examples/components/portal/ancestor-portal-target.svelte @@ -1,23 +1,23 @@ -
    -
    - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    +
    +
    + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    diff --git a/sites/docs/src/examples/components/portal/basic.svelte b/sites/docs/src/examples/components/portal/basic.svelte index 0a282a2..c5bdd2d 100644 --- a/sites/docs/src/examples/components/portal/basic.svelte +++ b/sites/docs/src/examples/components/portal/basic.svelte @@ -1,19 +1,19 @@
    - - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    + + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    diff --git a/sites/docs/src/examples/components/portal/custom-target.svelte b/sites/docs/src/examples/components/portal/custom-target.svelte index b6a3baa..1e303c9 100644 --- a/sites/docs/src/examples/components/portal/custom-target.svelte +++ b/sites/docs/src/examples/components/portal/custom-target.svelte @@ -1,22 +1,22 @@ -
    - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    +
    + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    diff --git a/sites/docs/src/examples/components/portal/destroyable.svelte b/sites/docs/src/examples/components/portal/destroyable.svelte index b30823f..f086f3f 100644 --- a/sites/docs/src/examples/components/portal/destroyable.svelte +++ b/sites/docs/src/examples/components/portal/destroyable.svelte @@ -1,29 +1,29 @@ - - {#if !destroyed} -
    -
    - - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    -
    - {:else} - - {/if} -
    + + {#if !destroyed} +
    +
    + + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    +
    + {:else} + + {/if} +
    diff --git a/sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte b/sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte index c18c59c..888f10d 100644 --- a/sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte +++ b/sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte @@ -1,22 +1,22 @@ -
    - -
    -
    Portal content
    - {#if enabled} - - {/if} -
    -
    -
    +
    + +
    +
    Portal content
    + {#if enabled} + + {/if} +
    +
    +
    diff --git a/sites/docs/src/examples/components/scroll/basic.svelte b/sites/docs/src/examples/components/scroll/basic.svelte index 7805abe..5b79b76 100644 --- a/sites/docs/src/examples/components/scroll/basic.svelte +++ b/sites/docs/src/examples/components/scroll/basic.svelte @@ -1,21 +1,21 @@ {scrolledIndex}
    - {#each items as item, i} -
    - {item} -
    - {/each} + {#each items as item, i} +
    + {item} +
    + {/each}
    diff --git a/sites/docs/src/examples/components/scroll/only-if-needed.svelte b/sites/docs/src/examples/components/scroll/only-if-needed.svelte index c77f5a1..0fa464d 100644 --- a/sites/docs/src/examples/components/scroll/only-if-needed.svelte +++ b/sites/docs/src/examples/components/scroll/only-if-needed.svelte @@ -1,21 +1,21 @@ {scrolledIndex}
    - {#each items as item, i} -
    - {item} -
    - {/each} + {#each items as item, i} +
    + {item} +
    + {/each}
    diff --git a/sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte b/sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte index 3ee001a..eb10e5c 100644 --- a/sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte +++ b/sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte @@ -1,24 +1,24 @@
    - {#each items as item, i (item)} -
    {item}
    - {/each} + {#each items as item, i (item)} +
    {item}
    + {/each}
    - +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte b/sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte index a361978..84a249f 100644 --- a/sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte +++ b/sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte @@ -1,14 +1,14 @@
    -
    - {#each items as item, i} -
    {item}
    - {/each} -
    +
    + {#each items as item, i} +
    {item}
    + {/each} +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-fade.svelte b/sites/docs/src/examples/components/scroll/scroll-fade.svelte index 0276a96..c8544c7 100644 --- a/sites/docs/src/examples/components/scroll/scroll-fade.svelte +++ b/sites/docs/src/examples/components/scroll/scroll-fade.svelte @@ -1,12 +1,12 @@
    - {#each items as item, i (item)} -
    {item}
    - {/each} + {#each items as item, i (item)} +
    {item}
    + {/each}
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte index c75ff16..1426818 100644 --- a/sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte +++ b/sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte @@ -1,17 +1,17 @@
    - {#each items as item, i} -
    {item}
    - {/each} + {#each items as item, i} +
    {item}
    + {/each}
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte index 341d0a1..e8edba5 100644 --- a/sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte +++ b/sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte @@ -1,24 +1,24 @@
    - {#each items as item, i (item)} -
    {item}
    - {/each} + {#each items as item, i (item)} +
    {item}
    + {/each}
    - +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte index 9b43d17..647ac7a 100644 --- a/sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte +++ b/sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte @@ -1,14 +1,14 @@
    -
    - {#each items as item, i} -
    {item}
    - {/each} -
    +
    + {#each items as item, i} +
    {item}
    + {/each} +
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte index 68fc200..6660864 100644 --- a/sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte +++ b/sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte @@ -1,12 +1,12 @@
    - {#each items as item, i} -
    {item} with a really long description
    - {/each} + {#each items as item, i} +
    {item} with a really long description
    + {/each}
    diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow.svelte b/sites/docs/src/examples/components/scroll/scroll-shadow.svelte index 10d899c..1b76a8c 100644 --- a/sites/docs/src/examples/components/scroll/scroll-shadow.svelte +++ b/sites/docs/src/examples/components/scroll/scroll-shadow.svelte @@ -1,12 +1,12 @@
    - {#each items as item, i (item)} -
    {item}
    - {/each} + {#each items as item, i (item)} +
    {item}
    + {/each}
    diff --git a/sites/docs/src/examples/components/selectionStore/basic.svelte b/sites/docs/src/examples/components/selectionStore/basic.svelte index 2818397..f850747 100644 --- a/sites/docs/src/examples/components/selectionStore/basic.svelte +++ b/sites/docs/src/examples/components/selectionStore/basic.svelte @@ -1,20 +1,20 @@ {#each data as d} -
    - $selection.toggleSelected(d.id)} - > - {d.id} - -
    +
    + $selection.toggleSelected(d.id)} + > + {d.id} + +
    {/each} selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/selectionStore/initial-selection.svelte b/sites/docs/src/examples/components/selectionStore/initial-selection.svelte index d509b44..13ba31f 100644 --- a/sites/docs/src/examples/components/selectionStore/initial-selection.svelte +++ b/sites/docs/src/examples/components/selectionStore/initial-selection.svelte @@ -1,20 +1,20 @@ {#each data as d} -
    - $selection.toggleSelected(d.id)} - > - {d.id} - -
    +
    + $selection.toggleSelected(d.id)} + > + {d.id} + +
    {/each} selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/selectionStore/max.svelte b/sites/docs/src/examples/components/selectionStore/max.svelte index 683de11..0e35e1a 100644 --- a/sites/docs/src/examples/components/selectionStore/max.svelte +++ b/sites/docs/src/examples/components/selectionStore/max.svelte @@ -1,21 +1,21 @@ {#each data as d} -
    - $selection.toggleSelected(d.id)} - disabled={$selection.isDisabled(d.id)} - > - {d.id} - -
    +
    + $selection.toggleSelected(d.id)} + disabled={$selection.isDisabled(d.id)} + > + {d.id} + +
    {/each} selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/selectionStore/select-all.svelte b/sites/docs/src/examples/components/selectionStore/select-all.svelte index faa89f2..4b288d4 100644 --- a/sites/docs/src/examples/components/selectionStore/select-all.svelte +++ b/sites/docs/src/examples/components/selectionStore/select-all.svelte @@ -1,27 +1,27 @@ $selection.toggleAll()} + checked={$selection.isAnySelected()} + indeterminate={!$selection.isAllSelected()} + on:change={() => $selection.toggleAll()} > - Select all + Select all {#each data as d} -
    - $selection.toggleSelected(d.id)} - > - {d.id} - -
    +
    + $selection.toggleSelected(d.id)} + > + {d.id} + +
    {/each} selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/selectionStore/single.svelte b/sites/docs/src/examples/components/selectionStore/single.svelte index bb0d791..b28f160 100644 --- a/sites/docs/src/examples/components/selectionStore/single.svelte +++ b/sites/docs/src/examples/components/selectionStore/single.svelte @@ -1,21 +1,21 @@ {#each data as d} -
    - $selection.toggleSelected(d.id)} - > - {d.id} - -
    +
    + $selection.toggleSelected(d.id)} + > + {d.id} + +
    {/each} selected: {JSON.stringify($selection.selected)} diff --git a/sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte b/sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte index 6724043..e973db8 100644 --- a/sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte +++ b/sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte @@ -1,35 +1,35 @@ { - const body = window.document.body; - body.style.setProperty('--x', e.clientX + 'px'); - body.style.setProperty('--y', e.clientY + 'px'); - }} + on:mousemove={(e) => { + const body = window.document.body; + body.style.setProperty('--x', e.clientX + 'px'); + body.style.setProperty('--y', e.clientY + 'px'); + }} />
    - {#each items as item, i} -
    - {item} -
    - {/each} + {#each items as item, i} +
    + {item} +
    + {/each}
    diff --git a/sites/docs/src/examples/components/spotlight/global-context-and-options.svelte b/sites/docs/src/examples/components/spotlight/global-context-and-options.svelte index dd8c5e5..267d1a7 100644 --- a/sites/docs/src/examples/components/spotlight/global-context-and-options.svelte +++ b/sites/docs/src/examples/components/spotlight/global-context-and-options.svelte @@ -1,45 +1,45 @@ { - const body = window.document.body; - body.style.setProperty('--x', e.clientX + 'px'); - body.style.setProperty('--y', e.clientY + 'px'); - }} + on:mousemove={(e) => { + const body = window.document.body; + body.style.setProperty('--x', e.clientX + 'px'); + body.style.setProperty('--y', e.clientY + 'px'); + }} />
    - {#each items as item, i} -
    - {item} -
    - {/each} + {#each items as item, i} +
    + {item} +
    + {/each}
    diff --git a/sites/docs/src/examples/components/spotlight/line.svelte b/sites/docs/src/examples/components/spotlight/line.svelte index 827ef9e..777a3c3 100644 --- a/sites/docs/src/examples/components/spotlight/line.svelte +++ b/sites/docs/src/examples/components/spotlight/line.svelte @@ -1,36 +1,36 @@ { - const body = window.document.body; - body.style.setProperty('--x', e.clientX + 'px'); - body.style.setProperty('--y', e.clientY + 'px'); - }} + on:mousemove={(e) => { + const body = window.document.body; + body.style.setProperty('--x', e.clientX + 'px'); + body.style.setProperty('--y', e.clientY + 'px'); + }} />
    - {#each items as item, i} -
    - {item} -
    - {/each} + {#each items as item, i} +
    + {item} +
    + {/each}
    diff --git a/sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte b/sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte index db32599..431cdaa 100644 --- a/sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte +++ b/sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte @@ -1,7 +1,7 @@
    {truncate(str, 20, 10)}
    diff --git a/sites/docs/src/examples/components/string/truncate-playground.svelte b/sites/docs/src/examples/components/string/truncate-playground.svelte index adc6363..6bb68a4 100644 --- a/sites/docs/src/examples/components/string/truncate-playground.svelte +++ b/sites/docs/src/examples/components/string/truncate-playground.svelte @@ -1,14 +1,14 @@
    - - + +
    {truncate(str, totalChars, endChars)}
    diff --git a/sites/docs/src/examples/components/string/truncate-total-only.svelte b/sites/docs/src/examples/components/string/truncate-total-only.svelte index db535f3..c984600 100644 --- a/sites/docs/src/examples/components/string/truncate-total-only.svelte +++ b/sites/docs/src/examples/components/string/truncate-total-only.svelte @@ -1,7 +1,7 @@
    {truncate(str, 20)}
    diff --git a/sites/docs/src/examples/components/string/unique-basic.svelte b/sites/docs/src/examples/components/string/unique-basic.svelte index 8ea76f8..66b0932 100644 --- a/sites/docs/src/examples/components/string/unique-basic.svelte +++ b/sites/docs/src/examples/components/string/unique-basic.svelte @@ -1,5 +1,5 @@
    {uniqueId('checkbox-')}
    diff --git a/sites/docs/src/examples/components/styles/computed-styles.svelte b/sites/docs/src/examples/components/styles/computed-styles.svelte index f4611c2..4b773cb 100644 --- a/sites/docs/src/examples/components/styles/computed-styles.svelte +++ b/sites/docs/src/examples/components/styles/computed-styles.svelte @@ -1,47 +1,47 @@
    -
    (_styles = styles)} - class={cls('size-10 rounded-sm outline-offset-2', backgroundClass)} - style:outline-style={outlineStyle} - >
    +
    (_styles = styles)} + class={cls('size-10 rounded-sm outline-offset-2', backgroundClass)} + style:outline-style={outlineStyle} + >
    -
    - - - primary - secondary - - +
    + + + primary + secondary + + - - - solid - dashed - dotted - - -
    + + + solid + dashed + dotted + + +
    - - - + + + - - - + + +
    diff --git a/sites/docs/src/examples/components/styles/style-props.svelte b/sites/docs/src/examples/components/styles/style-props.svelte index 8d2d40c..32f39d4 100644 --- a/sites/docs/src/examples/components/styles/style-props.svelte +++ b/sites/docs/src/examples/components/styles/style-props.svelte @@ -1,21 +1,21 @@
    -
    -
    - - -
    +
    +
    + + +
    diff --git a/sites/docs/src/examples/components/uniqueStore/basic.svelte b/sites/docs/src/examples/components/uniqueStore/basic.svelte index b9c0d11..9884760 100644 --- a/sites/docs/src/examples/components/uniqueStore/basic.svelte +++ b/sites/docs/src/examples/components/uniqueStore/basic.svelte @@ -1,17 +1,17 @@ {#each data as d} -
    - selected.toggle(d.id)}> - {d.id} - -
    +
    + selected.toggle(d.id)}> + {d.id} + +
    {/each} selected: {JSON.stringify([...$selected])} diff --git a/sites/docs/src/lib/components/Example.svelte b/sites/docs/src/lib/components/Example.svelte index 6cf7384..113f334 100644 --- a/sites/docs/src/lib/components/Example.svelte +++ b/sites/docs/src/lib/components/Example.svelte @@ -1,81 +1,77 @@
    - {#if example} - {@const ExampleComponent = example.component} -
    -
    - -
    -
    + {#if example} + {@const ExampleComponent = example.component} +
    +
    + +
    +
    - {#if example.source} - + {#if example.source} + - {#if codeVisible} -
    - -
    - {/if} - {/if} - {:else} -
    - Example not found{name - ? `: ${resolvedComponent}/${name}` - : path - ? `: ${path}` - : ''} -
    - {/if} + {#if codeVisible} +
    + +
    + {/if} + {/if} + {:else} +
    + Example not found{name ? `: ${resolvedComponent}/${name}` : path ? `: ${path}` : ''} +
    + {/if}
    diff --git a/sites/docs/src/lib/components/OpenWithButton.svelte b/sites/docs/src/lib/components/OpenWithButton.svelte index cfbab16..b86b858 100644 --- a/sites/docs/src/lib/components/OpenWithButton.svelte +++ b/sites/docs/src/lib/components/OpenWithButton.svelte @@ -1,16 +1,16 @@ diff --git a/sites/docs/src/lib/content.ts b/sites/docs/src/lib/content.ts index 001089f..39ada13 100644 --- a/sites/docs/src/lib/content.ts +++ b/sites/docs/src/lib/content.ts @@ -1,9 +1,9 @@ import { error } from '@sveltejs/kit'; import { - allReferences, - type Reference as ReferenceMetadata, - allGuides, - type Guide as GuideMetadata + allReferences, + type Reference as ReferenceMetadata, + allGuides, + type Guide as GuideMetadata, } from 'content-collections'; import { createContentLoaders, type ContentType } from '@layerstack/docs/content'; import { loadExample, loadExampleByPath } from '$lib/examples.js'; @@ -11,22 +11,22 @@ import { loadExample, loadExampleByPath } from '$lib/examples.js'; type Metadata = ReferenceMetadata | GuideMetadata; const modules = import.meta.glob<{ default: import('svelte').Component; metadata: Metadata }>( - '/src/content/**/*.md' + '/src/content/**/*.md' ); const contentLoaders = createContentLoaders({ - modules, - getMetadata, - loadExample, - loadExampleByPath, - notFound: () => error(404, 'Could not find the document.') + modules, + getMetadata, + loadExample, + loadExampleByPath, + notFound: () => error(404, 'Could not find the document.'), }); function getMetadata(slug: string, type: ContentType): Metadata | undefined { - if (type === 'guides') { - return allGuides.find((g) => g.slug === slug); - } - return allReferences.find((r) => r.slug === slug); + if (type === 'guides') { + return allGuides.find((g) => g.slug === slug); + } + return allReferences.find((r) => r.slug === slug); } export const { getMarkdownComponent, loadExamplesFromMarkdown } = contentLoaders; diff --git a/sites/docs/src/lib/examples.ts b/sites/docs/src/lib/examples.ts index 870ca1b..a1cee34 100644 --- a/sites/docs/src/lib/examples.ts +++ b/sites/docs/src/lib/examples.ts @@ -2,25 +2,25 @@ import type { Component } from 'svelte'; import { createExampleLoaders } from '@layerstack/docs/examples'; const pathExamples = import.meta.glob<{ default: Component }>([ - '/src/routes/**/*.svelte', - '/src/content/**/*.svelte' + '/src/routes/**/*.svelte', + '/src/content/**/*.svelte', ]); const rawPathExamples = import.meta.glob( - ['/src/routes/**/*.svelte', '/src/content/**/*.svelte'], - { - query: '?raw', - import: 'default' - } + ['/src/routes/**/*.svelte', '/src/content/**/*.svelte'], + { + query: '?raw', + import: 'default', + } ); export const { loadExample, loadExamples, loadExampleByPath } = createExampleLoaders({ - loadComponentExample: (type, component, name) => - import(`../examples/${type}/${component}/${name}.svelte`), - loadRawExample: async (type, component, name) => { - const raw = await import(`../examples/${type}/${component}/${name}.svelte?raw`); - return raw.default as string; - }, - loadPathExample: (path) => pathExamples[path]?.(), - loadRawPathExample: (path) => rawPathExamples[path]?.() + loadComponentExample: (type, component, name) => + import(`../examples/${type}/${component}/${name}.svelte`), + loadRawExample: async (type, component, name) => { + const raw = await import(`../examples/${type}/${component}/${name}.svelte?raw`); + return raw.default as string; + }, + loadPathExample: (path) => pathExamples[path]?.(), + loadRawPathExample: (path) => rawPathExamples[path]?.(), }); diff --git a/sites/docs/src/lib/llms.ts b/sites/docs/src/lib/llms.ts index b5e87c4..07ee4af 100644 --- a/sites/docs/src/lib/llms.ts +++ b/sites/docs/src/lib/llms.ts @@ -1,108 +1,108 @@ import { allReferences, allGuides, type Reference } from 'content-collections'; import { sortCollection } from '@layerstack/docs/collections'; import { - generateGuideMarkdown as generateGuideMarkdownContent, - generateReferenceMarkdown as generateReferenceMarkdownDoc, - groupBySlugSegment, - linkListSection, - type ExampleSourceResolver + generateGuideMarkdown as generateGuideMarkdownContent, + generateReferenceMarkdown as generateReferenceMarkdownDoc, + groupBySlugSegment, + linkListSection, + type ExampleSourceResolver, } from '@layerstack/docs/llms'; const exampleSources = import.meta.glob('/src/examples/**/*.svelte', { - eager: true, - query: '?raw', - import: 'default' + eager: true, + query: '?raw', + import: 'default', }); const guideSources = import.meta.glob('/src/content/guides/**/*.md', { - eager: true, - query: '?raw', - import: 'default' + eager: true, + query: '?raw', + import: 'default', }); const resolveExampleSource: ExampleSourceResolver = (component, name) => { - if (!component) return undefined; - return exampleSources[`/src/examples/components/${component}/${name}.svelte`]; + if (!component) return undefined; + return exampleSources[`/src/examples/components/${component}/${name}.svelte`]; }; /** Group reference docs by their package (first slug segment), sorted within each group. */ function referencesByPackage(): [string, Reference[]][] { - return groupBySlugSegment(allReferences, { sort: sortCollection }); + return groupBySlugSegment(allReferences, { sort: sortCollection }); } /** LLM-optimized markdown for a single reference doc (examples inlined). */ export function generateReferenceMarkdown(doc: Reference): string { - return generateReferenceMarkdownDoc(doc, { - inlineExamples: true, - resolveSource: resolveExampleSource, - defaultComponent: doc.slug.split('/').pop() - }); + return generateReferenceMarkdownDoc(doc, { + inlineExamples: true, + resolveSource: resolveExampleSource, + defaultComponent: doc.slug.split('/').pop(), + }); } /** LLM-optimized markdown for a guide. */ export function generateGuideMarkdown(name: string): string { - const raw = guideSources[`/src/content/guides/${name}.md`]; - if (!raw) throw new Error(`Guide "${name}" not found`); - return generateGuideMarkdownContent(raw, { fallbackTitle: name }); + const raw = guideSources[`/src/content/guides/${name}.md`]; + if (!raw) throw new Error(`Guide "${name}" not found`); + return generateGuideMarkdownContent(raw, { fallbackTitle: name }); } /** Root `/llms.txt` index — links to each page's `/llms.txt`. */ export function generateLlmsTxt(baseUrl: string): string { - const sections: string[] = [ - `# LayerStack Documentation for LLMs + const sections: string[] = [ + `# LayerStack Documentation for LLMs > LayerStack is a collection of Svelte actions, stores, state, table utilities, and general utils for Svelte. -This file links to LLM-optimized documentation in markdown format. Append \`/llms.txt\` to any page URL for its markdown, or see [/docs/llms.txt](${baseUrl}/docs/llms.txt) for everything in one file.` - ]; - - const guides = sortCollection(allGuides.filter((g) => !g.draft)); - if (guides.length) { - sections.push( - linkListSection( - 'Guides', - guides.map((g) => ({ - name: g.name, - url: `${baseUrl}/docs/guides/${g.slug}/llms.txt`, - description: g.description - })) - ) - ); - } - - for (const [pkg, docs] of referencesByPackage()) { - sections.push( - linkListSection( - pkg, - docs.map((d) => ({ - name: d.name, - url: `${baseUrl}/docs/${d.slug}/llms.txt`, - description: d.description - })) - ) - ); - } - - return sections.join('\n\n'); +This file links to LLM-optimized documentation in markdown format. Append \`/llms.txt\` to any page URL for its markdown, or see [/docs/llms.txt](${baseUrl}/docs/llms.txt) for everything in one file.`, + ]; + + const guides = sortCollection(allGuides.filter((g) => !g.draft)); + if (guides.length) { + sections.push( + linkListSection( + 'Guides', + guides.map((g) => ({ + name: g.name, + url: `${baseUrl}/docs/guides/${g.slug}/llms.txt`, + description: g.description, + })) + ) + ); + } + + for (const [pkg, docs] of referencesByPackage()) { + sections.push( + linkListSection( + pkg, + docs.map((d) => ({ + name: d.name, + url: `${baseUrl}/docs/${d.slug}/llms.txt`, + description: d.description, + })) + ) + ); + } + + return sections.join('\n\n'); } /** `/docs/llms.txt` — the full documentation inlined into one file. */ export function generateFullLlmsTxt(baseUrl: string): string { - const sections: string[] = [ - `# LayerStack Full Documentation for LLMs + const sections: string[] = [ + `# LayerStack Full Documentation for LLMs > LayerStack is a collection of Svelte actions, stores, state, table utilities, and general utils for Svelte. -This file contains the complete LLM-optimized documentation. Index: [/llms.txt](${baseUrl}/llms.txt).` - ]; +This file contains the complete LLM-optimized documentation. Index: [/llms.txt](${baseUrl}/llms.txt).`, + ]; - for (const [pkg, docs] of referencesByPackage()) { - sections.push('---'); - sections.push(`# ${pkg}`); - for (const doc of docs) { - sections.push(generateReferenceMarkdown(doc)); - } - } + for (const [pkg, docs] of referencesByPackage()) { + sections.push('---'); + sections.push(`# ${pkg}`); + for (const doc of docs) { + sections.push(generateReferenceMarkdown(doc)); + } + } - return sections.join('\n\n'); + return sections.join('\n\n'); } diff --git a/sites/docs/src/routes/+layout.svelte b/sites/docs/src/routes/+layout.svelte index 787ca5d..84f6cd7 100644 --- a/sites/docs/src/routes/+layout.svelte +++ b/sites/docs/src/routes/+layout.svelte @@ -1,100 +1,92 @@ - {title} - - {#if page.url.origin.includes('https')} - - - - {/if} + {title} + + {#if page.url.origin.includes('https')} + + + + {/if} @@ -102,131 +94,138 @@
    - - -
    - -
    - - - - { - window.open(e.detail.value, '_blank'); - }} - class="inline-block md:hidden" - > - - - + + +
    + +
    + + + + { + window.open(e.detail.value, '_blank'); + }} + class="inline-block md:hidden" + > + + +
    - - - - (showDrawer = false)} /> - - -
    - {@render children()} -
    - - - {#if !page.data.metadata?.hideTableOfContents && page.data.metadata?.toc?.length} - - {/if} + + + + (showDrawer = false)} /> + + +
    + {@render children()} +
    + + + {#if !page.data.metadata?.hideTableOfContents && page.data.metadata?.toc?.length} + + {/if}
    diff --git a/sites/docs/src/routes/_NavMenu.svelte b/sites/docs/src/routes/_NavMenu.svelte index 80464e4..c9ad4e3 100644 --- a/sites/docs/src/routes/_NavMenu.svelte +++ b/sites/docs/src/routes/_NavMenu.svelte @@ -1,127 +1,127 @@ {#snippet navItem({ label, path, icon }: { label: string; path: string; icon?: IconProp })} - onItemClick?.()} - /> + onItemClick?.()} + /> {/snippet} diff --git a/sites/docs/src/routes/api/search.json/+server.ts b/sites/docs/src/routes/api/search.json/+server.ts index 70069cf..0c50b69 100644 --- a/sites/docs/src/routes/api/search.json/+server.ts +++ b/sites/docs/src/routes/api/search.json/+server.ts @@ -4,5 +4,5 @@ import { searchContent } from '$lib/searchContent'; export const prerender = true; export const GET = async () => { - return json(searchContent); + return json(searchContent); }; diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte index fe92835..0833396 100644 --- a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte +++ b/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte @@ -1,92 +1,92 @@
    -
    - Docs - - {page.params.packageName} -
    +
    + Docs + + {page.params.packageName} +
    -
    - {metadata.name} - {#if metadata.status} - - {metadata.status} - - {/if} -
    +
    + {metadata.name} + {#if metadata.status} + + {metadata.status} + + {/if} +
    - {#if metadata.description} -
    - {metadata.description} -
    - {/if} + {#if metadata.description} +
    + {metadata.description} +
    + {/if} -
    - -
    +
    + +
    - {#if metadata.features?.length} -

    Features

    -
      - {#each metadata.features as feature (feature)} -
    • {@html feature}
    • - {/each} -
    - {/if} + {#if metadata.features?.length} +

    Features

    +
      + {#each metadata.features as feature (feature)} +
    • {@html feature}
    • + {/each} +
    + {/if} - {#key page.url.pathname} - - {/key} + {#key page.url.pathname} + + {/key} - {#if metadata.related?.length} - -
    - {#each metadata.related as related (related)} - - {/each} -
    - {/if} + {#if metadata.related?.length} + +
    + {#each metadata.related as related (related)} + + {/each} +
    + {/if} - +
    diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/+page.ts b/sites/docs/src/routes/docs/[packageName]/[name]/+page.ts index 421aba7..5caec57 100644 --- a/sites/docs/src/routes/docs/[packageName]/[name]/+page.ts +++ b/sites/docs/src/routes/docs/[packageName]/[name]/+page.ts @@ -1,13 +1,13 @@ import { getMarkdownComponent, loadExamplesFromMarkdown } from '$lib/content.js'; export const load = async ({ params }) => { - const slug = `${params.packageName}/${params.name}`; + const slug = `${params.packageName}/${params.name}`; - const { PageComponent, metadata } = await getMarkdownComponent(slug, 'reference'); + const { PageComponent, metadata } = await getMarkdownComponent(slug, 'reference'); - // Eagerly load any examples referenced by the markdown (`:example{name="..."}`), - // defaulting the component to the current item name. - const examples = await loadExamplesFromMarkdown(metadata.content, params.name, 'reference'); + // Eagerly load any examples referenced by the markdown (`:example{name="..."}`), + // defaulting the component to the current item name. + const examples = await loadExamplesFromMarkdown(metadata.content, params.name, 'reference'); - return { PageComponent, metadata, examples }; + return { PageComponent, metadata, examples }; }; diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts b/sites/docs/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts index a18d79b..4fcdde6 100644 --- a/sites/docs/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts +++ b/sites/docs/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts @@ -6,11 +6,11 @@ import { markdownResponse } from '@layerstack/docs/llms'; /** LLM-optimized markdown for a reference doc (page content + inlined examples). */ export const GET: RequestHandler = async ({ params }) => { - const slug = `${params.packageName}/${params.name}`; - const doc = allReferences.find((r) => r.slug === slug); - if (!doc) { - error(404, 'Not found'); - } + const slug = `${params.packageName}/${params.name}`; + const doc = allReferences.find((r) => r.slug === slug); + if (!doc) { + error(404, 'Not found'); + } - return markdownResponse(generateReferenceMarkdown(doc), `${params.name}.md`); + return markdownResponse(generateReferenceMarkdown(doc), `${params.name}.md`); }; diff --git a/sites/docs/src/routes/docs/guides/[name]/+page.svelte b/sites/docs/src/routes/docs/guides/[name]/+page.svelte index 7eac958..6bee264 100644 --- a/sites/docs/src/routes/docs/guides/[name]/+page.svelte +++ b/sites/docs/src/routes/docs/guides/[name]/+page.svelte @@ -1,58 +1,58 @@
    -
    - Docs - - Guides -
    - -
    {metadata.name}
    - - {#if metadata.description} -
    - {metadata.description} -
    - {/if} - -
    - -
    +
    + Docs + + Guides +
    + +
    {metadata.name}
    + + {#if metadata.description} +
    + {metadata.description} +
    + {/if} + +
    + +
    - {#key page.url.pathname} - - {/key} - - + {#key page.url.pathname} + + {/key} + +
    diff --git a/sites/docs/src/routes/docs/guides/[name]/+page.ts b/sites/docs/src/routes/docs/guides/[name]/+page.ts index 7dca271..f74122b 100644 --- a/sites/docs/src/routes/docs/guides/[name]/+page.ts +++ b/sites/docs/src/routes/docs/guides/[name]/+page.ts @@ -1,8 +1,8 @@ import { getMarkdownComponent, loadExamplesFromMarkdown } from '$lib/content.js'; export const load = async ({ params }) => { - const { PageComponent, metadata } = await getMarkdownComponent(params.name, 'guides'); - const examples = await loadExamplesFromMarkdown(metadata.content, undefined, 'guides'); + const { PageComponent, metadata } = await getMarkdownComponent(params.name, 'guides'); + const examples = await loadExamplesFromMarkdown(metadata.content, undefined, 'guides'); - return { PageComponent, metadata, examples }; + return { PageComponent, metadata, examples }; }; diff --git a/sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts b/sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts index d2072f9..020e424 100644 --- a/sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts +++ b/sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts @@ -4,9 +4,9 @@ import { generateGuideMarkdown } from '$lib/llms'; import { markdownResponse } from '@layerstack/docs/llms'; export const GET: RequestHandler = async ({ params }) => { - try { - return markdownResponse(generateGuideMarkdown(params.name), `${params.name}.md`); - } catch { - error(404, 'Not found'); - } + try { + return markdownResponse(generateGuideMarkdown(params.name), `${params.name}.md`); + } catch { + error(404, 'Not found'); + } }; diff --git a/sites/docs/src/routes/docs/llms.txt/+server.ts b/sites/docs/src/routes/docs/llms.txt/+server.ts index 9547319..0dd50a9 100644 --- a/sites/docs/src/routes/docs/llms.txt/+server.ts +++ b/sites/docs/src/routes/docs/llms.txt/+server.ts @@ -3,5 +3,5 @@ import { generateFullLlmsTxt } from '$lib/llms'; import { markdownResponse } from '@layerstack/docs/llms'; export const GET: RequestHandler = async ({ url }) => { - return markdownResponse(generateFullLlmsTxt(url.origin), 'llms-full.md'); + return markdownResponse(generateFullLlmsTxt(url.origin), 'llms-full.md'); }; diff --git a/sites/docs/src/routes/llms.txt/+server.ts b/sites/docs/src/routes/llms.txt/+server.ts index ae940a4..dcfee02 100644 --- a/sites/docs/src/routes/llms.txt/+server.ts +++ b/sites/docs/src/routes/llms.txt/+server.ts @@ -3,5 +3,5 @@ import { generateLlmsTxt } from '$lib/llms'; import { markdownResponse } from '@layerstack/docs/llms'; export const GET: RequestHandler = async ({ url }) => { - return markdownResponse(generateLlmsTxt(url.origin), 'llms.md'); + return markdownResponse(generateLlmsTxt(url.origin), 'llms.md'); }; From c37b3ee8e16eef46e2b1df76d1576de494964bc8 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 10:43:49 -0400 Subject: [PATCH 15/21] ignore generated content-collections in lint --- sites/docs/.prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/sites/docs/.prettierignore b/sites/docs/.prettierignore index 17a42fc..ed0d600 100644 --- a/sites/docs/.prettierignore +++ b/sites/docs/.prettierignore @@ -3,6 +3,7 @@ node_modules /build /dist /.svelte-kit +/.content-collections /package .env .env.* From 2cb9314a6e377f1e7ce5f91748f7252e37c9d23a Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 11:35:15 -0400 Subject: [PATCH 16/21] add prettierignore (fix pnpm lint) --- packages/docs/.prettierignore | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 packages/docs/.prettierignore diff --git a/packages/docs/.prettierignore b/packages/docs/.prettierignore new file mode 100644 index 0000000..17a42fc --- /dev/null +++ b/packages/docs/.prettierignore @@ -0,0 +1,15 @@ +.DS_Store +node_modules +/build +/dist +/.svelte-kit +/package +.env +.env.* +!.env.example +coverage/ + +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock From 76fbf47f4791c27fab9c58cc2c9493bc381a4bf9 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 12:01:00 -0400 Subject: [PATCH 17/21] ignore .live-code and .wrangler from prettier --- sites/docs/.prettierignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sites/docs/.prettierignore b/sites/docs/.prettierignore index ed0d600..0c08ad4 100644 --- a/sites/docs/.prettierignore +++ b/sites/docs/.prettierignore @@ -4,6 +4,8 @@ node_modules /dist /.svelte-kit /.content-collections +/.live-code +/.wrangler /package .env .env.* From 5a6166ed029e5979e7ae8257a1b27f6a4643c07c Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 12:54:41 -0400 Subject: [PATCH 18/21] Move docs cli to src/lib/cli.ts and build using svelte-package --- packages/docs/bin/layerstack-docs.js | 23 ----------------------- packages/docs/package.json | 5 +---- packages/docs/src/{ => lib}/cli.ts | 11 ++++++----- pnpm-lock.yaml | 5 ++--- 4 files changed, 9 insertions(+), 35 deletions(-) delete mode 100755 packages/docs/bin/layerstack-docs.js rename packages/docs/src/{ => lib}/cli.ts (94%) diff --git a/packages/docs/bin/layerstack-docs.js b/packages/docs/bin/layerstack-docs.js deleted file mode 100755 index 74fa279..0000000 --- a/packages/docs/bin/layerstack-docs.js +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env node -/** - * Thin launcher that runs the TypeScript CLI (`src/cli.ts`) through `tsx`, - * resolved from this package's own dependencies (no global install required). - */ -import { spawn } from 'node:child_process'; -import { createRequire } from 'node:module'; -import { dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const cliPath = join(__dirname, '../src/cli.ts'); - -const require = createRequire(import.meta.url); -const tsxPkgPath = require.resolve('tsx/package.json'); -const tsxPkg = require(tsxPkgPath); -const binRel = typeof tsxPkg.bin === 'string' ? tsxPkg.bin : tsxPkg.bin.tsx; -const tsxBin = join(dirname(tsxPkgPath), binRel); - -const child = spawn(process.execPath, [tsxBin, cliPath, ...process.argv.slice(2)], { - stdio: 'inherit', -}); -child.on('exit', (code) => process.exit(code ?? 0)); diff --git a/packages/docs/package.json b/packages/docs/package.json index d745df1..2c24b34 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -8,7 +8,7 @@ "version": "0.0.0", "type": "module", "bin": { - "layerstack-docs": "./bin/layerstack-docs.js" + "layerstack-docs": "./dist/cli.js" }, "scripts": { "dev": "trap 'exit 0' INT; svelte-package --watch", @@ -42,7 +42,6 @@ "sharp": "^0.34.5", "shiki": "^4.1.0", "svelte-ux": "2.0.0-next.22", - "tsx": "^4.22.3", "typescript": "^5.8.3", "unist-builder": "^4.0.0", "unist-util-visit": "^5.1.0", @@ -186,8 +185,6 @@ }, "files": [ "dist", - "bin", - "src", "templates" ] } diff --git a/packages/docs/src/cli.ts b/packages/docs/src/lib/cli.ts similarity index 94% rename from packages/docs/src/cli.ts rename to packages/docs/src/lib/cli.ts index 842531e..7db4bf6 100644 --- a/packages/docs/src/cli.ts +++ b/packages/docs/src/lib/cli.ts @@ -1,3 +1,4 @@ +#!/usr/bin/env node /** * `layerstack-docs` CLI — build-time generators for LayerStack docs apps. * @@ -8,11 +9,11 @@ * generate-stackblitz [remote-sources-file] [--template-dir ] [--source out=src ...] [--remote out=src ...] * generate-releases */ -import { writeComponentAPIs } from './lib/node/component-api.js'; -import { writeExampleCatalogs } from './lib/node/example-catalog.js'; -import { generateScreenshots } from './lib/node/screenshots.js'; -import { generateStackBlitzFiles, getDefaultStackBlitzTemplateDir } from './lib/node/stackblitz.js'; -import { generateReleases } from './lib/node/releases.js'; +import { writeComponentAPIs } from './node/component-api.js'; +import { writeExampleCatalogs } from './node/example-catalog.js'; +import { generateScreenshots } from './node/screenshots.js'; +import { generateStackBlitzFiles, getDefaultStackBlitzTemplateDir } from './node/stackblitz.js'; +import { generateReleases } from './node/releases.js'; type ParsedArgs = { positionals: string[]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d5cae0..a7d08dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,9 +86,6 @@ importers: svelte-ux: specifier: 2.0.0-next.22 version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3)(svelte@5.28.6) - tsx: - specifier: ^4.22.3 - version: 4.22.3 typescript: specifier: ^5.8.3 version: 5.8.3 @@ -5345,6 +5342,7 @@ snapshots: '@esbuild/win32-arm64': 0.28.0 '@esbuild/win32-ia32': 0.28.0 '@esbuild/win32-x64': 0.28.0 + optional: true escape-string-regexp@5.0.0: {} @@ -6856,6 +6854,7 @@ snapshots: esbuild: 0.28.0 optionalDependencies: fsevents: 2.3.3 + optional: true typescript@5.8.3: {} From eeaa3f16e2465ad3099f62159664e096618dc33c Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 13:06:57 -0400 Subject: [PATCH 19/21] Move sites/docs to docs --- .github/workflows/build-preview.yml | 2 +- .github/workflows/ci.yml | 4 +- .github/workflows/deploy-prod.yml | 4 +- {sites/docs => docs}/.prettierignore | 0 {sites/docs => docs}/CHANGELOG.md | 0 {sites/docs => docs}/LICENSE | 0 {sites/docs => docs}/README.md | 0 {sites/docs => docs}/content-collections.ts | 4 +- {sites/docs => docs}/mdsx.config.js | 0 {sites/docs => docs}/package.json | 0 {sites/docs => docs}/src/app.d.ts | 2 +- {sites/docs => docs}/src/app.html | 0 .../docs => docs}/src/content/guides/LLMs.md | 0 .../svelte-actions/dataBackground.md | 0 .../content/reference/svelte-actions/input.md | 0 .../reference/svelte-actions/layout.md | 0 .../content/reference/svelte-actions/mouse.md | 0 .../content/reference/svelte-actions/multi.md | 0 .../reference/svelte-actions/observer.md | 0 .../reference/svelte-actions/popover.md | 0 .../reference/svelte-actions/portal.md | 0 .../reference/svelte-actions/scroll.md | 0 .../reference/svelte-actions/spotlight.md | 0 .../reference/svelte-actions/sticky.md | 0 .../reference/svelte-actions/styles.md | 0 .../svelte-state/MediaQueryPresets.md | 0 .../reference/svelte-state/PaginationState.md | 0 .../reference/svelte-state/SelectionState.md | 0 .../reference/svelte-state/TimerState.md | 0 .../reference/svelte-state/UniqueState.md | 0 .../reference/svelte-stores/changeStore.md | 0 .../reference/svelte-stores/debounceStore.md | 0 .../reference/svelte-stores/dirtyStore.md | 0 .../reference/svelte-stores/fetchStore.md | 0 .../reference/svelte-stores/formStore.md | 0 .../reference/svelte-stores/graphStore.md | 0 .../reference/svelte-stores/localStore.md | 0 .../reference/svelte-stores/mapStore.md | 0 .../reference/svelte-stores/matchMedia.md | 0 .../svelte-stores/paginationStore.md | 0 .../reference/svelte-stores/promiseStore.md | 0 .../svelte-stores/queryParamsStore.md | 0 .../reference/svelte-stores/selectionStore.md | 0 .../reference/svelte-stores/timerStore.md | 0 .../reference/svelte-stores/uniqueStore.md | 0 .../content/reference/svelte-table/actions.md | 0 .../content/reference/svelte-table/stores.md | 0 .../src/content/reference/tailwind/utils.md | 0 .../src/content/reference/utils/Duration.md | 0 .../src/content/reference/utils/Logger.md | 0 .../src/content/reference/utils/format.md | 0 .../src/content/reference/utils/json.md | 0 .../src/content/reference/utils/string.md | 0 .../Duration/format-date-range.svelte | 0 .../Duration/format-duration-object.svelte | 0 .../format-leap-year-comparison.svelte | 0 .../Duration/format-string-range.svelte | 0 .../Duration/new-duration-date-range.svelte | 0 .../Duration/new-duration-string-range.svelte | 0 .../components/MediaQueryPresets/basic.svelte | 0 .../components/SelectionState/basic.svelte | 0 .../SelectionState/initial-selection.svelte | 0 .../components/SelectionState/max.svelte | 0 .../SelectionState/select-all.svelte | 0 .../SelectionState/set-selection.svelte | 0 .../components/SelectionState/single.svelte | 0 .../components/TimerState/basic.svelte | 0 .../components/TimerState/tick-count.svelte | 0 .../components/UniqueState/basic.svelte | 0 .../components/changeStore/basic.svelte | 0 .../components/changeStore/pagination.svelte | 0 .../components/dataBackground/basic.svelte | 0 .../dataBackground/tailwind-gradient.svelte | 0 .../components/debounceStore/basic.svelte | 0 .../components/dirtyStore/basic.svelte | 0 .../components/format/dates-custom.svelte | 0 .../format/dates-period-types.svelte | 0 .../components/format/numbers-config.svelte | 0 .../components/format/numbers-default.svelte | 0 .../components/format/numbers-options.svelte | 0 .../components/format/playground-dates.svelte | 0 .../format/playground-numbers.svelte | 0 .../components/input/auto-focus.svelte | 0 .../components/input/auto-height.svelte | 0 .../components/input/blur-on-escape.svelte | 0 .../components/input/debounce-event.svelte | 0 .../components/input/select-on-focus.svelte | 0 .../components/layout/overflow.svelte | 0 .../components/matchMedia/basic.svelte | 0 .../components/mouse/longpress.svelte | 0 .../mouse/movable-step-percent.svelte | 0 .../components/mouse/movable-step.svelte | 0 .../components/mouse/movable-x-axis.svelte | 0 .../examples/components/mouse/movable.svelte | 0 .../adding-class-when-fully-visible.svelte | 0 .../examples/components/observer/basic.svelte | 0 .../observer/full-coordinates.svelte | 0 .../observer/setting-css-variable.svelte | 0 .../show-header-on-scroll-away.svelte | 0 .../portal/ancestor-portal-target.svelte | 0 .../examples/components/portal/basic.svelte | 0 .../components/portal/custom-target.svelte | 0 .../components/portal/destroyable.svelte | 0 .../portal/first-sibling-portal-target.svelte | 0 .../examples/components/scroll/basic.svelte | 0 .../components/scroll/only-if-needed.svelte | 0 .../components/scroll/scroll-fade-flip.svelte | 0 .../scroll/scroll-fade-horizontal.svelte | 0 .../components/scroll/scroll-fade.svelte | 0 .../scroll-shadow-bottom-surface.svelte | 0 .../scroll/scroll-shadow-flip.svelte | 0 .../scroll/scroll-shadow-horizontal.svelte | 0 .../scroll/scroll-shadow-truncation.svelte | 0 .../components/scroll/scroll-shadow.svelte | 0 .../components/selectionStore/basic.svelte | 0 .../selectionStore/initial-selection.svelte | 0 .../components/selectionStore/max.svelte | 0 .../selectionStore/select-all.svelte | 0 .../components/selectionStore/single.svelte | 0 .../global-context-and-css-variables.svelte | 0 .../global-context-and-options.svelte | 0 .../examples/components/spotlight/line.svelte | 0 .../string/truncate-middle-ellipsis.svelte | 0 .../string/truncate-playground.svelte | 0 .../string/truncate-total-only.svelte | 0 .../components/string/unique-basic.svelte | 0 .../components/styles/computed-styles.svelte | 0 .../components/styles/style-props.svelte | 0 .../components/timerStore/default.svelte | 0 .../components/timerStore/tick-count.svelte | 0 .../components/uniqueStore/basic.svelte | 0 .../src/lib/components/Example.svelte | 0 .../src/lib/components/OpenWithButton.svelte | 0 {sites/docs => docs}/src/lib/content.ts | 0 {sites/docs => docs}/src/lib/examples.ts | 0 {sites/docs => docs}/src/lib/llms.ts | 0 {sites/docs => docs}/src/lib/searchContent.ts | 0 {sites/docs => docs}/src/routes/+error.svelte | 0 .../src/routes/+layout.server.ts | 0 .../docs => docs}/src/routes/+layout.svelte | 0 {sites/docs => docs}/src/routes/+layout.ts | 0 {sites/docs => docs}/src/routes/+page.svelte | 0 .../docs => docs}/src/routes/_NavMenu.svelte | 0 .../src/routes/api/search.json/+server.ts | 0 {sites/docs => docs}/src/routes/app.css | 0 .../src/routes/docs/+layout.svelte | 0 .../docs/[packageName]/[name]/+page.svelte | 2 +- .../routes/docs/[packageName]/[name]/+page.ts | 0 .../[packageName]/[name]/llms.txt/+server.ts | 0 .../routes/docs/guides/[name]/+page.svelte | 4 +- .../src/routes/docs/guides/[name]/+page.ts | 0 .../docs/guides/[name]/llms.txt/+server.ts | 0 .../src/routes/docs/llms.txt/+server.ts | 0 .../docs/svelte-actions/+page.server.ts | 0 .../routes/docs/svelte-state/+page.server.ts | 0 .../routes/docs/svelte-stores/+page.server.ts | 0 .../routes/docs/svelte-table/+page.server.ts | 0 .../src/routes/docs/tailwind/+page.server.ts | 0 .../src/routes/docs/utils/+page.server.ts | 0 .../src/routes/llms.txt/+server.ts | 0 {sites/docs => docs}/static/favicon.jpg | Bin .../static/fonts/DepartureMono-Regular.woff2 | Bin {sites/docs => docs}/svelte.config.js | 22 +- {sites/docs => docs}/tsconfig.json | 0 {sites/docs => docs}/vite.config.js | 0 pnpm-lock.yaml | 281 +++++++++--------- pnpm-workspace.yaml | 2 +- 167 files changed, 156 insertions(+), 171 deletions(-) rename {sites/docs => docs}/.prettierignore (100%) rename {sites/docs => docs}/CHANGELOG.md (100%) rename {sites/docs => docs}/LICENSE (100%) rename {sites/docs => docs}/README.md (100%) rename {sites/docs => docs}/content-collections.ts (82%) rename {sites/docs => docs}/mdsx.config.js (100%) rename {sites/docs => docs}/package.json (100%) rename {sites/docs => docs}/src/app.d.ts (88%) rename {sites/docs => docs}/src/app.html (100%) rename {sites/docs => docs}/src/content/guides/LLMs.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/dataBackground.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/input.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/layout.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/mouse.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/multi.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/observer.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/popover.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/portal.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/scroll.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/spotlight.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/sticky.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-actions/styles.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-state/MediaQueryPresets.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-state/PaginationState.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-state/SelectionState.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-state/TimerState.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-state/UniqueState.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/changeStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/debounceStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/dirtyStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/fetchStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/formStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/graphStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/localStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/mapStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/matchMedia.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/paginationStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/promiseStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/queryParamsStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/selectionStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/timerStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-stores/uniqueStore.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-table/actions.md (100%) rename {sites/docs => docs}/src/content/reference/svelte-table/stores.md (100%) rename {sites/docs => docs}/src/content/reference/tailwind/utils.md (100%) rename {sites/docs => docs}/src/content/reference/utils/Duration.md (100%) rename {sites/docs => docs}/src/content/reference/utils/Logger.md (100%) rename {sites/docs => docs}/src/content/reference/utils/format.md (100%) rename {sites/docs => docs}/src/content/reference/utils/json.md (100%) rename {sites/docs => docs}/src/content/reference/utils/string.md (100%) rename {sites/docs => docs}/src/examples/components/Duration/format-date-range.svelte (100%) rename {sites/docs => docs}/src/examples/components/Duration/format-duration-object.svelte (100%) rename {sites/docs => docs}/src/examples/components/Duration/format-leap-year-comparison.svelte (100%) rename {sites/docs => docs}/src/examples/components/Duration/format-string-range.svelte (100%) rename {sites/docs => docs}/src/examples/components/Duration/new-duration-date-range.svelte (100%) rename {sites/docs => docs}/src/examples/components/Duration/new-duration-string-range.svelte (100%) rename {sites/docs => docs}/src/examples/components/MediaQueryPresets/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/SelectionState/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/SelectionState/initial-selection.svelte (100%) rename {sites/docs => docs}/src/examples/components/SelectionState/max.svelte (100%) rename {sites/docs => docs}/src/examples/components/SelectionState/select-all.svelte (100%) rename {sites/docs => docs}/src/examples/components/SelectionState/set-selection.svelte (100%) rename {sites/docs => docs}/src/examples/components/SelectionState/single.svelte (100%) rename {sites/docs => docs}/src/examples/components/TimerState/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/TimerState/tick-count.svelte (100%) rename {sites/docs => docs}/src/examples/components/UniqueState/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/changeStore/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/changeStore/pagination.svelte (100%) rename {sites/docs => docs}/src/examples/components/dataBackground/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/dataBackground/tailwind-gradient.svelte (100%) rename {sites/docs => docs}/src/examples/components/debounceStore/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/dirtyStore/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/format/dates-custom.svelte (100%) rename {sites/docs => docs}/src/examples/components/format/dates-period-types.svelte (100%) rename {sites/docs => docs}/src/examples/components/format/numbers-config.svelte (100%) rename {sites/docs => docs}/src/examples/components/format/numbers-default.svelte (100%) rename {sites/docs => docs}/src/examples/components/format/numbers-options.svelte (100%) rename {sites/docs => docs}/src/examples/components/format/playground-dates.svelte (100%) rename {sites/docs => docs}/src/examples/components/format/playground-numbers.svelte (100%) rename {sites/docs => docs}/src/examples/components/input/auto-focus.svelte (100%) rename {sites/docs => docs}/src/examples/components/input/auto-height.svelte (100%) rename {sites/docs => docs}/src/examples/components/input/blur-on-escape.svelte (100%) rename {sites/docs => docs}/src/examples/components/input/debounce-event.svelte (100%) rename {sites/docs => docs}/src/examples/components/input/select-on-focus.svelte (100%) rename {sites/docs => docs}/src/examples/components/layout/overflow.svelte (100%) rename {sites/docs => docs}/src/examples/components/matchMedia/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/mouse/longpress.svelte (100%) rename {sites/docs => docs}/src/examples/components/mouse/movable-step-percent.svelte (100%) rename {sites/docs => docs}/src/examples/components/mouse/movable-step.svelte (100%) rename {sites/docs => docs}/src/examples/components/mouse/movable-x-axis.svelte (100%) rename {sites/docs => docs}/src/examples/components/mouse/movable.svelte (100%) rename {sites/docs => docs}/src/examples/components/observer/adding-class-when-fully-visible.svelte (100%) rename {sites/docs => docs}/src/examples/components/observer/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/observer/full-coordinates.svelte (100%) rename {sites/docs => docs}/src/examples/components/observer/setting-css-variable.svelte (100%) rename {sites/docs => docs}/src/examples/components/observer/show-header-on-scroll-away.svelte (100%) rename {sites/docs => docs}/src/examples/components/portal/ancestor-portal-target.svelte (100%) rename {sites/docs => docs}/src/examples/components/portal/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/portal/custom-target.svelte (100%) rename {sites/docs => docs}/src/examples/components/portal/destroyable.svelte (100%) rename {sites/docs => docs}/src/examples/components/portal/first-sibling-portal-target.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/only-if-needed.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/scroll-fade-flip.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/scroll-fade-horizontal.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/scroll-fade.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/scroll-shadow-flip.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/scroll-shadow-horizontal.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/scroll-shadow-truncation.svelte (100%) rename {sites/docs => docs}/src/examples/components/scroll/scroll-shadow.svelte (100%) rename {sites/docs => docs}/src/examples/components/selectionStore/basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/selectionStore/initial-selection.svelte (100%) rename {sites/docs => docs}/src/examples/components/selectionStore/max.svelte (100%) rename {sites/docs => docs}/src/examples/components/selectionStore/select-all.svelte (100%) rename {sites/docs => docs}/src/examples/components/selectionStore/single.svelte (100%) rename {sites/docs => docs}/src/examples/components/spotlight/global-context-and-css-variables.svelte (100%) rename {sites/docs => docs}/src/examples/components/spotlight/global-context-and-options.svelte (100%) rename {sites/docs => docs}/src/examples/components/spotlight/line.svelte (100%) rename {sites/docs => docs}/src/examples/components/string/truncate-middle-ellipsis.svelte (100%) rename {sites/docs => docs}/src/examples/components/string/truncate-playground.svelte (100%) rename {sites/docs => docs}/src/examples/components/string/truncate-total-only.svelte (100%) rename {sites/docs => docs}/src/examples/components/string/unique-basic.svelte (100%) rename {sites/docs => docs}/src/examples/components/styles/computed-styles.svelte (100%) rename {sites/docs => docs}/src/examples/components/styles/style-props.svelte (100%) rename {sites/docs => docs}/src/examples/components/timerStore/default.svelte (100%) rename {sites/docs => docs}/src/examples/components/timerStore/tick-count.svelte (100%) rename {sites/docs => docs}/src/examples/components/uniqueStore/basic.svelte (100%) rename {sites/docs => docs}/src/lib/components/Example.svelte (100%) rename {sites/docs => docs}/src/lib/components/OpenWithButton.svelte (100%) rename {sites/docs => docs}/src/lib/content.ts (100%) rename {sites/docs => docs}/src/lib/examples.ts (100%) rename {sites/docs => docs}/src/lib/llms.ts (100%) rename {sites/docs => docs}/src/lib/searchContent.ts (100%) rename {sites/docs => docs}/src/routes/+error.svelte (100%) rename {sites/docs => docs}/src/routes/+layout.server.ts (100%) rename {sites/docs => docs}/src/routes/+layout.svelte (100%) rename {sites/docs => docs}/src/routes/+layout.ts (100%) rename {sites/docs => docs}/src/routes/+page.svelte (100%) rename {sites/docs => docs}/src/routes/_NavMenu.svelte (100%) rename {sites/docs => docs}/src/routes/api/search.json/+server.ts (100%) rename {sites/docs => docs}/src/routes/app.css (100%) rename {sites/docs => docs}/src/routes/docs/+layout.svelte (100%) rename {sites/docs => docs}/src/routes/docs/[packageName]/[name]/+page.svelte (96%) rename {sites/docs => docs}/src/routes/docs/[packageName]/[name]/+page.ts (100%) rename {sites/docs => docs}/src/routes/docs/[packageName]/[name]/llms.txt/+server.ts (100%) rename {sites/docs => docs}/src/routes/docs/guides/[name]/+page.svelte (91%) rename {sites/docs => docs}/src/routes/docs/guides/[name]/+page.ts (100%) rename {sites/docs => docs}/src/routes/docs/guides/[name]/llms.txt/+server.ts (100%) rename {sites/docs => docs}/src/routes/docs/llms.txt/+server.ts (100%) rename {sites/docs => docs}/src/routes/docs/svelte-actions/+page.server.ts (100%) rename {sites/docs => docs}/src/routes/docs/svelte-state/+page.server.ts (100%) rename {sites/docs => docs}/src/routes/docs/svelte-stores/+page.server.ts (100%) rename {sites/docs => docs}/src/routes/docs/svelte-table/+page.server.ts (100%) rename {sites/docs => docs}/src/routes/docs/tailwind/+page.server.ts (100%) rename {sites/docs => docs}/src/routes/docs/utils/+page.server.ts (100%) rename {sites/docs => docs}/src/routes/llms.txt/+server.ts (100%) rename {sites/docs => docs}/static/favicon.jpg (100%) rename {sites/docs => docs}/static/fonts/DepartureMono-Regular.woff2 (100%) rename {sites/docs => docs}/svelte.config.js (59%) rename {sites/docs => docs}/tsconfig.json (100%) rename {sites/docs => docs}/vite.config.js (100%) diff --git a/.github/workflows/build-preview.yml b/.github/workflows/build-preview.yml index 34ec19f..e00db0f 100644 --- a/.github/workflows/build-preview.yml +++ b/.github/workflows/build-preview.yml @@ -30,5 +30,5 @@ jobs: uses: actions/upload-artifact@v4 with: name: preview-build - path: sites/docs/.svelte-kit + path: docs/.svelte-kit include-hidden-files: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e45aebc..e77eff3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,9 +29,9 @@ jobs: - run: pnpm --filter "./packages/*" build - # Build sites before `pnpm check`: the docs site generates the `content-collections` + # Build the docs site before `pnpm check`: it generates the `content-collections` # module at build time, which the type-check then consumes. - - run: pnpm --filter "./sites/*" build + - run: pnpm --filter "./docs" build - run: pnpm check diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index aa201e4..5515868 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -4,7 +4,7 @@ on: branches: - main paths: - - sites/docs/** + - docs/** - packages/** jobs: @@ -36,5 +36,5 @@ jobs: githubToken: ${{ secrets.GITHUB_TOKEN }} projectName: layerstack directory: ./.svelte-kit/cloudflare - workingDirectory: sites/docs + workingDirectory: docs deploymentName: Production diff --git a/sites/docs/.prettierignore b/docs/.prettierignore similarity index 100% rename from sites/docs/.prettierignore rename to docs/.prettierignore diff --git a/sites/docs/CHANGELOG.md b/docs/CHANGELOG.md similarity index 100% rename from sites/docs/CHANGELOG.md rename to docs/CHANGELOG.md diff --git a/sites/docs/LICENSE b/docs/LICENSE similarity index 100% rename from sites/docs/LICENSE rename to docs/LICENSE diff --git a/sites/docs/README.md b/docs/README.md similarity index 100% rename from sites/docs/README.md rename to docs/README.md diff --git a/sites/docs/content-collections.ts b/docs/content-collections.ts similarity index 82% rename from sites/docs/content-collections.ts rename to docs/content-collections.ts index ccb099d..3b74ef5 100644 --- a/sites/docs/content-collections.ts +++ b/docs/content-collections.ts @@ -6,6 +6,6 @@ export default createContentConfig({ packageName: 'layerstack', repo: 'techniq/layerstack', branch: 'main', - // `sites/docs` -> repo root `packages` - packagesRoot: '../../packages', + // `docs` -> repo root `packages` + packagesRoot: '../packages', }); diff --git a/sites/docs/mdsx.config.js b/docs/mdsx.config.js similarity index 100% rename from sites/docs/mdsx.config.js rename to docs/mdsx.config.js diff --git a/sites/docs/package.json b/docs/package.json similarity index 100% rename from sites/docs/package.json rename to docs/package.json diff --git a/sites/docs/src/app.d.ts b/docs/src/app.d.ts similarity index 88% rename from sites/docs/src/app.d.ts rename to docs/src/app.d.ts index 23f62aa..637b6ee 100644 --- a/sites/docs/src/app.d.ts +++ b/docs/src/app.d.ts @@ -1,4 +1,4 @@ -/// +/// export * from 'unplugin-icons/types/svelte'; // See https://kit.svelte.dev/docs/types#app diff --git a/sites/docs/src/app.html b/docs/src/app.html similarity index 100% rename from sites/docs/src/app.html rename to docs/src/app.html diff --git a/sites/docs/src/content/guides/LLMs.md b/docs/src/content/guides/LLMs.md similarity index 100% rename from sites/docs/src/content/guides/LLMs.md rename to docs/src/content/guides/LLMs.md diff --git a/sites/docs/src/content/reference/svelte-actions/dataBackground.md b/docs/src/content/reference/svelte-actions/dataBackground.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/dataBackground.md rename to docs/src/content/reference/svelte-actions/dataBackground.md diff --git a/sites/docs/src/content/reference/svelte-actions/input.md b/docs/src/content/reference/svelte-actions/input.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/input.md rename to docs/src/content/reference/svelte-actions/input.md diff --git a/sites/docs/src/content/reference/svelte-actions/layout.md b/docs/src/content/reference/svelte-actions/layout.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/layout.md rename to docs/src/content/reference/svelte-actions/layout.md diff --git a/sites/docs/src/content/reference/svelte-actions/mouse.md b/docs/src/content/reference/svelte-actions/mouse.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/mouse.md rename to docs/src/content/reference/svelte-actions/mouse.md diff --git a/sites/docs/src/content/reference/svelte-actions/multi.md b/docs/src/content/reference/svelte-actions/multi.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/multi.md rename to docs/src/content/reference/svelte-actions/multi.md diff --git a/sites/docs/src/content/reference/svelte-actions/observer.md b/docs/src/content/reference/svelte-actions/observer.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/observer.md rename to docs/src/content/reference/svelte-actions/observer.md diff --git a/sites/docs/src/content/reference/svelte-actions/popover.md b/docs/src/content/reference/svelte-actions/popover.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/popover.md rename to docs/src/content/reference/svelte-actions/popover.md diff --git a/sites/docs/src/content/reference/svelte-actions/portal.md b/docs/src/content/reference/svelte-actions/portal.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/portal.md rename to docs/src/content/reference/svelte-actions/portal.md diff --git a/sites/docs/src/content/reference/svelte-actions/scroll.md b/docs/src/content/reference/svelte-actions/scroll.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/scroll.md rename to docs/src/content/reference/svelte-actions/scroll.md diff --git a/sites/docs/src/content/reference/svelte-actions/spotlight.md b/docs/src/content/reference/svelte-actions/spotlight.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/spotlight.md rename to docs/src/content/reference/svelte-actions/spotlight.md diff --git a/sites/docs/src/content/reference/svelte-actions/sticky.md b/docs/src/content/reference/svelte-actions/sticky.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/sticky.md rename to docs/src/content/reference/svelte-actions/sticky.md diff --git a/sites/docs/src/content/reference/svelte-actions/styles.md b/docs/src/content/reference/svelte-actions/styles.md similarity index 100% rename from sites/docs/src/content/reference/svelte-actions/styles.md rename to docs/src/content/reference/svelte-actions/styles.md diff --git a/sites/docs/src/content/reference/svelte-state/MediaQueryPresets.md b/docs/src/content/reference/svelte-state/MediaQueryPresets.md similarity index 100% rename from sites/docs/src/content/reference/svelte-state/MediaQueryPresets.md rename to docs/src/content/reference/svelte-state/MediaQueryPresets.md diff --git a/sites/docs/src/content/reference/svelte-state/PaginationState.md b/docs/src/content/reference/svelte-state/PaginationState.md similarity index 100% rename from sites/docs/src/content/reference/svelte-state/PaginationState.md rename to docs/src/content/reference/svelte-state/PaginationState.md diff --git a/sites/docs/src/content/reference/svelte-state/SelectionState.md b/docs/src/content/reference/svelte-state/SelectionState.md similarity index 100% rename from sites/docs/src/content/reference/svelte-state/SelectionState.md rename to docs/src/content/reference/svelte-state/SelectionState.md diff --git a/sites/docs/src/content/reference/svelte-state/TimerState.md b/docs/src/content/reference/svelte-state/TimerState.md similarity index 100% rename from sites/docs/src/content/reference/svelte-state/TimerState.md rename to docs/src/content/reference/svelte-state/TimerState.md diff --git a/sites/docs/src/content/reference/svelte-state/UniqueState.md b/docs/src/content/reference/svelte-state/UniqueState.md similarity index 100% rename from sites/docs/src/content/reference/svelte-state/UniqueState.md rename to docs/src/content/reference/svelte-state/UniqueState.md diff --git a/sites/docs/src/content/reference/svelte-stores/changeStore.md b/docs/src/content/reference/svelte-stores/changeStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/changeStore.md rename to docs/src/content/reference/svelte-stores/changeStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/debounceStore.md b/docs/src/content/reference/svelte-stores/debounceStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/debounceStore.md rename to docs/src/content/reference/svelte-stores/debounceStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/dirtyStore.md b/docs/src/content/reference/svelte-stores/dirtyStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/dirtyStore.md rename to docs/src/content/reference/svelte-stores/dirtyStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/fetchStore.md b/docs/src/content/reference/svelte-stores/fetchStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/fetchStore.md rename to docs/src/content/reference/svelte-stores/fetchStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/formStore.md b/docs/src/content/reference/svelte-stores/formStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/formStore.md rename to docs/src/content/reference/svelte-stores/formStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/graphStore.md b/docs/src/content/reference/svelte-stores/graphStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/graphStore.md rename to docs/src/content/reference/svelte-stores/graphStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/localStore.md b/docs/src/content/reference/svelte-stores/localStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/localStore.md rename to docs/src/content/reference/svelte-stores/localStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/mapStore.md b/docs/src/content/reference/svelte-stores/mapStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/mapStore.md rename to docs/src/content/reference/svelte-stores/mapStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/matchMedia.md b/docs/src/content/reference/svelte-stores/matchMedia.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/matchMedia.md rename to docs/src/content/reference/svelte-stores/matchMedia.md diff --git a/sites/docs/src/content/reference/svelte-stores/paginationStore.md b/docs/src/content/reference/svelte-stores/paginationStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/paginationStore.md rename to docs/src/content/reference/svelte-stores/paginationStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/promiseStore.md b/docs/src/content/reference/svelte-stores/promiseStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/promiseStore.md rename to docs/src/content/reference/svelte-stores/promiseStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/queryParamsStore.md b/docs/src/content/reference/svelte-stores/queryParamsStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/queryParamsStore.md rename to docs/src/content/reference/svelte-stores/queryParamsStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/selectionStore.md b/docs/src/content/reference/svelte-stores/selectionStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/selectionStore.md rename to docs/src/content/reference/svelte-stores/selectionStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/timerStore.md b/docs/src/content/reference/svelte-stores/timerStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/timerStore.md rename to docs/src/content/reference/svelte-stores/timerStore.md diff --git a/sites/docs/src/content/reference/svelte-stores/uniqueStore.md b/docs/src/content/reference/svelte-stores/uniqueStore.md similarity index 100% rename from sites/docs/src/content/reference/svelte-stores/uniqueStore.md rename to docs/src/content/reference/svelte-stores/uniqueStore.md diff --git a/sites/docs/src/content/reference/svelte-table/actions.md b/docs/src/content/reference/svelte-table/actions.md similarity index 100% rename from sites/docs/src/content/reference/svelte-table/actions.md rename to docs/src/content/reference/svelte-table/actions.md diff --git a/sites/docs/src/content/reference/svelte-table/stores.md b/docs/src/content/reference/svelte-table/stores.md similarity index 100% rename from sites/docs/src/content/reference/svelte-table/stores.md rename to docs/src/content/reference/svelte-table/stores.md diff --git a/sites/docs/src/content/reference/tailwind/utils.md b/docs/src/content/reference/tailwind/utils.md similarity index 100% rename from sites/docs/src/content/reference/tailwind/utils.md rename to docs/src/content/reference/tailwind/utils.md diff --git a/sites/docs/src/content/reference/utils/Duration.md b/docs/src/content/reference/utils/Duration.md similarity index 100% rename from sites/docs/src/content/reference/utils/Duration.md rename to docs/src/content/reference/utils/Duration.md diff --git a/sites/docs/src/content/reference/utils/Logger.md b/docs/src/content/reference/utils/Logger.md similarity index 100% rename from sites/docs/src/content/reference/utils/Logger.md rename to docs/src/content/reference/utils/Logger.md diff --git a/sites/docs/src/content/reference/utils/format.md b/docs/src/content/reference/utils/format.md similarity index 100% rename from sites/docs/src/content/reference/utils/format.md rename to docs/src/content/reference/utils/format.md diff --git a/sites/docs/src/content/reference/utils/json.md b/docs/src/content/reference/utils/json.md similarity index 100% rename from sites/docs/src/content/reference/utils/json.md rename to docs/src/content/reference/utils/json.md diff --git a/sites/docs/src/content/reference/utils/string.md b/docs/src/content/reference/utils/string.md similarity index 100% rename from sites/docs/src/content/reference/utils/string.md rename to docs/src/content/reference/utils/string.md diff --git a/sites/docs/src/examples/components/Duration/format-date-range.svelte b/docs/src/examples/components/Duration/format-date-range.svelte similarity index 100% rename from sites/docs/src/examples/components/Duration/format-date-range.svelte rename to docs/src/examples/components/Duration/format-date-range.svelte diff --git a/sites/docs/src/examples/components/Duration/format-duration-object.svelte b/docs/src/examples/components/Duration/format-duration-object.svelte similarity index 100% rename from sites/docs/src/examples/components/Duration/format-duration-object.svelte rename to docs/src/examples/components/Duration/format-duration-object.svelte diff --git a/sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte b/docs/src/examples/components/Duration/format-leap-year-comparison.svelte similarity index 100% rename from sites/docs/src/examples/components/Duration/format-leap-year-comparison.svelte rename to docs/src/examples/components/Duration/format-leap-year-comparison.svelte diff --git a/sites/docs/src/examples/components/Duration/format-string-range.svelte b/docs/src/examples/components/Duration/format-string-range.svelte similarity index 100% rename from sites/docs/src/examples/components/Duration/format-string-range.svelte rename to docs/src/examples/components/Duration/format-string-range.svelte diff --git a/sites/docs/src/examples/components/Duration/new-duration-date-range.svelte b/docs/src/examples/components/Duration/new-duration-date-range.svelte similarity index 100% rename from sites/docs/src/examples/components/Duration/new-duration-date-range.svelte rename to docs/src/examples/components/Duration/new-duration-date-range.svelte diff --git a/sites/docs/src/examples/components/Duration/new-duration-string-range.svelte b/docs/src/examples/components/Duration/new-duration-string-range.svelte similarity index 100% rename from sites/docs/src/examples/components/Duration/new-duration-string-range.svelte rename to docs/src/examples/components/Duration/new-duration-string-range.svelte diff --git a/sites/docs/src/examples/components/MediaQueryPresets/basic.svelte b/docs/src/examples/components/MediaQueryPresets/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/MediaQueryPresets/basic.svelte rename to docs/src/examples/components/MediaQueryPresets/basic.svelte diff --git a/sites/docs/src/examples/components/SelectionState/basic.svelte b/docs/src/examples/components/SelectionState/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/SelectionState/basic.svelte rename to docs/src/examples/components/SelectionState/basic.svelte diff --git a/sites/docs/src/examples/components/SelectionState/initial-selection.svelte b/docs/src/examples/components/SelectionState/initial-selection.svelte similarity index 100% rename from sites/docs/src/examples/components/SelectionState/initial-selection.svelte rename to docs/src/examples/components/SelectionState/initial-selection.svelte diff --git a/sites/docs/src/examples/components/SelectionState/max.svelte b/docs/src/examples/components/SelectionState/max.svelte similarity index 100% rename from sites/docs/src/examples/components/SelectionState/max.svelte rename to docs/src/examples/components/SelectionState/max.svelte diff --git a/sites/docs/src/examples/components/SelectionState/select-all.svelte b/docs/src/examples/components/SelectionState/select-all.svelte similarity index 100% rename from sites/docs/src/examples/components/SelectionState/select-all.svelte rename to docs/src/examples/components/SelectionState/select-all.svelte diff --git a/sites/docs/src/examples/components/SelectionState/set-selection.svelte b/docs/src/examples/components/SelectionState/set-selection.svelte similarity index 100% rename from sites/docs/src/examples/components/SelectionState/set-selection.svelte rename to docs/src/examples/components/SelectionState/set-selection.svelte diff --git a/sites/docs/src/examples/components/SelectionState/single.svelte b/docs/src/examples/components/SelectionState/single.svelte similarity index 100% rename from sites/docs/src/examples/components/SelectionState/single.svelte rename to docs/src/examples/components/SelectionState/single.svelte diff --git a/sites/docs/src/examples/components/TimerState/basic.svelte b/docs/src/examples/components/TimerState/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/TimerState/basic.svelte rename to docs/src/examples/components/TimerState/basic.svelte diff --git a/sites/docs/src/examples/components/TimerState/tick-count.svelte b/docs/src/examples/components/TimerState/tick-count.svelte similarity index 100% rename from sites/docs/src/examples/components/TimerState/tick-count.svelte rename to docs/src/examples/components/TimerState/tick-count.svelte diff --git a/sites/docs/src/examples/components/UniqueState/basic.svelte b/docs/src/examples/components/UniqueState/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/UniqueState/basic.svelte rename to docs/src/examples/components/UniqueState/basic.svelte diff --git a/sites/docs/src/examples/components/changeStore/basic.svelte b/docs/src/examples/components/changeStore/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/changeStore/basic.svelte rename to docs/src/examples/components/changeStore/basic.svelte diff --git a/sites/docs/src/examples/components/changeStore/pagination.svelte b/docs/src/examples/components/changeStore/pagination.svelte similarity index 100% rename from sites/docs/src/examples/components/changeStore/pagination.svelte rename to docs/src/examples/components/changeStore/pagination.svelte diff --git a/sites/docs/src/examples/components/dataBackground/basic.svelte b/docs/src/examples/components/dataBackground/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/dataBackground/basic.svelte rename to docs/src/examples/components/dataBackground/basic.svelte diff --git a/sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte b/docs/src/examples/components/dataBackground/tailwind-gradient.svelte similarity index 100% rename from sites/docs/src/examples/components/dataBackground/tailwind-gradient.svelte rename to docs/src/examples/components/dataBackground/tailwind-gradient.svelte diff --git a/sites/docs/src/examples/components/debounceStore/basic.svelte b/docs/src/examples/components/debounceStore/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/debounceStore/basic.svelte rename to docs/src/examples/components/debounceStore/basic.svelte diff --git a/sites/docs/src/examples/components/dirtyStore/basic.svelte b/docs/src/examples/components/dirtyStore/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/dirtyStore/basic.svelte rename to docs/src/examples/components/dirtyStore/basic.svelte diff --git a/sites/docs/src/examples/components/format/dates-custom.svelte b/docs/src/examples/components/format/dates-custom.svelte similarity index 100% rename from sites/docs/src/examples/components/format/dates-custom.svelte rename to docs/src/examples/components/format/dates-custom.svelte diff --git a/sites/docs/src/examples/components/format/dates-period-types.svelte b/docs/src/examples/components/format/dates-period-types.svelte similarity index 100% rename from sites/docs/src/examples/components/format/dates-period-types.svelte rename to docs/src/examples/components/format/dates-period-types.svelte diff --git a/sites/docs/src/examples/components/format/numbers-config.svelte b/docs/src/examples/components/format/numbers-config.svelte similarity index 100% rename from sites/docs/src/examples/components/format/numbers-config.svelte rename to docs/src/examples/components/format/numbers-config.svelte diff --git a/sites/docs/src/examples/components/format/numbers-default.svelte b/docs/src/examples/components/format/numbers-default.svelte similarity index 100% rename from sites/docs/src/examples/components/format/numbers-default.svelte rename to docs/src/examples/components/format/numbers-default.svelte diff --git a/sites/docs/src/examples/components/format/numbers-options.svelte b/docs/src/examples/components/format/numbers-options.svelte similarity index 100% rename from sites/docs/src/examples/components/format/numbers-options.svelte rename to docs/src/examples/components/format/numbers-options.svelte diff --git a/sites/docs/src/examples/components/format/playground-dates.svelte b/docs/src/examples/components/format/playground-dates.svelte similarity index 100% rename from sites/docs/src/examples/components/format/playground-dates.svelte rename to docs/src/examples/components/format/playground-dates.svelte diff --git a/sites/docs/src/examples/components/format/playground-numbers.svelte b/docs/src/examples/components/format/playground-numbers.svelte similarity index 100% rename from sites/docs/src/examples/components/format/playground-numbers.svelte rename to docs/src/examples/components/format/playground-numbers.svelte diff --git a/sites/docs/src/examples/components/input/auto-focus.svelte b/docs/src/examples/components/input/auto-focus.svelte similarity index 100% rename from sites/docs/src/examples/components/input/auto-focus.svelte rename to docs/src/examples/components/input/auto-focus.svelte diff --git a/sites/docs/src/examples/components/input/auto-height.svelte b/docs/src/examples/components/input/auto-height.svelte similarity index 100% rename from sites/docs/src/examples/components/input/auto-height.svelte rename to docs/src/examples/components/input/auto-height.svelte diff --git a/sites/docs/src/examples/components/input/blur-on-escape.svelte b/docs/src/examples/components/input/blur-on-escape.svelte similarity index 100% rename from sites/docs/src/examples/components/input/blur-on-escape.svelte rename to docs/src/examples/components/input/blur-on-escape.svelte diff --git a/sites/docs/src/examples/components/input/debounce-event.svelte b/docs/src/examples/components/input/debounce-event.svelte similarity index 100% rename from sites/docs/src/examples/components/input/debounce-event.svelte rename to docs/src/examples/components/input/debounce-event.svelte diff --git a/sites/docs/src/examples/components/input/select-on-focus.svelte b/docs/src/examples/components/input/select-on-focus.svelte similarity index 100% rename from sites/docs/src/examples/components/input/select-on-focus.svelte rename to docs/src/examples/components/input/select-on-focus.svelte diff --git a/sites/docs/src/examples/components/layout/overflow.svelte b/docs/src/examples/components/layout/overflow.svelte similarity index 100% rename from sites/docs/src/examples/components/layout/overflow.svelte rename to docs/src/examples/components/layout/overflow.svelte diff --git a/sites/docs/src/examples/components/matchMedia/basic.svelte b/docs/src/examples/components/matchMedia/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/matchMedia/basic.svelte rename to docs/src/examples/components/matchMedia/basic.svelte diff --git a/sites/docs/src/examples/components/mouse/longpress.svelte b/docs/src/examples/components/mouse/longpress.svelte similarity index 100% rename from sites/docs/src/examples/components/mouse/longpress.svelte rename to docs/src/examples/components/mouse/longpress.svelte diff --git a/sites/docs/src/examples/components/mouse/movable-step-percent.svelte b/docs/src/examples/components/mouse/movable-step-percent.svelte similarity index 100% rename from sites/docs/src/examples/components/mouse/movable-step-percent.svelte rename to docs/src/examples/components/mouse/movable-step-percent.svelte diff --git a/sites/docs/src/examples/components/mouse/movable-step.svelte b/docs/src/examples/components/mouse/movable-step.svelte similarity index 100% rename from sites/docs/src/examples/components/mouse/movable-step.svelte rename to docs/src/examples/components/mouse/movable-step.svelte diff --git a/sites/docs/src/examples/components/mouse/movable-x-axis.svelte b/docs/src/examples/components/mouse/movable-x-axis.svelte similarity index 100% rename from sites/docs/src/examples/components/mouse/movable-x-axis.svelte rename to docs/src/examples/components/mouse/movable-x-axis.svelte diff --git a/sites/docs/src/examples/components/mouse/movable.svelte b/docs/src/examples/components/mouse/movable.svelte similarity index 100% rename from sites/docs/src/examples/components/mouse/movable.svelte rename to docs/src/examples/components/mouse/movable.svelte diff --git a/sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte b/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte similarity index 100% rename from sites/docs/src/examples/components/observer/adding-class-when-fully-visible.svelte rename to docs/src/examples/components/observer/adding-class-when-fully-visible.svelte diff --git a/sites/docs/src/examples/components/observer/basic.svelte b/docs/src/examples/components/observer/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/observer/basic.svelte rename to docs/src/examples/components/observer/basic.svelte diff --git a/sites/docs/src/examples/components/observer/full-coordinates.svelte b/docs/src/examples/components/observer/full-coordinates.svelte similarity index 100% rename from sites/docs/src/examples/components/observer/full-coordinates.svelte rename to docs/src/examples/components/observer/full-coordinates.svelte diff --git a/sites/docs/src/examples/components/observer/setting-css-variable.svelte b/docs/src/examples/components/observer/setting-css-variable.svelte similarity index 100% rename from sites/docs/src/examples/components/observer/setting-css-variable.svelte rename to docs/src/examples/components/observer/setting-css-variable.svelte diff --git a/sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte b/docs/src/examples/components/observer/show-header-on-scroll-away.svelte similarity index 100% rename from sites/docs/src/examples/components/observer/show-header-on-scroll-away.svelte rename to docs/src/examples/components/observer/show-header-on-scroll-away.svelte diff --git a/sites/docs/src/examples/components/portal/ancestor-portal-target.svelte b/docs/src/examples/components/portal/ancestor-portal-target.svelte similarity index 100% rename from sites/docs/src/examples/components/portal/ancestor-portal-target.svelte rename to docs/src/examples/components/portal/ancestor-portal-target.svelte diff --git a/sites/docs/src/examples/components/portal/basic.svelte b/docs/src/examples/components/portal/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/portal/basic.svelte rename to docs/src/examples/components/portal/basic.svelte diff --git a/sites/docs/src/examples/components/portal/custom-target.svelte b/docs/src/examples/components/portal/custom-target.svelte similarity index 100% rename from sites/docs/src/examples/components/portal/custom-target.svelte rename to docs/src/examples/components/portal/custom-target.svelte diff --git a/sites/docs/src/examples/components/portal/destroyable.svelte b/docs/src/examples/components/portal/destroyable.svelte similarity index 100% rename from sites/docs/src/examples/components/portal/destroyable.svelte rename to docs/src/examples/components/portal/destroyable.svelte diff --git a/sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte b/docs/src/examples/components/portal/first-sibling-portal-target.svelte similarity index 100% rename from sites/docs/src/examples/components/portal/first-sibling-portal-target.svelte rename to docs/src/examples/components/portal/first-sibling-portal-target.svelte diff --git a/sites/docs/src/examples/components/scroll/basic.svelte b/docs/src/examples/components/scroll/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/basic.svelte rename to docs/src/examples/components/scroll/basic.svelte diff --git a/sites/docs/src/examples/components/scroll/only-if-needed.svelte b/docs/src/examples/components/scroll/only-if-needed.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/only-if-needed.svelte rename to docs/src/examples/components/scroll/only-if-needed.svelte diff --git a/sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte b/docs/src/examples/components/scroll/scroll-fade-flip.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/scroll-fade-flip.svelte rename to docs/src/examples/components/scroll/scroll-fade-flip.svelte diff --git a/sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte b/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/scroll-fade-horizontal.svelte rename to docs/src/examples/components/scroll/scroll-fade-horizontal.svelte diff --git a/sites/docs/src/examples/components/scroll/scroll-fade.svelte b/docs/src/examples/components/scroll/scroll-fade.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/scroll-fade.svelte rename to docs/src/examples/components/scroll/scroll-fade.svelte diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte b/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte rename to docs/src/examples/components/scroll/scroll-shadow-bottom-surface.svelte diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte b/docs/src/examples/components/scroll/scroll-shadow-flip.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/scroll-shadow-flip.svelte rename to docs/src/examples/components/scroll/scroll-shadow-flip.svelte diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte b/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte rename to docs/src/examples/components/scroll/scroll-shadow-horizontal.svelte diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte b/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/scroll-shadow-truncation.svelte rename to docs/src/examples/components/scroll/scroll-shadow-truncation.svelte diff --git a/sites/docs/src/examples/components/scroll/scroll-shadow.svelte b/docs/src/examples/components/scroll/scroll-shadow.svelte similarity index 100% rename from sites/docs/src/examples/components/scroll/scroll-shadow.svelte rename to docs/src/examples/components/scroll/scroll-shadow.svelte diff --git a/sites/docs/src/examples/components/selectionStore/basic.svelte b/docs/src/examples/components/selectionStore/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/selectionStore/basic.svelte rename to docs/src/examples/components/selectionStore/basic.svelte diff --git a/sites/docs/src/examples/components/selectionStore/initial-selection.svelte b/docs/src/examples/components/selectionStore/initial-selection.svelte similarity index 100% rename from sites/docs/src/examples/components/selectionStore/initial-selection.svelte rename to docs/src/examples/components/selectionStore/initial-selection.svelte diff --git a/sites/docs/src/examples/components/selectionStore/max.svelte b/docs/src/examples/components/selectionStore/max.svelte similarity index 100% rename from sites/docs/src/examples/components/selectionStore/max.svelte rename to docs/src/examples/components/selectionStore/max.svelte diff --git a/sites/docs/src/examples/components/selectionStore/select-all.svelte b/docs/src/examples/components/selectionStore/select-all.svelte similarity index 100% rename from sites/docs/src/examples/components/selectionStore/select-all.svelte rename to docs/src/examples/components/selectionStore/select-all.svelte diff --git a/sites/docs/src/examples/components/selectionStore/single.svelte b/docs/src/examples/components/selectionStore/single.svelte similarity index 100% rename from sites/docs/src/examples/components/selectionStore/single.svelte rename to docs/src/examples/components/selectionStore/single.svelte diff --git a/sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte b/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte similarity index 100% rename from sites/docs/src/examples/components/spotlight/global-context-and-css-variables.svelte rename to docs/src/examples/components/spotlight/global-context-and-css-variables.svelte diff --git a/sites/docs/src/examples/components/spotlight/global-context-and-options.svelte b/docs/src/examples/components/spotlight/global-context-and-options.svelte similarity index 100% rename from sites/docs/src/examples/components/spotlight/global-context-and-options.svelte rename to docs/src/examples/components/spotlight/global-context-and-options.svelte diff --git a/sites/docs/src/examples/components/spotlight/line.svelte b/docs/src/examples/components/spotlight/line.svelte similarity index 100% rename from sites/docs/src/examples/components/spotlight/line.svelte rename to docs/src/examples/components/spotlight/line.svelte diff --git a/sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte b/docs/src/examples/components/string/truncate-middle-ellipsis.svelte similarity index 100% rename from sites/docs/src/examples/components/string/truncate-middle-ellipsis.svelte rename to docs/src/examples/components/string/truncate-middle-ellipsis.svelte diff --git a/sites/docs/src/examples/components/string/truncate-playground.svelte b/docs/src/examples/components/string/truncate-playground.svelte similarity index 100% rename from sites/docs/src/examples/components/string/truncate-playground.svelte rename to docs/src/examples/components/string/truncate-playground.svelte diff --git a/sites/docs/src/examples/components/string/truncate-total-only.svelte b/docs/src/examples/components/string/truncate-total-only.svelte similarity index 100% rename from sites/docs/src/examples/components/string/truncate-total-only.svelte rename to docs/src/examples/components/string/truncate-total-only.svelte diff --git a/sites/docs/src/examples/components/string/unique-basic.svelte b/docs/src/examples/components/string/unique-basic.svelte similarity index 100% rename from sites/docs/src/examples/components/string/unique-basic.svelte rename to docs/src/examples/components/string/unique-basic.svelte diff --git a/sites/docs/src/examples/components/styles/computed-styles.svelte b/docs/src/examples/components/styles/computed-styles.svelte similarity index 100% rename from sites/docs/src/examples/components/styles/computed-styles.svelte rename to docs/src/examples/components/styles/computed-styles.svelte diff --git a/sites/docs/src/examples/components/styles/style-props.svelte b/docs/src/examples/components/styles/style-props.svelte similarity index 100% rename from sites/docs/src/examples/components/styles/style-props.svelte rename to docs/src/examples/components/styles/style-props.svelte diff --git a/sites/docs/src/examples/components/timerStore/default.svelte b/docs/src/examples/components/timerStore/default.svelte similarity index 100% rename from sites/docs/src/examples/components/timerStore/default.svelte rename to docs/src/examples/components/timerStore/default.svelte diff --git a/sites/docs/src/examples/components/timerStore/tick-count.svelte b/docs/src/examples/components/timerStore/tick-count.svelte similarity index 100% rename from sites/docs/src/examples/components/timerStore/tick-count.svelte rename to docs/src/examples/components/timerStore/tick-count.svelte diff --git a/sites/docs/src/examples/components/uniqueStore/basic.svelte b/docs/src/examples/components/uniqueStore/basic.svelte similarity index 100% rename from sites/docs/src/examples/components/uniqueStore/basic.svelte rename to docs/src/examples/components/uniqueStore/basic.svelte diff --git a/sites/docs/src/lib/components/Example.svelte b/docs/src/lib/components/Example.svelte similarity index 100% rename from sites/docs/src/lib/components/Example.svelte rename to docs/src/lib/components/Example.svelte diff --git a/sites/docs/src/lib/components/OpenWithButton.svelte b/docs/src/lib/components/OpenWithButton.svelte similarity index 100% rename from sites/docs/src/lib/components/OpenWithButton.svelte rename to docs/src/lib/components/OpenWithButton.svelte diff --git a/sites/docs/src/lib/content.ts b/docs/src/lib/content.ts similarity index 100% rename from sites/docs/src/lib/content.ts rename to docs/src/lib/content.ts diff --git a/sites/docs/src/lib/examples.ts b/docs/src/lib/examples.ts similarity index 100% rename from sites/docs/src/lib/examples.ts rename to docs/src/lib/examples.ts diff --git a/sites/docs/src/lib/llms.ts b/docs/src/lib/llms.ts similarity index 100% rename from sites/docs/src/lib/llms.ts rename to docs/src/lib/llms.ts diff --git a/sites/docs/src/lib/searchContent.ts b/docs/src/lib/searchContent.ts similarity index 100% rename from sites/docs/src/lib/searchContent.ts rename to docs/src/lib/searchContent.ts diff --git a/sites/docs/src/routes/+error.svelte b/docs/src/routes/+error.svelte similarity index 100% rename from sites/docs/src/routes/+error.svelte rename to docs/src/routes/+error.svelte diff --git a/sites/docs/src/routes/+layout.server.ts b/docs/src/routes/+layout.server.ts similarity index 100% rename from sites/docs/src/routes/+layout.server.ts rename to docs/src/routes/+layout.server.ts diff --git a/sites/docs/src/routes/+layout.svelte b/docs/src/routes/+layout.svelte similarity index 100% rename from sites/docs/src/routes/+layout.svelte rename to docs/src/routes/+layout.svelte diff --git a/sites/docs/src/routes/+layout.ts b/docs/src/routes/+layout.ts similarity index 100% rename from sites/docs/src/routes/+layout.ts rename to docs/src/routes/+layout.ts diff --git a/sites/docs/src/routes/+page.svelte b/docs/src/routes/+page.svelte similarity index 100% rename from sites/docs/src/routes/+page.svelte rename to docs/src/routes/+page.svelte diff --git a/sites/docs/src/routes/_NavMenu.svelte b/docs/src/routes/_NavMenu.svelte similarity index 100% rename from sites/docs/src/routes/_NavMenu.svelte rename to docs/src/routes/_NavMenu.svelte diff --git a/sites/docs/src/routes/api/search.json/+server.ts b/docs/src/routes/api/search.json/+server.ts similarity index 100% rename from sites/docs/src/routes/api/search.json/+server.ts rename to docs/src/routes/api/search.json/+server.ts diff --git a/sites/docs/src/routes/app.css b/docs/src/routes/app.css similarity index 100% rename from sites/docs/src/routes/app.css rename to docs/src/routes/app.css diff --git a/sites/docs/src/routes/docs/+layout.svelte b/docs/src/routes/docs/+layout.svelte similarity index 100% rename from sites/docs/src/routes/docs/+layout.svelte rename to docs/src/routes/docs/+layout.svelte diff --git a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte b/docs/src/routes/docs/[packageName]/[name]/+page.svelte similarity index 96% rename from sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte rename to docs/src/routes/docs/[packageName]/[name]/+page.svelte index 0833396..ff081aa 100644 --- a/sites/docs/src/routes/docs/[packageName]/[name]/+page.svelte +++ b/docs/src/routes/docs/[packageName]/[name]/+page.svelte @@ -80,7 +80,7 @@
    diff --git a/sites/docs/src/routes/docs/guides/[name]/+page.ts b/docs/src/routes/docs/guides/[name]/+page.ts similarity index 100% rename from sites/docs/src/routes/docs/guides/[name]/+page.ts rename to docs/src/routes/docs/guides/[name]/+page.ts diff --git a/sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts b/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts similarity index 100% rename from sites/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts rename to docs/src/routes/docs/guides/[name]/llms.txt/+server.ts diff --git a/sites/docs/src/routes/docs/llms.txt/+server.ts b/docs/src/routes/docs/llms.txt/+server.ts similarity index 100% rename from sites/docs/src/routes/docs/llms.txt/+server.ts rename to docs/src/routes/docs/llms.txt/+server.ts diff --git a/sites/docs/src/routes/docs/svelte-actions/+page.server.ts b/docs/src/routes/docs/svelte-actions/+page.server.ts similarity index 100% rename from sites/docs/src/routes/docs/svelte-actions/+page.server.ts rename to docs/src/routes/docs/svelte-actions/+page.server.ts diff --git a/sites/docs/src/routes/docs/svelte-state/+page.server.ts b/docs/src/routes/docs/svelte-state/+page.server.ts similarity index 100% rename from sites/docs/src/routes/docs/svelte-state/+page.server.ts rename to docs/src/routes/docs/svelte-state/+page.server.ts diff --git a/sites/docs/src/routes/docs/svelte-stores/+page.server.ts b/docs/src/routes/docs/svelte-stores/+page.server.ts similarity index 100% rename from sites/docs/src/routes/docs/svelte-stores/+page.server.ts rename to docs/src/routes/docs/svelte-stores/+page.server.ts diff --git a/sites/docs/src/routes/docs/svelte-table/+page.server.ts b/docs/src/routes/docs/svelte-table/+page.server.ts similarity index 100% rename from sites/docs/src/routes/docs/svelte-table/+page.server.ts rename to docs/src/routes/docs/svelte-table/+page.server.ts diff --git a/sites/docs/src/routes/docs/tailwind/+page.server.ts b/docs/src/routes/docs/tailwind/+page.server.ts similarity index 100% rename from sites/docs/src/routes/docs/tailwind/+page.server.ts rename to docs/src/routes/docs/tailwind/+page.server.ts diff --git a/sites/docs/src/routes/docs/utils/+page.server.ts b/docs/src/routes/docs/utils/+page.server.ts similarity index 100% rename from sites/docs/src/routes/docs/utils/+page.server.ts rename to docs/src/routes/docs/utils/+page.server.ts diff --git a/sites/docs/src/routes/llms.txt/+server.ts b/docs/src/routes/llms.txt/+server.ts similarity index 100% rename from sites/docs/src/routes/llms.txt/+server.ts rename to docs/src/routes/llms.txt/+server.ts diff --git a/sites/docs/static/favicon.jpg b/docs/static/favicon.jpg similarity index 100% rename from sites/docs/static/favicon.jpg rename to docs/static/favicon.jpg diff --git a/sites/docs/static/fonts/DepartureMono-Regular.woff2 b/docs/static/fonts/DepartureMono-Regular.woff2 similarity index 100% rename from sites/docs/static/fonts/DepartureMono-Regular.woff2 rename to docs/static/fonts/DepartureMono-Regular.woff2 diff --git a/sites/docs/svelte.config.js b/docs/svelte.config.js similarity index 59% rename from sites/docs/svelte.config.js rename to docs/svelte.config.js index efa7700..f7bd60e 100644 --- a/sites/docs/svelte.config.js +++ b/docs/svelte.config.js @@ -25,18 +25,18 @@ const config = { // them directly — instant HMR, no per-package build/watch. (`@layerstack/tailwind` // is intentionally excluded: its CSS themes are generated into `dist`, and // `@layerstack/docs` keeps its custom export map, so both stay dist-resolved.) - '@layerstack/svelte-actions': '../../packages/svelte-actions/src/lib', - '@layerstack/svelte-state': '../../packages/svelte-state/src/lib', - '@layerstack/svelte-stores': '../../packages/svelte-stores/src/lib', - '@layerstack/svelte-table': '../../packages/svelte-table/src/lib', - '@layerstack/utils': '../../packages/utils/src/lib', + '@layerstack/svelte-actions': '../packages/svelte-actions/src/lib', + '@layerstack/svelte-state': '../packages/svelte-state/src/lib', + '@layerstack/svelte-stores': '../packages/svelte-stores/src/lib', + '@layerstack/svelte-table': '../packages/svelte-table/src/lib', + '@layerstack/utils': '../packages/utils/src/lib', // `?raw` source-display aliases (kept for legacy pages) - '$svelte-actions': '../../packages/svelte-actions/src/lib', - '$svelte-state': '../../packages/svelte-state/src/lib', - '$svelte-stores': '../../packages/svelte-stores/src/lib', - '$svelte-table': '../../packages/svelte-table/src/lib', - $tailwind: '../../packages/tailwind/src/lib', - $utils: '../../packages/utils/src/lib', + '$svelte-actions': '../packages/svelte-actions/src/lib', + '$svelte-state': '../packages/svelte-state/src/lib', + '$svelte-stores': '../packages/svelte-stores/src/lib', + '$svelte-table': '../packages/svelte-table/src/lib', + $tailwind: '../packages/tailwind/src/lib', + $utils: '../packages/utils/src/lib', }, }, }; diff --git a/sites/docs/tsconfig.json b/docs/tsconfig.json similarity index 100% rename from sites/docs/tsconfig.json rename to docs/tsconfig.json diff --git a/sites/docs/vite.config.js b/docs/vite.config.js similarity index 100% rename from sites/docs/vite.config.js rename to docs/vite.config.js diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a7d08dc..ade85c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,6 +21,136 @@ importers: specifier: ^4.14.4 version: 4.14.4(@cloudflare/workers-types@4.20250514.0) + docs: + dependencies: + '@fontsource-variable/inter': + specifier: ^5.2.8 + version: 5.2.8 + '@fortawesome/fontawesome-common-types': + specifier: ^6.7.2 + version: 6.7.2 + '@layerstack/docs': + specifier: workspace:* + version: link:../packages/docs + '@layerstack/svelte-actions': + specifier: workspace:* + version: link:../packages/svelte-actions + '@layerstack/svelte-state': + specifier: workspace:* + version: link:../packages/svelte-state + '@layerstack/svelte-stores': + specifier: workspace:* + version: link:../packages/svelte-stores + '@layerstack/svelte-table': + specifier: workspace:* + version: link:../packages/svelte-table + '@layerstack/tailwind': + specifier: workspace:* + version: link:../packages/tailwind + '@layerstack/utils': + specifier: workspace:* + version: link:../packages/utils + '@mdi/js': + specifier: ^7.4.47 + version: 7.4.47 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + d3-array: + specifier: ^3.2.4 + version: 3.2.4 + tailwind-merge: + specifier: ^3.2.0 + version: 3.3.0 + devDependencies: + '@changesets/cli': + specifier: ^2.29.4 + version: 2.29.4 + '@content-collections/core': + specifier: ^0.14.3 + version: 0.14.3(typescript@5.8.3) + '@content-collections/markdown': + specifier: ^0.1.4 + version: 0.1.4(@content-collections/core@0.14.3(typescript@5.8.3)) + '@content-collections/vite': + specifier: ^0.2.9 + version: 0.2.9(@content-collections/core@0.14.3(typescript@5.8.3))(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) + '@fortawesome/free-solid-svg-icons': + specifier: ^6.7.2 + version: 6.7.2 + '@iconify-json/lucide': + specifier: ^1.2.53 + version: 1.2.53 + '@iconify-json/simple-icons': + specifier: ^1.2.84 + version: 1.2.84 + '@sveltejs/adapter-cloudflare': + specifier: ^7.0.3 + version: 7.0.3(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(wrangler@4.14.4(@cloudflare/workers-types@4.20250514.0)) + '@sveltejs/kit': + specifier: ^2.21.0 + version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) + '@sveltejs/package': + specifier: ^2.3.11 + version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) + '@sveltejs/vite-plugin-svelte': + specifier: ^5.0.3 + version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) + '@tailwindcss/typography': + specifier: ^0.5.16 + version: 0.5.16(tailwindcss@4.1.6) + '@tailwindcss/vite': + specifier: ^4.1.5 + version: 4.1.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) + '@types/d3-array': + specifier: ^3.2.1 + version: 3.2.1 + mdsx: + specifier: ^0.0.7 + version: 0.0.7(svelte@5.28.6) + posthog-js: + specifier: ^1.239.0 + version: 1.242.1 + prettier: + specifier: ^3.5.3 + version: 3.5.3 + prettier-plugin-svelte: + specifier: ^3.3.3 + version: 3.3.3(prettier@3.5.3)(svelte@5.28.6) + rehype-slug: + specifier: ^6.0.0 + version: 6.0.0 + svelte: + specifier: ^5.28.2 + version: 5.28.6 + svelte-check: + specifier: ^4.1.6 + version: 4.1.7(picomatch@4.0.2)(svelte@5.28.6)(typescript@5.8.3) + svelte-ux: + specifier: 2.0.0-next.22 + version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3)(svelte@5.28.6) + svelte2tsx: + specifier: ^0.7.36 + version: 0.7.37(svelte@5.28.6)(typescript@5.8.3) + tailwindcss: + specifier: ^4.1.5 + version: 4.1.6 + tslib: + specifier: ^2.8.1 + version: 2.8.1 + typescript: + specifier: ^5.8.3 + version: 5.8.3 + unist-util-visit: + specifier: ^5.0.0 + version: 5.1.0 + unplugin-icons: + specifier: ^22.1.0 + version: 22.1.0(svelte@5.28.6) + vite: + specifier: ^6.3.5 + version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) + packages/docs: dependencies: '@content-collections/core': @@ -463,136 +593,6 @@ importers: specifier: ^3.1.3 version: 3.1.3(@types/debug@4.1.13)(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) - sites/docs: - dependencies: - '@fontsource-variable/inter': - specifier: ^5.2.8 - version: 5.2.8 - '@fortawesome/fontawesome-common-types': - specifier: ^6.7.2 - version: 6.7.2 - '@layerstack/docs': - specifier: workspace:* - version: link:../../packages/docs - '@layerstack/svelte-actions': - specifier: workspace:* - version: link:../../packages/svelte-actions - '@layerstack/svelte-state': - specifier: workspace:* - version: link:../../packages/svelte-state - '@layerstack/svelte-stores': - specifier: workspace:* - version: link:../../packages/svelte-stores - '@layerstack/svelte-table': - specifier: workspace:* - version: link:../../packages/svelte-table - '@layerstack/tailwind': - specifier: workspace:* - version: link:../../packages/tailwind - '@layerstack/utils': - specifier: workspace:* - version: link:../../packages/utils - '@mdi/js': - specifier: ^7.4.47 - version: 7.4.47 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - d3-array: - specifier: ^3.2.4 - version: 3.2.4 - tailwind-merge: - specifier: ^3.2.0 - version: 3.3.0 - devDependencies: - '@changesets/cli': - specifier: ^2.29.4 - version: 2.29.4 - '@content-collections/core': - specifier: ^0.14.3 - version: 0.14.3(typescript@5.8.3) - '@content-collections/markdown': - specifier: ^0.1.4 - version: 0.1.4(@content-collections/core@0.14.3(typescript@5.8.3)) - '@content-collections/vite': - specifier: ^0.2.9 - version: 0.2.9(@content-collections/core@0.14.3(typescript@5.8.3))(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) - '@fortawesome/free-solid-svg-icons': - specifier: ^6.7.2 - version: 6.7.2 - '@iconify-json/lucide': - specifier: ^1.2.53 - version: 1.2.53 - '@iconify-json/simple-icons': - specifier: ^1.2.84 - version: 1.2.84 - '@sveltejs/adapter-cloudflare': - specifier: ^7.0.3 - version: 7.0.3(@sveltejs/kit@2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(wrangler@4.14.4(@cloudflare/workers-types@4.20250514.0)) - '@sveltejs/kit': - specifier: ^2.21.0 - version: 2.21.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)))(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) - '@sveltejs/package': - specifier: ^2.3.11 - version: 2.3.11(svelte@5.28.6)(typescript@5.8.3) - '@sveltejs/vite-plugin-svelte': - specifier: ^5.0.3 - version: 5.0.3(svelte@5.28.6)(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) - '@tailwindcss/typography': - specifier: ^0.5.16 - version: 0.5.16(tailwindcss@4.1.6) - '@tailwindcss/vite': - specifier: ^4.1.5 - version: 4.1.6(vite@6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0)) - '@types/d3-array': - specifier: ^3.2.1 - version: 3.2.1 - mdsx: - specifier: ^0.0.7 - version: 0.0.7(svelte@5.28.6) - posthog-js: - specifier: ^1.239.0 - version: 1.242.1 - prettier: - specifier: ^3.5.3 - version: 3.5.3 - prettier-plugin-svelte: - specifier: ^3.3.3 - version: 3.3.3(prettier@3.5.3)(svelte@5.28.6) - rehype-slug: - specifier: ^6.0.0 - version: 6.0.0 - svelte: - specifier: ^5.28.2 - version: 5.28.6 - svelte-check: - specifier: ^4.1.6 - version: 4.1.7(picomatch@4.0.2)(svelte@5.28.6)(typescript@5.8.3) - svelte-ux: - specifier: 2.0.0-next.22 - version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.22.3)(yaml@2.9.0))(postcss@8.5.3)(svelte@5.28.6) - svelte2tsx: - specifier: ^0.7.36 - version: 0.7.37(svelte@5.28.6)(typescript@5.8.3) - tailwindcss: - specifier: ^4.1.5 - version: 4.1.6 - tslib: - specifier: ^2.8.1 - version: 2.8.1 - typescript: - specifier: ^5.8.3 - version: 5.8.3 - unist-util-visit: - specifier: ^5.0.0 - version: 5.0.0 - unplugin-icons: - specifier: ^22.1.0 - version: 22.1.0(svelte@5.28.6) - vite: - specifier: ^6.3.5 - version: 6.3.5(@types/node@24.0.1)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.22.3)(yaml@2.9.0) - packages: '@ampproject/remapping@2.3.0': @@ -2254,10 +2254,6 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} - engines: {node: '>=8'} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -3572,9 +3568,6 @@ packages: unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - unist-util-visit@5.1.0: resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} @@ -4863,7 +4856,7 @@ snapshots: '@tailwindcss/oxide@4.1.6': dependencies: - detect-libc: 2.0.4 + detect-libc: 2.1.2 tar: 7.4.3 optionalDependencies: '@tailwindcss/oxide-android-arm64': 4.1.6 @@ -5221,8 +5214,6 @@ snapshots: detect-indent@6.1.0: {} - detect-libc@2.0.4: {} - detect-libc@2.1.2: {} devalue@5.1.1: {} @@ -5697,7 +5688,7 @@ snapshots: lightningcss@1.29.2: dependencies: - detect-libc: 2.0.4 + detect-libc: 2.1.2 optionalDependencies: lightningcss-darwin-arm64: 1.29.2 lightningcss-darwin-x64: 1.29.2 @@ -6526,7 +6517,7 @@ snapshots: sharp@0.33.5: dependencies: color: 4.2.3 - detect-libc: 2.0.4 + detect-libc: 2.1.2 semver: 7.7.2 optionalDependencies: '@img/sharp-darwin-arm64': 0.33.5 @@ -6910,12 +6901,6 @@ snapshots: '@types/unist': 3.0.3 unist-util-is: 6.0.0 - unist-util-visit@5.0.0: - dependencies: - '@types/unist': 3.0.2 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 - unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5aef8cc..59a60bd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,3 @@ packages: - 'packages/*' - - 'sites/*' + - 'docs' From 9b62cfe69e7e7a56989bea847814b61b48f7855d Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 17:04:58 -0400 Subject: [PATCH 20/21] move more common pieces to @layerstack/docs and add docs --- docs/src/lib/examples.ts | 36 +- docs/src/lib/searchContent.ts | 126 +----- .../guides/{[name] => [...name]}/+page.svelte | 0 .../guides/{[name] => [...name]}/+page.ts | 0 .../{[name] => [...name]}/llms.txt/+server.ts | 0 docs/vite.config.js | 6 + packages/docs/README.md | 411 ++++++++++++++++-- packages/docs/package.json | 4 + packages/docs/src/lib/examples.ts | 40 ++ packages/docs/src/lib/search.ts | 111 +++++ packages/docs/src/lib/utils/index.ts | 1 + 11 files changed, 566 insertions(+), 169 deletions(-) rename docs/src/routes/docs/guides/{[name] => [...name]}/+page.svelte (100%) rename docs/src/routes/docs/guides/{[name] => [...name]}/+page.ts (100%) rename docs/src/routes/docs/guides/{[name] => [...name]}/llms.txt/+server.ts (100%) create mode 100644 packages/docs/src/lib/utils/index.ts diff --git a/docs/src/lib/examples.ts b/docs/src/lib/examples.ts index a1cee34..ab0e426 100644 --- a/docs/src/lib/examples.ts +++ b/docs/src/lib/examples.ts @@ -1,26 +1,20 @@ import type { Component } from 'svelte'; -import { createExampleLoaders } from '@layerstack/docs/examples'; +import { createGlobExampleLoaders } from '@layerstack/docs/examples'; -const pathExamples = import.meta.glob<{ default: Component }>([ - '/src/routes/**/*.svelte', - '/src/content/**/*.svelte', -]); - -const rawPathExamples = import.meta.glob( - ['/src/routes/**/*.svelte', '/src/content/**/*.svelte'], - { - query: '?raw', - import: 'default', - } -); - -export const { loadExample, loadExamples, loadExampleByPath } = createExampleLoaders({ +export const { loadExample, loadExamples, loadExampleByPath } = createGlobExampleLoaders({ loadComponentExample: (type, component, name) => import(`../examples/${type}/${component}/${name}.svelte`), - loadRawExample: async (type, component, name) => { - const raw = await import(`../examples/${type}/${component}/${name}.svelte?raw`); - return raw.default as string; - }, - loadPathExample: (path) => pathExamples[path]?.(), - loadRawPathExample: (path) => rawPathExamples[path]?.(), + loadRawExampleModule: (type, component, name) => + import(`../examples/${type}/${component}/${name}.svelte?raw`), + pathExamples: import.meta.glob<{ default: Component }>([ + '/src/routes/**/*.svelte', + '/src/content/**/*.svelte', + ]), + rawPathExamples: import.meta.glob( + ['/src/routes/**/*.svelte', '/src/content/**/*.svelte'], + { + query: '?raw', + import: 'default', + } + ), }); diff --git a/docs/src/lib/searchContent.ts b/docs/src/lib/searchContent.ts index e8ba4f4..2443915 100644 --- a/docs/src/lib/searchContent.ts +++ b/docs/src/lib/searchContent.ts @@ -1,117 +1,5 @@ -import { allReferences, allGuides, type Reference, type Guide } from 'content-collections'; -import { stripMarkdown } from '@layerstack/docs/markdown'; -import type { SearchEntry } from '@layerstack/docs/search'; - -type TocEntry = { id: string; text: string; level: number }; - -function escapeRegexChars(str: string): string { - return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); -} - -/** - * Extract the content under each heading from markdown, keyed by heading text. - */ -function extractHeadingContents(markdown: string, toc: TocEntry[]): Map { - const result = new Map(); - const headingPositions: { text: string; start: number; end: number }[] = []; - - for (const heading of toc) { - const headingPattern = new RegExp( - `^#{1,6}\\s+${escapeRegexChars(heading.text)}(?:\\s*:[a-zA-Z][\\w-]*\\{[^}]*\\})*\\s*$`, - 'gm' - ); - const match = headingPattern.exec(markdown); - if (match) { - headingPositions.push({ - text: heading.text, - start: match.index + match[0].length, - end: markdown.length, - }); - } - } - - headingPositions.sort((a, b) => a.start - b.start); - for (let i = 0; i < headingPositions.length - 1; i++) { - const nextHeadingMatch = markdown.slice(headingPositions[i].start).match(/^#{1,6}\s+/m); - if (nextHeadingMatch) { - headingPositions[i].end = headingPositions[i].start + (nextHeadingMatch.index ?? 0); - } - } - - for (const pos of headingPositions) { - const rawContent = markdown.slice(pos.start, pos.end).trim(); - result.set(pos.text, stripMarkdown(rawContent).slice(0, 200)); - } - - return result; -} - -function referenceToEntry(doc: Reference): SearchEntry { - const description = doc.description ?? ''; - const content = stripMarkdown(doc.content); - return { - title: doc.name, - slug: `docs/${doc.slug}`, - content: description ? `${description} ${content}` : content, - type: 'reference', - category: doc.slug.split('/')[0], - }; -} - -function referenceHeadingsToEntries(doc: Reference): SearchEntry[] { - const seen = new Set(); - const parentSlug = `docs/${doc.slug}`; - const headingContents = extractHeadingContents(doc.content, doc.toc); - - return doc.toc - .filter((heading: TocEntry) => { - if (seen.has(heading.id)) return false; - seen.add(heading.id); - return true; - }) - .map((heading: TocEntry) => ({ - title: heading.text, - slug: `${parentSlug}#${heading.id}`, - content: headingContents.get(heading.text) || doc.name, - type: 'heading' as const, - parent: doc.name, - parentSlug, - parentType: 'reference', - })); -} - -function guideToEntry(doc: Guide): SearchEntry { - const description = doc.description ?? ''; - const content = stripMarkdown(doc.content); - return { - title: doc.name, - slug: `docs/guides/${doc.slug}`, - content: description ? `${description} ${content}` : content, - type: 'guide', - }; -} - -function guideHeadingsToEntries(doc: Guide): SearchEntry[] { - const seen = new Set(); - const parentSlug = `docs/guides/${doc.slug}`; - const headingContents = extractHeadingContents(doc.content, doc.toc); - - return doc.toc - .filter((heading: TocEntry) => { - if (seen.has(heading.id)) return false; - seen.add(heading.id); - return true; - }) - .map((heading: TocEntry) => ({ - title: heading.text, - slug: `${parentSlug}#${heading.id}`, - content: headingContents.get(heading.text) || doc.name, - type: 'heading' as const, - parent: doc.name, - parentSlug, - parentType: 'guide', - })); -} +import { allReferences, allGuides } from 'content-collections'; +import { buildSearchEntries, type SearchEntry } from '@layerstack/docs/search'; const topLevelPages: SearchEntry[] = [ { @@ -127,8 +15,10 @@ const guides = allGuides.filter((g) => !g.draft); export const searchContent: SearchEntry[] = [ ...topLevelPages, - ...guides.map(guideToEntry), - ...guides.flatMap(guideHeadingsToEntries), - ...allReferences.map(referenceToEntry), - ...allReferences.flatMap(referenceHeadingsToEntries), + ...buildSearchEntries(guides, { type: 'guide', slugPrefix: 'docs/guides' }), + ...buildSearchEntries(allReferences, { + type: 'reference', + slugPrefix: 'docs', + category: (doc) => doc.slug.split('/')[0], + }), ]; diff --git a/docs/src/routes/docs/guides/[name]/+page.svelte b/docs/src/routes/docs/guides/[...name]/+page.svelte similarity index 100% rename from docs/src/routes/docs/guides/[name]/+page.svelte rename to docs/src/routes/docs/guides/[...name]/+page.svelte diff --git a/docs/src/routes/docs/guides/[name]/+page.ts b/docs/src/routes/docs/guides/[...name]/+page.ts similarity index 100% rename from docs/src/routes/docs/guides/[name]/+page.ts rename to docs/src/routes/docs/guides/[...name]/+page.ts diff --git a/docs/src/routes/docs/guides/[name]/llms.txt/+server.ts b/docs/src/routes/docs/guides/[...name]/llms.txt/+server.ts similarity index 100% rename from docs/src/routes/docs/guides/[name]/llms.txt/+server.ts rename to docs/src/routes/docs/guides/[...name]/llms.txt/+server.ts diff --git a/docs/vite.config.js b/docs/vite.config.js index b355f10..b8ca1c0 100644 --- a/docs/vite.config.js +++ b/docs/vite.config.js @@ -9,4 +9,10 @@ export default defineConfig({ resolve: { noExternal: true, // https://github.com/AdrianGonz97/refined-cf-pages-action/issues/26#issuecomment-2878397440 }, + server: { + fs: { + // Allow serving the generated `live` code-block components (```svelte live) + allow: ['.live-code'], + }, + }, }); diff --git a/packages/docs/README.md b/packages/docs/README.md index f870df1..13c7679 100644 --- a/packages/docs/README.md +++ b/packages/docs/README.md @@ -1,48 +1,118 @@ # @layerstack/docs -Reusable documentation framework and tooling for LayerStack projects (LayerStack, LayerChart, …). +Reusable documentation framework and tooling for LayerStack projects (LayerStack, LayerChart, svelte-ux, …). -It provides: +It turns a folder of markdown + Svelte example files into a full documentation site — markdown rendering, content collections, doc UI components, client-side search, `llms.txt` output, and a build-time CLI — so each project only writes content and a thin layer of glue. -- **Markdown rendering** — a shared [mdsx](https://github.com/huntabyte/mdsx) config (`createMdsxConfig`) with GFM, MDC directives, [Shiki](https://shiki.style/) syntax highlighting, automatic heading slugs, and a set of styled markdown element components. -- **Content collections** — a [`@content-collections`](https://www.content-collections.dev/) config factory (`createContentConfig`) that turns `src/content/**/*.md` into typed collections (components, utils, guides, references, releases) with TOC, source links, and generated API/catalog data. -- **Doc UI components** — `Code`, `Json`, `TableOfContents`, `ViewSourceButton`, `ExampleLink`, `ExampleListing`, `RelatedLink`, `LoadingPlaceholder`, etc. -- **Example/content loaders** — `createExampleLoaders` / `createContentLoaders` to wire a docs app's `import.meta.glob` to the framework. -- **CLI (`layerstack-docs`)** — build-time generators for component API JSON, example catalogs, screenshots, StackBlitz projects, and release notes. +## Contents -## Usage +- [What it provides](#what-it-provides) +- [How it fits together](#how-it-fits-together) +- [Prerequisites](#prerequisites) +- [Set up a new docs site](#set-up-a-new-docs-site) + - [1. Dependencies](#1-dependencies) + - [2. `content-collections.ts`](#2-content-collectionsts) + - [3. `mdsx.config.js`](#3-mdsxconfigjs) + - [4. `svelte.config.js`](#4-svelteconfigjs) + - [5. `vite.config.js`](#5-viteconfigjs) + - [6. `app.css`](#6-appcss) + - [7. `src/lib` glue](#7-srclib-glue) + - [8. Routes](#8-routes) +- [Authoring content](#authoring-content) +- [The `layerstack-docs` CLI](#the-layerstack-docs-cli) +- [Export reference](#export-reference) +- [Reference consumers](#reference-consumers) -A docs app depends on this package via `workspace:*` (in this monorepo) or `link:` (cross-repo), and follows this convention: +## What it provides + +- **Markdown rendering** — a shared [mdsx](https://github.com/huntabyte/mdsx) config (`createMdsxConfig`) with GFM, [MDC directives](https://content.nuxt.com/docs/files/markdown#mdc-syntax), [Shiki](https://shiki.style/) syntax highlighting (with diff + line highlighting), automatic heading slugs, and styled markdown element components. +- **Content collections** — a [`@content-collections`](https://www.content-collections.dev/) factory (`createContentConfig`) that turns `src/content/**/*.md` into typed collections (`components`, `utils`, `guides`, `references`, `releases`) with TOC, GitHub source links, and generated API/catalog data attached. +- **Doc UI components** — `Code`, `Json`, `Search`, `TableOfContents`, `ViewSourceButton`, `OpenWithButton`, `ExampleLink`, `ExampleListing`, `ComponentLink`, `RelatedLink`, `ExampleScreenshot`, `LoadingPlaceholder`, … (see [Export reference](#export-reference)). +- **Content & example loaders** — `createContentLoaders` / `createExampleLoaders` wire a docs app's `import.meta.glob` to the framework so `:example{}` directives and dynamic markdown pages resolve. +- **Search** — `initSearch` / `search` build a [FlexSearch](https://github.com/nextapps-de/flexsearch) index over a prerendered `/api/search.json`, surfaced by the `Search` command palette (⌘K). +- **`llms.txt`** — helpers (`processMarkdownContent`, `generateReferenceMarkdown`, `generateGuideMarkdown`, `markdownResponse`, …) to emit LLM-friendly markdown endpoints. +- **CLI (`layerstack-docs`)** — build-time generators for component API JSON, example catalogs, screenshots, StackBlitz bundles, and release notes. + +## How it fits together + +The framework owns the **mechanics**; the consumer owns the **content** and a small amount of **glue** (mostly because `import.meta.glob` must be evaluated in the consumer's project root). + +| Responsibility | Owner | +| ---------------------------------------------------------------------------- | ----------------------------------------------------------- | +| Markdown/mdsx pipeline, content-collection schemas & transforms | **framework** (`createMdsxConfig`, `createContentConfig`) | +| Doc UI components, search engine, `llms.txt` string assembly, CLI generators | **framework** | +| `content/**/*.md` + `examples/**/*.svelte` source | **consumer** | +| `import.meta.glob` wiring (`src/lib/content.ts`, `examples.ts`) | **consumer** (thin — calls framework factories) | +| Routes (`+page.ts`/`+page.svelte` renderers, `llms.txt`, `api/search.json`) | **consumer** (boilerplate — copy from a reference consumer) | +| App shell, nav menu, theme, analytics | **consumer** | + +There are two common shapes of docs site: + +- **Hand-authored reference docs** — e.g. LayerStack. Uses the `references` + `guides` collections; source files are inferred by convention; no generators. +- **Generated component docs** — e.g. LayerChart. Uses `components`/`utils`/`guides` collections plus the CLI generators (API tables, example catalogs, screenshots, StackBlitz, releases). + +## Prerequisites + +- **Svelte 5** and **SvelteKit 2** (peer dependencies). +- A **Tailwind v4** setup with [`@layerstack/tailwind`](../tailwind) (themes + utilities). +- The package is referenced as `workspace:*` inside this monorepo, or `link:`/the published `@layerstack/docs` cross-repo. + +The framework bundles most of its own runtime dependencies (mdsx, shiki, content-collections core/markdown, svelte-ux, …). A consumer still installs the **build tooling it invokes directly** — see [Dependencies](#1-dependencies). + +## Set up a new docs site + +The shape of a docs app: ``` docs-app/ - content-collections.ts # createContentConfig({ packageName, repo }) - mdsx.config.js # createMdsxConfig({ exampleComponentPath }) + content-collections.ts # createContentConfig({ packageName, repo }) + mdsx.config.js # createMdsxConfig({ exampleComponentPath }) + svelte.config.js # mdsx preprocessor + `content-collections` alias + vite.config.js # tailwind + sveltekit + contentCollections + Icons src/ - content/ # *.md docs (components/, utils/, guides/, reference/) - examples/ # *.svelte examples referenced from markdown + routes/ + app.css # tailwind + @layerstack/*/…css imports + +layout.svelte # shell: , , nav + docs/[…]/+page.{ts,svelte} # markdown renderers (+ llms.txt/+server.ts) + api/search.json/+server.ts # prerendered search index lib/ - content.ts # createContentLoaders(...) - examples.ts # createExampleLoaders(...) - generated/ # CLI output (api/, releases/) + content.ts # createContentLoaders(...) + examples.ts # createExampleLoaders(...) + components/Example.svelte # renders :example{} directives + content/ # *.md docs (reference/ | components/ | utils/ | guides/) + examples/ # *.svelte examples referenced from markdown + generated/ # CLI output (api/, releases/) — generated sites only ``` -### Markdown (`mdsx.config.js`) +The fastest path is to copy a [reference consumer](#reference-consumers) and adjust. The steps below explain each piece. -```js -import { createMdsxConfig } from '@layerstack/docs/markdown/config'; +### 1. Dependencies -export const mdsxConfig = createMdsxConfig({ - exampleComponentPath: '$lib/components', -}); +```jsonc +{ + "dependencies": { + "@layerstack/docs": "workspace:*", // or "link:…" / a published version + "@layerstack/tailwind": "workspace:*", + }, + "devDependencies": { + // build tooling the consumer's vite/svelte config invokes directly: + "@content-collections/core": "…", + "@content-collections/markdown": "…", + "@content-collections/vite": "…", + "mdsx": "…", + "unplugin-icons": "…", + "@iconify-json/lucide": "…", + "@iconify-json/simple-icons": "…", + "@tailwindcss/vite": "…", + "@tailwindcss/typography": "…", + "svelte-ux": "…", + }, +} ``` -The `reference` collection infers each doc's source file from its path by convention — -`src/content/reference//.md` → `packages//src/lib/.{ts,svelte.ts}` -(with a camelCase fallback, e.g. `Duration` → `duration.ts`, `SelectionState` → `selectionState.svelte.ts`). -Add a `sourceFile:` frontmatter (relative to `packages/`) only to override the inferred path. +> The authoritative dependency set is whatever a working [reference consumer](#reference-consumers) declares — copy from there. -### Content collections (`content-collections.ts`) +### 2. `content-collections.ts` ```ts import { createContentConfig } from '@layerstack/docs/content-collections'; @@ -50,10 +120,77 @@ import { createContentConfig } from '@layerstack/docs/content-collections'; export default createContentConfig({ packageName: 'layerstack', repo: 'techniq/layerstack', + branch: 'main', // default: 'next' + packagesRoot: '../packages', // default: '../packages' — used to infer source files +}); +``` + +`createContentConfig` defines all five collections with their Zod schemas, slug/name derivation, TOC extraction, and GitHub source-URL inference. Options: + +| Option | Default | Purpose | +| -------------------- | ------------------------------ | -------------------------------------------------------- | +| `packageName` | _(required)_ | Used for source-link inference and defaults | +| `repo` | `` `techniq/${packageName}` `` | GitHub repo for source/edit links | +| `branch` | `'next'` | Branch for source/edit links | +| `packagesRoot` | `'../packages'` | Path (from the docs app) to the monorepo `packages/` dir | +| `referenceDirectory` | `'src/content/reference'` | Where `references` collection markdown lives | + +### 3. `mdsx.config.js` + +```js +import { createMdsxConfig } from '@layerstack/docs/markdown/config'; + +export const mdsxConfig = createMdsxConfig({ + markdownComponentsPath: '@layerstack/docs/markdown/components', + exampleComponentPath: '$lib/components', // your local renderer (and friends) + liveCodeComponent: '@layerstack/docs/markdown/components/LiveCode.svelte', }); ``` -### Styles (`app.css`) +`exampleComponentPath` points at your local components dir so `:example{}` directives render through your own `Example.svelte` chrome. The other two paths are the same for every consumer. + +### 4. `svelte.config.js` + +```js +import adapter from '@sveltejs/adapter-cloudflare'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; +import { mdsx } from 'mdsx'; +import { mdsxConfig } from './mdsx.config.js'; + +/** @type {import('@sveltejs/kit').Config} */ +export default { + extensions: ['.svelte', '.md'], // compile .md as components/routes + preprocess: [mdsx(mdsxConfig), vitePreprocess()], + kit: { + adapter: adapter(), + alias: { + $examples: 'src/examples', + // required virtual module so `import { allReferences } from 'content-collections'` resolves: + 'content-collections': './.content-collections/generated', + }, + }, +}; +``` + +> `@layerstack/docs` is consumed from its built `dist/` (it relies on its `exports` map), so **the framework must be built before the docs app builds.** Don't source-alias it. (You _may_ source-alias the workspace libraries you're documenting for instant HMR — see the LayerStack `svelte.config.js`.) + +### 5. `vite.config.js` + +```js +import { defineConfig } from 'vite'; +import { sveltekit } from '@sveltejs/kit/vite'; +import tailwindcss from '@tailwindcss/vite'; +import Icons from 'unplugin-icons/vite'; +import contentCollections from '@content-collections/vite'; + +export default defineConfig({ + plugins: [tailwindcss(), sveltekit(), contentCollections(), Icons({ compiler: 'svelte' })], +}); +``` + +`contentCollections()` regenerates `.content-collections/generated` (the `content-collections` virtual module) on build/dev. `Icons({ compiler: 'svelte' })` powers the `~icons/*` imports the framework and MDC `:icon{}` directives use. + +### 6. `app.css` ```css @import 'tailwindcss'; @@ -61,13 +198,176 @@ export default createContentConfig({ @import '@layerstack/tailwind/utils.css'; @import '@layerstack/tailwind/themes/all.css'; @import '@layerstack/docs/styles.css'; + +/* Tailwind must scan the framework's compiled components for class usage: */ +@source '../../node_modules/svelte-ux/dist'; +@source '../../node_modules/@layerstack/docs/dist'; + +@plugin '@tailwindcss/typography'; +``` + +`@layerstack/docs/styles.css` provides Shiki theming, inline-code/code-block/diff/line-number styling, and the `.steps` numbering. The two `@source` lines are required because the framework is dist-resolved (Tailwind won't otherwise see its classes). + +### 7. `src/lib` glue + +These two files are the only real glue — they hand the consumer's `import.meta.glob` (which must be evaluated in the consumer root) to the framework factories. They're nearly identical across consumers; copy and adjust the collection names. + +**`src/lib/examples.ts`** + +```ts +import type { Component } from 'svelte'; +import { createExampleLoaders } from '@layerstack/docs/examples'; + +const pathExamples = import.meta.glob<{ default: Component }>([ + '/src/routes/**/*.svelte', + '/src/content/**/*.svelte', +]); +const rawPathExamples = import.meta.glob( + ['/src/routes/**/*.svelte', '/src/content/**/*.svelte'], + { query: '?raw', import: 'default' } +); + +export const { loadExample, loadExamples, loadExampleByPath } = createExampleLoaders({ + loadComponentExample: (type, component, name) => + import(`../examples/${type}/${component}/${name}.svelte`), + loadRawExample: async (type, component, name) => + (await import(`../examples/${type}/${component}/${name}.svelte?raw`)).default as string, + loadPathExample: (path) => pathExamples[path]?.(), + loadRawPathExample: (path) => rawPathExamples[path]?.(), +}); +``` + +**`src/lib/content.ts`** + +```ts +import { error } from '@sveltejs/kit'; +import { allReferences, allGuides, type Reference, type Guide } from 'content-collections'; +import { createContentLoaders, type ContentType } from '@layerstack/docs/content'; +import { loadExample, loadExampleByPath } from '$lib/examples.js'; + +type Metadata = Reference | Guide; + +const modules = import.meta.glob<{ default: import('svelte').Component; metadata: Metadata }>( + '/src/content/**/*.md' +); + +export const { getMarkdownComponent, loadExamplesFromMarkdown } = createContentLoaders({ + modules, + getMetadata: (slug, type: ContentType) => + type === 'guides' + ? allGuides.find((g) => g.slug === slug) + : allReferences.find((r) => r.slug === slug), + loadExample, + loadExampleByPath, + notFound: () => error(404, 'Could not find the document.'), +}); +``` + +You also provide a local **`src/lib/components/Example.svelte`** that the `:example{}` directive renders — it reads the `examples` context (`@layerstack/docs/context`), resolves a path with `resolveExamplePath` (`@layerstack/docs/content`), and shows the example + source via the framework `Code` component. Copy a reference consumer's. + +### 8. Routes + +The routes are boilerplate that delegates to the framework — copy them from a [reference consumer](#reference-consumers) and adjust collection/slug shapes. You need: + +- **Markdown renderers** — dynamic routes (e.g. `docs/[packageName]/[name]/` and `docs/guides/[name]/`) whose `+page.ts` calls `getMarkdownComponent` + `loadExamplesFromMarkdown`, and whose `+page.svelte` sets the `examples` context (`@layerstack/docs/context`) and renders `` plus title/related/edit-link chrome. +- **`llms.txt` endpoints** — `+server.ts` files returning `markdownResponse(generateReferenceMarkdown(...) | generateGuideMarkdown(...))`, plus a root `llms.txt` index and a `docs/llms.txt` full dump. +- **Search index** — `routes/api/search.json/+server.ts` with `export const prerender = true` returning the entries the `Search` component fetches. Build entries with `stripMarkdown` (`@layerstack/docs/markdown`) and the `SearchEntry` type (`@layerstack/docs/search`). +- **App shell** — a `+layout.svelte` with ``, ``, and a nav menu (group collections with `sortCollection` from `@layerstack/docs/collections`). Optionally call `preparePageTransition()` (`@layerstack/docs/page-transitions`) for View-Transition navigation. + +## Authoring content + +### Directory layout + +``` +src/content/ + reference//.md # references collection (hand-authored) + components/.md # components collection (generated sites) + utils/.md # utils collection + guides/.md # guides collection (nest in subdirs → categories) +src/examples/ + components//.svelte # referenced by :example{name="…"} + utils//.svelte +``` + +### Frontmatter + +Common fields (full schemas in [`content-collections/index.js`](src/lib/content-collections/index.js)): + +```md +--- +title: SelectionState # required (reference/guide); becomes `name` +description: Manage a set of selected items +category: State # optional grouping +related: # cross-links (slug, component, or URL) + - svelte-state/UniqueState + - https://example.com +order: 1 # optional manual sort +status: beta # optional badge (reference) +hideTableOfContents: false +--- +``` + +`components`/`utils` collections add `layers`, `withinLayer`, `resize`; `references` add `features`, `kind`, `sourceFile`, `hideUsage`, `packageName`; `releases` are generated from GitHub. + +### Source-file inference (reference collection) + +A reference doc's source file is inferred from its path — +`src/content/reference//.md` → `//src/lib/.{ts,svelte.ts}` +(with a camelCase fallback: `Duration` → `duration.ts`, `SelectionState` → `selectionState.svelte.ts`). Add a `sourceFile:` frontmatter (relative to `packagesRoot`) only to override. + +### MDC directives + +Authored in markdown, rendered by the framework's markdown components: + +```md +:example{name="basic" showCode} + +::note +Heads up. +:: + +::steps + +### First + +### Second + +:: + +:::tabs +::tab{label="npm"} +`npm i …` +:: +::tab{label="pnpm"} +`pnpm add …` +:: +::: + +:icon{name="lucide:check"} :button{label="Label" href="/x" icon="lucide:arrow-right"} ``` -### CLI +### Live code blocks + +A fenced ` ```svelte live ` block is written to disk and rendered as an interactive preview above its source (via `remarkLiveCode` → ``): + +````md +```svelte live + + + +``` +```` + +## The `layerstack-docs` CLI + +Build-time generators (bin → `dist/cli.js`). Wire them into `package.json` scripts; run heavy/committed artifacts (catalog, screenshots) manually and the rest in `prebuild`: ```jsonc { "scripts": { + "prebuild": "pnpm generate:api && pnpm generate:stackblitz && pnpm generate:releases", "generate:api": "layerstack-docs generate-api ../packages//src/lib/components generated/api", "generate:catalog": "layerstack-docs generate-catalog ../packages//src/lib/components src/examples/components src/examples/catalog", "generate:screenshots": "layerstack-docs generate-screenshots src/examples/components static/screenshots", @@ -77,4 +377,55 @@ export default createContentConfig({ } ``` -`generate-stackblitz` uses this package's bundled template at `templates/stackblitz-template` by default; `--template-dir` overrides it. +| Command | Args / flags | Generates | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| `generate-api` | ` ` | Per-component prop API JSON (`.json` + `index.json`) via the TypeScript compiler | +| `generate-catalog` | ` ` | Per-component example + cross-usage catalogs | +| `generate-screenshots` | ` [--base-url ] [--route-base ] [--all]` | Responsive light/dark WebP screenshots (Playwright + sharp; checksum-skipped unless `--all`) | +| `generate-stackblitz` | ` [remote-sources-file] [--template-dir ] [--source out=src …] [--remote out=src …]` | A StackBlitz/WebContainer file bundle (defaults to the bundled `templates/stackblitz-template`) | +| `generate-releases` | ` ` | GitHub releases → frontmatter markdown files | + +The generated `generated/api/*` and `generated/releases/*` are picked up automatically by the `references`/`components`/`releases` collections. + +## Export reference + +Import from subpaths (e.g. `import { Code } from '@layerstack/docs/components'`). + +**Runtime / browser** + +| Subpath | Key exports | +| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `.` | barrel of `api`, `catalog`, `collections`, `components`, `content`, `context`, `examples`, `markdown`, `page-transitions`, `project-stats` | +| `/components` | `Code`, `Json`, `Search`, `TableOfContents`, `OpenWithButton`, `ViewSourceButton`, `ExampleLink`, `ExampleListing`, `ComponentLink`, `RelatedLink`, `ExampleScreenshot`, `ImageLink`, `Tabs`, `Steps`, `Step`, `Blockquote`, `LoadingPlaceholder` (also via `/components/*.svelte`) | +| `/markdown/components` | markdown element components (`A`, `Code`, `H1`–`H4`, `P`, `Table`, …) + directive components (`Note`, `Tabs`, `Tab`, `Steps`, `Button`, `LiveCode`) | +| `/content` | `createContentLoaders`, `resolveExamplePath`, `extractExampleReferences`, `getFirstExampleName` | +| `/examples` | `createExampleLoaders`, `cleanExampleSource` | +| `/context` | `examples` (runed context) | +| `/collections` | `sortCollection` | +| `/search` | `initSearch`, `search`, type `SearchEntry` | +| `/page-transitions` | `preparePageTransition` | +| `/project-stats` | `getProjectStats` | +| `/api`, `/catalog` | type-only (`ComponentAPI`, `ComponentCatalog`, …) | + +**Build-time / Node** + +| Subpath | Key exports | +| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `/content-collections` | `createContentConfig`, the five Zod schemas | +| `/markdown/config` | `createMdsxConfig`, `prettyCodeOptions`, `remarkComponents`, `remarkLiveCode`, `rehypeCodeBlocks`, `shikiDiffTransformer` | +| `/markdown` | `extractTocFromMarkdown`, `stripMarkdown` | +| `/markdown/rehype/live-code` | `remarkLiveCode` | +| `/llms` | `processMarkdownContent`, `inlineExampleDirectives`, `generateReferenceMarkdown`, `generateGuideMarkdown`, `linkListSection`, `groupBySlugSegment`, `generateApiTable`, `markdownResponse`, `trimCode`, `extractFrontmatterTitle` | +| `/node/component-api` | `writeComponentAPIs`, `extractComponentAPI` | +| `/node/example-catalog` | `writeExampleCatalogs` | +| `/node/screenshots` | `generateScreenshots` | +| `/node/stackblitz` | `generateStackBlitzFiles`, `getDefaultStackBlitzTemplateDir` | +| `/node/releases` | `generateReleases` | +| `/styles.css` | shipped CSS | + +## Reference consumers + +Two real apps exercise the framework — copy whichever shape matches your project: + +- **LayerStack docs** (`layerstack/docs`, `@layerstack/docs-site`) — hand-authored **reference** docs across many small packages; no generators; `references` + `guides` collections. +- **LayerChart docs** (`layerchart/docs`) — **generated** component docs; uses all five `generate:*` CLI scripts, `components`/`utils`/`guides` collections, screenshots, StackBlitz playground, and releases. diff --git a/packages/docs/package.json b/packages/docs/package.json index 2c24b34..d9f476a 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -119,6 +119,10 @@ "types": "./dist/search.d.ts", "default": "./dist/search.js" }, + "./utils": { + "types": "./dist/utils/index.d.ts", + "default": "./dist/utils/index.js" + }, "./components": { "types": "./dist/components/index.d.ts", "svelte": "./dist/components/index.js", diff --git a/packages/docs/src/lib/examples.ts b/packages/docs/src/lib/examples.ts index 5d0d8d3..d8e8fc0 100644 --- a/packages/docs/src/lib/examples.ts +++ b/packages/docs/src/lib/examples.ts @@ -107,3 +107,43 @@ export function createExampleLoaders(options: { return { loadExample, loadExamples, loadExampleByPath }; } + +/** + * Convenience wrapper around {@link createExampleLoaders} for the conventional + * `import.meta.glob`-backed setup. Pass the (literal) dynamic `import()` calls and glob + * maps — this derives the path lookups and unwraps `?raw` modules for you. + * + * ```ts + * export const { loadExample, loadExamples, loadExampleByPath } = createGlobExampleLoaders({ + * loadComponentExample: (type, component, name) => + * import(`../examples/${type}/${component}/${name}.svelte`), + * loadRawExampleModule: (type, component, name) => + * import(`../examples/${type}/${component}/${name}.svelte?raw`), + * pathExamples: import.meta.glob<{ default: Component }>(['/src/routes/**\/*.svelte']), + * rawPathExamples: import.meta.glob(['/src/routes/**\/*.svelte'], { + * query: '?raw', + * import: 'default', + * }), + * }); + * ``` + */ +export function createGlobExampleLoaders(options: { + loadComponentExample: ComponentExampleImporter; + loadRawExampleModule: ( + type: ExampleType, + component: string, + name: string + ) => Promise<{ default: string }>; + pathExamples: Record Promise<{ default: Component }>>; + rawPathExamples: Record Promise>; + warn?: typeof console.warn; +}) { + return createExampleLoaders({ + loadComponentExample: options.loadComponentExample, + loadRawExample: async (type, component, name) => + (await options.loadRawExampleModule(type, component, name)).default, + loadPathExample: (path) => options.pathExamples[path]?.(), + loadRawPathExample: (path) => options.rawPathExamples[path]?.(), + warn: options.warn, + }); +} diff --git a/packages/docs/src/lib/search.ts b/packages/docs/src/lib/search.ts index fdf066e..0cb6797 100644 --- a/packages/docs/src/lib/search.ts +++ b/packages/docs/src/lib/search.ts @@ -1,4 +1,5 @@ import FlexSearch, { type Index as FlexSearchIndex } from 'flexsearch'; +import { stripMarkdown } from './markdown/utils.js'; /** * A single searchable entry. `type` is intentionally a free string so each docs app @@ -111,3 +112,113 @@ export function search(query: string): SearchEntry[] { content: entry.type === 'example' ? entry.content : getSnippet(entry.content, searchTerm), })); } + +// ─── Index builders (build-time) ────────────────────────────────────────────── +// Helpers for assembling the `/api/search.json` payload from content collections. + +export type TocEntry = { id: string; text: string; level: number }; + +/** Minimal content-collection document shape consumed by {@link buildSearchEntries}. */ +export type SearchDoc = { + name: string; + slug: string; + description?: string | null; + content: string; + toc: TocEntry[]; +}; + +/** + * Extract the cleaned text under each heading from markdown, keyed by heading text. + * Gives per-heading search entries a content snippet. + */ +export function extractHeadingContents(markdown: string, toc: TocEntry[]): Map { + const result = new Map(); + const headingPositions: { text: string; start: number; end: number }[] = []; + + for (const heading of toc) { + // Match the heading line, allowing trailing MDC directives (e.g. `## Title :icon{...}`) + const headingPattern = new RegExp( + `^#{1,6}\\s+${escapeRegex(heading.text)}(?:\\s*:[a-zA-Z][\\w-]*\\{[^}]*\\})*\\s*$`, + 'gm' + ); + const match = headingPattern.exec(markdown); + if (match) { + headingPositions.push({ + text: heading.text, + start: match.index + match[0].length, + end: markdown.length, + }); + } + } + + headingPositions.sort((a, b) => a.start - b.start); + for (let i = 0; i < headingPositions.length - 1; i++) { + const nextHeadingMatch = markdown.slice(headingPositions[i].start).match(/^#{1,6}\s+/m); + if (nextHeadingMatch) { + headingPositions[i].end = headingPositions[i].start + (nextHeadingMatch.index ?? 0); + } + } + + for (const pos of headingPositions) { + const rawContent = markdown.slice(pos.start, pos.end).trim(); + result.set(pos.text, stripMarkdown(rawContent).slice(0, 200)); + } + + return result; +} + +/** + * Build a page `SearchEntry` plus one entry per heading for each doc in a collection. + * Pass a `category` resolver to tag page entries (set `headingCategory` to also tag headings). + */ +export function buildSearchEntries( + docs: T[], + config: { + /** Entry `type` for the page (and `parentType` for its headings), e.g. `reference`. */ + type: string; + /** Slug prefix prepended to each doc's slug, e.g. `docs/components`. */ + slugPrefix: string; + /** Optional category resolver applied to page entries. */ + category?: (doc: T) => string | undefined; + /** Also apply `category` to heading entries (default `false`). */ + headingCategory?: boolean; + } +): SearchEntry[] { + return docs.flatMap((doc) => { + const parentSlug = config.slugPrefix ? `${config.slugPrefix}/${doc.slug}` : doc.slug; + const category = config.category?.(doc); + const description = doc.description ?? ''; + const content = stripMarkdown(doc.content); + + const pageEntry: SearchEntry = { + title: doc.name, + slug: parentSlug, + content: description ? `${description} ${content}` : content, + type: config.type, + ...(category != null ? { category } : {}), + }; + + const headingContents = extractHeadingContents(doc.content, doc.toc); + const seen = new Set(); + const headingEntries = doc.toc + .filter((heading) => { + if (seen.has(heading.id)) return false; + seen.add(heading.id); + return true; + }) + .map( + (heading): SearchEntry => ({ + title: heading.text, + slug: `${parentSlug}#${heading.id}`, + content: headingContents.get(heading.text) || doc.name, + type: 'heading', + parent: doc.name, + parentSlug, + parentType: config.type, + ...(config.headingCategory && category != null ? { category } : {}), + }) + ); + + return [pageEntry, ...headingEntries]; + }); +} diff --git a/packages/docs/src/lib/utils/index.ts b/packages/docs/src/lib/utils/index.ts new file mode 100644 index 0000000..46af93b --- /dev/null +++ b/packages/docs/src/lib/utils/index.ts @@ -0,0 +1 @@ +export * from './string.js'; From bea6a2b8eddb30f14f31d878a8e3eb6a49a7d817 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 2 Jun 2026 23:39:00 -0400 Subject: [PATCH 21/21] add docs for layerstack/docs --- docs/content-collections.ts | 1 - docs/src/content/guides/docs/authoring.md | 65 +++ docs/src/content/guides/docs/cli.md | 46 ++ .../content/guides/docs/getting-started.md | 56 +++ docs/src/content/guides/docs/markdown.md | 235 ++++++++++ docs/src/content/guides/docs/setup.md | 154 +++++++ packages/docs/README.md | 410 ++---------------- .../docs/src/lib/content-collections/index.js | 2 +- 8 files changed, 596 insertions(+), 373 deletions(-) create mode 100644 docs/src/content/guides/docs/authoring.md create mode 100644 docs/src/content/guides/docs/cli.md create mode 100644 docs/src/content/guides/docs/getting-started.md create mode 100644 docs/src/content/guides/docs/markdown.md create mode 100644 docs/src/content/guides/docs/setup.md diff --git a/docs/content-collections.ts b/docs/content-collections.ts index 3b74ef5..2177078 100644 --- a/docs/content-collections.ts +++ b/docs/content-collections.ts @@ -5,7 +5,6 @@ export default createContentConfig({ // organized by package under `src/content/reference//.md`. packageName: 'layerstack', repo: 'techniq/layerstack', - branch: 'main', // `docs` -> repo root `packages` packagesRoot: '../packages', }); diff --git a/docs/src/content/guides/docs/authoring.md b/docs/src/content/guides/docs/authoring.md new file mode 100644 index 0000000..0437750 --- /dev/null +++ b/docs/src/content/guides/docs/authoring.md @@ -0,0 +1,65 @@ +--- +title: Authoring content +description: Directory layout, frontmatter, source inference, and examples. +order: 3 +--- + +Docs are plain markdown under `src/content/`, with live Svelte examples under +`src/examples/`. Adding a page is usually just dropping in a `.md` file — the nav, table of +contents, search index, and edit link all derive from it automatically. + +## Directory layout + +``` +src/content/ + reference//.md # references collection (hand-authored) + guides/.md # guides — nest in subdirs to form categories +src/examples/ + components//.svelte # referenced by :example{name="…"} +``` + +This page lives at `src/content/guides/docs/authoring.md` — the `docs/` subdirectory becomes +the **Docs** category you see in the sidebar. + +## Frontmatter + +```md +--- +title: SelectionState # required; becomes the page `name` +description: Manage a set of selected items +related: # cross-links (slug, or full URL) + - svelte-state/UniqueState +order: 1 # optional manual sort within a group +status: beta # optional badge (reference) +hideTableOfContents: false +--- +``` + +Guides accept `title`, `description`, `category`, `order`, `draft`. References add `related`, +`features`, `status`, `kind`, `sourceFile`, `hideUsage`, and more. Full schemas live in the +framework's `content-collections` config. + +## Source-file inference (reference) + +A reference doc's source file is inferred from its path — +`src/content/reference//.md` → `//src/lib/.{ts,svelte.ts}` +(with a camelCase fallback: `Duration` → `duration.ts`, `SelectionState` → +`selectionState.svelte.ts`). Add a `sourceFile:` frontmatter only to override. + +## Examples + +Reference a Svelte example from markdown with the `:example` directive: + +```md +:example{name="basic" showCode} +``` + +The `name` resolves to `src/examples/components//.svelte`. Supported props: +`name`, `component`, `path`, `showCode`, `highlight` (e.g. `"7"` or `"7-9"`), and `class`. +The example's `?raw` source powers both the show-code toggle and the inlined `llms.txt` +output. + +:::note +For all the markdown rendering features — callouts, tabs, steps, code highlighting, live +code — see [Markdown & directives](/docs/guides/docs/markdown). +::: diff --git a/docs/src/content/guides/docs/cli.md b/docs/src/content/guides/docs/cli.md new file mode 100644 index 0000000..267000c --- /dev/null +++ b/docs/src/content/guides/docs/cli.md @@ -0,0 +1,46 @@ +--- +title: CLI & generators +description: Build-time generation for component docs via the layerstack-docs CLI. +order: 5 +--- + +`@layerstack/docs` ships a `layerstack-docs` binary with build-time generators. Hand-authored +reference sites (like this one) don't need them; **generated** component-doc sites (like +[LayerChart](https://layerchart.com)) use them to produce API tables, example catalogs, +screenshots, StackBlitz bundles, and release notes. + +## Wiring + +Run cheap generators in `prebuild`; run heavy/committed artifacts (catalogs, screenshots) +manually. + +```jsonc title="package.json" +{ + "scripts": { + "prebuild": "pnpm generate:api && pnpm generate:stackblitz && pnpm generate:releases", + "generate:api": "layerstack-docs generate-api ../packages//src/lib/components generated/api", + "generate:catalog": "layerstack-docs generate-catalog ../packages//src/lib/components src/examples/components src/examples/catalog", + "generate:screenshots": "layerstack-docs generate-screenshots src/examples/components static/screenshots", + "generate:stackblitz": "layerstack-docs generate-stackblitz src static/stackblitz-files.json [remote-sources.json]", + "generate:releases": "layerstack-docs generate-releases techniq/ generated/releases", + }, +} +``` + +## Commands + +| Command | Arguments | Generates | +| ---------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------- | +| `generate-api` | ` ` | Per-component prop API JSON (via the TypeScript compiler) | +| `generate-catalog` | ` ` | Per-component example + cross-usage catalogs | +| `generate-screenshots` | ` [--base-url] [--route-base] [--all]` | Responsive light/dark WebP screenshots (Playwright + sharp) | +| `generate-stackblitz` | ` [remote-sources-file] [--template-dir] [--source] [--remote]` | A StackBlitz/WebContainer file bundle | +| `generate-releases` | ` ` | GitHub releases → frontmatter markdown files | + +The output under `generated/api/*` and `generated/releases/*` is picked up automatically by +the `references`/`components`/`releases` collections. + +:::note +`generate-stackblitz` uses the package's bundled template at `templates/stackblitz-template` +by default; pass `--template-dir` to override it. +::: diff --git a/docs/src/content/guides/docs/getting-started.md b/docs/src/content/guides/docs/getting-started.md new file mode 100644 index 0000000..9aaa7cd --- /dev/null +++ b/docs/src/content/guides/docs/getting-started.md @@ -0,0 +1,56 @@ +--- +title: Getting started +description: What @layerstack/docs is, and how a documentation site fits together. +order: 1 +--- + +`@layerstack/docs` is a reusable documentation framework. It turns a folder of markdown +and Svelte example files into a full documentation site — markdown rendering, content +collections, doc UI components, client-side search, `llms.txt` output, and a build-time +CLI — so each project only writes content and a thin layer of glue. + +These very pages are built with it. + +## What it provides + +- **Markdown rendering** — a shared [mdsx](https://github.com/huntabyte/mdsx) config with + GFM, MDC directives, Shiki syntax highlighting, automatic heading slugs, and styled + element components. +- **Content collections** — a [content-collections](https://www.content-collections.dev/) + factory that turns `src/content/**/*.md` into typed collections (`references`, `guides`, + `components`, `utils`, `releases`) with TOC, source links, and generated data attached. +- **Doc UI components** — `Code`, `Search`, `TableOfContents`, `OpenWithButton`, + `RelatedLink`, `ExampleScreenshot`, and more. +- **Search** — a FlexSearch index served from a prerendered `/api/search.json`, surfaced by + the `Search` command palette (`⌘K`). +- **`llms.txt`** — helpers that emit LLM-friendly markdown endpoints. +- **CLI (`layerstack-docs`)** — generators for component API JSON, example catalogs, + screenshots, StackBlitz bundles, and release notes. + +## How it fits together + +The framework owns the **mechanics**; your app owns the **content** and a small amount of +**glue** (mostly because `import.meta.glob` must be evaluated in your project root). + +| Responsibility | Owner | +| --------------------------------------------------------------- | -------------- | +| Markdown/mdsx pipeline, content-collection schemas & transforms | **framework** | +| Doc UI components, search, `llms.txt` assembly, CLI generators | **framework** | +| `content/**/*.md` + `examples/**/*.svelte` source | **you** | +| `import.meta.glob` wiring (`src/lib/content.ts`, `examples.ts`) | **you** (thin) | +| Routes, app shell, nav, theme | **you** | + +## Two shapes of docs site + +- **Hand-authored reference docs** — like LayerStack. Uses the `references` + `guides` + collections; source files are inferred by convention; no generators. +- **Generated component docs** — like [LayerChart](https://layerchart.com). Uses + `components`/`utils`/`guides` collections plus the CLI generators (API tables, example + catalogs, screenshots, StackBlitz, releases). + +## Next + +- [Setup](/docs/guides/docs/setup) — wire up a new docs site. +- [Authoring content](/docs/guides/docs/authoring) — directory layout, frontmatter, examples. +- [Markdown & directives](/docs/guides/docs/markdown) — the rendering features, live. +- [CLI & generators](/docs/guides/docs/cli) — build-time generation for component docs. diff --git a/docs/src/content/guides/docs/markdown.md b/docs/src/content/guides/docs/markdown.md new file mode 100644 index 0000000..d6f3434 --- /dev/null +++ b/docs/src/content/guides/docs/markdown.md @@ -0,0 +1,235 @@ +--- +title: Markdown & directives +description: Syntax highlighting, callouts, tabs, steps, live code, and more — rendered live. +order: 4 +--- + +Every page is markdown processed by the framework's [mdsx](https://github.com/huntabyte/mdsx) +pipeline: GFM, [MDC directives](https://content.nuxt.com/docs/files/markdown#mdc-syntax), and +[Shiki](https://shiki.style/) highlighting. Each feature below shows its source followed by +the rendered result. + +## Code blocks + +Supported meta: `title`, `live`, `diff`, `showLineNumbers`, and line highlighting like +`{2,5-7}`. + +````md +```svelte + + +
    Hello
    +``` +```` + +```svelte + + +
    Hello
    +``` + +### Line numbers + +````md +```ts showLineNumbers +const items = await load(); +const total = items.reduce((sum, d) => sum + d.value, 0); +const average = total / items.length; +``` +```` + +```ts showLineNumbers +const items = await load(); +const total = items.reduce((sum, d) => sum + d.value, 0); +const average = total / items.length; +``` + +### Diff + +````md +```diff +- const label = 'old'; ++ const label = 'new'; +``` +```` + +```diff +- const label = 'old'; ++ const label = 'new'; +``` + +### Line highlighting + +````md +```ts {2,4} +const a = 1; +const b = 2; // highlighted +const c = 3; +const d = 4; // highlighted +``` +```` + +```ts {2,4} +const a = 1; +const b = 2; // highlighted +const c = 3; +const d = 4; // highlighted +``` + +### Title + +````md +```svelte title="+layout.svelte" + +``` +```` + +```svelte title="+layout.svelte" + +``` + +### Live code + +A ` ```svelte live ` block renders an interactive preview above its source. + +````md +```svelte live title="Counter.svelte" + + + +``` +```` + +```svelte live title="Counter.svelte" + + + +``` + +## Callouts + +```md +:::note +A neutral aside. +::: +``` + +:::note +A neutral aside. +::: + +:::tip +A helpful suggestion. +::: + +:::warning +Something to be careful about. +::: + +:::caution +This action cannot be undone. +::: + +## Steps + +````md +:::steps + +## Install + +```bash +pnpm add @layerstack/docs +``` + +## Configure + +Wire up `content-collections.ts` and `mdsx.config.js`. + +## Profit + +Author markdown and you're done. +::: +```` + +:::steps + +## Install + +```bash +pnpm add @layerstack/docs +``` + +## Configure + +Wire up `content-collections.ts` and `mdsx.config.js`. + +## Profit + +Author markdown and you're done. +::: + +## Tabs + +```md +:::tabs + +::tab{label="npm" icon="simple-icons:npm"} +`npm i @layerstack/docs` +:: + +::tab{label="pnpm" icon="simple-icons:pnpm"} +`pnpm add @layerstack/docs` +:: + +::: +``` + +:::tabs + +::tab{label="npm" icon="simple-icons:npm"} +`npm i @layerstack/docs` +:: + +::tab{label="pnpm" icon="simple-icons:pnpm"} +`pnpm add @layerstack/docs` +:: + +::: + +## Icons + +```md +A :icon{name="lucide:rocket" class="text-primary"} rocket and a +:icon{name="simple-icons:github"} GitHub logo, inline. +``` + +A :icon{name="lucide:rocket" class="text-primary"} rocket and a +:icon{name="simple-icons:github"} GitHub logo, inline. + +## Tables + +`:---` left-aligns, `---:` right-aligns, `:---:` centers. + +```md +| First | Second | Third | +| :---- | :----: | ----: | +| 1 | 2 | 3 | +``` + +| First | Second | Third | +| :---- | :----: | ----: | +| 1 | 2 | 3 | + +## Links + +- On-domain links open in the same tab: [Setup](/docs/guides/docs/setup) +- External links open in a new tab with an arrow: [LayerStack](https://layerstack.dev) +- Hash links jump to a heading: [Back to top](#markdown--directives) diff --git a/docs/src/content/guides/docs/setup.md b/docs/src/content/guides/docs/setup.md new file mode 100644 index 0000000..b9367cd --- /dev/null +++ b/docs/src/content/guides/docs/setup.md @@ -0,0 +1,154 @@ +--- +title: Setup +description: Wire up a new documentation site with @layerstack/docs. +order: 2 +--- + +A docs app is a SvelteKit project that depends on `@layerstack/docs` and follows this shape: + +``` +docs-app/ + content-collections.ts # createContentConfig({ packageName, repo }) + mdsx.config.js # createMdsxConfig({ exampleComponentPath }) + svelte.config.js # mdsx preprocessor + `content-collections` alias + vite.config.js # tailwind + sveltekit + contentCollections + Icons + src/ + routes/ + app.css # tailwind + @layerstack/*/…css imports + docs/[…]/+page.{ts,svelte} # markdown renderers (+ llms.txt/+server.ts) + api/search.json/+server.ts # prerendered search index + lib/ + content.ts # createContentLoaders(...) + examples.ts # createGlobExampleLoaders(...) + content/ # *.md docs (reference/ | guides/ | …) + examples/ # *.svelte examples referenced from markdown +``` + +:::tip +The fastest path is to copy this site (`@layerstack/docs-site`) or +[LayerChart's docs](https://github.com/techniq/layerchart/tree/main/docs) and adjust. +::: + +## Content collections + +```ts title="content-collections.ts" +import { createContentConfig } from '@layerstack/docs/content-collections'; + +export default createContentConfig({ + packageName: 'layerstack', + repo: 'techniq/layerstack', + packagesRoot: '../packages', // used to infer source files +}); +``` + +The factory defines all five collections with their schemas, slug/name derivation, TOC +extraction, and GitHub source-URL inference — you author zero schema logic. + +## Markdown + +```js title="mdsx.config.js" +import { createMdsxConfig } from '@layerstack/docs/markdown/config'; + +export const mdsxConfig = createMdsxConfig({ + markdownComponentsPath: '@layerstack/docs/markdown/components', + exampleComponentPath: '$lib/components', // your local renderer + liveCodeComponent: '@layerstack/docs/markdown/components/LiveCode.svelte', +}); +``` + +## SvelteKit & Vite + +```js title="svelte.config.js" +extensions: ['.svelte', '.md'], +preprocess: [mdsx(mdsxConfig), vitePreprocess()], +kit: { + alias: { + $examples: 'src/examples', + // required so `import { allReferences } from 'content-collections'` resolves: + 'content-collections': './.content-collections/generated', + }, +}, +``` + +```js title="vite.config.js" +plugins: [tailwindcss(), sveltekit(), contentCollections(), Icons({ compiler: 'svelte' })], +``` + +:::warning +`@layerstack/docs` is consumed from its built `dist/` (it relies on its `exports` map), so +**the framework must be built before the docs app builds.** Don't source-alias it. +::: + +## Styles + +```css title="app.css" +@import 'tailwindcss'; +@import '@layerstack/tailwind/core.css'; +@import '@layerstack/tailwind/utils.css'; +@import '@layerstack/tailwind/themes/all.css'; +@import '@layerstack/docs/styles.css'; + +/* Tailwind must scan the framework's compiled components: */ +@source '../../node_modules/svelte-ux/dist'; +@source '../../node_modules/@layerstack/docs/dist'; + +@plugin '@tailwindcss/typography'; +``` + +## The `src/lib` glue + +Two small files hand your `import.meta.glob` (which must live in your project root) to the +framework factories. + +```ts title="src/lib/examples.ts" +import type { Component } from 'svelte'; +import { createGlobExampleLoaders } from '@layerstack/docs/examples'; + +export const { loadExample, loadExamples, loadExampleByPath } = createGlobExampleLoaders({ + loadComponentExample: (type, component, name) => + import(`../examples/${type}/${component}/${name}.svelte`), + loadRawExampleModule: (type, component, name) => + import(`../examples/${type}/${component}/${name}.svelte?raw`), + pathExamples: import.meta.glob<{ default: Component }>([ + '/src/routes/**/*.svelte', + '/src/content/**/*.svelte', + ]), + rawPathExamples: import.meta.glob( + ['/src/routes/**/*.svelte', '/src/content/**/*.svelte'], + { query: '?raw', import: 'default' } + ), +}); +``` + +```ts title="src/lib/content.ts" +import { error } from '@sveltejs/kit'; +import { allReferences, allGuides, type Reference, type Guide } from 'content-collections'; +import { createContentLoaders, type ContentType } from '@layerstack/docs/content'; +import { loadExample, loadExampleByPath } from '$lib/examples.js'; + +type Metadata = Reference | Guide; + +const modules = import.meta.glob<{ default: import('svelte').Component; metadata: Metadata }>( + '/src/content/**/*.md' +); + +export const { getMarkdownComponent, loadExamplesFromMarkdown } = createContentLoaders({ + modules, + getMetadata: (slug, type: ContentType) => + type === 'guides' + ? allGuides.find((g) => g.slug === slug) + : allReferences.find((r) => r.slug === slug), + loadExample, + loadExampleByPath, + notFound: () => error(404, 'Could not find the document.'), +}); +``` + +## Routes + +The dynamic renderers, `llms.txt` endpoints, and `api/search.json` are boilerplate that +delegates to the framework — copy them from this site and adjust collection/slug shapes. +Build the search index with `buildSearchEntries` from `@layerstack/docs/search`, and add +`` + `` to your shell layout. + +Next: [Authoring content](/docs/guides/docs/authoring). diff --git a/packages/docs/README.md b/packages/docs/README.md index 13c7679..f62f31d 100644 --- a/packages/docs/README.md +++ b/packages/docs/README.md @@ -4,388 +4,59 @@ Reusable documentation framework and tooling for LayerStack projects (LayerStack It turns a folder of markdown + Svelte example files into a full documentation site — markdown rendering, content collections, doc UI components, client-side search, `llms.txt` output, and a build-time CLI — so each project only writes content and a thin layer of glue. -## Contents - -- [What it provides](#what-it-provides) -- [How it fits together](#how-it-fits-together) -- [Prerequisites](#prerequisites) -- [Set up a new docs site](#set-up-a-new-docs-site) - - [1. Dependencies](#1-dependencies) - - [2. `content-collections.ts`](#2-content-collectionsts) - - [3. `mdsx.config.js`](#3-mdsxconfigjs) - - [4. `svelte.config.js`](#4-svelteconfigjs) - - [5. `vite.config.js`](#5-viteconfigjs) - - [6. `app.css`](#6-appcss) - - [7. `src/lib` glue](#7-srclib-glue) - - [8. Routes](#8-routes) -- [Authoring content](#authoring-content) -- [The `layerstack-docs` CLI](#the-layerstack-docs-cli) -- [Export reference](#export-reference) -- [Reference consumers](#reference-consumers) +> **📚 Guides** — _getting started_, _setup_, _authoring_, _markdown & directives_, and the +> _CLI_ — are written **with** this framework and live at +> [`docs/src/content/guides/docs/`](https://github.com/techniq/layerstack/tree/main/docs/src/content/guides/docs) +> (rendered at `/docs/guides/docs`). Start there for the full walkthrough; this README is a +> quick orientation plus the export reference. ## What it provides -- **Markdown rendering** — a shared [mdsx](https://github.com/huntabyte/mdsx) config (`createMdsxConfig`) with GFM, [MDC directives](https://content.nuxt.com/docs/files/markdown#mdc-syntax), [Shiki](https://shiki.style/) syntax highlighting (with diff + line highlighting), automatic heading slugs, and styled markdown element components. -- **Content collections** — a [`@content-collections`](https://www.content-collections.dev/) factory (`createContentConfig`) that turns `src/content/**/*.md` into typed collections (`components`, `utils`, `guides`, `references`, `releases`) with TOC, GitHub source links, and generated API/catalog data attached. -- **Doc UI components** — `Code`, `Json`, `Search`, `TableOfContents`, `ViewSourceButton`, `OpenWithButton`, `ExampleLink`, `ExampleListing`, `ComponentLink`, `RelatedLink`, `ExampleScreenshot`, `LoadingPlaceholder`, … (see [Export reference](#export-reference)). -- **Content & example loaders** — `createContentLoaders` / `createExampleLoaders` wire a docs app's `import.meta.glob` to the framework so `:example{}` directives and dynamic markdown pages resolve. -- **Search** — `initSearch` / `search` build a [FlexSearch](https://github.com/nextapps-de/flexsearch) index over a prerendered `/api/search.json`, surfaced by the `Search` command palette (⌘K). -- **`llms.txt`** — helpers (`processMarkdownContent`, `generateReferenceMarkdown`, `generateGuideMarkdown`, `markdownResponse`, …) to emit LLM-friendly markdown endpoints. -- **CLI (`layerstack-docs`)** — build-time generators for component API JSON, example catalogs, screenshots, StackBlitz bundles, and release notes. +- **Markdown rendering** — a shared [mdsx](https://github.com/huntabyte/mdsx) config (`createMdsxConfig`) with GFM, [MDC directives](https://content.nuxt.com/docs/files/markdown#mdc-syntax), [Shiki](https://shiki.style/) highlighting (diff + line highlighting), heading slugs, and styled element components. +- **Content collections** — a [content-collections](https://www.content-collections.dev/) factory (`createContentConfig`) that turns `src/content/**/*.md` into typed collections (`references`, `guides`, `components`, `utils`, `releases`) with TOC, GitHub source links, and generated API/catalog data attached. +- **Doc UI components** — `Code`, `Search`, `TableOfContents`, `OpenWithButton`, `RelatedLink`, `ExampleScreenshot`, … (see [Export reference](#export-reference)). +- **Content & example loaders** — `createContentLoaders` / `createGlobExampleLoaders` wire a docs app's `import.meta.glob` to the framework. +- **Search** — a FlexSearch index (`buildSearchEntries` → `/api/search.json`) surfaced by the `Search` command palette (⌘K). +- **`llms.txt`** — helpers to emit LLM-friendly markdown endpoints. +- **CLI (`layerstack-docs`)** — generators for component API JSON, example catalogs, screenshots, StackBlitz bundles, and release notes. ## How it fits together The framework owns the **mechanics**; the consumer owns the **content** and a small amount of **glue** (mostly because `import.meta.glob` must be evaluated in the consumer's project root). -| Responsibility | Owner | -| ---------------------------------------------------------------------------- | ----------------------------------------------------------- | -| Markdown/mdsx pipeline, content-collection schemas & transforms | **framework** (`createMdsxConfig`, `createContentConfig`) | -| Doc UI components, search engine, `llms.txt` string assembly, CLI generators | **framework** | -| `content/**/*.md` + `examples/**/*.svelte` source | **consumer** | -| `import.meta.glob` wiring (`src/lib/content.ts`, `examples.ts`) | **consumer** (thin — calls framework factories) | -| Routes (`+page.ts`/`+page.svelte` renderers, `llms.txt`, `api/search.json`) | **consumer** (boilerplate — copy from a reference consumer) | -| App shell, nav menu, theme, analytics | **consumer** | - -There are two common shapes of docs site: - -- **Hand-authored reference docs** — e.g. LayerStack. Uses the `references` + `guides` collections; source files are inferred by convention; no generators. -- **Generated component docs** — e.g. LayerChart. Uses `components`/`utils`/`guides` collections plus the CLI generators (API tables, example catalogs, screenshots, StackBlitz, releases). - -## Prerequisites - -- **Svelte 5** and **SvelteKit 2** (peer dependencies). -- A **Tailwind v4** setup with [`@layerstack/tailwind`](../tailwind) (themes + utilities). -- The package is referenced as `workspace:*` inside this monorepo, or `link:`/the published `@layerstack/docs` cross-repo. - -The framework bundles most of its own runtime dependencies (mdsx, shiki, content-collections core/markdown, svelte-ux, …). A consumer still installs the **build tooling it invokes directly** — see [Dependencies](#1-dependencies). +| Responsibility | Owner | +| --------------------------------------------------------------- | ------------------------- | +| Markdown/mdsx pipeline, content-collection schemas & transforms | **framework** | +| Doc UI components, search, `llms.txt` assembly, CLI generators | **framework** | +| `content/**/*.md` + `examples/**/*.svelte` source | **you** | +| `import.meta.glob` wiring (`src/lib/content.ts`, `examples.ts`) | **you** (thin) | +| Routes, app shell, nav, theme | **you** (copy a consumer) | -## Set up a new docs site +Two common shapes: **hand-authored reference docs** (LayerStack — `references` + `guides`, no generators) and **generated component docs** (LayerChart — `components`/`utils`/`guides` plus the CLI generators). -The shape of a docs app: +## Quick start -``` -docs-app/ - content-collections.ts # createContentConfig({ packageName, repo }) - mdsx.config.js # createMdsxConfig({ exampleComponentPath }) - svelte.config.js # mdsx preprocessor + `content-collections` alias - vite.config.js # tailwind + sveltekit + contentCollections + Icons - src/ - routes/ - app.css # tailwind + @layerstack/*/…css imports - +layout.svelte # shell: , , nav - docs/[…]/+page.{ts,svelte} # markdown renderers (+ llms.txt/+server.ts) - api/search.json/+server.ts # prerendered search index - lib/ - content.ts # createContentLoaders(...) - examples.ts # createExampleLoaders(...) - components/Example.svelte # renders :example{} directives - content/ # *.md docs (reference/ | components/ | utils/ | guides/) - examples/ # *.svelte examples referenced from markdown - generated/ # CLI output (api/, releases/) — generated sites only -``` - -The fastest path is to copy a [reference consumer](#reference-consumers) and adjust. The steps below explain each piece. - -### 1. Dependencies - -```jsonc -{ - "dependencies": { - "@layerstack/docs": "workspace:*", // or "link:…" / a published version - "@layerstack/tailwind": "workspace:*", - }, - "devDependencies": { - // build tooling the consumer's vite/svelte config invokes directly: - "@content-collections/core": "…", - "@content-collections/markdown": "…", - "@content-collections/vite": "…", - "mdsx": "…", - "unplugin-icons": "…", - "@iconify-json/lucide": "…", - "@iconify-json/simple-icons": "…", - "@tailwindcss/vite": "…", - "@tailwindcss/typography": "…", - "svelte-ux": "…", - }, -} -``` - -> The authoritative dependency set is whatever a working [reference consumer](#reference-consumers) declares — copy from there. - -### 2. `content-collections.ts` +Requires **Svelte 5** + **SvelteKit 2** and a **Tailwind v4** setup with [`@layerstack/tailwind`](../tailwind). A docs app wires up a handful of files — the +[Setup guide](https://github.com/techniq/layerstack/blob/main/docs/src/content/guides/docs/setup.md) +has the full walkthrough: ```ts -import { createContentConfig } from '@layerstack/docs/content-collections'; - -export default createContentConfig({ - packageName: 'layerstack', - repo: 'techniq/layerstack', - branch: 'main', // default: 'next' - packagesRoot: '../packages', // default: '../packages' — used to infer source files -}); +// content-collections.ts +export default createContentConfig({ packageName: 'layerstack', repo: 'techniq/layerstack' }); ``` -`createContentConfig` defines all five collections with their Zod schemas, slug/name derivation, TOC extraction, and GitHub source-URL inference. Options: - -| Option | Default | Purpose | -| -------------------- | ------------------------------ | -------------------------------------------------------- | -| `packageName` | _(required)_ | Used for source-link inference and defaults | -| `repo` | `` `techniq/${packageName}` `` | GitHub repo for source/edit links | -| `branch` | `'next'` | Branch for source/edit links | -| `packagesRoot` | `'../packages'` | Path (from the docs app) to the monorepo `packages/` dir | -| `referenceDirectory` | `'src/content/reference'` | Where `references` collection markdown lives | - -### 3. `mdsx.config.js` - ```js -import { createMdsxConfig } from '@layerstack/docs/markdown/config'; - -export const mdsxConfig = createMdsxConfig({ - markdownComponentsPath: '@layerstack/docs/markdown/components', - exampleComponentPath: '$lib/components', // your local renderer (and friends) - liveCodeComponent: '@layerstack/docs/markdown/components/LiveCode.svelte', -}); -``` - -`exampleComponentPath` points at your local components dir so `:example{}` directives render through your own `Example.svelte` chrome. The other two paths are the same for every consumer. - -### 4. `svelte.config.js` - -```js -import adapter from '@sveltejs/adapter-cloudflare'; -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; -import { mdsx } from 'mdsx'; -import { mdsxConfig } from './mdsx.config.js'; - -/** @type {import('@sveltejs/kit').Config} */ -export default { - extensions: ['.svelte', '.md'], // compile .md as components/routes - preprocess: [mdsx(mdsxConfig), vitePreprocess()], - kit: { - adapter: adapter(), - alias: { - $examples: 'src/examples', - // required virtual module so `import { allReferences } from 'content-collections'` resolves: - 'content-collections': './.content-collections/generated', - }, - }, -}; -``` - -> `@layerstack/docs` is consumed from its built `dist/` (it relies on its `exports` map), so **the framework must be built before the docs app builds.** Don't source-alias it. (You _may_ source-alias the workspace libraries you're documenting for instant HMR — see the LayerStack `svelte.config.js`.) - -### 5. `vite.config.js` - -```js -import { defineConfig } from 'vite'; -import { sveltekit } from '@sveltejs/kit/vite'; -import tailwindcss from '@tailwindcss/vite'; -import Icons from 'unplugin-icons/vite'; -import contentCollections from '@content-collections/vite'; - -export default defineConfig({ - plugins: [tailwindcss(), sveltekit(), contentCollections(), Icons({ compiler: 'svelte' })], -}); -``` - -`contentCollections()` regenerates `.content-collections/generated` (the `content-collections` virtual module) on build/dev. `Icons({ compiler: 'svelte' })` powers the `~icons/*` imports the framework and MDC `:icon{}` directives use. - -### 6. `app.css` - -```css -@import 'tailwindcss'; -@import '@layerstack/tailwind/core.css'; -@import '@layerstack/tailwind/utils.css'; -@import '@layerstack/tailwind/themes/all.css'; -@import '@layerstack/docs/styles.css'; - -/* Tailwind must scan the framework's compiled components for class usage: */ -@source '../../node_modules/svelte-ux/dist'; -@source '../../node_modules/@layerstack/docs/dist'; - -@plugin '@tailwindcss/typography'; -``` - -`@layerstack/docs/styles.css` provides Shiki theming, inline-code/code-block/diff/line-number styling, and the `.steps` numbering. The two `@source` lines are required because the framework is dist-resolved (Tailwind won't otherwise see its classes). - -### 7. `src/lib` glue - -These two files are the only real glue — they hand the consumer's `import.meta.glob` (which must be evaluated in the consumer root) to the framework factories. They're nearly identical across consumers; copy and adjust the collection names. - -**`src/lib/examples.ts`** - -```ts -import type { Component } from 'svelte'; -import { createExampleLoaders } from '@layerstack/docs/examples'; - -const pathExamples = import.meta.glob<{ default: Component }>([ - '/src/routes/**/*.svelte', - '/src/content/**/*.svelte', -]); -const rawPathExamples = import.meta.glob( - ['/src/routes/**/*.svelte', '/src/content/**/*.svelte'], - { query: '?raw', import: 'default' } -); - -export const { loadExample, loadExamples, loadExampleByPath } = createExampleLoaders({ - loadComponentExample: (type, component, name) => - import(`../examples/${type}/${component}/${name}.svelte`), - loadRawExample: async (type, component, name) => - (await import(`../examples/${type}/${component}/${name}.svelte?raw`)).default as string, - loadPathExample: (path) => pathExamples[path]?.(), - loadRawPathExample: (path) => rawPathExamples[path]?.(), -}); -``` - -**`src/lib/content.ts`** - -```ts -import { error } from '@sveltejs/kit'; -import { allReferences, allGuides, type Reference, type Guide } from 'content-collections'; -import { createContentLoaders, type ContentType } from '@layerstack/docs/content'; -import { loadExample, loadExampleByPath } from '$lib/examples.js'; - -type Metadata = Reference | Guide; - -const modules = import.meta.glob<{ default: import('svelte').Component; metadata: Metadata }>( - '/src/content/**/*.md' -); - -export const { getMarkdownComponent, loadExamplesFromMarkdown } = createContentLoaders({ - modules, - getMetadata: (slug, type: ContentType) => - type === 'guides' - ? allGuides.find((g) => g.slug === slug) - : allReferences.find((r) => r.slug === slug), - loadExample, - loadExampleByPath, - notFound: () => error(404, 'Could not find the document.'), -}); -``` - -You also provide a local **`src/lib/components/Example.svelte`** that the `:example{}` directive renders — it reads the `examples` context (`@layerstack/docs/context`), resolves a path with `resolveExamplePath` (`@layerstack/docs/content`), and shows the example + source via the framework `Code` component. Copy a reference consumer's. - -### 8. Routes - -The routes are boilerplate that delegates to the framework — copy them from a [reference consumer](#reference-consumers) and adjust collection/slug shapes. You need: - -- **Markdown renderers** — dynamic routes (e.g. `docs/[packageName]/[name]/` and `docs/guides/[name]/`) whose `+page.ts` calls `getMarkdownComponent` + `loadExamplesFromMarkdown`, and whose `+page.svelte` sets the `examples` context (`@layerstack/docs/context`) and renders `` plus title/related/edit-link chrome. -- **`llms.txt` endpoints** — `+server.ts` files returning `markdownResponse(generateReferenceMarkdown(...) | generateGuideMarkdown(...))`, plus a root `llms.txt` index and a `docs/llms.txt` full dump. -- **Search index** — `routes/api/search.json/+server.ts` with `export const prerender = true` returning the entries the `Search` component fetches. Build entries with `stripMarkdown` (`@layerstack/docs/markdown`) and the `SearchEntry` type (`@layerstack/docs/search`). -- **App shell** — a `+layout.svelte` with ``, ``, and a nav menu (group collections with `sortCollection` from `@layerstack/docs/collections`). Optionally call `preparePageTransition()` (`@layerstack/docs/page-transitions`) for View-Transition navigation. - -## Authoring content - -### Directory layout - -``` -src/content/ - reference//.md # references collection (hand-authored) - components/.md # components collection (generated sites) - utils/.md # utils collection - guides/.md # guides collection (nest in subdirs → categories) -src/examples/ - components//.svelte # referenced by :example{name="…"} - utils//.svelte -``` - -### Frontmatter - -Common fields (full schemas in [`content-collections/index.js`](src/lib/content-collections/index.js)): - -```md ---- -title: SelectionState # required (reference/guide); becomes `name` -description: Manage a set of selected items -category: State # optional grouping -related: # cross-links (slug, component, or URL) - - svelte-state/UniqueState - - https://example.com -order: 1 # optional manual sort -status: beta # optional badge (reference) -hideTableOfContents: false ---- -``` - -`components`/`utils` collections add `layers`, `withinLayer`, `resize`; `references` add `features`, `kind`, `sourceFile`, `hideUsage`, `packageName`; `releases` are generated from GitHub. - -### Source-file inference (reference collection) - -A reference doc's source file is inferred from its path — -`src/content/reference//.md` → `//src/lib/.{ts,svelte.ts}` -(with a camelCase fallback: `Duration` → `duration.ts`, `SelectionState` → `selectionState.svelte.ts`). Add a `sourceFile:` frontmatter (relative to `packagesRoot`) only to override. - -### MDC directives - -Authored in markdown, rendered by the framework's markdown components: - -```md -:example{name="basic" showCode} - -::note -Heads up. -:: - -::steps - -### First - -### Second - -:: - -:::tabs -::tab{label="npm"} -`npm i …` -:: -::tab{label="pnpm"} -`pnpm add …` -:: -::: - -:icon{name="lucide:check"} :button{label="Label" href="/x" icon="lucide:arrow-right"} -``` - -### Live code blocks - -A fenced ` ```svelte live ` block is written to disk and rendered as an interactive preview above its source (via `remarkLiveCode` → ``): - -````md -```svelte live - - - -``` -```` - -## The `layerstack-docs` CLI - -Build-time generators (bin → `dist/cli.js`). Wire them into `package.json` scripts; run heavy/committed artifacts (catalog, screenshots) manually and the rest in `prebuild`: - -```jsonc -{ - "scripts": { - "prebuild": "pnpm generate:api && pnpm generate:stackblitz && pnpm generate:releases", - "generate:api": "layerstack-docs generate-api ../packages//src/lib/components generated/api", - "generate:catalog": "layerstack-docs generate-catalog ../packages//src/lib/components src/examples/components src/examples/catalog", - "generate:screenshots": "layerstack-docs generate-screenshots src/examples/components static/screenshots", - "generate:stackblitz": "layerstack-docs generate-stackblitz src static/stackblitz-files.json [remote-sources.json]", - "generate:releases": "layerstack-docs generate-releases techniq/ generated/releases", - }, -} +// mdsx.config.js +export const mdsxConfig = createMdsxConfig({ exampleComponentPath: '$lib/components' }); ``` -| Command | Args / flags | Generates | -| ---------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -| `generate-api` | ` ` | Per-component prop API JSON (`.json` + `index.json`) via the TypeScript compiler | -| `generate-catalog` | ` ` | Per-component example + cross-usage catalogs | -| `generate-screenshots` | ` [--base-url ] [--route-base ] [--all]` | Responsive light/dark WebP screenshots (Playwright + sharp; checksum-skipped unless `--all`) | -| `generate-stackblitz` | ` [remote-sources-file] [--template-dir ] [--source out=src …] [--remote out=src …]` | A StackBlitz/WebContainer file bundle (defaults to the bundled `templates/stackblitz-template`) | -| `generate-releases` | ` ` | GitHub releases → frontmatter markdown files | +- `svelte.config.js` — `.md` extension, the `mdsx` preprocessor, and a `content-collections` alias. +- `vite.config.js` — `tailwindcss()`, `sveltekit()`, `contentCollections()`, `Icons()`. +- `app.css` — import `@layerstack/tailwind/*` + `@layerstack/docs/styles.css`. +- `src/lib/{content,examples}.ts` — hand your `import.meta.glob` to `createContentLoaders` / `createGlobExampleLoaders`. +- Routes (`+page.ts`/`+page.svelte`, `llms.txt`, `api/search.json`) — boilerplate; copy a [reference consumer](#reference-consumers). -The generated `generated/api/*` and `generated/releases/*` are picked up automatically by the `references`/`components`/`releases` collections. +> `@layerstack/docs` is consumed from its built `dist/`, so **the framework must be built before a docs app builds.** Don't source-alias it. ## Export reference @@ -399,10 +70,11 @@ Import from subpaths (e.g. `import { Code } from '@layerstack/docs/components'`) | `/components` | `Code`, `Json`, `Search`, `TableOfContents`, `OpenWithButton`, `ViewSourceButton`, `ExampleLink`, `ExampleListing`, `ComponentLink`, `RelatedLink`, `ExampleScreenshot`, `ImageLink`, `Tabs`, `Steps`, `Step`, `Blockquote`, `LoadingPlaceholder` (also via `/components/*.svelte`) | | `/markdown/components` | markdown element components (`A`, `Code`, `H1`–`H4`, `P`, `Table`, …) + directive components (`Note`, `Tabs`, `Tab`, `Steps`, `Button`, `LiveCode`) | | `/content` | `createContentLoaders`, `resolveExamplePath`, `extractExampleReferences`, `getFirstExampleName` | -| `/examples` | `createExampleLoaders`, `cleanExampleSource` | +| `/examples` | `createGlobExampleLoaders`, `createExampleLoaders`, `cleanExampleSource` | | `/context` | `examples` (runed context) | | `/collections` | `sortCollection` | -| `/search` | `initSearch`, `search`, type `SearchEntry` | +| `/search` | `initSearch`, `search`, `buildSearchEntries`, `extractHeadingContents`, type `SearchEntry` | +| `/utils` | `stripIndent` | | `/page-transitions` | `preparePageTransition` | | `/project-stats` | `getProjectStats` | | `/api`, `/catalog` | type-only (`ComponentAPI`, `ComponentCatalog`, …) | @@ -416,16 +88,12 @@ Import from subpaths (e.g. `import { Code } from '@layerstack/docs/components'`) | `/markdown` | `extractTocFromMarkdown`, `stripMarkdown` | | `/markdown/rehype/live-code` | `remarkLiveCode` | | `/llms` | `processMarkdownContent`, `inlineExampleDirectives`, `generateReferenceMarkdown`, `generateGuideMarkdown`, `linkListSection`, `groupBySlugSegment`, `generateApiTable`, `markdownResponse`, `trimCode`, `extractFrontmatterTitle` | -| `/node/component-api` | `writeComponentAPIs`, `extractComponentAPI` | -| `/node/example-catalog` | `writeExampleCatalogs` | -| `/node/screenshots` | `generateScreenshots` | -| `/node/stackblitz` | `generateStackBlitzFiles`, `getDefaultStackBlitzTemplateDir` | -| `/node/releases` | `generateReleases` | +| `/node/*` | `writeComponentAPIs`, `writeExampleCatalogs`, `generateScreenshots`, `generateStackBlitzFiles`, `generateReleases` (the `layerstack-docs` CLI wraps these) | | `/styles.css` | shipped CSS | ## Reference consumers Two real apps exercise the framework — copy whichever shape matches your project: -- **LayerStack docs** (`layerstack/docs`, `@layerstack/docs-site`) — hand-authored **reference** docs across many small packages; no generators; `references` + `guides` collections. +- **LayerStack docs** (`docs/`, `@layerstack/docs-site`) — hand-authored **reference** docs across many small packages; no generators; `references` + `guides` collections. - **LayerChart docs** (`layerchart/docs`) — **generated** component docs; uses all five `generate:*` CLI scripts, `components`/`utils`/`guides` collections, screenshots, StackBlitz playground, and releases. diff --git a/packages/docs/src/lib/content-collections/index.js b/packages/docs/src/lib/content-collections/index.js index 45484e6..0997de8 100644 --- a/packages/docs/src/lib/content-collections/index.js +++ b/packages/docs/src/lib/content-collections/index.js @@ -89,7 +89,7 @@ function normalizeOptions(options) { return { packageName: options.packageName, repo: options.repo ?? `techniq/${options.packageName}`, - branch: options.branch ?? 'next', + branch: options.branch ?? 'main', packagesRoot: options.packagesRoot ?? '../packages', referenceDirectory: options.referenceDirectory ?? 'src/content/reference', };