blume 2.0.1 → 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/CHANGELOG.md +82 -0
- package/dist/cli/{chunk-vtk4a6dg.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-yw7dm696.js → chunk-3yce002v.js} +21 -8
- package/dist/cli/{chunk-yw7dm696.js.map → chunk-3yce002v.js.map} +3 -3
- package/dist/cli/{chunk-yt5n7ppj.js → chunk-4e9b9ra6.js} +17 -7
- package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
- package/dist/cli/{chunk-fs23ddbb.js → chunk-5r8g91qn.js} +352 -676
- package/dist/cli/chunk-5r8g91qn.js.map +34 -0
- package/dist/cli/{chunk-6vm74dry.js → chunk-6dtt0zfn.js} +8 -8
- package/dist/cli/{chunk-qwsrynx5.js → chunk-6k4ftwze.js} +38 -19
- package/dist/cli/{chunk-qwsrynx5.js.map → chunk-6k4ftwze.js.map} +4 -4
- package/dist/cli/{chunk-qs4q5p4e.js → chunk-7mbqtmgb.js} +16 -7
- package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
- package/dist/cli/{chunk-q5163e60.js → chunk-7vtckvaw.js} +21 -19
- package/dist/cli/chunk-7vtckvaw.js.map +11 -0
- package/dist/cli/{chunk-kdp5q7ke.js → chunk-8g8ytmgx.js} +17 -18
- package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-8g8ytmgx.js.map} +2 -2
- package/dist/cli/{chunk-epjnccmv.js → chunk-91ws1n6j.js} +18 -15
- package/dist/cli/chunk-91ws1n6j.js.map +10 -0
- package/dist/cli/{chunk-fxypxtvm.js → chunk-bbnwccaz.js} +2 -2
- package/dist/cli/{chunk-m3vmjgmq.js → chunk-bfwp9vp6.js} +16 -8
- package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
- package/dist/cli/{chunk-f2z5v128.js → chunk-d1v5rhy0.js} +14 -15
- package/dist/cli/{chunk-f2z5v128.js.map → chunk-d1v5rhy0.js.map} +2 -2
- package/dist/cli/{chunk-6crbhc3x.js → chunk-ddndchfr.js} +21 -6
- package/dist/cli/chunk-ddndchfr.js.map +14 -0
- package/dist/cli/{chunk-ce574jw2.js → chunk-esh98wmb.js} +1 -1
- package/dist/cli/{chunk-zxcczpyx.js → chunk-fsmrqk8a.js} +1 -1
- package/dist/cli/{chunk-hdpx1tax.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-zxh4d9vy.js → chunk-h2ez8dzb.js} +4 -4
- package/dist/cli/{chunk-5shv93fd.js → chunk-h7k3nq3v.js} +2 -2
- package/dist/cli/{chunk-79jhk4py.js → chunk-hqp2ajnh.js} +251 -122
- package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
- package/dist/cli/{chunk-2hn4b8z7.js → chunk-hr8ne106.js} +109 -40
- package/dist/cli/chunk-hr8ne106.js.map +13 -0
- package/dist/cli/{chunk-6hsn950k.js → chunk-j85scx15.js} +62 -18
- package/dist/cli/chunk-j85scx15.js.map +10 -0
- package/dist/cli/{chunk-s1p84fyh.js → chunk-k7pj68a8.js} +63 -22
- package/dist/cli/chunk-k7pj68a8.js.map +11 -0
- package/dist/cli/{chunk-ah61y8py.js → chunk-mqc662a6.js} +2 -2
- package/dist/cli/{chunk-ch6g3ar0.js → chunk-n1yg3tj3.js} +4 -4
- package/dist/cli/{chunk-mb2919y2.js → chunk-nfcyttvj.js} +17 -6
- package/dist/cli/chunk-nfcyttvj.js.map +10 -0
- package/dist/cli/{chunk-kpf8rrjc.js → chunk-pbg5a4s3.js} +56 -24
- package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
- package/dist/cli/{chunk-jwyddg7y.js → chunk-ppzjqwx2.js} +21 -14
- package/dist/cli/{chunk-jwyddg7y.js.map → chunk-ppzjqwx2.js.map} +4 -4
- package/dist/cli/{chunk-dh8cwk36.js → chunk-qkb5a8sa.js} +24 -9
- package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
- package/dist/cli/{chunk-wm7js3j9.js → chunk-sqw4ekg1.js} +2 -2
- package/dist/cli/{chunk-qkqwkpte.js → chunk-v6ya5kcb.js} +3083 -953
- package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
- package/dist/cli/{chunk-fz5wtpmh.js → chunk-w4bxdvsa.js} +18 -15
- package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
- package/dist/cli/{chunk-27g6wdth.js → chunk-wdrt2k2v.js} +2 -2
- package/dist/cli/{chunk-wgm7m9qk.js → chunk-xh43dwgw.js} +158 -43
- package/dist/cli/chunk-xh43dwgw.js.map +36 -0
- package/dist/cli/{chunk-s6jhgk0q.js → chunk-zp79m0ts.js} +2 -2
- package/dist/cli/index.js +160 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +7 -0
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/relative-links.d.ts +9 -4
- package/dist/types/ai/static-expression.d.ts +28 -0
- 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 +4 -4
- package/dist/types/core/config.d.ts +2 -2
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/i18n-ui.d.ts +31 -0
- 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 +52 -13
- 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/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/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +17 -8
- package/docs/08-faq.mdx +9 -2
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +4 -2
- package/docs/cli/audit.mdx +2 -2
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +2 -2
- package/docs/cli/index.mdx +4 -1
- package/docs/cli/translate.mdx +1 -1
- package/docs/configuration/analytics.mdx +23 -2
- package/docs/configuration/assistant.mdx +1 -1
- package/docs/configuration/customization.mdx +4 -3
- package/docs/configuration/index.mdx +5 -3
- package/docs/configuration/search.mdx +1 -1
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/index.mdx +4 -2
- 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 +21 -7
- package/docs/discoverability/index.mdx +2 -2
- 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/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-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-surface.ts +56 -0
- package/src/ai/api/spec.ts +15 -2
- package/src/ai/api-catalog.ts +7 -1
- package/src/ai/ask-context.ts +14 -2
- package/src/ai/ask-data.ts +26 -12
- package/src/ai/component-markdown.ts +43 -37
- 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/relative-links.ts +78 -10
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/visibility.ts +45 -14
- 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 +71 -27
- package/src/astro/templates.ts +61 -23
- 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/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +7 -0
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/eval.ts +1 -7
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +9 -6
- package/src/cli/commands/upgrade.ts +11 -0
- 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/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 +35 -8
- package/src/components/islands/assistant.tsx +16 -2
- package/src/components/islands/hooks.ts +7 -2
- package/src/components/islands/webmcp.ts +12 -8
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Header.astro +22 -9
- 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 +22 -8
- package/src/components/layout/ReferenceLayout.astro +4 -1
- package/src/components/layout/RootLayout.astro +21 -8
- package/src/components/layout/Search.astro +5 -1
- package/src/components/layout/analytics-client.ts +2 -0
- 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/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/config-input.ts +4 -4
- package/src/core/config.ts +18 -4
- package/src/core/diagnostics.ts +217 -30
- package/src/core/graph.ts +120 -11
- package/src/core/i18n-ui.ts +39 -2
- 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/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +70 -14
- 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 +13 -0
- package/src/core/ui-packs/bg.ts +13 -0
- package/src/core/ui-packs/bn.ts +13 -0
- package/src/core/ui-packs/ca.ts +13 -0
- package/src/core/ui-packs/cs.ts +13 -0
- package/src/core/ui-packs/da.ts +13 -0
- package/src/core/ui-packs/de.ts +13 -0
- package/src/core/ui-packs/el.ts +13 -0
- package/src/core/ui-packs/es.ts +13 -0
- package/src/core/ui-packs/fa.ts +13 -0
- package/src/core/ui-packs/fi.ts +13 -0
- package/src/core/ui-packs/fr.ts +13 -0
- package/src/core/ui-packs/he.ts +13 -0
- package/src/core/ui-packs/hi.ts +13 -0
- package/src/core/ui-packs/hr.ts +13 -0
- package/src/core/ui-packs/hu.ts +13 -0
- package/src/core/ui-packs/id.ts +13 -0
- package/src/core/ui-packs/it.ts +13 -0
- package/src/core/ui-packs/ja.ts +13 -0
- package/src/core/ui-packs/ko.ts +13 -0
- package/src/core/ui-packs/nl.ts +13 -0
- package/src/core/ui-packs/no.ts +13 -0
- package/src/core/ui-packs/pl.ts +13 -0
- package/src/core/ui-packs/pt-br.ts +13 -0
- package/src/core/ui-packs/pt.ts +13 -0
- package/src/core/ui-packs/ro.ts +13 -0
- package/src/core/ui-packs/ru.ts +13 -0
- package/src/core/ui-packs/sk.ts +13 -0
- package/src/core/ui-packs/sr.ts +13 -0
- package/src/core/ui-packs/sv.ts +13 -0
- package/src/core/ui-packs/th.ts +13 -0
- package/src/core/ui-packs/tr.ts +13 -0
- package/src/core/ui-packs/uk.ts +13 -0
- package/src/core/ui-packs/vi.ts +13 -0
- package/src/core/ui-packs/zh-tw.ts +13 -0
- package/src/core/ui-packs/zh.ts +13 -0
- 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 +119 -22
- package/src/search/documents.ts +22 -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/run.ts +11 -5
- package/src/translate/validate.ts +10 -1
- package/src/translate/work-list.ts +36 -3
- package/src/upgrade/upgrade.ts +36 -4
- package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
- package/dist/cli/chunk-6crbhc3x.js.map +0 -14
- package/dist/cli/chunk-6hsn950k.js.map +0 -10
- package/dist/cli/chunk-79jhk4py.js.map +0 -35
- package/dist/cli/chunk-82bbrxdn.js +0 -51
- package/dist/cli/chunk-82bbrxdn.js.map +0 -10
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-dh8cwk36.js.map +0 -10
- package/dist/cli/chunk-epjnccmv.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-fs23ddbb.js.map +0 -35
- package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
- package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
- package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
- package/dist/cli/chunk-mb2919y2.js.map +0 -10
- package/dist/cli/chunk-q5163e60.js.map +0 -11
- package/dist/cli/chunk-qkqwkpte.js.map +0 -182
- package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
- package/dist/cli/chunk-s1p84fyh.js.map +0 -10
- package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
- package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
- /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-00gs3wqs.js.map} +0 -0
- /package/dist/cli/{chunk-6vm74dry.js.map → chunk-6dtt0zfn.js.map} +0 -0
- /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-bbnwccaz.js.map} +0 -0
- /package/dist/cli/{chunk-ce574jw2.js.map → chunk-esh98wmb.js.map} +0 -0
- /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-fsmrqk8a.js.map} +0 -0
- /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-g698a744.js.map} +0 -0
- /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-h2ez8dzb.js.map} +0 -0
- /package/dist/cli/{chunk-5shv93fd.js.map → chunk-h7k3nq3v.js.map} +0 -0
- /package/dist/cli/{chunk-ah61y8py.js.map → chunk-mqc662a6.js.map} +0 -0
- /package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-n1yg3tj3.js.map} +0 -0
- /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-sqw4ekg1.js.map} +0 -0
- /package/dist/cli/{chunk-27g6wdth.js.map → chunk-wdrt2k2v.js.map} +0 -0
- /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-zp79m0ts.js.map} +0 -0
|
@@ -308,12 +308,17 @@ export const useAssistant = (
|
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
310
|
if (live()) {
|
|
311
|
-
// A 200 with nothing in it (no body, an empty stream)
|
|
312
|
-
//
|
|
311
|
+
// A 200 with nothing in it (no body, an empty stream) is not an
|
|
312
|
+
// answer. It is also how a provider failure after the 200 arrives
|
|
313
|
+
// (a bad key, a rate limit, an unknown model): the route's text
|
|
314
|
+
// stream carries only text, so the error ends it empty. Show the
|
|
315
|
+
// error notice instead of leaving a pulsing blank bubble.
|
|
313
316
|
if (assistant.content) {
|
|
314
317
|
outcome("ask_answer", { chars: assistant.content.length });
|
|
315
318
|
} else {
|
|
316
319
|
outcome("ask_error", { status });
|
|
320
|
+
assistant.content = errorMessage;
|
|
321
|
+
setMessages([...history, { ...assistant }]);
|
|
317
322
|
}
|
|
318
323
|
}
|
|
319
324
|
} catch {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { unescape } from "html-escaper";
|
|
2
|
+
|
|
1
3
|
import type { SearchFn } from "../layout/search/types.ts";
|
|
2
4
|
import { joinBase, prefixBase } from "./base-path.ts";
|
|
3
5
|
|
|
@@ -80,13 +82,15 @@ const isCallable = <T extends (...args: never[]) => void>(
|
|
|
80
82
|
const TAG = /<[^>]*>?/gu;
|
|
81
83
|
|
|
82
84
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
85
|
+
* Search-hit HTML as the plain text an agent reads: the `<mark>`
|
|
86
|
+
* highlighting (and any other markup) dropped, then the entities the
|
|
87
|
+
* highlighter escaped decoded (`<T> &` → `<T> &`). The closing `>`
|
|
88
|
+
* is optional so every `<` starts a strip: a dangling `<script` fragment
|
|
89
|
+
* can't survive the way it would if a full `<...>` pair were required. The
|
|
90
|
+
* input is HTML, where a literal `<` is `<`, so consuming from every raw
|
|
91
|
+
* `<` loses nothing legitimate. Stripping repeats to a fixed point so the
|
|
92
|
+
* no-fragment guarantee is explicit rather than an artifact of the regex
|
|
93
|
+
* shape; decoding comes last, so a decoded `<` is text, never a tag.
|
|
90
94
|
*/
|
|
91
95
|
const plain = (html: string): string => {
|
|
92
96
|
let stripped = html;
|
|
@@ -95,7 +99,7 @@ const plain = (html: string): string => {
|
|
|
95
99
|
previous = stripped;
|
|
96
100
|
stripped = stripped.replaceAll(TAG, "");
|
|
97
101
|
} while (stripped !== previous);
|
|
98
|
-
return stripped;
|
|
102
|
+
return unescape(stripped);
|
|
99
103
|
};
|
|
100
104
|
|
|
101
105
|
export interface WebMcpToolOptions {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
import data from "blume:data";
|
|
2
3
|
import { EN_UI } from "../../core/i18n-ui.ts";
|
|
3
4
|
import type { UIStrings } from "../../core/i18n-ui.ts";
|
|
4
5
|
import { withBase } from "../islands/base-path.ts";
|
|
@@ -18,13 +19,31 @@ interface Props {
|
|
|
18
19
|
| null;
|
|
19
20
|
/** Localized banner labels. */
|
|
20
21
|
strings?: UIStrings["banner"];
|
|
22
|
+
/**
|
|
23
|
+
* Active locale of the page. The link follows it the way the sidebar's
|
|
24
|
+
* featured links do (`/guide` -> `/fr/guide` when French serves it).
|
|
25
|
+
* Absent, the link resolves for the default locale.
|
|
26
|
+
*/
|
|
27
|
+
locale?: string;
|
|
21
28
|
}
|
|
22
29
|
|
|
23
|
-
const { banner, strings } = Astro.props;
|
|
30
|
+
const { banner, strings, locale } = Astro.props;
|
|
24
31
|
// Merge over the English baseline per key (rather than `strings ?? …`) so a
|
|
25
32
|
// partial — or missing — strings object still resolves every label to a
|
|
26
33
|
// default, matching the pattern PageFeedback and Search use.
|
|
27
34
|
const b = { ...EN_UI.banner, ...strings };
|
|
35
|
+
// The configured `banner.link.href` is authored as if the site were mounted at
|
|
36
|
+
// root, in the default locale's path space; the locale's navigation carries it
|
|
37
|
+
// localized and mounted under `basePath` (the default navigation on a
|
|
38
|
+
// single-locale site). A banner a custom page passes with a link of its own
|
|
39
|
+
// renders that link as given.
|
|
40
|
+
const navigation =
|
|
41
|
+
(locale === undefined ? undefined : data.navigationByLocale[locale]) ??
|
|
42
|
+
data.navigation;
|
|
43
|
+
const linkHref =
|
|
44
|
+
banner?.link && banner.link.href === data.config.banner?.link?.href
|
|
45
|
+
? (navigation.bannerHref ?? banner.link.href)
|
|
46
|
+
: banner?.link?.href;
|
|
28
47
|
---
|
|
29
48
|
|
|
30
49
|
{
|
|
@@ -37,13 +56,13 @@ const b = { ...EN_UI.banner, ...strings };
|
|
|
37
56
|
{/* The message is authored in one language, whatever the page's
|
|
38
57
|
direction: `dir="auto"` keeps its punctuation where it was typed. */}
|
|
39
58
|
<span dir="auto">{banner.content}</span>
|
|
40
|
-
{banner.link && (
|
|
59
|
+
{banner.link && linkHref && (
|
|
41
60
|
<a
|
|
42
61
|
class="inline-flex items-center gap-1 font-medium underline underline-offset-2"
|
|
43
|
-
href={withBase(
|
|
62
|
+
href={withBase(linkHref)}
|
|
44
63
|
>
|
|
45
64
|
{banner.link.text}
|
|
46
|
-
<Icon name="arrow-right" size={14} />
|
|
65
|
+
<Icon class="rtl:-scale-x-100" name="arrow-right" size={14} />
|
|
47
66
|
</a>
|
|
48
67
|
)}
|
|
49
68
|
{banner.dismissible && (
|
|
@@ -17,6 +17,7 @@ import LanguageSwitcher from "./LanguageSwitcher.astro";
|
|
|
17
17
|
import Logo from "./Logo.astro";
|
|
18
18
|
import { currentTabForRoute } from "./nav-utils.ts";
|
|
19
19
|
import NavSelector from "./NavSelector.astro";
|
|
20
|
+
import NavTabMenu from "./NavTabMenu.astro";
|
|
20
21
|
import { resolveSlot } from "./overrides.ts";
|
|
21
22
|
import Search from "./Search.astro";
|
|
22
23
|
|
|
@@ -216,15 +217,27 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
|
|
|
216
217
|
{
|
|
217
218
|
navigation.tabs.length > 0 && (
|
|
218
219
|
<nav aria-label={n.sections} class={tabsNavClass}>
|
|
219
|
-
{navigation.tabs.map((tab) =>
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
220
|
+
{navigation.tabs.map((tab) =>
|
|
221
|
+
tab.items && tab.items.length > 0 ? (
|
|
222
|
+
<NavTabMenu
|
|
223
|
+
active={tab === activeTab}
|
|
224
|
+
route={route}
|
|
225
|
+
tab={tab}
|
|
226
|
+
variant="bar"
|
|
227
|
+
/>
|
|
228
|
+
) : (
|
|
229
|
+
<a
|
|
230
|
+
aria-current={tab === activeTab ? "page" : undefined}
|
|
231
|
+
class="inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:text-foreground"
|
|
232
|
+
href={withBase(tab.href ?? tab.path)}
|
|
233
|
+
>
|
|
234
|
+
{tab.icon && (
|
|
235
|
+
<Icon class="shrink-0" name={tab.icon} size={14} />
|
|
236
|
+
)}
|
|
237
|
+
{tab.label}
|
|
238
|
+
</a>
|
|
239
|
+
)
|
|
240
|
+
)}
|
|
228
241
|
</nav>
|
|
229
242
|
)
|
|
230
243
|
}
|
|
@@ -47,9 +47,14 @@ const brandHref =
|
|
|
47
47
|
// it's omitted. An explicit `""` hides it (an image-only logo whose mark already
|
|
48
48
|
// carries the wordmark).
|
|
49
49
|
const brandText = logo?.text ?? site.title;
|
|
50
|
+
// Without a wordmark the link's only content is the mark, and an inline SVG
|
|
51
|
+
// mark is decorative (`aria-hidden`), so the link would have no accessible
|
|
52
|
+
// name. Name it after the image's `alt`, else the site title.
|
|
53
|
+
const linkLabel = brandText ? undefined : logoAlt || site.title;
|
|
50
54
|
---
|
|
51
55
|
|
|
52
56
|
<a
|
|
57
|
+
aria-label={linkLabel}
|
|
53
58
|
class="inline-flex min-w-0 items-center gap-2 font-semibold text-base text-foreground"
|
|
54
59
|
href={withBase(brandHref)}
|
|
55
60
|
>
|
|
@@ -38,6 +38,11 @@ const active =
|
|
|
38
38
|
// it switches. Longer product names still collapse to the icon there.
|
|
39
39
|
const label = active?.label ?? selector.label;
|
|
40
40
|
const labelClass = label.length <= 6 ? undefined : "max-sm:hidden";
|
|
41
|
+
// The accessible name carries the visible active label too (WCAG 2.5.3,
|
|
42
|
+
// label in name), so a voice-control user can say "v2" to open it — the
|
|
43
|
+
// language switcher's pattern.
|
|
44
|
+
const summaryLabel =
|
|
45
|
+
label === selector.label ? selector.label : `${selector.label}: ${label}`;
|
|
41
46
|
|
|
42
47
|
const iconButton =
|
|
43
48
|
"inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-full border border-border bg-background px-3 text-muted-foreground text-sm transition-colors hover:border-foreground hover:text-foreground";
|
|
@@ -49,7 +54,7 @@ const menuRowClass =
|
|
|
49
54
|
selector.items.length > 0 && (
|
|
50
55
|
<details class="group relative" data-blume-dropdown>
|
|
51
56
|
<summary
|
|
52
|
-
aria-label={
|
|
57
|
+
aria-label={summaryLabel}
|
|
53
58
|
class={`${iconButton} list-none [&::-webkit-details-marker]:hidden`}
|
|
54
59
|
>
|
|
55
60
|
{active?.icon && <Icon name={active.icon} size={16} />}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
// A header tab with dropdown `items` (`navigation.tabs[].items`). In the
|
|
3
|
+
// header's tab bar (`variant="bar"`) it is the nav selectors' floating
|
|
4
|
+
// `<details>` dropdown: the `<summary>` is the disclosure button (the browser
|
|
5
|
+
// exposes its expanded state), the panel a list of links, and the shared
|
|
6
|
+
// light-dismiss closes it on an outside press, Escape (focus returns to the
|
|
7
|
+
// tab), or focus leaving it. In a navigation drawer (`variant="drawer"`) the
|
|
8
|
+
// same items expand in place under the tab, like a sidebar group, open from
|
|
9
|
+
// the start on the tab's own section. Both are server-rendered and the scripts
|
|
10
|
+
// delegate from `document`, so client-router swaps need no re-init.
|
|
11
|
+
import type { NavTab } from "../../core/types.ts";
|
|
12
|
+
import Icon from "../Icon.astro";
|
|
13
|
+
import { withBase } from "../islands/base-path.ts";
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
tab: NavTab;
|
|
17
|
+
/** The page's route, to mark the item it is on. */
|
|
18
|
+
route: string;
|
|
19
|
+
/** Whether the current route falls under this tab. */
|
|
20
|
+
active: boolean;
|
|
21
|
+
variant: "bar" | "drawer";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { tab, route, active, variant } = Astro.props;
|
|
25
|
+
const items = tab.items ?? [];
|
|
26
|
+
// The tab itself is a button, not a page, so its "you are here" state is
|
|
27
|
+
// `aria-current="true"` (current item of a set); an item is the page.
|
|
28
|
+
const tabCurrent = active ? "true" : undefined;
|
|
29
|
+
const itemCurrent = (path: string): "page" | undefined =>
|
|
30
|
+
path === route ? "page" : undefined;
|
|
31
|
+
|
|
32
|
+
const barRowClass =
|
|
33
|
+
"flex w-full items-start gap-2.5 rounded-md px-2 py-1.5 text-start text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:text-foreground";
|
|
34
|
+
const drawerRowClass =
|
|
35
|
+
"flex items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:text-foreground";
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
{
|
|
39
|
+
variant === "bar" ? (
|
|
40
|
+
<details class="group relative" data-blume-dropdown>
|
|
41
|
+
<summary
|
|
42
|
+
aria-current={tabCurrent}
|
|
43
|
+
class="inline-flex cursor-pointer list-none items-center gap-1 rounded-full px-3 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=true]:text-foreground [&::-webkit-details-marker]:hidden"
|
|
44
|
+
>
|
|
45
|
+
{tab.icon && (
|
|
46
|
+
<Icon class="me-0.5 shrink-0" name={tab.icon} size={14} />
|
|
47
|
+
)}
|
|
48
|
+
{tab.label}
|
|
49
|
+
<Icon
|
|
50
|
+
class="transition-transform group-open:rotate-180"
|
|
51
|
+
name="chevron-down"
|
|
52
|
+
size={14}
|
|
53
|
+
/>
|
|
54
|
+
</summary>
|
|
55
|
+
<div
|
|
56
|
+
class="absolute start-0 z-50 mt-2 min-w-56 max-w-[calc(100vw-1rem)] rounded-blume border border-border bg-background p-1 shadow-xl"
|
|
57
|
+
data-blume-dropdown-panel
|
|
58
|
+
>
|
|
59
|
+
{items.map((item) => (
|
|
60
|
+
<a
|
|
61
|
+
aria-current={itemCurrent(item.path)}
|
|
62
|
+
class={barRowClass}
|
|
63
|
+
href={withBase(item.path)}
|
|
64
|
+
>
|
|
65
|
+
{item.icon && <Icon class="mt-0.5" name={item.icon} size={16} />}
|
|
66
|
+
<span class="flex-1">
|
|
67
|
+
<span class="flex items-center gap-2">
|
|
68
|
+
{item.label}
|
|
69
|
+
{item.tag && (
|
|
70
|
+
<span class="rounded-full bg-muted px-1.5 py-0.5 text-[0.65rem] text-muted-foreground">
|
|
71
|
+
{item.tag}
|
|
72
|
+
</span>
|
|
73
|
+
)}
|
|
74
|
+
</span>
|
|
75
|
+
{item.description && (
|
|
76
|
+
<span class="mt-0.5 block text-muted-foreground text-xs">
|
|
77
|
+
{item.description}
|
|
78
|
+
</span>
|
|
79
|
+
)}
|
|
80
|
+
</span>
|
|
81
|
+
</a>
|
|
82
|
+
))}
|
|
83
|
+
</div>
|
|
84
|
+
</details>
|
|
85
|
+
) : (
|
|
86
|
+
<details class="group" open={active}>
|
|
87
|
+
<summary
|
|
88
|
+
aria-current={tabCurrent}
|
|
89
|
+
class="flex cursor-pointer list-none items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=true]:text-foreground [&::-webkit-details-marker]:hidden"
|
|
90
|
+
>
|
|
91
|
+
{tab.icon && <Icon class="shrink-0" name={tab.icon} size={14} />}
|
|
92
|
+
<span class="flex-1 truncate">{tab.label}</span>
|
|
93
|
+
<Icon
|
|
94
|
+
class="shrink-0 transition-transform group-open:rotate-180"
|
|
95
|
+
name="chevron-down"
|
|
96
|
+
size={14}
|
|
97
|
+
/>
|
|
98
|
+
</summary>
|
|
99
|
+
<ul class="m-0 ms-2.5 list-none space-y-px border-border border-s p-0 ps-2">
|
|
100
|
+
{items.map((item) => (
|
|
101
|
+
<li>
|
|
102
|
+
<a
|
|
103
|
+
aria-current={itemCurrent(item.path)}
|
|
104
|
+
class={drawerRowClass}
|
|
105
|
+
href={withBase(item.path)}
|
|
106
|
+
>
|
|
107
|
+
{item.icon && (
|
|
108
|
+
<Icon class="shrink-0" name={item.icon} size={14} />
|
|
109
|
+
)}
|
|
110
|
+
<span class="flex-1 truncate">{item.label}</span>
|
|
111
|
+
{item.tag && (
|
|
112
|
+
<span class="shrink-0 rounded-full bg-muted px-1.5 py-0.5 text-[0.65rem] text-muted-foreground">
|
|
113
|
+
{item.tag}
|
|
114
|
+
</span>
|
|
115
|
+
)}
|
|
116
|
+
</a>
|
|
117
|
+
</li>
|
|
118
|
+
))}
|
|
119
|
+
</ul>
|
|
120
|
+
</details>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
<script>
|
|
125
|
+
import { installDropdownDismiss } from "../dropdown-dismiss.ts";
|
|
126
|
+
import { installDropdownClamp } from "./dropdown-clamp.ts";
|
|
127
|
+
|
|
128
|
+
// Outside-click / Escape / focus-out dismissal and viewport clamping for
|
|
129
|
+
// the header dropdown, shared with the nav selectors. The drawer variant
|
|
130
|
+
// opts into neither: it is an in-place disclosure, not a floating panel.
|
|
131
|
+
installDropdownDismiss();
|
|
132
|
+
installDropdownClamp();
|
|
133
|
+
</script>
|
|
@@ -79,6 +79,9 @@ const fragmentFor = (node: NavNode, id: string): string | undefined =>
|
|
|
79
79
|
// blank — the PageActions pattern.
|
|
80
80
|
const n = { ...EN_UI.nav, ...strings };
|
|
81
81
|
|
|
82
|
+
/** The DOM id of a drill-in panel, which its drill button controls. */
|
|
83
|
+
const navPanelId = (id: string): string => `blume-nav-panel-${id}`;
|
|
84
|
+
|
|
82
85
|
const badgeBase =
|
|
83
86
|
"shrink-0 rounded-full px-1.5 py-0.5 font-medium text-[0.65rem] leading-none";
|
|
84
87
|
// HTTP-method, AsyncAPI-action, and GraphQL operation-kind badges (from a
|
|
@@ -165,6 +168,7 @@ const initialId =
|
|
|
165
168
|
data-nav-panel={panel.id}
|
|
166
169
|
data-nav-src={src}
|
|
167
170
|
hidden={panel.id !== initialId}
|
|
171
|
+
id={navPanelId(panel.id)}
|
|
168
172
|
>
|
|
169
173
|
{/* The title is the only sidebar link to the section's own page, so
|
|
170
174
|
a routed panel keeps it as a link; without a route the whole row
|
|
@@ -174,7 +178,7 @@ const initialId =
|
|
|
174
178
|
<div class="mb-3 flex items-center gap-0.5">
|
|
175
179
|
<button
|
|
176
180
|
aria-label={n.back}
|
|
177
|
-
class="-
|
|
181
|
+
class="-ms-1 flex shrink-0 items-center justify-center self-stretch rounded-[0.65rem] px-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
|
|
178
182
|
data-nav-back={panel.parentId}
|
|
179
183
|
type="button"
|
|
180
184
|
>
|
|
@@ -195,7 +199,7 @@ const initialId =
|
|
|
195
199
|
) : (
|
|
196
200
|
<button
|
|
197
201
|
aria-label={`${n.back}: ${panel.label}`}
|
|
198
|
-
class="-
|
|
202
|
+
class="-ms-1 mb-3 flex w-full items-center gap-1.5 rounded-[0.65rem] p-1 text-start font-semibold text-foreground text-sm transition-colors hover:bg-muted"
|
|
199
203
|
data-nav-back={panel.parentId}
|
|
200
204
|
type="button"
|
|
201
205
|
>
|
|
@@ -293,11 +297,16 @@ const initialId =
|
|
|
293
297
|
const spacing =
|
|
294
298
|
index === 0 ? "mt-0" : display === "flat" ? "mt-6" : "mt-0.5";
|
|
295
299
|
|
|
296
|
-
// `page`: a single row that drills into this group's panel.
|
|
300
|
+
// `page`: a single row that drills into this group's panel. It
|
|
301
|
+
// controls that panel; NavTreeScript keeps `aria-expanded` in step
|
|
302
|
+
// with the panel shown (static markup, since cached subtrees and
|
|
303
|
+
// fragments can't carry per-page state).
|
|
297
304
|
if (display === "page") {
|
|
298
305
|
return (
|
|
299
306
|
<li class={spacing}>
|
|
300
307
|
<button
|
|
308
|
+
aria-controls={navPanelId(id)}
|
|
309
|
+
aria-expanded="false"
|
|
301
310
|
class="blume-nav-drill"
|
|
302
311
|
data-nav-to={id}
|
|
303
312
|
type="button"
|
|
@@ -377,7 +386,7 @@ const initialId =
|
|
|
377
386
|
</span>
|
|
378
387
|
</summary>
|
|
379
388
|
<div
|
|
380
|
-
class="space-y-0.5 border-border border-
|
|
389
|
+
class="space-y-0.5 border-border border-s ps-3"
|
|
381
390
|
data-nav-src={open ? undefined : fragmentFor(item, id)}
|
|
382
391
|
>
|
|
383
392
|
{/* A closed group's children are deferred (fetched into this
|
|
@@ -434,7 +443,7 @@ const initialId =
|
|
|
434
443
|
)}
|
|
435
444
|
<span class="truncate">{item.label}</span>
|
|
436
445
|
{item.badge && (
|
|
437
|
-
<span class={`
|
|
446
|
+
<span class={`ms-auto ${badgeClassFor(item.badge)}`}>{item.badge}</span>
|
|
438
447
|
)}
|
|
439
448
|
</a>
|
|
440
449
|
) : (
|
|
@@ -448,7 +457,7 @@ const initialId =
|
|
|
448
457
|
)}
|
|
449
458
|
<span class="truncate">{item.label}</span>
|
|
450
459
|
{item.badge && (
|
|
451
|
-
<span class={`
|
|
460
|
+
<span class={`ms-auto ${badgeClassFor(item.badge)}`}>{item.badge}</span>
|
|
452
461
|
)}
|
|
453
462
|
</>
|
|
454
463
|
)}
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
// once per group instead of once per page. Off in dev, where component edits
|
|
5
5
|
// must show on the next request. The cached HTML references the page's icon
|
|
6
6
|
// sprite (see icon-sprite.ts), so the symbols it used ride along and are
|
|
7
|
-
// registered into whichever page reuses it.
|
|
7
|
+
// registered into whichever page reuses it. A render with no sprite (the
|
|
8
|
+
// `/blume-nav/` fragment route) inlines its icons instead, so it is cached
|
|
9
|
+
// apart: sprite references reused there would point at symbols the page that
|
|
10
|
+
// fetches the fragment may never have rendered.
|
|
8
11
|
import type { NavNode } from "../../core/types.ts";
|
|
9
12
|
import { iconSpriteFor, referencedIconSymbols } from "../icon-sprite.ts";
|
|
10
13
|
import type { IconSymbol } from "../icon-sprite.ts";
|
|
@@ -19,7 +22,7 @@ const { node, variant } = Astro.props;
|
|
|
19
22
|
const sprite = iconSpriteFor(Astro.locals);
|
|
20
23
|
const { html, icons } = await cachedNavSubtree(
|
|
21
24
|
node,
|
|
22
|
-
variant
|
|
25
|
+
`${variant}|${sprite ? "sprite" : "inline"}`,
|
|
23
26
|
async () => {
|
|
24
27
|
const rendered = await Astro.slots.render("default");
|
|
25
28
|
const used: [string, IconSymbol][] = [];
|
|
@@ -40,7 +40,12 @@
|
|
|
40
40
|
return pending;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Fill a deferred element from its fragment; a no-op once filled. The rows
|
|
45
|
+
* are appended, not swapped in: a drill-in panel keeps its own back row
|
|
46
|
+
* (the Back button and the section's title) above the deferred rows, and a
|
|
47
|
+
* collapsed group's slot is empty anyway.
|
|
48
|
+
*/
|
|
44
49
|
const fillDeferred = async (slot: HTMLElement): Promise<void> => {
|
|
45
50
|
const src = slot.dataset.navSrc;
|
|
46
51
|
if (!src) {
|
|
@@ -48,8 +53,12 @@
|
|
|
48
53
|
}
|
|
49
54
|
slot.setAttribute("aria-busy", "true");
|
|
50
55
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
const html = await loadFragment(src);
|
|
57
|
+
// Two opens racing on the same fetch fill it once.
|
|
58
|
+
if (slot.dataset.navSrc) {
|
|
59
|
+
slot.insertAdjacentHTML("beforeend", html);
|
|
60
|
+
delete slot.dataset.navSrc;
|
|
61
|
+
}
|
|
53
62
|
} finally {
|
|
54
63
|
slot.removeAttribute("aria-busy");
|
|
55
64
|
}
|
|
@@ -179,21 +188,52 @@
|
|
|
179
188
|
if (prev === next) {
|
|
180
189
|
return;
|
|
181
190
|
}
|
|
191
|
+
// The pressed drill or back button sits in the panel about to hide, so
|
|
192
|
+
// its focus has to move into the panel replacing it — left behind, the
|
|
193
|
+
// next Tab would leave the sidebar.
|
|
194
|
+
const hadFocus = prev?.contains(document.activeElement) ?? false;
|
|
182
195
|
// Settle any in-flight slide before starting the next one.
|
|
183
196
|
if (this.finishSlide) {
|
|
184
197
|
this.finishSlide();
|
|
185
198
|
}
|
|
186
199
|
this.active = next;
|
|
187
200
|
this.dataset.active = next.dataset.navPanel;
|
|
201
|
+
this.syncExpanded(next);
|
|
188
202
|
|
|
189
203
|
if (!(animate && prev) || this.reduced()) {
|
|
190
204
|
for (const panel of this.querySelectorAll<HTMLElement>("[data-nav-panel]")) {
|
|
191
205
|
panel.hidden = panel !== next;
|
|
192
206
|
}
|
|
193
|
-
|
|
207
|
+
} else {
|
|
208
|
+
this.slide(prev, next, this.depth(next) > this.depth(prev));
|
|
194
209
|
}
|
|
210
|
+
if (hadFocus && prev) {
|
|
211
|
+
this.focusInto(next, prev);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Each drill button is expanded exactly while the panel it opens shows. */
|
|
216
|
+
syncExpanded(shown: HTMLElement): void {
|
|
217
|
+
for (const drill of this.querySelectorAll("[data-nav-to]")) {
|
|
218
|
+
drill.setAttribute(
|
|
219
|
+
"aria-expanded",
|
|
220
|
+
String(drill.getAttribute("data-nav-to") === shown.dataset.navPanel)
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
195
224
|
|
|
196
|
-
|
|
225
|
+
/**
|
|
226
|
+
* Focus `next` after leaving `prev`: going back, the drill button that
|
|
227
|
+
* opened `prev`; drilling in, the new panel's back button (its first
|
|
228
|
+
* control). `preventScroll` keeps the focus from scrolling the clipped
|
|
229
|
+
* container mid-slide.
|
|
230
|
+
*/
|
|
231
|
+
focusInto(next: HTMLElement, prev: HTMLElement): void {
|
|
232
|
+
const target =
|
|
233
|
+
next.querySelector<HTMLElement>(
|
|
234
|
+
`[data-nav-to="${prev.dataset.navPanel}"]`
|
|
235
|
+
) ?? next.querySelector<HTMLElement>("button, a[href]");
|
|
236
|
+
target?.focus({ preventScroll: true });
|
|
197
237
|
}
|
|
198
238
|
|
|
199
239
|
slide(out: HTMLElement, into: HTMLElement, forward: boolean): void {
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
} from "../../og/dimensions.ts";
|
|
39
39
|
import { buildStructuredData } from "../../seo/jsonld.ts";
|
|
40
40
|
import { normalizeXHandle } from "../../seo/x-handle.ts";
|
|
41
|
+
import Icon from "../Icon.astro";
|
|
41
42
|
import { stripBase, withBase } from "../islands/base-path.ts";
|
|
42
43
|
import { pageDirection, pageLocale } from "./page-locale.ts";
|
|
43
44
|
import { searchLocaleFor } from "./search-locale.ts";
|
|
@@ -55,6 +56,7 @@ import {
|
|
|
55
56
|
} from "./head-scripts.ts";
|
|
56
57
|
import Header from "./Header.astro";
|
|
57
58
|
import { currentTabForRoute } from "./nav-utils.ts";
|
|
59
|
+
import NavTabMenu from "./NavTabMenu.astro";
|
|
58
60
|
import WebMcp from "./WebMcp.astro";
|
|
59
61
|
|
|
60
62
|
interface Props {
|
|
@@ -387,7 +389,7 @@ createIconSprite(Astro.locals);
|
|
|
387
389
|
>
|
|
388
390
|
{/* Every new-tab link's aria-describedby target (see core/new-tab.ts). */}
|
|
389
391
|
<span hidden id={NEW_TAB_HINT_ID}>{navStrings.opensInNewTab}</span>
|
|
390
|
-
<Banner banner={banner} strings={strings.banner} />
|
|
392
|
+
<Banner banner={banner} locale={locale} strings={strings.banner} />
|
|
391
393
|
<Header
|
|
392
394
|
assistantEnabled={assistantEnabled}
|
|
393
395
|
assistantStrings={strings.assistant}
|
|
@@ -426,13 +428,25 @@ createIconSprite(Astro.locals);
|
|
|
426
428
|
<ul class="m-0 list-none p-0">
|
|
427
429
|
{navigation.tabs.map((tab) => (
|
|
428
430
|
<li>
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
431
|
+
{tab.items && tab.items.length > 0 ? (
|
|
432
|
+
<NavTabMenu
|
|
433
|
+
active={tab === activeTab}
|
|
434
|
+
route={route}
|
|
435
|
+
tab={tab}
|
|
436
|
+
variant="drawer"
|
|
437
|
+
/>
|
|
438
|
+
) : (
|
|
439
|
+
<a
|
|
440
|
+
aria-current={tab === activeTab ? "page" : undefined}
|
|
441
|
+
class="flex items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:text-foreground"
|
|
442
|
+
href={withBase(tab.href ?? tab.path)}
|
|
443
|
+
>
|
|
444
|
+
{tab.icon && (
|
|
445
|
+
<Icon class="shrink-0" name={tab.icon} size={14} />
|
|
446
|
+
)}
|
|
447
|
+
<span class="flex-1 truncate">{tab.label}</span>
|
|
448
|
+
</a>
|
|
449
|
+
)}
|
|
436
450
|
</li>
|
|
437
451
|
))}
|
|
438
452
|
</ul>
|
|
@@ -146,18 +146,21 @@ createIconSprite(Astro.locals);
|
|
|
146
146
|
>
|
|
147
147
|
{/* Every new-tab link's aria-describedby target (see core/new-tab.ts). */}
|
|
148
148
|
<span hidden id={NEW_TAB_HINT_ID}>{navStrings.opensInNewTab}</span>
|
|
149
|
-
<Banner banner={banner} strings={strings.banner} />
|
|
149
|
+
<Banner banner={banner} locale={locale} strings={strings.banner} />
|
|
150
150
|
<Header
|
|
151
151
|
assistantStrings={strings.assistant}
|
|
152
152
|
hasDrawer={false}
|
|
153
153
|
hasSidebar={false}
|
|
154
154
|
locale={locale}
|
|
155
155
|
logo={logo}
|
|
156
|
+
navStrings={navStrings}
|
|
156
157
|
navigation={navigation}
|
|
157
158
|
route={route}
|
|
158
159
|
searchEnabled={searchEnabled}
|
|
159
160
|
searchLocale={searchLocale}
|
|
161
|
+
searchStrings={strings.search}
|
|
160
162
|
site={site}
|
|
163
|
+
switcherStrings={strings.languageSwitcher}
|
|
161
164
|
/>
|
|
162
165
|
<div
|
|
163
166
|
class="h-[calc(100dvh-4rem)] overflow-auto border-border border-t [&>[data-scalar-client]]:h-full"
|
|
@@ -66,6 +66,7 @@ import {
|
|
|
66
66
|
navGroupIds,
|
|
67
67
|
sidebarForRoute,
|
|
68
68
|
} from "./nav-utils.ts";
|
|
69
|
+
import NavTabMenu from "./NavTabMenu.astro";
|
|
69
70
|
import NavTree from "./NavTree.astro";
|
|
70
71
|
import { resolveSlot } from "./overrides.ts";
|
|
71
72
|
import { pageDirection, pageLocale } from "./page-locale.ts";
|
|
@@ -579,7 +580,7 @@ createIconSprite(Astro.locals);
|
|
|
579
580
|
>
|
|
580
581
|
{/* Every new-tab link's aria-describedby target (see core/new-tab.ts). */}
|
|
581
582
|
<span hidden id={NEW_TAB_HINT_ID}>{navStrings.opensInNewTab}</span>
|
|
582
|
-
<Banner banner={banner} strings={strings.banner} />
|
|
583
|
+
<Banner banner={banner} locale={locale} strings={strings.banner} />
|
|
583
584
|
<VersionBanner notice={versionNotice ?? null} />
|
|
584
585
|
<HeaderSlot
|
|
585
586
|
assistantEnabled={assistantEnabled}
|
|
@@ -677,13 +678,25 @@ createIconSprite(Astro.locals);
|
|
|
677
678
|
<ul class="m-0 list-none p-0">
|
|
678
679
|
{navigation.tabs.map((tab) => (
|
|
679
680
|
<li>
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
681
|
+
{tab.items && tab.items.length > 0 ? (
|
|
682
|
+
<NavTabMenu
|
|
683
|
+
active={tab === activeTab}
|
|
684
|
+
route={page.route}
|
|
685
|
+
tab={tab}
|
|
686
|
+
variant="drawer"
|
|
687
|
+
/>
|
|
688
|
+
) : (
|
|
689
|
+
<a
|
|
690
|
+
aria-current={tab === activeTab ? "page" : undefined}
|
|
691
|
+
class="flex items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:text-foreground"
|
|
692
|
+
href={withBase(tab.href ?? tab.path)}
|
|
693
|
+
>
|
|
694
|
+
{tab.icon && (
|
|
695
|
+
<Icon class="shrink-0" name={tab.icon} size={14} />
|
|
696
|
+
)}
|
|
697
|
+
<span class="flex-1 truncate">{tab.label}</span>
|
|
698
|
+
</a>
|
|
699
|
+
)}
|
|
687
700
|
</li>
|
|
688
701
|
))}
|
|
689
702
|
</ul>
|