blume 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +110 -0
- package/README.md +2 -2
- package/dist/cli/{chunk-f2972sbt.js → chunk-00gs3wqs.js} +1 -1
- package/dist/cli/{chunk-fa25z98p.js → chunk-273ygyr4.js} +4 -3
- package/dist/cli/chunk-273ygyr4.js.map +11 -0
- package/dist/cli/{chunk-pat2zzwc.js → chunk-3yce002v.js} +21 -8
- package/dist/cli/{chunk-pat2zzwc.js.map → chunk-3yce002v.js.map} +4 -4
- package/dist/cli/{chunk-d1tadaw7.js → chunk-4e9b9ra6.js} +17 -7
- package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
- package/dist/cli/{chunk-zg2gtj10.js → chunk-5r8g91qn.js} +352 -676
- package/dist/cli/chunk-5r8g91qn.js.map +34 -0
- package/dist/cli/{chunk-11j0384y.js → chunk-6dtt0zfn.js} +14 -14
- package/dist/cli/{chunk-11j0384y.js.map → chunk-6dtt0zfn.js.map} +3 -3
- package/dist/cli/{chunk-bw22s759.js → chunk-6k4ftwze.js} +38 -19
- package/dist/cli/{chunk-bw22s759.js.map → chunk-6k4ftwze.js.map} +4 -4
- package/dist/cli/{chunk-sqn5t4q0.js → chunk-7mbqtmgb.js} +16 -7
- package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
- package/dist/cli/{chunk-79njf86q.js → chunk-7vtckvaw.js} +21 -19
- package/dist/cli/chunk-7vtckvaw.js.map +11 -0
- package/dist/cli/{chunk-fh5hj5jt.js → chunk-8g8ytmgx.js} +17 -18
- package/dist/cli/{chunk-fh5hj5jt.js.map → chunk-8g8ytmgx.js.map} +2 -2
- package/dist/cli/{chunk-1w8dp3qb.js → chunk-91ws1n6j.js} +18 -15
- package/dist/cli/chunk-91ws1n6j.js.map +10 -0
- package/dist/cli/{chunk-7ez8ny0t.js → chunk-bbnwccaz.js} +2 -2
- package/dist/cli/{chunk-5a2z0198.js → chunk-bfwp9vp6.js} +18 -10
- package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
- package/dist/cli/{chunk-ernrthtr.js → chunk-d1v5rhy0.js} +14 -15
- package/dist/cli/{chunk-ernrthtr.js.map → chunk-d1v5rhy0.js.map} +2 -2
- package/dist/cli/{chunk-a9kptbw5.js → chunk-ddndchfr.js} +21 -6
- package/dist/cli/chunk-ddndchfr.js.map +14 -0
- package/dist/cli/{chunk-zxccj738.js → chunk-esh98wmb.js} +1 -1
- package/dist/cli/{chunk-88cpgt6h.js → chunk-fsmrqk8a.js} +1 -1
- package/dist/cli/{chunk-b5aj94ah.js → chunk-g698a744.js} +5 -5
- package/dist/cli/{chunk-jts8mvcz.js → chunk-gs7r695n.js} +9 -3
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-gs7r695n.js.map} +3 -3
- package/dist/cli/{chunk-41za066z.js → chunk-h2ez8dzb.js} +4 -4
- package/dist/cli/{chunk-by2290sx.js → chunk-h7k3nq3v.js} +2 -2
- package/dist/cli/{chunk-j8mw0za6.js → chunk-hqp2ajnh.js} +252 -123
- package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
- package/dist/cli/{chunk-mnqj32sj.js → chunk-hr8ne106.js} +119 -50
- package/dist/cli/chunk-hr8ne106.js.map +13 -0
- package/dist/cli/{chunk-mwt1k8n7.js → chunk-j85scx15.js} +74 -30
- package/dist/cli/chunk-j85scx15.js.map +10 -0
- package/dist/cli/{chunk-z01ze5c1.js → chunk-k7pj68a8.js} +63 -22
- package/dist/cli/chunk-k7pj68a8.js.map +11 -0
- package/dist/cli/{chunk-2q1dwty4.js → chunk-mqc662a6.js} +8 -8
- package/dist/cli/{chunk-2q1dwty4.js.map → chunk-mqc662a6.js.map} +4 -4
- package/dist/cli/{chunk-y3e45rc8.js → chunk-n1yg3tj3.js} +4 -4
- package/dist/cli/{chunk-bctazmbk.js → chunk-nfcyttvj.js} +17 -6
- package/dist/cli/chunk-nfcyttvj.js.map +10 -0
- package/dist/cli/{chunk-6k8vp3ta.js → chunk-pbg5a4s3.js} +60 -28
- package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
- package/dist/cli/{chunk-d80hr03s.js → chunk-ppzjqwx2.js} +24 -17
- package/dist/cli/{chunk-d80hr03s.js.map → chunk-ppzjqwx2.js.map} +4 -4
- package/dist/cli/{chunk-beat36xx.js → chunk-qkb5a8sa.js} +25 -10
- package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
- package/dist/cli/{chunk-bnbmcwfb.js → chunk-sqw4ekg1.js} +5 -5
- package/dist/cli/{chunk-bnbmcwfb.js.map → chunk-sqw4ekg1.js.map} +3 -3
- package/dist/cli/{chunk-xaz13gwg.js → chunk-v6ya5kcb.js} +3268 -1150
- package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
- package/dist/cli/{chunk-tzne8qfq.js → chunk-w4bxdvsa.js} +18 -15
- package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
- package/dist/cli/{chunk-f7t03s3g.js → chunk-wdrt2k2v.js} +2 -2
- package/dist/cli/{chunk-z1f5arsg.js → chunk-xh43dwgw.js} +170 -55
- package/dist/cli/chunk-xh43dwgw.js.map +36 -0
- package/dist/cli/{chunk-pnnvybbk.js → chunk-zp79m0ts.js} +5 -5
- package/dist/cli/{chunk-pnnvybbk.js.map → chunk-zp79m0ts.js.map} +2 -2
- package/dist/cli/index.js +160 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-readability.d.ts +1 -1
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api/paths.d.ts +1 -1
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +14 -7
- package/dist/types/ai/ask.d.ts +43 -43
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/index.d.ts +3 -3
- package/dist/types/ai/openapi-components.d.ts +1 -1
- package/dist/types/ai/relative-links.d.ts +9 -4
- package/dist/types/ai/serializers.d.ts +1 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/visibility.d.ts +1 -1
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- package/dist/types/cli/env.d.ts +5 -0
- package/dist/types/cli/init/scaffold.d.ts +19 -3
- package/dist/types/cli/init/starter-spec.d.ts +11 -0
- package/dist/types/core/base-path.d.ts +9 -0
- package/dist/types/core/config-input.d.ts +21 -21
- package/dist/types/core/config.d.ts +5 -5
- package/dist/types/core/data.d.ts +3 -3
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/i18n-ui.d.ts +37 -8
- package/dist/types/core/i18n.d.ts +7 -1
- package/dist/types/core/links.d.ts +3 -1
- package/dist/types/core/load-module.d.ts +10 -0
- package/dist/types/core/locale-links.d.ts +12 -2
- package/dist/types/core/meta.d.ts +5 -1
- package/dist/types/core/nav-diagnostics.d.ts +10 -0
- package/dist/types/core/navigation.d.ts +38 -0
- package/dist/types/core/ordering-prefix.d.ts +4 -0
- package/dist/types/core/safe-links.d.ts +3 -1
- package/dist/types/core/schema.d.ts +57 -18
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +14 -2
- package/dist/types/core/sources/normalize.d.ts +10 -1
- package/dist/types/core/sources/remote.d.ts +11 -1
- package/dist/types/core/sources/resolve.d.ts +12 -0
- package/dist/types/core/sources/types.d.ts +31 -0
- package/dist/types/core/types.d.ts +9 -0
- package/dist/types/core/unrecognized-keys.d.ts +1 -1
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +31 -7
- package/dist/types/deploy/node-headers.d.ts +43 -8
- package/dist/types/deploy/platforms/netlify.d.ts +27 -2
- package/dist/types/deploy/platforms/node.d.ts +6 -5
- package/dist/types/deploy/platforms/types.d.ts +7 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +7 -2
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/documents.d.ts +1 -1
- package/dist/types/search/orama-index.d.ts +1 -1
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +21 -12
- package/docs/03-upgrading.mdx +22 -9
- package/docs/04-migrating.mdx +4 -4
- package/docs/08-faq.mdx +12 -5
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +5 -3
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +5 -5
- package/docs/cli/doctor.mdx +4 -4
- package/docs/cli/evals.mdx +9 -9
- package/docs/cli/index.mdx +6 -3
- package/docs/cli/translate.mdx +8 -8
- package/docs/configuration/analytics.mdx +23 -2
- package/docs/configuration/{ask-ai.mdx → assistant.mdx} +20 -20
- package/docs/configuration/customization.mdx +5 -4
- package/docs/configuration/index.mdx +7 -5
- package/docs/configuration/meta.ts +1 -1
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -3
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +5 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -12
- package/docs/content/versioning.mdx +1 -0
- package/docs/discoverability/agent-discovery.mdx +22 -8
- package/docs/discoverability/index.mdx +3 -3
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +5 -3
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +6 -4
- package/docs/discoverability/rss.mdx +3 -1
- package/docs/index.mdx +2 -2
- package/docs/references/asyncapi.mdx +1 -1
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +3 -3
- package/package.json +1 -1
- package/skills/blume/SKILL.md +5 -5
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- package/skills/blume-migrate/references/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +1 -1
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +2 -2
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-readability.ts +4 -4
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/api/paths.ts +1 -1
- package/src/ai/api/spec.ts +15 -2
- package/src/ai/api-catalog.ts +7 -1
- package/src/ai/ask-context.ts +21 -9
- package/src/ai/ask-data.ts +28 -14
- package/src/ai/ask.ts +84 -71
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/cors.ts +3 -3
- package/src/ai/index.ts +16 -16
- package/src/ai/link-headers.ts +8 -3
- package/src/ai/llms.ts +4 -3
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/server.ts +78 -7
- package/src/ai/openapi-components.ts +1 -1
- package/src/ai/relative-links.ts +78 -10
- package/src/ai/serializers.ts +1 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/visibility.ts +46 -15
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +90 -45
- package/src/astro/module-types.ts +1 -1
- package/src/astro/runtime-deps.ts +6 -6
- package/src/astro/templates.ts +87 -49
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +25 -5
- package/src/audit/checks/content.ts +20 -2
- package/src/audit/checks/i18n.ts +46 -8
- package/src/audit/checks/indexability.ts +39 -19
- package/src/audit/checks/links.ts +14 -0
- package/src/audit/checks/llms.ts +6 -3
- package/src/audit/checks/network.ts +3 -1
- package/src/audit/checks/og-image.ts +10 -0
- package/src/audit/checks/robots.ts +6 -1
- package/src/audit/checks/sitemap.ts +56 -31
- package/src/audit/checks/social.ts +21 -2
- package/src/audit/crawl.ts +88 -15
- package/src/audit/report.ts +54 -17
- package/src/audit/run.ts +1 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/blume-modules.d.ts +2 -2
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +8 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +7 -5
- package/src/cli/commands/eval.ts +4 -10
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/migrate.ts +2 -2
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +12 -9
- package/src/cli/commands/upgrade.ts +13 -2
- package/src/cli/eject-scripts.ts +32 -7
- package/src/cli/env.ts +12 -1
- package/src/cli/init/scaffold.ts +117 -11
- package/src/cli/init/starter-spec.ts +235 -0
- package/src/cli/required-secrets.ts +3 -3
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +2 -9
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +9 -3
- package/src/components/content/Expandable.astro +5 -1
- package/src/components/content/Frame.astro +2 -7
- package/src/components/content/GithubInfo.astro +12 -2
- package/src/components/content/Prompt.astro +2 -7
- package/src/components/content/Tabs.astro +54 -5
- package/src/components/content/Tile.astro +1 -1
- package/src/components/content/Tooltip.astro +69 -7
- package/src/components/content/Tree.astro +7 -2
- package/src/components/content/TypeTable.astro +10 -5
- package/src/components/content/Update.astro +8 -2
- package/src/components/content/auto-type-table.ts +4 -1
- package/src/components/content/badge-color.ts +17 -0
- package/src/components/content/base-href.ts +18 -3
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +36 -9
- package/src/components/islands/{AskAI.astro → Assistant.astro} +10 -10
- package/src/components/islands/{ask-ai.tsx → assistant.tsx} +39 -25
- package/src/components/islands/hooks.ts +21 -14
- package/src/components/islands/webmcp.ts +12 -8
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Header.astro +32 -19
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +6 -1
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +15 -6
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageLayout.astro +28 -14
- package/src/components/layout/Pagination.astro +7 -7
- package/src/components/layout/ReferenceLayout.astro +5 -2
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +18 -14
- package/src/components/layout/analytics-client.ts +3 -1
- package/src/components/layout/drawer-inert.ts +1 -1
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +21 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +9 -5
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +27 -52
- package/src/components/openapi/description.ts +2 -2
- package/src/components/openapi/helpers.ts +90 -12
- package/src/components/openapi/message-composer.ts +8 -0
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +4 -1
- package/src/components/openapi/operation-model.ts +40 -8
- package/src/components/openapi/panel.ts +29 -5
- package/src/components/openapi/playground-client.ts +37 -7
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +2 -0
- package/src/components/openapi/schema-tree.ts +203 -0
- package/src/components/openapi/snippets.ts +30 -15
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/core/base-path.ts +15 -0
- package/src/core/code-fences.ts +1 -1
- package/src/core/config-input.ts +23 -23
- package/src/core/config.ts +21 -7
- package/src/core/data.ts +3 -3
- package/src/core/diagnostics.ts +217 -30
- package/src/core/graph.ts +120 -11
- package/src/core/i18n-ui.ts +74 -11
- package/src/core/i18n.ts +13 -2
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +17 -17
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +69 -6
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +245 -76
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +23 -1
- package/src/core/request-body.ts +1 -1
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +95 -34
- package/src/core/server-features.ts +2 -2
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +3 -2
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +5 -1
- package/src/core/sources/github-releases.ts +106 -5
- package/src/core/sources/lexical.ts +9 -4
- package/src/core/sources/lower.ts +79 -26
- package/src/core/sources/mdx-remote.ts +1 -0
- package/src/core/sources/normalize.ts +132 -30
- package/src/core/sources/notion.ts +26 -10
- package/src/core/sources/obsidian.ts +17 -3
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +63 -44
- package/src/core/sources/remote.ts +18 -2
- package/src/core/sources/resolve.ts +52 -33
- package/src/core/sources/sanity.ts +1 -0
- package/src/core/sources/strapi-blocks.ts +9 -4
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +17 -5
- package/src/core/ui-packs/bg.ts +17 -5
- package/src/core/ui-packs/bn.ts +17 -5
- package/src/core/ui-packs/ca.ts +17 -5
- package/src/core/ui-packs/cs.ts +17 -5
- package/src/core/ui-packs/da.ts +17 -5
- package/src/core/ui-packs/de.ts +17 -5
- package/src/core/ui-packs/el.ts +17 -5
- package/src/core/ui-packs/es.ts +17 -5
- package/src/core/ui-packs/fa.ts +17 -5
- package/src/core/ui-packs/fi.ts +17 -5
- package/src/core/ui-packs/fr.ts +17 -5
- package/src/core/ui-packs/he.ts +17 -5
- package/src/core/ui-packs/hi.ts +17 -5
- package/src/core/ui-packs/hr.ts +17 -5
- package/src/core/ui-packs/hu.ts +17 -5
- package/src/core/ui-packs/id.ts +17 -5
- package/src/core/ui-packs/it.ts +17 -5
- package/src/core/ui-packs/ja.ts +17 -5
- package/src/core/ui-packs/ko.ts +17 -5
- package/src/core/ui-packs/nl.ts +17 -5
- package/src/core/ui-packs/no.ts +17 -5
- package/src/core/ui-packs/pl.ts +17 -5
- package/src/core/ui-packs/pt-br.ts +17 -5
- package/src/core/ui-packs/pt.ts +17 -5
- package/src/core/ui-packs/ro.ts +17 -5
- package/src/core/ui-packs/ru.ts +17 -5
- package/src/core/ui-packs/sk.ts +17 -5
- package/src/core/ui-packs/sr.ts +17 -5
- package/src/core/ui-packs/sv.ts +17 -5
- package/src/core/ui-packs/th.ts +17 -5
- package/src/core/ui-packs/tr.ts +17 -5
- package/src/core/ui-packs/uk.ts +17 -5
- package/src/core/ui-packs/vi.ts +17 -5
- package/src/core/ui-packs/zh-tw.ts +17 -5
- package/src/core/ui-packs/zh.ts +17 -5
- package/src/core/unrecognized-keys.ts +1 -1
- package/src/core/version-cut.ts +17 -2
- package/src/core/versions.ts +4 -1
- package/src/deploy/adapters/node.ts +5 -2
- package/src/deploy/adapters/registry.ts +2 -1
- package/src/deploy/adapters/types.ts +13 -1
- package/src/deploy/artifacts.ts +25 -5
- package/src/deploy/cloudflare-negotiation.ts +23 -4
- package/src/deploy/headers.ts +67 -51
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +1 -0
- package/src/deploy/platforms/netlify.ts +82 -5
- package/src/deploy/platforms/node.ts +7 -5
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +7 -0
- package/src/deploy/platforms/vercel.ts +9 -3
- package/src/deploy/redirects.ts +14 -3
- package/src/deploy/vercel-negotiation.ts +35 -3
- package/src/eval/agents.ts +10 -2
- package/src/eval/run.ts +25 -0
- package/src/markdown/base-links.ts +55 -8
- package/src/markdown/index.ts +6 -3
- package/src/markdown/relative-links.ts +3 -23
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +20 -4
- package/src/og/derive.ts +145 -4
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +77 -13
- package/src/openapi/render-mdx.ts +10 -1
- package/src/registry/eject.ts +135 -37
- package/src/search/documents.ts +24 -3
- package/src/search/orama-index.ts +1 -1
- package/src/search/sync/algolia.ts +36 -2
- package/src/sources/registry.ts +5 -0
- package/src/theme/entry.ts +11 -4
- package/src/translate/agents.ts +6 -1
- package/src/translate/ledger.ts +26 -3
- package/src/translate/meta.ts +11 -3
- package/src/translate/report.ts +1 -1
- package/src/translate/run.ts +11 -5
- package/src/translate/validate.ts +10 -1
- package/src/translate/work-list.ts +36 -3
- package/src/upgrade/upgrade.ts +37 -5
- package/dist/cli/chunk-1w8dp3qb.js.map +0 -10
- package/dist/cli/chunk-5a2z0198.js.map +0 -10
- package/dist/cli/chunk-6k8vp3ta.js.map +0 -19
- package/dist/cli/chunk-79njf86q.js.map +0 -11
- package/dist/cli/chunk-a9kptbw5.js.map +0 -14
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-bctazmbk.js.map +0 -10
- package/dist/cli/chunk-beat36xx.js.map +0 -10
- package/dist/cli/chunk-d1tadaw7.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-j8mw0za6.js.map +0 -35
- package/dist/cli/chunk-mnqj32sj.js.map +0 -12
- package/dist/cli/chunk-mwt1k8n7.js.map +0 -10
- package/dist/cli/chunk-nk3ts2xk.js +0 -51
- package/dist/cli/chunk-nk3ts2xk.js.map +0 -10
- package/dist/cli/chunk-sqn5t4q0.js.map +0 -10
- package/dist/cli/chunk-tzne8qfq.js.map +0 -10
- package/dist/cli/chunk-xaz13gwg.js.map +0 -182
- package/dist/cli/chunk-z01ze5c1.js.map +0 -10
- package/dist/cli/chunk-z1f5arsg.js.map +0 -36
- package/dist/cli/chunk-zg2gtj10.js.map +0 -35
- /package/dist/cli/{chunk-f2972sbt.js.map → chunk-00gs3wqs.js.map} +0 -0
- /package/dist/cli/{chunk-7ez8ny0t.js.map → chunk-bbnwccaz.js.map} +0 -0
- /package/dist/cli/{chunk-zxccj738.js.map → chunk-esh98wmb.js.map} +0 -0
- /package/dist/cli/{chunk-88cpgt6h.js.map → chunk-fsmrqk8a.js.map} +0 -0
- /package/dist/cli/{chunk-b5aj94ah.js.map → chunk-g698a744.js.map} +0 -0
- /package/dist/cli/{chunk-41za066z.js.map → chunk-h2ez8dzb.js.map} +0 -0
- /package/dist/cli/{chunk-by2290sx.js.map → chunk-h7k3nq3v.js.map} +0 -0
- /package/dist/cli/{chunk-y3e45rc8.js.map → chunk-n1yg3tj3.js.map} +0 -0
- /package/dist/cli/{chunk-f7t03s3g.js.map → chunk-wdrt2k2v.js.map} +0 -0
|
@@ -9,6 +9,7 @@ import { NEW_TAB_ATTRS } from "../../core/new-tab.ts";
|
|
|
9
9
|
import { resolveIcon } from "../../theme/icons.ts";
|
|
10
10
|
import data from "blume:data";
|
|
11
11
|
import { GITHUB_MARK } from "../github-mark.ts";
|
|
12
|
+
import { contentStrings } from "./content-strings.ts";
|
|
12
13
|
import { fetchRepositoryInfo } from "./github-info.ts";
|
|
13
14
|
|
|
14
15
|
// Star/fork glyphs resolve from Lucide at build time; the `<svg>` wrappers below
|
|
@@ -63,6 +64,9 @@ const numbers = new Intl.NumberFormat("en", {
|
|
|
63
64
|
|
|
64
65
|
const statIcon =
|
|
65
66
|
"size-3.5 shrink-0 text-muted-foreground"; /* shared classes for stat icons */
|
|
67
|
+
// The glyphs are decorative, so each count carries a text label for screen
|
|
68
|
+
// readers ("Stars: 1.2K"), in the page's language.
|
|
69
|
+
const { content: strings } = contentStrings(data, Astro.currentLocale);
|
|
66
70
|
---
|
|
67
71
|
|
|
68
72
|
{
|
|
@@ -108,7 +112,10 @@ const statIcon =
|
|
|
108
112
|
width="14"
|
|
109
113
|
set:html={starIcon}
|
|
110
114
|
/>
|
|
111
|
-
<span>
|
|
115
|
+
<span>
|
|
116
|
+
<span class="sr-only">{strings.stars}: </span>
|
|
117
|
+
{numbers.format(info.stars)}
|
|
118
|
+
</span>
|
|
112
119
|
</span>
|
|
113
120
|
<span class="flex items-center gap-1.5">
|
|
114
121
|
<svg
|
|
@@ -124,7 +131,10 @@ const statIcon =
|
|
|
124
131
|
width="14"
|
|
125
132
|
set:html={forkIcon}
|
|
126
133
|
/>
|
|
127
|
-
<span>
|
|
134
|
+
<span>
|
|
135
|
+
<span class="sr-only">{strings.forks}: </span>
|
|
136
|
+
{numbers.format(info.forks)}
|
|
137
|
+
</span>
|
|
128
138
|
</span>
|
|
129
139
|
</span>
|
|
130
140
|
)}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { createSatteriMarkdownProcessor } from "@astrojs/markdown-satteri";
|
|
3
2
|
import data from "blume:data";
|
|
4
3
|
|
|
5
4
|
import { contentStrings } from "./content-strings.ts";
|
|
6
|
-
import {
|
|
5
|
+
import { renderInlineMarkdown } from "./inline-markdown.ts";
|
|
7
6
|
import { promptMarkdown } from "./prompt-markdown.ts";
|
|
8
7
|
|
|
9
8
|
interface Props {
|
|
@@ -24,11 +23,7 @@ const normalizeActions = (value: Props["actions"]): string[] => {
|
|
|
24
23
|
};
|
|
25
24
|
|
|
26
25
|
const enabledActions = new Set(normalizeActions(actions));
|
|
27
|
-
const
|
|
28
|
-
const renderedDescription = await markdownProcessor.render(
|
|
29
|
-
escapeRawHtml(description)
|
|
30
|
-
);
|
|
31
|
-
const descriptionHtml = unwrapParagraph(renderedDescription.code);
|
|
26
|
+
const descriptionHtml = await renderInlineMarkdown(description);
|
|
32
27
|
// The prompt as Markdown, for the copy button and the Cursor link: the rendered
|
|
33
28
|
// body's text alone would drop its links, list markers, and code fences.
|
|
34
29
|
const promptSource = Astro.slots.has("default")
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
+
import data from "blume:data";
|
|
3
|
+
|
|
4
|
+
import { contentStrings } from "./content-strings.ts";
|
|
5
|
+
|
|
2
6
|
interface Props {
|
|
3
7
|
borderBottom?: boolean;
|
|
4
8
|
defaultTabIndex?: number;
|
|
@@ -45,6 +49,8 @@ const hashEnabled = String(hash) !== "false";
|
|
|
45
49
|
// The dropdown (select) affordance belongs to the boxed layout; inline always
|
|
46
50
|
// renders a tab strip.
|
|
47
51
|
const useDropdown = dropdown && !inline;
|
|
52
|
+
// The labels the client script builds the strip with, in the page's locale.
|
|
53
|
+
const { content: strings } = contentStrings(data, Astro.currentLocale);
|
|
48
54
|
---
|
|
49
55
|
|
|
50
56
|
<blume-tabs
|
|
@@ -58,6 +64,8 @@ const useDropdown = dropdown && !inline;
|
|
|
58
64
|
data-default-tab-index={defaultTabIndex}
|
|
59
65
|
data-dropdown={useDropdown ? "true" : "false"}
|
|
60
66
|
data-hash={hashEnabled ? "true" : "false"}
|
|
67
|
+
data-i18n-select-tab={strings.selectTab}
|
|
68
|
+
data-i18n-tab={strings.tab}
|
|
61
69
|
data-param={param}
|
|
62
70
|
data-sync={sync ? "true" : "false"}
|
|
63
71
|
data-sync-key={syncKey}
|
|
@@ -112,8 +120,12 @@ const useDropdown = dropdown && !inline;
|
|
|
112
120
|
// in several <Tabs> instances on one page.
|
|
113
121
|
let instanceCount = 0;
|
|
114
122
|
|
|
123
|
+
// An untitled panel is numbered with its group's localized `Tab {n}`.
|
|
115
124
|
const panelTitle = (panel: HTMLElement, index: number) =>
|
|
116
|
-
panel.dataset.title ??
|
|
125
|
+
panel.dataset.title ??
|
|
126
|
+
(
|
|
127
|
+
panel.closest<HTMLElement>("blume-tabs")?.dataset.i18nTab ?? "Tab {n}"
|
|
128
|
+
).replace("{n}", String(index + 1));
|
|
117
129
|
const panelId = (panel: HTMLElement) => panel.dataset.tabId ?? panel.id;
|
|
118
130
|
const boundedIndex = (value: number, length: number) =>
|
|
119
131
|
Math.min(Math.max(value, 0), Math.max(length - 1, 0));
|
|
@@ -149,6 +161,8 @@ const useDropdown = dropdown && !inline;
|
|
|
149
161
|
// CodeGroup passes raw code fences instead of <Tab> elements, so adopt
|
|
150
162
|
// the content wrapper's direct code blocks as panels. The tab label comes
|
|
151
163
|
// from each block's title (the text after the language in the fence).
|
|
164
|
+
// A ts2js fence arrives as its own TypeScript/JavaScript group; it is
|
|
165
|
+
// one panel too, labeled by the fence title both of its blocks carry.
|
|
152
166
|
if (panels.length === 0) {
|
|
153
167
|
const wrapper = this.querySelector<HTMLElement>(
|
|
154
168
|
":scope > [data-blume-tab-content]"
|
|
@@ -156,11 +170,19 @@ const useDropdown = dropdown && !inline;
|
|
|
156
170
|
const blocks = wrapper
|
|
157
171
|
? Array.from(wrapper.children).filter(
|
|
158
172
|
(child): child is HTMLElement =>
|
|
159
|
-
child instanceof HTMLElement &&
|
|
173
|
+
child instanceof HTMLElement &&
|
|
174
|
+
child.matches("pre, figure, blume-tabs")
|
|
160
175
|
)
|
|
161
176
|
: [];
|
|
162
177
|
for (const block of blocks) {
|
|
163
178
|
block.setAttribute("data-blume-tab-panel", "");
|
|
179
|
+
const fenceTitle = block.matches("blume-tabs")
|
|
180
|
+
? block.querySelector<HTMLElement>("pre[data-title]")?.dataset
|
|
181
|
+
.title
|
|
182
|
+
: undefined;
|
|
183
|
+
if (fenceTitle && !block.dataset.title) {
|
|
184
|
+
block.dataset.title = fenceTitle;
|
|
185
|
+
}
|
|
164
186
|
}
|
|
165
187
|
panels = blocks;
|
|
166
188
|
}
|
|
@@ -184,7 +206,10 @@ const useDropdown = dropdown && !inline;
|
|
|
184
206
|
this.#select = document.createElement("select");
|
|
185
207
|
this.#select.className = SELECT_CLASS;
|
|
186
208
|
// Neutral default: tab sets aren't necessarily code examples.
|
|
187
|
-
this.#select.setAttribute(
|
|
209
|
+
this.#select.setAttribute(
|
|
210
|
+
"aria-label",
|
|
211
|
+
this.dataset.i18nSelectTab ?? "Select tab"
|
|
212
|
+
);
|
|
188
213
|
panels.forEach((panel, index) => {
|
|
189
214
|
const option = document.createElement("option");
|
|
190
215
|
option.value = String(index);
|
|
@@ -298,6 +323,14 @@ const useDropdown = dropdown && !inline;
|
|
|
298
323
|
}
|
|
299
324
|
}
|
|
300
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Re-pick the tab from the current URL, as on first load. Neither syncs
|
|
328
|
+
* other groups nor writes history, exactly like the initial selection.
|
|
329
|
+
*/
|
|
330
|
+
selectFromUrl() {
|
|
331
|
+
this.activate(this.#initialIndex(), false, false);
|
|
332
|
+
}
|
|
333
|
+
|
|
301
334
|
#activateByHash() {
|
|
302
335
|
if (!this.#hashEnabled()) {
|
|
303
336
|
return false;
|
|
@@ -348,10 +381,12 @@ const useDropdown = dropdown && !inline;
|
|
|
348
381
|
|
|
349
382
|
#onTriggerKeydown(event: KeyboardEvent, index: number) {
|
|
350
383
|
const lastIndex = this.#triggers.length - 1;
|
|
384
|
+
// The strip runs right to left under dir="rtl", so the arrows swap.
|
|
385
|
+
const rtl = getComputedStyle(this).direction === "rtl";
|
|
351
386
|
let nextIndex: number | undefined;
|
|
352
|
-
if (event.key === "ArrowRight") {
|
|
387
|
+
if (event.key === (rtl ? "ArrowLeft" : "ArrowRight")) {
|
|
353
388
|
nextIndex = index === lastIndex ? 0 : index + 1;
|
|
354
|
-
} else if (event.key === "ArrowLeft") {
|
|
389
|
+
} else if (event.key === (rtl ? "ArrowRight" : "ArrowLeft")) {
|
|
355
390
|
nextIndex = index === 0 ? lastIndex : index - 1;
|
|
356
391
|
} else if (event.key === "Home") {
|
|
357
392
|
nextIndex = 0;
|
|
@@ -414,5 +449,19 @@ const useDropdown = dropdown && !inline;
|
|
|
414
449
|
|
|
415
450
|
if (!customElements.get("blume-tabs")) {
|
|
416
451
|
customElements.define("blume-tabs", BlumeTabs);
|
|
452
|
+
|
|
453
|
+
// The client router inserts the next page (connecting its tabs, which
|
|
454
|
+
// read the URL then) before it moves history to that page's URL, so
|
|
455
|
+
// those tabs saw the previous page's hash and query. `astro:after-swap`
|
|
456
|
+
// fires once the URL is the new page's and before the reader can
|
|
457
|
+
// interact, so selecting again here honors `?install=windows` and
|
|
458
|
+
// `#windows` deep links as a full load does.
|
|
459
|
+
document.addEventListener("astro:after-swap", () => {
|
|
460
|
+
for (const tabs of document.querySelectorAll("blume-tabs")) {
|
|
461
|
+
if (tabs instanceof BlumeTabs) {
|
|
462
|
+
tabs.selectFromUrl();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
});
|
|
417
466
|
}
|
|
418
467
|
</script>
|
|
@@ -28,7 +28,7 @@ const previewPattern =
|
|
|
28
28
|
<p class="m-0! flex items-center gap-1.5 font-semibold">
|
|
29
29
|
{title}
|
|
30
30
|
{href && (
|
|
31
|
-
<Icon class="text-muted-foreground" name="arrow-right" size={14} />
|
|
31
|
+
<Icon class="text-muted-foreground rtl:-scale-x-100" name="arrow-right" size={14} />
|
|
32
32
|
)}
|
|
33
33
|
</p>
|
|
34
34
|
)
|
|
@@ -38,7 +38,7 @@ const tooltipId = tooltipIdFor(Astro.locals, [
|
|
|
38
38
|
set:html={labelHtml}
|
|
39
39
|
/>
|
|
40
40
|
<span
|
|
41
|
-
class="absolute bottom-full left-1/2 z-20 mb-2 w-max max-w-
|
|
41
|
+
class="absolute bottom-full left-1/2 z-20 mb-2 w-max max-w-[min(20rem,calc(100vw-1rem))] -translate-x-1/2 rounded-blume border border-border bg-background p-3 text-start font-sans text-foreground text-sm shadow-lg"
|
|
42
42
|
data-blume-tooltip-panel
|
|
43
43
|
id={tooltipId}
|
|
44
44
|
role="tooltip"
|
|
@@ -60,23 +60,33 @@ const tooltipId = tooltipIdFor(Astro.locals, [
|
|
|
60
60
|
</span>
|
|
61
61
|
|
|
62
62
|
<style>
|
|
63
|
+
/* Out of layout while hidden, not just invisible: a hidden panel past the
|
|
64
|
+
inline end of a line would otherwise still widen the page. */
|
|
63
65
|
[data-blume-tooltip-panel] {
|
|
64
|
-
|
|
65
|
-
visibility: hidden;
|
|
66
|
+
display: none;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
/* Focus anywhere inside keeps it open, so a keyboard reader can Tab from
|
|
69
70
|
the trigger to the call-to-action link without the panel vanishing. */
|
|
70
71
|
[data-blume-tooltip]:hover [data-blume-tooltip-panel],
|
|
71
72
|
[data-blume-tooltip]:focus-within [data-blume-tooltip-panel] {
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
display: block;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Bridge the gap down to the trigger, so the pointer keeps the tooltip
|
|
77
|
+
hovered on its way to the panel's link (WCAG 1.4.13). The extra pixel is
|
|
78
|
+
the bottom border, which top: 100% starts inside. */
|
|
79
|
+
[data-blume-tooltip-panel]::after {
|
|
80
|
+
content: "";
|
|
81
|
+
height: calc(0.5rem + 1px);
|
|
82
|
+
inset-inline: 0;
|
|
83
|
+
position: absolute;
|
|
84
|
+
top: 100%;
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
/* Escape hides it until the pointer or focus leaves (WCAG 1.4.13). */
|
|
77
88
|
[data-blume-tooltip][data-dismissed] [data-blume-tooltip-panel] {
|
|
78
|
-
|
|
79
|
-
visibility: hidden;
|
|
89
|
+
display: none;
|
|
80
90
|
}
|
|
81
91
|
</style>
|
|
82
92
|
|
|
@@ -110,4 +120,56 @@ const tooltipId = tooltipIdFor(Astro.locals, [
|
|
|
110
120
|
};
|
|
111
121
|
document.addEventListener("focusout", rearm);
|
|
112
122
|
document.addEventListener("pointerout", rearm);
|
|
123
|
+
|
|
124
|
+
// The panel centers over its trigger, so near either edge of the viewport
|
|
125
|
+
// it would run off-screen. As it shows, shift it in by the overhang.
|
|
126
|
+
const VIEWPORT_MARGIN = 8;
|
|
127
|
+
const place = (tooltip: Element) => {
|
|
128
|
+
const panel = tooltip.querySelector<HTMLElement>(
|
|
129
|
+
"[data-blume-tooltip-panel]"
|
|
130
|
+
);
|
|
131
|
+
if (!panel) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
// Measure it parked off the side the page can't scroll toward: a panel
|
|
135
|
+
// laid out past the viewport's end even for a moment leaves WebKit's page
|
|
136
|
+
// scroll width stuck wide.
|
|
137
|
+
const rtl = getComputedStyle(document.documentElement).direction === "rtl";
|
|
138
|
+
panel.style.marginLeft = rtl ? "100vw" : "-100vw";
|
|
139
|
+
const { width } = panel.getBoundingClientRect();
|
|
140
|
+
// Zero width: not showing (yet, or any more).
|
|
141
|
+
if (width === 0) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
const anchor = tooltip.getBoundingClientRect();
|
|
145
|
+
const left = anchor.left + anchor.width / 2 - width / 2;
|
|
146
|
+
const end = document.documentElement.clientWidth - VIEWPORT_MARGIN;
|
|
147
|
+
let shift = 0;
|
|
148
|
+
if (left < VIEWPORT_MARGIN) {
|
|
149
|
+
shift = VIEWPORT_MARGIN - left;
|
|
150
|
+
} else if (left + width > end) {
|
|
151
|
+
shift = end - left - width;
|
|
152
|
+
}
|
|
153
|
+
panel.style.marginLeft = `${shift}px`;
|
|
154
|
+
return true;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Hover and focus styles already apply when these events fire; should the
|
|
158
|
+
// panel not show yet, place it in the next frame, before it paints.
|
|
159
|
+
const show = (event: FocusEvent | PointerEvent) => {
|
|
160
|
+
const tooltip =
|
|
161
|
+
event.target instanceof Element ? event.target.closest(TOOLTIP) : null;
|
|
162
|
+
const { relatedTarget } = event;
|
|
163
|
+
if (
|
|
164
|
+
tooltip &&
|
|
165
|
+
!(relatedTarget instanceof Node && tooltip.contains(relatedTarget)) &&
|
|
166
|
+
!place(tooltip)
|
|
167
|
+
) {
|
|
168
|
+
requestAnimationFrame(() => {
|
|
169
|
+
place(tooltip);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
document.addEventListener("focusin", show);
|
|
174
|
+
document.addEventListener("pointerover", show);
|
|
113
175
|
</script>
|
|
@@ -239,6 +239,11 @@
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
const folder = folderForItem(item);
|
|
242
|
+
// Deeper items sit further toward the inline end (the left under
|
|
243
|
+
// dir="rtl"), so the expand and collapse arrows swap there.
|
|
244
|
+
const rtl = getComputedStyle(this).direction === "rtl";
|
|
245
|
+
const expandKey = rtl ? "ArrowLeft" : "ArrowRight";
|
|
246
|
+
const collapseKey = rtl ? "ArrowRight" : "ArrowLeft";
|
|
242
247
|
if (event.key === "ArrowDown") {
|
|
243
248
|
event.preventDefault();
|
|
244
249
|
this.#move(1);
|
|
@@ -251,7 +256,7 @@
|
|
|
251
256
|
} else if (event.key === "End") {
|
|
252
257
|
event.preventDefault();
|
|
253
258
|
this.#moveToEdge("last");
|
|
254
|
-
} else if (event.key ===
|
|
259
|
+
} else if (event.key === expandKey && folder) {
|
|
255
260
|
event.preventDefault();
|
|
256
261
|
if (isOpenableDetails(folder) && !folder.open) {
|
|
257
262
|
folder.open = true;
|
|
@@ -259,7 +264,7 @@
|
|
|
259
264
|
} else {
|
|
260
265
|
this.#setActive(this.#firstChild(folder), true);
|
|
261
266
|
}
|
|
262
|
-
} else if (event.key ===
|
|
267
|
+
} else if (event.key === collapseKey) {
|
|
263
268
|
const parent = this.#parentItem(item);
|
|
264
269
|
if (isOpenableDetails(folder) && folder.open) {
|
|
265
270
|
event.preventDefault();
|
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
// the accent-colored prop name (with a `?` suffix when optional) and its type;
|
|
5
5
|
// expanded, the row lifts into a card showing the description and a Type/Default
|
|
6
6
|
// detail grid. Uses native <details>/<summary> so the core stays React-free.
|
|
7
|
+
import data from "blume:data";
|
|
8
|
+
|
|
7
9
|
import { resolveIcon } from "../../theme/icons.ts";
|
|
10
|
+
import { contentHref } from "./base-href.ts";
|
|
11
|
+
import { contentStrings } from "./content-strings.ts";
|
|
8
12
|
|
|
9
13
|
// The row disclosure caret; resolved from Lucide at build time and injected into
|
|
10
14
|
// the summary's `<svg>` (which supplies size and the rotate-on-open transition).
|
|
@@ -25,6 +29,7 @@ interface Props {
|
|
|
25
29
|
|
|
26
30
|
const { type = {} } = Astro.props;
|
|
27
31
|
const entries = Object.entries(type);
|
|
32
|
+
const { content: strings } = contentStrings(data, Astro.currentLocale);
|
|
28
33
|
|
|
29
34
|
// Shared column track so the header, every summary, and the detail grid align.
|
|
30
35
|
const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
|
|
@@ -34,8 +39,8 @@ const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
|
|
|
34
39
|
entries.length > 0 && (
|
|
35
40
|
<div class="not-prose my-6 rounded-blume border border-border bg-muted/30 p-1.5">
|
|
36
41
|
<div class={`${columns} px-3 py-2 font-medium text-muted-foreground text-xs`}>
|
|
37
|
-
<span>
|
|
38
|
-
<span>
|
|
42
|
+
<span>{strings.prop}</span>
|
|
43
|
+
<span>{strings.type}</span>
|
|
39
44
|
<span aria-hidden="true" class="size-3.5" />
|
|
40
45
|
</div>
|
|
41
46
|
|
|
@@ -50,7 +55,7 @@ const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
|
|
|
50
55
|
{info.typeDescriptionLink ? (
|
|
51
56
|
<a
|
|
52
57
|
class="break-words font-mono text-foreground text-xs underline-offset-2 hover:underline"
|
|
53
|
-
href={info.typeDescriptionLink}
|
|
58
|
+
href={contentHref(info.typeDescriptionLink)}
|
|
54
59
|
>
|
|
55
60
|
{info.type}
|
|
56
61
|
</a>
|
|
@@ -85,7 +90,7 @@ const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
|
|
|
85
90
|
)}
|
|
86
91
|
<div class="space-y-1.5">
|
|
87
92
|
<div class={columns}>
|
|
88
|
-
<span class="text-muted-foreground">
|
|
93
|
+
<span class="text-muted-foreground">{strings.type}</span>
|
|
89
94
|
<code class="break-words font-mono text-foreground">
|
|
90
95
|
{info.type}
|
|
91
96
|
</code>
|
|
@@ -93,7 +98,7 @@ const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
|
|
|
93
98
|
</div>
|
|
94
99
|
{info.default && (
|
|
95
100
|
<div class={columns}>
|
|
96
|
-
<span class="text-muted-foreground">
|
|
101
|
+
<span class="text-muted-foreground">{strings.default}</span>
|
|
97
102
|
<code class="break-words font-mono text-foreground">
|
|
98
103
|
{info.default}
|
|
99
104
|
</code>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
+
import data from "blume:data";
|
|
3
|
+
|
|
2
4
|
import { componentSlug } from "../slug.ts";
|
|
3
5
|
import { contentHref } from "./base-href.ts";
|
|
6
|
+
import { contentStrings } from "./content-strings.ts";
|
|
4
7
|
|
|
5
8
|
interface RssMetadata {
|
|
6
9
|
description?: string;
|
|
@@ -32,8 +35,11 @@ const {
|
|
|
32
35
|
tags,
|
|
33
36
|
title,
|
|
34
37
|
} = Astro.props;
|
|
35
|
-
const
|
|
36
|
-
const
|
|
38
|
+
const { content: strings } = contentStrings(data, Astro.currentLocale);
|
|
39
|
+
const updateLabel = label ?? title ?? strings.update;
|
|
40
|
+
// The anchor comes from the authored label only: the localized fallback
|
|
41
|
+
// heading would give an unlabeled update a different anchor per locale.
|
|
42
|
+
const id = providedId ?? (componentSlug(label ?? title ?? "") || "update");
|
|
37
43
|
const tagList = Array.isArray(tags) ? tags : tags ? [tags] : [];
|
|
38
44
|
---
|
|
39
45
|
|
|
@@ -128,8 +128,11 @@ export const extractTypeTable = async (
|
|
|
128
128
|
return checker.getPropertiesOfType(type).map((symbol) => {
|
|
129
129
|
const decl = symbol.declarations?.[0];
|
|
130
130
|
const signature = decl && ts.isPropertySignature(decl) ? decl : undefined;
|
|
131
|
+
// Slice the text from the file that declares the property: an inherited
|
|
132
|
+
// member (`Props extends Base`, Base imported) lives in another file, and
|
|
133
|
+
// its positions mean nothing in the documented one.
|
|
131
134
|
const typeText = signature?.type
|
|
132
|
-
? signature.type.getText(
|
|
135
|
+
? signature.type.getText(signature.getSourceFile())
|
|
133
136
|
: checker.typeToString(
|
|
134
137
|
checker.getTypeOfSymbolAtLocation(symbol, decl ?? declaration)
|
|
135
138
|
);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** The named color each documented Badge `variant` paints with. */
|
|
2
|
+
const VARIANT_COLOR = new Map([
|
|
3
|
+
["accent", "blue"],
|
|
4
|
+
["danger", "red"],
|
|
5
|
+
["default", "gray"],
|
|
6
|
+
["success", "green"],
|
|
7
|
+
["warning", "orange"],
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The color a badge renders with: an explicit `color` wins, then the
|
|
12
|
+
* variant's hue. MDX props aren't type-checked, so a variant Badge doesn't
|
|
13
|
+
* know (`info`, which Callout accepts) renders as the default gray badge
|
|
14
|
+
* instead of failing the page build.
|
|
15
|
+
*/
|
|
16
|
+
export const badgeColorName = (variant: string, color?: string): string =>
|
|
17
|
+
color ?? VARIANT_COLOR.get(variant) ?? "gray";
|
|
@@ -3,17 +3,32 @@ import data from "blume:data";
|
|
|
3
3
|
import {
|
|
4
4
|
isInternalPath,
|
|
5
5
|
normalizeBasePath,
|
|
6
|
+
withBasePath,
|
|
6
7
|
withComposedBasePath,
|
|
7
8
|
} from "../../core/base-path.ts";
|
|
9
|
+
import { routeSetFor, servesRoute } from "../../core/locale-links.ts";
|
|
8
10
|
|
|
9
11
|
// Mirrors `markdown/base-links.ts`: a path whose final segment carries a file
|
|
10
12
|
// extension is a `public/` asset, served at the site root and never moved
|
|
11
|
-
// under `basePath
|
|
12
|
-
|
|
13
|
+
// under `basePath` — unless a page is served there (a dotted route like
|
|
14
|
+
// `/releases/v1.2`).
|
|
15
|
+
const DOTTED_PATH = /\.[a-z0-9]+$/iu;
|
|
13
16
|
|
|
14
17
|
/** Strip any `#fragment`/`?query` so only the path is extension-tested. */
|
|
15
18
|
const pathOf = (url: string): string => url.replace(/[#?].*$/u, "");
|
|
16
19
|
|
|
20
|
+
/** Whether an internal `href` links a page rather than a public asset. */
|
|
21
|
+
const isPageHref = (href: string): boolean => {
|
|
22
|
+
const path = pathOf(href);
|
|
23
|
+
return (
|
|
24
|
+
!DOTTED_PATH.test(path) ||
|
|
25
|
+
servesRoute(
|
|
26
|
+
routeSetFor(data.routes),
|
|
27
|
+
withBasePath(data.config.basePath, path)
|
|
28
|
+
)
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
17
32
|
/**
|
|
18
33
|
* Rebase a component-emitted `href` the way `markdown/base-links.ts` rebases
|
|
19
34
|
* `[x](/guide)`: a root-relative internal page link gains the composed
|
|
@@ -24,7 +39,7 @@ const pathOf = (url: string): string => url.replace(/[#?].*$/u, "");
|
|
|
24
39
|
* asset links.
|
|
25
40
|
*/
|
|
26
41
|
export const contentHref = (href: string): string =>
|
|
27
|
-
isInternalPath(href) &&
|
|
42
|
+
isInternalPath(href) && isPageHref(href)
|
|
28
43
|
? withComposedBasePath(
|
|
29
44
|
normalizeBasePath(import.meta.env.BASE_URL),
|
|
30
45
|
data.config.basePath,
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { createSatteriMarkdownProcessor } from "@astrojs/markdown-satteri";
|
|
2
|
+
import { defineMdastPlugin } from "satteri";
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Shared helpers for components that render a short Markdown prop (a caption,
|
|
3
6
|
* a description, a tooltip label) into inline HTML injected via `set:html`.
|
|
@@ -5,14 +8,19 @@
|
|
|
5
8
|
*/
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
|
-
* Neutralize raw HTML in a Markdown-rendered text prop
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Neutralize raw HTML in a Markdown-rendered text prop: each raw HTML node
|
|
12
|
+
* the parser finds (an inline tag, a block, a comment) renders as its literal
|
|
13
|
+
* text instead. Deciding in the tree rather than escaping `<`/`>` in the
|
|
14
|
+
* source keeps what only looks like HTML intact — a code span's
|
|
15
|
+
* `` `Array<string>` `` and an autolink's `<https://…>` — and `&` entity
|
|
16
|
+
* references keep resolving (`©` renders as ©).
|
|
13
17
|
*/
|
|
14
|
-
export const
|
|
15
|
-
|
|
18
|
+
export const rawHtmlAsTextPlugin = defineMdastPlugin({
|
|
19
|
+
html(node, ctx) {
|
|
20
|
+
ctx.replaceNode(node, { type: "text", value: node.value });
|
|
21
|
+
},
|
|
22
|
+
name: "blume-raw-html-as-text",
|
|
23
|
+
});
|
|
16
24
|
|
|
17
25
|
/**
|
|
18
26
|
* Unwrap the `<p>` a block-level Markdown render wraps around single-line
|
|
@@ -26,3 +34,15 @@ export const unwrapParagraph = (html: string): string => {
|
|
|
26
34
|
const match = trimmed.match(/^<p>(?<content>(?:(?!<\/p>)[\s\S])*)<\/p>$/u);
|
|
27
35
|
return match?.groups?.content ?? trimmed;
|
|
28
36
|
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Render a short Markdown text prop to inline HTML, its raw HTML shown as
|
|
40
|
+
* text (see {@link rawHtmlAsTextPlugin}) and a single paragraph unwrapped.
|
|
41
|
+
*/
|
|
42
|
+
export const renderInlineMarkdown = async (value: string): Promise<string> => {
|
|
43
|
+
const processor = await createSatteriMarkdownProcessor({
|
|
44
|
+
mdastPlugins: [rawHtmlAsTextPlugin],
|
|
45
|
+
});
|
|
46
|
+
const rendered = await processor.render(value);
|
|
47
|
+
return unwrapParagraph(rendered.code);
|
|
48
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared clipboard + "Copied" feedback used by every copy affordance (code
|
|
3
|
-
* blocks, page actions, color swatches, prompts, API panels,
|
|
3
|
+
* blocks, page actions, color swatches, prompts, API panels, the assistant). One
|
|
4
4
|
* implementation owns the invariants each site used to hand-roll:
|
|
5
5
|
*
|
|
6
6
|
* - the clipboard write is guarded and a confirmation must never lie: a
|
|
@@ -16,23 +16,50 @@
|
|
|
16
16
|
/** How long the copied confirmation holds before reverting. */
|
|
17
17
|
const HOLD_MS = 1500;
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* How long a just-inserted live region waits before its first message. Screen
|
|
21
|
+
* readers start watching a region once it is in the document, so text written
|
|
22
|
+
* in the same task as the insertion is often never announced.
|
|
23
|
+
*/
|
|
24
|
+
const REGISTER_MS = 100;
|
|
25
|
+
|
|
19
26
|
/** The shared visually-hidden live region, created on first announcement. */
|
|
20
27
|
let region: HTMLElement | null = null;
|
|
28
|
+
/** Pending while a fresh region registers; its first message waits for it. */
|
|
29
|
+
let registering: ReturnType<typeof setTimeout> | undefined;
|
|
30
|
+
/** The newest message asked for while the region was registering. */
|
|
31
|
+
let queued = "";
|
|
32
|
+
|
|
33
|
+
const write = (target: HTMLElement, message: string): void => {
|
|
34
|
+
// Clear first so repeating the same message is re-announced.
|
|
35
|
+
target.textContent = "";
|
|
36
|
+
target.textContent = message;
|
|
37
|
+
};
|
|
21
38
|
|
|
22
39
|
/**
|
|
23
40
|
* Announce `message` to screen readers. The region is re-created if a swap
|
|
24
|
-
* (view transition, client router) disconnected it
|
|
41
|
+
* (view transition, client router) disconnected it — the router replaces
|
|
42
|
+
* `<body>` on every navigation — and a fresh region gets its first message
|
|
43
|
+
* only after it has had time to register.
|
|
25
44
|
*/
|
|
26
45
|
export const announceCopied = (message: string): void => {
|
|
27
46
|
if (!region?.isConnected) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
document.body.append(
|
|
47
|
+
const fresh = document.createElement("div");
|
|
48
|
+
fresh.setAttribute("role", "status");
|
|
49
|
+
fresh.className = "sr-only";
|
|
50
|
+
document.body.append(fresh);
|
|
51
|
+
region = fresh;
|
|
52
|
+
clearTimeout(registering);
|
|
53
|
+
registering = setTimeout(() => {
|
|
54
|
+
registering = undefined;
|
|
55
|
+
write(fresh, queued);
|
|
56
|
+
}, REGISTER_MS);
|
|
57
|
+
}
|
|
58
|
+
if (registering === undefined) {
|
|
59
|
+
write(region, message);
|
|
60
|
+
} else {
|
|
61
|
+
queued = message;
|
|
32
62
|
}
|
|
33
|
-
// Clear first so repeating the same message is re-announced.
|
|
34
|
-
region.textContent = "";
|
|
35
|
-
region.textContent = message;
|
|
36
63
|
};
|
|
37
64
|
|
|
38
65
|
/**
|