blume 1.7.3 → 2.0.0
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 +19 -0
- package/CHANGELOG.md +217 -0
- package/README.md +34 -21
- package/dist/cli/chunk-11j0384y.js +148 -0
- package/dist/cli/chunk-11j0384y.js.map +10 -0
- package/dist/cli/{chunk-rqy0s5wh.js → chunk-1w8dp3qb.js} +17 -16
- package/dist/cli/{chunk-rqy0s5wh.js.map → chunk-1w8dp3qb.js.map} +3 -3
- package/dist/cli/chunk-2q1dwty4.js +75 -0
- package/dist/cli/chunk-2q1dwty4.js.map +11 -0
- package/dist/cli/chunk-41za066z.js +122 -0
- package/dist/cli/chunk-41za066z.js.map +11 -0
- package/dist/cli/chunk-5a2z0198.js +133 -0
- package/dist/cli/chunk-5a2z0198.js.map +10 -0
- package/dist/cli/{chunk-5g0w1e2c.js → chunk-6k8vp3ta.js} +25 -13
- package/dist/cli/{chunk-5g0w1e2c.js.map → chunk-6k8vp3ta.js.map} +4 -4
- package/dist/cli/{chunk-5qk08vmp.js → chunk-79njf86q.js} +133 -54
- package/dist/cli/chunk-79njf86q.js.map +11 -0
- package/dist/cli/{chunk-e7f42gdj.js → chunk-7ez8ny0t.js} +2 -2
- package/dist/cli/{chunk-nn13znc2.js → chunk-88cpgt6h.js} +1 -1
- package/dist/cli/chunk-a9kptbw5.js +361 -0
- package/dist/cli/chunk-a9kptbw5.js.map +14 -0
- package/dist/cli/chunk-abh8yjkn.js +31 -0
- package/dist/cli/chunk-abh8yjkn.js.map +10 -0
- package/dist/cli/chunk-b5aj94ah.js +91 -0
- package/dist/cli/chunk-b5aj94ah.js.map +10 -0
- package/dist/cli/{chunk-b27xqwn9.js → chunk-bctazmbk.js} +9 -5
- package/dist/cli/chunk-bctazmbk.js.map +10 -0
- package/dist/cli/chunk-beat36xx.js +279 -0
- package/dist/cli/chunk-beat36xx.js.map +10 -0
- package/dist/cli/chunk-bnbmcwfb.js +145 -0
- package/dist/cli/chunk-bnbmcwfb.js.map +11 -0
- package/dist/cli/{chunk-0xjyb285.js → chunk-bw22s759.js} +15 -5
- package/dist/cli/{chunk-0xjyb285.js.map → chunk-bw22s759.js.map} +4 -4
- package/dist/cli/chunk-by2290sx.js +39 -0
- package/dist/cli/chunk-by2290sx.js.map +10 -0
- package/dist/cli/chunk-d1tadaw7.js +79 -0
- package/dist/cli/chunk-d1tadaw7.js.map +10 -0
- package/dist/cli/{chunk-ahnw3kxw.js → chunk-d80hr03s.js} +24 -19
- package/dist/cli/chunk-d80hr03s.js.map +15 -0
- package/dist/cli/chunk-ernrthtr.js +97 -0
- package/dist/cli/chunk-ernrthtr.js.map +10 -0
- package/dist/cli/chunk-f2972sbt.js +374 -0
- package/dist/cli/chunk-f2972sbt.js.map +10 -0
- package/dist/cli/{chunk-vacwm2hv.js → chunk-f7t03s3g.js} +2 -2
- package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
- package/dist/cli/chunk-fa25z98p.js.map +11 -0
- package/dist/cli/{chunk-cjtn640a.js → chunk-fh5hj5jt.js} +43 -20
- package/dist/cli/chunk-fh5hj5jt.js.map +10 -0
- package/dist/cli/{chunk-yg63d42r.js → chunk-j8mw0za6.js} +86 -57
- package/dist/cli/chunk-j8mw0za6.js.map +35 -0
- package/dist/cli/{chunk-ct47dqpx.js → chunk-jts8mvcz.js} +67 -7
- package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
- package/dist/cli/{chunk-ps4m1xh4.js → chunk-mnqj32sj.js} +505 -542
- package/dist/cli/chunk-mnqj32sj.js.map +12 -0
- package/dist/cli/{chunk-8cjtbafj.js → chunk-mwt1k8n7.js} +100 -374
- package/dist/cli/chunk-mwt1k8n7.js.map +10 -0
- package/dist/cli/chunk-nk3ts2xk.js +51 -0
- package/dist/cli/chunk-nk3ts2xk.js.map +10 -0
- package/dist/cli/{chunk-3r45185y.js → chunk-pat2zzwc.js} +9 -11
- package/dist/cli/{chunk-3r45185y.js.map → chunk-pat2zzwc.js.map} +2 -2
- package/dist/cli/chunk-pnnvybbk.js +176 -0
- package/dist/cli/chunk-pnnvybbk.js.map +11 -0
- package/dist/cli/{chunk-4x36ddpw.js → chunk-sqn5t4q0.js} +81 -87
- package/dist/cli/chunk-sqn5t4q0.js.map +10 -0
- package/dist/cli/{chunk-bvwwhd84.js → chunk-tzne8qfq.js} +15 -15
- package/dist/cli/{chunk-bvwwhd84.js.map → chunk-tzne8qfq.js.map} +1 -1
- package/dist/cli/chunk-xaz13gwg.js +12449 -0
- package/dist/cli/chunk-xaz13gwg.js.map +182 -0
- package/dist/cli/chunk-y3e45rc8.js +102 -0
- package/dist/cli/chunk-y3e45rc8.js.map +10 -0
- package/dist/cli/chunk-z01ze5c1.js +261 -0
- package/dist/cli/chunk-z01ze5c1.js.map +10 -0
- package/dist/cli/{chunk-k79xp7av.js → chunk-z1f5arsg.js} +219 -689
- package/dist/cli/chunk-z1f5arsg.js.map +36 -0
- package/dist/cli/{chunk-1jefwnfs.js → chunk-zg2gtj10.js} +1076 -2592
- package/dist/cli/chunk-zg2gtj10.js.map +35 -0
- package/dist/cli/{chunk-dwgcp5sm.js → chunk-zxccj738.js} +1 -1
- package/dist/cli/index.js +214 -57
- package/dist/cli/index.js.map +8 -7
- package/dist/types/ai/agent-readability.d.ts +52 -0
- package/dist/types/ai/ai-catalog.d.ts +42 -0
- package/dist/types/ai/api/paths.d.ts +17 -0
- package/dist/types/ai/api-catalog.d.ts +18 -0
- package/dist/types/ai/ask.d.ts +368 -0
- package/dist/types/ai/changelog-markdown.d.ts +2 -0
- package/dist/types/ai/component-markdown.d.ts +2 -2
- package/dist/types/ai/index.d.ts +24 -0
- package/dist/types/ai/link-headers.d.ts +24 -0
- package/dist/types/ai/llms.d.ts +25 -0
- package/dist/types/ai/markdown.d.ts +45 -0
- package/dist/types/ai/mcp/discovery.d.ts +68 -0
- package/dist/types/ai/mcp/tools.d.ts +16 -0
- package/dist/types/ai/openapi-components.d.ts +43 -0
- package/dist/types/ai/relative-links.d.ts +26 -0
- package/dist/types/ai/serializers.d.ts +15 -0
- package/dist/types/ai/skills.d.ts +42 -0
- package/dist/types/ai/tar.d.ts +25 -0
- package/dist/types/ai/visibility.d.ts +17 -0
- package/dist/types/ai/web-bot-auth.d.ts +16 -0
- package/dist/types/analytics/adobe.d.ts +35 -0
- package/dist/types/analytics/amplitude.d.ts +50 -0
- package/dist/types/analytics/clarity.d.ts +31 -0
- package/dist/types/analytics/clearbit.d.ts +29 -0
- package/dist/types/analytics/cloudflare.d.ts +41 -0
- package/dist/types/analytics/fathom.d.ts +41 -0
- package/dist/types/analytics/google-analytics.d.ts +44 -0
- package/dist/types/analytics/google-tag-manager.d.ts +40 -0
- package/dist/types/analytics/head.d.ts +30 -0
- package/dist/types/analytics/heap.d.ts +40 -0
- package/dist/types/analytics/hightouch.d.ts +44 -0
- package/dist/types/analytics/hotjar.d.ts +33 -0
- package/dist/types/analytics/index.d.ts +61 -0
- package/dist/types/analytics/inline.d.ts +17 -0
- package/dist/types/analytics/logrocket.d.ts +44 -0
- package/dist/types/analytics/mixpanel.d.ts +67 -0
- package/dist/types/analytics/pirsch.d.ts +42 -0
- package/dist/types/analytics/plausible.d.ts +56 -0
- package/dist/types/analytics/posthog.d.ts +45 -0
- package/dist/types/analytics/schema.d.ts +320 -0
- package/dist/types/analytics/script.d.ts +46 -0
- package/dist/types/analytics/segment.d.ts +50 -0
- package/dist/types/analytics/vercel.d.ts +48 -0
- package/dist/types/astro/integration.d.ts +76 -0
- package/dist/types/astro/markdown-negotiation.d.ts +23 -0
- package/dist/types/astro/module-types.d.ts +14 -0
- package/dist/types/astro/pages.d.ts +44 -0
- package/dist/types/cli/env.d.ts +12 -0
- package/dist/types/cli/init/scaffold.d.ts +154 -0
- package/dist/types/components/layout/nav-utils.d.ts +11 -0
- package/dist/types/core/adapter.d.ts +47 -0
- package/dist/types/core/api-name.d.ts +7 -0
- package/dist/types/core/changelog-index.d.ts +13 -0
- package/dist/types/core/config-input.d.ts +186 -515
- package/dist/types/core/config.d.ts +60 -34
- package/dist/types/core/content-assets.d.ts +76 -0
- package/dist/types/core/custom-pages.d.ts +33 -0
- package/dist/types/core/data.d.ts +27 -12
- package/dist/types/core/define-components.d.ts +12 -9
- package/dist/types/core/deployment-env.d.ts +6 -11
- package/dist/types/core/frontmatter.d.ts +10 -0
- package/dist/types/core/graph.d.ts +18 -0
- package/dist/types/core/heading-markers.d.ts +54 -0
- package/dist/types/core/i18n-ui.d.ts +6 -2
- package/dist/types/core/i18n.d.ts +87 -0
- package/dist/types/core/includes.d.ts +138 -0
- package/dist/types/core/last-modified.d.ts +47 -0
- package/dist/types/core/links.d.ts +95 -0
- package/dist/types/core/locale-links.d.ts +60 -0
- package/dist/types/core/manifest.d.ts +17 -0
- package/dist/types/core/meta.d.ts +38 -0
- package/dist/types/core/nav-diagnostics.d.ts +26 -0
- package/dist/types/core/navigation.d.ts +6 -0
- package/dist/types/core/node-require.d.ts +19 -0
- package/dist/types/core/package-json.d.ts +13 -0
- package/dist/types/core/probe.d.ts +42 -0
- package/dist/types/core/project-graph.d.ts +51 -0
- package/dist/types/core/project.d.ts +2 -0
- package/dist/types/core/safe-href.d.ts +2 -0
- package/dist/types/core/safe-links.d.ts +26 -0
- package/dist/types/core/schema.d.ts +2282 -452
- package/dist/types/core/site-url.d.ts +16 -0
- package/dist/types/core/sources/assets.d.ts +36 -0
- package/dist/types/core/sources/cache.d.ts +37 -0
- package/dist/types/core/sources/collection.d.ts +28 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
- package/dist/types/core/sources/contentful.d.ts +40 -0
- package/dist/types/core/sources/filesystem.d.ts +24 -0
- package/dist/types/core/sources/github-releases.d.ts +31 -0
- package/dist/types/core/sources/json.d.ts +30 -0
- package/dist/types/core/sources/lexical.d.ts +19 -0
- package/dist/types/core/sources/lower.d.ts +75 -0
- package/dist/types/core/sources/mdx-remote.d.ts +28 -0
- package/dist/types/core/sources/normalize.d.ts +147 -0
- package/dist/types/core/sources/notion.d.ts +131 -0
- package/dist/types/core/sources/obsidian.d.ts +46 -0
- package/dist/types/core/sources/payload.d.ts +39 -0
- package/dist/types/core/sources/portable-text.d.ts +42 -0
- package/dist/types/core/sources/read.d.ts +23 -0
- package/dist/types/core/sources/remote.d.ts +74 -0
- package/dist/types/core/sources/resolve.d.ts +19 -0
- package/dist/types/core/sources/sanity.d.ts +43 -0
- package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
- package/dist/types/core/sources/strapi.d.ts +33 -0
- package/dist/types/core/sources/types.d.ts +7 -0
- package/dist/types/core/sources/watch.d.ts +45 -0
- package/dist/types/core/text-width.d.ts +11 -0
- package/dist/types/core/types.d.ts +15 -1
- package/dist/types/core/unrecognized-keys.d.ts +7 -0
- package/dist/types/core/versions.d.ts +72 -0
- package/dist/types/core/yaml.d.ts +9 -0
- package/dist/types/deploy/adapter-output.d.ts +45 -0
- package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
- package/dist/types/deploy/adapters/index.d.ts +29 -0
- package/dist/types/deploy/adapters/netlify.d.ts +37 -0
- package/dist/types/deploy/adapters/node.d.ts +37 -0
- package/dist/types/deploy/adapters/registry.d.ts +133 -0
- package/dist/types/deploy/adapters/types.d.ts +71 -0
- package/dist/types/deploy/adapters/vercel.d.ts +38 -0
- package/dist/types/deploy/artifacts.d.ts +65 -0
- package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
- package/dist/types/deploy/function-bundle.d.ts +80 -0
- package/dist/types/deploy/headers.d.ts +50 -0
- package/dist/types/deploy/node-headers.d.ts +42 -0
- package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
- package/dist/types/deploy/platforms/index.d.ts +18 -0
- package/dist/types/deploy/platforms/netlify.d.ts +13 -0
- package/dist/types/deploy/platforms/node.d.ts +11 -0
- package/dist/types/deploy/platforms/paths.d.ts +27 -0
- package/dist/types/deploy/platforms/static.d.ts +10 -0
- package/dist/types/deploy/platforms/types.d.ts +104 -0
- package/dist/types/deploy/platforms/vercel.d.ts +32 -0
- package/dist/types/deploy/redirects.d.ts +53 -0
- package/dist/types/deploy/robots.d.ts +8 -0
- package/dist/types/deploy/rss.d.ts +31 -0
- package/dist/types/deploy/sitemap.d.ts +21 -0
- package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
- package/dist/types/markdown/code-title.d.ts +32 -0
- package/dist/types/markdown/fence-meta.d.ts +23 -0
- package/dist/types/markdown/themes.d.ts +3 -3
- package/dist/types/openapi/asyncapi.d.ts +129 -0
- package/dist/types/openapi/graphql-build.d.ts +8 -0
- package/dist/types/openapi/graphql.d.ts +122 -0
- package/dist/types/openapi/model.d.ts +158 -0
- package/dist/types/openapi/parse.d.ts +57 -0
- package/dist/types/openapi/references.d.ts +37 -25
- package/dist/types/openapi/render-mdx.d.ts +33 -0
- package/dist/types/openapi/sentence.d.ts +7 -0
- package/dist/types/openapi/signature.d.ts +10 -0
- package/dist/types/openapi/source.d.ts +22 -0
- package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
- package/dist/types/reference/asyncapi.d.ts +166 -0
- package/dist/types/reference/graphql.d.ts +181 -0
- package/dist/types/reference/index.d.ts +32 -0
- package/dist/types/reference/openapi.d.ts +165 -0
- package/dist/types/reference/options.d.ts +157 -0
- package/dist/types/reference/scalar.d.ts +136 -0
- package/dist/types/reference/schema.d.ts +630 -0
- package/dist/types/search/adapters/algolia.d.ts +32 -0
- package/dist/types/search/adapters/flexsearch.d.ts +12 -0
- package/dist/types/search/adapters/index.d.ts +31 -0
- package/dist/types/search/adapters/mixedbread.d.ts +22 -0
- package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
- package/dist/types/search/adapters/orama.d.ts +13 -0
- package/dist/types/search/adapters/pagefind.d.ts +12 -0
- package/dist/types/search/adapters/registry.d.ts +228 -0
- package/dist/types/search/adapters/types.d.ts +34 -0
- package/dist/types/search/adapters/typesense.d.ts +42 -0
- package/dist/types/search/build.d.ts +23 -0
- package/dist/types/search/documents.d.ts +90 -0
- package/dist/types/search/facets.d.ts +3 -0
- package/dist/types/search/sync/algolia.d.ts +14 -0
- package/dist/types/search/sync/index.d.ts +14 -0
- package/dist/types/search/sync/orama-cloud.d.ts +10 -0
- package/dist/types/search/sync/typesense.d.ts +14 -0
- package/dist/types/sources/contentful.d.ts +68 -0
- package/dist/types/sources/custom.d.ts +20 -0
- package/dist/types/sources/filesystem.d.ts +42 -0
- package/dist/types/sources/github-releases.d.ts +46 -0
- package/dist/types/sources/index.d.ts +48 -0
- package/dist/types/sources/mdx-remote.d.ts +63 -0
- package/dist/types/sources/notion.d.ts +65 -0
- package/dist/types/sources/obsidian.d.ts +34 -0
- package/dist/types/sources/payload.d.ts +68 -0
- package/dist/types/sources/registry.d.ts +1414 -0
- package/dist/types/sources/sanity.d.ts +69 -0
- package/dist/types/sources/shared.d.ts +46 -0
- package/dist/types/sources/strapi.d.ts +66 -0
- package/dist/types/theme/icon-kind.d.ts +11 -0
- package/dist/types/theme/icons.d.ts +20 -0
- package/docs/01-quickstart.mdx +18 -18
- package/docs/02-deployment.mdx +50 -26
- package/docs/03-upgrading.mdx +351 -0
- package/docs/04-migrating.mdx +58 -0
- package/docs/08-faq.mdx +3 -3
- package/docs/advanced/blog.mdx +13 -6
- package/docs/advanced/changelog.mdx +23 -35
- package/docs/advanced/custom-pages.mdx +20 -8
- package/docs/advanced/meta.ts +1 -8
- package/docs/advanced/skills.mdx +8 -0
- package/docs/cli/audit.mdx +646 -0
- package/docs/cli/doctor.mdx +29 -0
- package/docs/{reference/eval.mdx → cli/evals.mdx} +9 -8
- package/docs/cli/index.mdx +105 -0
- package/docs/cli/meta.ts +7 -0
- package/docs/{reference → cli}/translate.mdx +1 -1
- package/docs/cli/validate.mdx +41 -0
- package/docs/cli/version.mdx +40 -0
- package/docs/configuration/analytics.mdx +350 -59
- package/docs/configuration/ask-ai.mdx +162 -61
- package/docs/configuration/customization.mdx +15 -9
- package/docs/configuration/index.mdx +50 -31
- package/docs/configuration/search.mdx +75 -54
- package/docs/configuration/theming.mdx +24 -15
- package/docs/content/components.mdx +21 -5
- package/docs/{reference → content}/frontmatter.mdx +35 -1
- package/docs/content/i18n.mdx +8 -6
- package/docs/content/includes.mdx +2 -4
- package/docs/content/index.mdx +1 -1
- package/docs/content/islands.mdx +10 -5
- package/docs/content/meta.mdx +1 -1
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +9 -7
- package/docs/content/sources.mdx +145 -50
- package/docs/content/syntax.mdx +16 -12
- package/docs/content/versioning.mdx +3 -3
- package/docs/discoverability/agent-discovery.mdx +11 -11
- package/docs/discoverability/index.mdx +4 -4
- package/docs/discoverability/json-api.mdx +4 -4
- package/docs/discoverability/llms-txt.mdx +6 -6
- package/docs/discoverability/markdown.mdx +4 -4
- package/docs/discoverability/mcp.mdx +11 -11
- package/docs/discoverability/sitemap-and-robots.mdx +3 -3
- package/docs/index.mdx +2 -2
- package/docs/references/asyncapi.mdx +59 -0
- package/docs/{advanced → references}/graphql.mdx +45 -32
- package/docs/{reference → references}/meta.ts +2 -2
- package/docs/references/openapi.mdx +171 -0
- package/docs/references/scalar.mdx +64 -0
- package/package.json +42 -8
- package/skills/blume/SKILL.md +21 -8
- package/skills/blume-migrate/SKILL.md +22 -21
- package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
- package/skills/blume-migrate/references/docusaurus.md +5 -4
- package/skills/blume-migrate/references/fumadocs.md +4 -4
- package/skills/blume-migrate/references/mintlify.md +23 -8
- package/skills/blume-migrate/references/monorepo.md +6 -6
- package/skills/blume-migrate/references/starlight.md +4 -4
- package/src/ai/agent-readability.ts +21 -22
- package/src/ai/ai-catalog.ts +50 -32
- package/src/ai/api/handlers.ts +46 -11
- package/src/ai/api-catalog.ts +8 -8
- package/src/ai/ask-data.ts +1 -1
- package/src/ai/ask.ts +624 -100
- package/src/ai/changelog-markdown.ts +91 -0
- package/src/ai/component-markdown.ts +328 -12
- package/src/ai/index.ts +45 -0
- package/src/ai/link-headers.ts +7 -6
- package/src/ai/llms.ts +20 -15
- package/src/ai/markdown.ts +35 -5
- package/src/ai/mcp/data.ts +9 -5
- package/src/ai/openapi-components.ts +4 -1
- package/src/ai/relative-links.ts +170 -0
- package/src/ai/serializers.ts +2 -2
- package/src/ai/skills.ts +1 -1
- package/src/ai/web-bot-auth.ts +2 -2
- package/src/analytics/adobe.ts +46 -0
- package/src/analytics/amplitude.ts +79 -0
- package/src/analytics/clarity.ts +46 -0
- package/src/analytics/clearbit.ts +47 -0
- package/src/analytics/cloudflare.ts +67 -0
- package/src/analytics/fathom.ts +64 -0
- package/src/analytics/google-analytics.ts +84 -0
- package/src/analytics/google-tag-manager.ts +61 -0
- package/src/analytics/head.ts +130 -0
- package/src/analytics/heap.ts +65 -0
- package/src/analytics/hightouch.ts +77 -0
- package/src/analytics/hotjar.ts +47 -0
- package/src/analytics/index.ts +71 -0
- package/src/analytics/inline.ts +21 -0
- package/src/analytics/logrocket.ts +71 -0
- package/src/analytics/mixpanel.ts +92 -0
- package/src/analytics/pirsch.ts +66 -0
- package/src/analytics/plausible.ts +83 -0
- package/src/analytics/posthog.ts +78 -0
- package/src/analytics/schema.ts +60 -0
- package/src/analytics/script.ts +60 -0
- package/src/analytics/segment.ts +85 -0
- package/src/analytics/vercel.ts +50 -0
- package/src/astro/adapter-root.ts +7 -9
- package/src/astro/component-slots.ts +131 -91
- package/src/astro/generate.ts +112 -345
- package/src/astro/integration.ts +2 -6
- package/src/astro/pages.ts +13 -101
- package/src/astro/render-deps.ts +379 -0
- package/src/astro/runtime-deps.ts +201 -0
- package/src/astro/templates.ts +554 -541
- package/src/audit/agent.ts +24 -0
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +2 -2
- package/src/audit/checks/dns-aid.ts +1 -1
- package/src/audit/checks/duplicates.ts +3 -1
- package/src/audit/checks/i18n.ts +1 -1
- package/src/audit/checks/indexability.ts +7 -7
- package/src/audit/checks/links.ts +2 -2
- package/src/audit/checks/llms.ts +6 -6
- package/src/audit/checks/network.ts +3 -3
- package/src/audit/checks/og-image.ts +2 -2
- package/src/audit/checks/robots.ts +1 -1
- package/src/audit/checks/sitemap.ts +2 -2
- package/src/audit/checks/social.ts +1 -1
- package/src/audit/run.ts +4 -3
- package/src/audit/terms.ts +31 -0
- package/src/audit/url.ts +13 -13
- package/src/cli/command-meta.ts +10 -0
- package/src/cli/commands/audit.ts +39 -20
- package/src/cli/commands/build.ts +71 -316
- package/src/cli/commands/check.ts +1 -0
- package/src/cli/commands/dev.ts +40 -1
- package/src/cli/commands/doctor.ts +90 -14
- package/src/cli/commands/eject.ts +44 -7
- package/src/cli/commands/eval.ts +2 -2
- package/src/cli/commands/init.ts +161 -41
- package/src/cli/commands/migrate.ts +121 -0
- package/src/cli/commands/preview.ts +7 -1
- package/src/cli/commands/translate.ts +2 -2
- package/src/cli/commands/upgrade.ts +141 -0
- package/src/cli/commands/version.ts +57 -44
- package/src/cli/eject-scripts.ts +121 -6
- package/src/cli/index.ts +11 -1
- package/src/cli/init/install.ts +70 -0
- package/src/cli/init/questions.ts +7 -0
- package/src/cli/init/scaffold.ts +459 -75
- package/src/cli/lazy-command.ts +37 -1
- package/src/cli/prepare.ts +40 -6
- package/src/cli/required-secrets.ts +38 -11
- package/src/cli/unknown-flags.ts +266 -0
- package/src/cli/yarn-pnp.ts +52 -0
- package/src/components/content/AccordionItem.astro +7 -1
- package/src/components/content/Card.astro +4 -3
- package/src/components/content/ColorItem.astro +22 -4
- package/src/components/content/GithubInfo.astro +2 -2
- package/src/components/content/Prompt.astro +25 -25
- package/src/components/content/Tabs.astro +3 -1
- package/src/components/content/Tile.astro +2 -3
- package/src/components/content/Tooltip.astro +57 -9
- package/src/components/content/content-strings.ts +34 -0
- package/src/components/content/diff.ts +1 -1
- package/src/components/content/mermaid-element.ts +13 -2
- package/src/components/content/prompt-markdown.ts +292 -0
- package/src/components/content/tooltip-id.ts +41 -0
- package/src/components/islands/hooks.ts +25 -2
- package/src/components/layout/Analytics.astro +21 -79
- package/src/components/layout/Banner.astro +3 -1
- package/src/components/layout/DiscoveryLinks.astro +69 -0
- package/src/components/layout/Header.astro +83 -20
- package/src/components/layout/LanguageSwitcher.astro +4 -1
- package/src/components/layout/Logo.astro +23 -2
- package/src/components/layout/NavSelector.astro +13 -2
- package/src/components/layout/NavTree.astro +12 -3
- package/src/components/layout/NavTreeScript.astro +17 -3
- package/src/components/layout/PageActions.astro +3 -3
- package/src/components/layout/PageFeedback.astro +11 -1
- package/src/components/layout/PageLayout.astro +52 -5
- package/src/components/layout/ReferenceLayout.astro +21 -12
- package/src/components/layout/RootLayout.astro +69 -66
- package/src/components/layout/Search.astro +30 -6
- package/src/components/layout/WebMcp.astro +1 -1
- package/src/components/layout/analytics-client.ts +72 -15
- package/src/components/layout/drawer-inert.ts +113 -15
- package/src/components/layout/dropdown-clamp.ts +105 -0
- package/src/components/layout/head-scripts.ts +15 -6
- package/src/components/layout/nav-utils.ts +17 -0
- package/src/components/layout/search/algolia.ts +8 -8
- package/src/components/layout/search/orama-cloud.ts +9 -7
- package/src/components/layout/search/typesense.ts +11 -17
- package/src/components/openapi/MessageComposer.astro +2 -2
- package/src/components/openapi/Playground.astro +2 -2
- package/src/components/openapi/playground-client.ts +79 -10
- package/src/core/changelog-index.ts +24 -0
- package/src/core/component-overrides.ts +399 -154
- package/src/core/config-input.ts +188 -553
- package/src/core/config.ts +130 -41
- package/src/core/custom-pages.ts +105 -0
- package/src/core/data.ts +31 -12
- package/src/core/define-components.ts +12 -9
- package/src/core/deployment-env.ts +18 -74
- package/src/core/diagnostics.ts +14 -7
- package/src/core/graph.ts +69 -25
- package/src/core/i18n-ui.ts +6 -2
- package/src/core/i18n.ts +17 -0
- package/src/core/includes.ts +156 -38
- package/src/core/last-modified.ts +6 -11
- package/src/core/links.ts +166 -2
- package/src/core/manifest.ts +10 -3
- package/src/core/navigation.ts +115 -16
- package/src/core/new-tab.ts +35 -0
- package/src/core/node-require.ts +21 -0
- package/src/core/project-graph.ts +42 -26
- package/src/core/project.ts +9 -4
- package/src/core/request-body.ts +61 -0
- package/src/core/safe-href.ts +28 -0
- package/src/core/safe-links.ts +68 -0
- package/src/core/schema.ts +517 -739
- package/src/core/server-features.ts +8 -9
- package/src/core/sources/assets.ts +47 -11
- package/src/core/sources/collection.ts +67 -0
- package/src/core/sources/contentful-rich-text.ts +285 -0
- package/src/core/sources/contentful.ts +173 -0
- package/src/core/sources/github-releases.ts +51 -1
- package/src/core/sources/json.ts +71 -0
- package/src/core/sources/lexical.ts +195 -0
- package/src/core/sources/lower.ts +226 -0
- package/src/core/sources/normalize.ts +52 -2
- package/src/core/sources/notion.ts +39 -28
- package/src/core/sources/payload.ts +135 -0
- package/src/core/sources/portable-text.ts +11 -16
- package/src/core/sources/remote.ts +226 -0
- package/src/core/sources/resolve.ts +104 -166
- package/src/core/sources/sanity.ts +16 -49
- package/src/core/sources/strapi-blocks.ts +124 -0
- package/src/core/sources/strapi.ts +191 -0
- package/src/core/sources/types.ts +12 -1
- package/src/core/types.ts +15 -1
- package/src/core/ui-packs/ar.ts +6 -2
- package/src/core/ui-packs/bg.ts +6 -2
- package/src/core/ui-packs/bn.ts +6 -2
- package/src/core/ui-packs/ca.ts +3 -1
- package/src/core/ui-packs/cs.ts +6 -2
- package/src/core/ui-packs/da.ts +6 -2
- package/src/core/ui-packs/de.ts +6 -2
- package/src/core/ui-packs/el.ts +3 -1
- package/src/core/ui-packs/es.ts +3 -1
- package/src/core/ui-packs/fa.ts +6 -2
- package/src/core/ui-packs/fi.ts +6 -2
- package/src/core/ui-packs/fr.ts +3 -1
- package/src/core/ui-packs/he.ts +6 -2
- package/src/core/ui-packs/hi.ts +6 -2
- package/src/core/ui-packs/hr.ts +6 -2
- package/src/core/ui-packs/hu.ts +6 -2
- package/src/core/ui-packs/id.ts +6 -2
- package/src/core/ui-packs/it.ts +3 -1
- package/src/core/ui-packs/ja.ts +3 -1
- package/src/core/ui-packs/ko.ts +3 -1
- package/src/core/ui-packs/nl.ts +6 -2
- package/src/core/ui-packs/no.ts +6 -2
- package/src/core/ui-packs/pl.ts +6 -2
- package/src/core/ui-packs/pt-br.ts +3 -1
- package/src/core/ui-packs/pt.ts +3 -1
- package/src/core/ui-packs/ro.ts +6 -2
- package/src/core/ui-packs/ru.ts +6 -2
- package/src/core/ui-packs/sk.ts +6 -2
- package/src/core/ui-packs/sr.ts +6 -2
- package/src/core/ui-packs/sv.ts +6 -2
- package/src/core/ui-packs/th.ts +3 -1
- package/src/core/ui-packs/tr.ts +6 -2
- package/src/core/ui-packs/uk.ts +6 -2
- package/src/core/ui-packs/vi.ts +3 -1
- package/src/core/ui-packs/zh-tw.ts +3 -1
- package/src/core/ui-packs/zh.ts +3 -1
- package/src/core/unrecognized-keys.ts +10 -0
- package/src/core/version-cut.ts +116 -8
- package/src/deploy/adapter-output.ts +57 -97
- package/src/deploy/adapters/cloudflare.ts +39 -0
- package/src/deploy/adapters/index.ts +41 -0
- package/src/deploy/adapters/netlify.ts +34 -0
- package/src/deploy/adapters/node.ts +34 -0
- package/src/deploy/adapters/registry.ts +127 -0
- package/src/deploy/adapters/types.ts +92 -0
- package/src/deploy/adapters/vercel.ts +35 -0
- package/src/deploy/artifacts.ts +55 -27
- package/src/deploy/cloudflare-negotiation.ts +179 -100
- package/src/deploy/function-bundle.ts +18 -3
- package/src/deploy/headers.ts +124 -23
- package/src/deploy/node-headers.ts +198 -0
- package/src/deploy/platforms/cloudflare.ts +312 -0
- package/src/deploy/platforms/index.ts +67 -0
- package/src/deploy/platforms/netlify.ts +52 -0
- package/src/deploy/platforms/node.ts +40 -0
- package/src/deploy/platforms/paths.ts +42 -0
- package/src/deploy/platforms/static.ts +29 -0
- package/src/deploy/platforms/types.ts +112 -0
- package/src/deploy/platforms/vercel.ts +193 -0
- package/src/deploy/redirects.ts +30 -18
- package/src/deploy/robots.ts +3 -3
- package/src/deploy/rss.ts +2 -2
- package/src/deploy/sitemap.ts +2 -2
- package/src/deploy/vercel-negotiation.ts +2 -2
- package/src/eval/agents.ts +32 -1
- package/src/eval/findings.ts +19 -11
- package/src/eval/report.ts +10 -2
- package/src/markdown/external-links.ts +65 -0
- package/src/markdown/include.ts +45 -27
- package/src/markdown/index.ts +34 -9
- package/src/markdown/inline-code.ts +12 -6
- package/src/markdown/relative-links.ts +324 -0
- package/src/markdown/themes.ts +3 -3
- package/src/migrate/migrate.ts +149 -0
- package/src/openapi/parse.ts +64 -16
- package/src/openapi/proxy.ts +62 -10
- package/src/openapi/references.ts +147 -147
- package/src/openapi/render-mdx.ts +32 -10
- package/src/openapi/scalar.ts +15 -13
- package/src/openapi/sentence.ts +14 -0
- package/src/openapi/source.ts +37 -21
- package/src/openapi/spec-dependency-error.ts +15 -0
- package/src/reference/asyncapi.ts +83 -0
- package/src/reference/graphql.ts +89 -0
- package/src/reference/index.ts +40 -0
- package/src/reference/openapi.ts +83 -0
- package/src/reference/options.ts +201 -0
- package/src/reference/scalar.ts +136 -0
- package/src/reference/schema.ts +88 -0
- package/src/registry/eject.ts +97 -42
- package/src/search/adapters/algolia.ts +46 -0
- package/src/search/adapters/flexsearch.ts +29 -0
- package/src/search/adapters/index.ts +39 -0
- package/src/search/adapters/mixedbread.ts +39 -0
- package/src/search/adapters/orama-cloud.ts +51 -0
- package/src/search/adapters/orama.ts +24 -0
- package/src/search/adapters/pagefind.ts +27 -0
- package/src/search/adapters/registry.ts +131 -0
- package/src/search/adapters/types.ts +46 -0
- package/src/search/adapters/typesense.ts +57 -0
- package/src/search/build.ts +8 -4
- package/src/search/documents.ts +6 -0
- package/src/search/sync/algolia.ts +12 -11
- package/src/search/sync/index.ts +35 -20
- package/src/search/sync/orama-cloud.ts +12 -9
- package/src/search/sync/typesense.ts +15 -13
- package/src/sources/contentful.ts +63 -0
- package/src/sources/custom.ts +38 -0
- package/src/sources/filesystem.ts +51 -0
- package/src/sources/github-releases.ts +52 -0
- package/src/sources/index.ts +60 -0
- package/src/sources/mdx-remote.ts +76 -0
- package/src/sources/notion.ts +63 -0
- package/src/sources/obsidian.ts +38 -0
- package/src/sources/payload.ts +60 -0
- package/src/sources/registry.ts +182 -0
- package/src/sources/sanity.ts +66 -0
- package/src/sources/shared.ts +52 -0
- package/src/sources/strapi.ts +58 -0
- package/src/theme/entry.ts +24 -2
- package/src/translate/report.ts +40 -7
- package/src/upgrade/upgrade.ts +499 -0
- package/dist/cli/chunk-0qymqwzz.js +0 -164
- package/dist/cli/chunk-0qymqwzz.js.map +0 -15
- package/dist/cli/chunk-1jefwnfs.js.map +0 -48
- package/dist/cli/chunk-2mzebbbz.js +0 -69
- package/dist/cli/chunk-2z47ypj8.js.map +0 -11
- package/dist/cli/chunk-4x36ddpw.js.map +0 -11
- package/dist/cli/chunk-5093q3n7.js +0 -68
- package/dist/cli/chunk-5093q3n7.js.map +0 -10
- package/dist/cli/chunk-5qk08vmp.js.map +0 -11
- package/dist/cli/chunk-7s8hm3b6.js +0 -5347
- package/dist/cli/chunk-7s8hm3b6.js.map +0 -58
- package/dist/cli/chunk-8cjtbafj.js.map +0 -13
- package/dist/cli/chunk-97r59kpr.js +0 -381
- package/dist/cli/chunk-97r59kpr.js.map +0 -12
- package/dist/cli/chunk-ahnw3kxw.js.map +0 -15
- package/dist/cli/chunk-b27xqwn9.js.map +0 -10
- package/dist/cli/chunk-bf6bt1xt.js +0 -185
- package/dist/cli/chunk-bf6bt1xt.js.map +0 -11
- package/dist/cli/chunk-cjtn640a.js.map +0 -10
- package/dist/cli/chunk-ct47dqpx.js.map +0 -11
- package/dist/cli/chunk-esphfr8p.js +0 -107
- package/dist/cli/chunk-esphfr8p.js.map +0 -11
- package/dist/cli/chunk-ex56aa81.js +0 -1016
- package/dist/cli/chunk-ex56aa81.js.map +0 -13
- package/dist/cli/chunk-garjf5z9.js +0 -30
- package/dist/cli/chunk-garjf5z9.js.map +0 -10
- package/dist/cli/chunk-js7saxwm.js +0 -1045
- package/dist/cli/chunk-js7saxwm.js.map +0 -22
- package/dist/cli/chunk-k79xp7av.js.map +0 -39
- package/dist/cli/chunk-ps4m1xh4.js.map +0 -15
- package/dist/cli/chunk-q4rae3bg.js +0 -60
- package/dist/cli/chunk-q4rae3bg.js.map +0 -10
- package/dist/cli/chunk-rz9jmfhz.js +0 -108
- package/dist/cli/chunk-rz9jmfhz.js.map +0 -10
- package/dist/cli/chunk-vh9w1sgp.js +0 -73
- package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
- package/dist/cli/chunk-vrfp10qk.js +0 -81
- package/dist/cli/chunk-vrfp10qk.js.map +0 -10
- package/dist/cli/chunk-yg63d42r.js.map +0 -34
- package/docs/advanced/api-reference.mdx +0 -240
- package/docs/reference/cli.mdx +0 -197
- package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
- package/src/components/content/changelog-element.ts +0 -69
- package/src/search/providers.ts +0 -91
- /package/dist/cli/{chunk-e7f42gdj.js.map → chunk-7ez8ny0t.js.map} +0 -0
- /package/dist/cli/{chunk-nn13znc2.js.map → chunk-88cpgt6h.js.map} +0 -0
- /package/dist/cli/{chunk-vacwm2hv.js.map → chunk-f7t03s3g.js.map} +0 -0
- /package/dist/cli/{chunk-dwgcp5sm.js.map → chunk-zxccj738.js.map} +0 -0
|
@@ -161,6 +161,28 @@ export interface UseAskAIOptions {
|
|
|
161
161
|
/** Shown as the assistant's answer when the request fails or throws. */
|
|
162
162
|
const ASK_ERROR = "Something went wrong answering that. Please try again.";
|
|
163
163
|
|
|
164
|
+
/** How the generated Ask AI route opens its missing-credential notice. */
|
|
165
|
+
const NOT_CONFIGURED = /^Ask AI is not configured/u;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The route's own explanation of a 503 — the generated route's "Ask AI is not
|
|
169
|
+
* configured: set AI_GATEWAY_API_KEY." — when the response is that notice, or
|
|
170
|
+
* null. It names only the variable to set, never a value, so it's safe to
|
|
171
|
+
* show, and it tells a site owner trying a fresh deploy what's missing instead
|
|
172
|
+
* of the generic failure; any other error body (an HTML error page, a proxy's
|
|
173
|
+
* message) still gets the generic notice.
|
|
174
|
+
*/
|
|
175
|
+
const unavailableNotice = async (
|
|
176
|
+
response: Response
|
|
177
|
+
): Promise<string | null> => {
|
|
178
|
+
if (response.status !== 503) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const body = await response.text();
|
|
182
|
+
const text = body.trim();
|
|
183
|
+
return NOT_CONFIGURED.test(text) && text.length <= 200 ? text : null;
|
|
184
|
+
};
|
|
185
|
+
|
|
164
186
|
/** The current route with the deployment base stripped, for page grounding. */
|
|
165
187
|
const currentPath = (): string =>
|
|
166
188
|
stripBase(import.meta.env.BASE_URL, window.location.pathname);
|
|
@@ -253,10 +275,11 @@ export const useAskAI = (options: UseAskAIOptions = {}): UseAskAI => {
|
|
|
253
275
|
({ status } = response);
|
|
254
276
|
if (!response.ok) {
|
|
255
277
|
// An error body (JSON, HTML error page) must not stream in as the
|
|
256
|
-
// assistant's answer.
|
|
278
|
+
// assistant's answer — only the route's own not-configured notice.
|
|
279
|
+
const notice = await unavailableNotice(response).catch(() => null);
|
|
257
280
|
if (live()) {
|
|
258
281
|
outcome("ask_error", { status });
|
|
259
|
-
assistant.content = errorMessage;
|
|
282
|
+
assistant.content = notice ?? errorMessage;
|
|
260
283
|
setMessages([...history, { ...assistant }]);
|
|
261
284
|
}
|
|
262
285
|
return;
|
|
@@ -1,90 +1,32 @@
|
|
|
1
1
|
---
|
|
2
2
|
import VercelAnalytics from "@vercel/analytics/astro";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
4
|
+
import { analyticsHead } from "../../analytics/head.ts";
|
|
5
|
+
import type { BlumeDataConfig } from "../../core/data.ts";
|
|
6
|
+
|
|
7
|
+
// The analytics adapters' <head> output. Each adapter in `analytics` owns the
|
|
8
|
+
// snippet it emits (src/analytics/*); `analyticsHead` collects them into one
|
|
9
|
+
// list in declared order and this component renders it: the official Vercel
|
|
10
|
+
// component for `vercel()`, one <script> for every other adapter. Loads ONLY
|
|
11
|
+
// in production builds so `blume dev` stays clean and local traffic never
|
|
12
|
+
// reaches your analytics.
|
|
15
13
|
interface Props {
|
|
16
|
-
analytics?:
|
|
17
|
-
cloudflare?: { token: string };
|
|
18
|
-
posthog?: { host?: string; key: string };
|
|
19
|
-
scripts?: AnalyticsScript[];
|
|
20
|
-
vercel?: boolean;
|
|
21
|
-
} | null;
|
|
14
|
+
analytics?: BlumeDataConfig["analytics"] | null;
|
|
22
15
|
}
|
|
23
16
|
|
|
24
17
|
const { analytics } = Astro.props;
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
// Vercel Web Analytics: rendered via the official @vercel/analytics/astro
|
|
28
|
-
// component, which injects the first-party script Vercel serves at
|
|
29
|
-
// /_vercel/insights once Web Analytics is enabled for the project.
|
|
30
|
-
const vercelEnabled = enabled && analytics?.vercel === true;
|
|
31
|
-
|
|
32
|
-
// PostHog: the official array.js loader snippet, keyed off config. The host
|
|
33
|
-
// defaults to PostHog Cloud US; EU/self-hosted users override `posthog.host`.
|
|
34
|
-
const POSTHOG_LOADER =
|
|
35
|
-
'!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug getPageViewId captureTraceFeedback captureTraceMetric".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);';
|
|
36
|
-
const posthog = enabled ? analytics?.posthog : undefined;
|
|
37
|
-
// PostHog's loader only captures a pageview per real page load, but the client
|
|
38
|
-
// router turns link clicks into in-place swaps — capture those too, keyed off
|
|
39
|
-
// `astro:page-load` with a pathname guard so the initial load (which the
|
|
40
|
-
// loader already counted) and same-page hash moves aren't double-counted.
|
|
41
|
-
// Vercel Web Analytics and GA4's enhanced measurement track history changes
|
|
42
|
-
// on their own.
|
|
43
|
-
const POSTHOG_SPA_PAGEVIEWS =
|
|
44
|
-
'document.addEventListener("astro:page-load",function(){var p=window.__blumePhPath;window.__blumePhPath=location.pathname;if(p!==undefined&&p!==location.pathname){posthog.capture("$pageview");}});';
|
|
45
|
-
const posthogSnippet = posthog
|
|
46
|
-
? `${POSTHOG_LOADER}posthog.init(${JSON.stringify(posthog.key)},{api_host:${JSON.stringify(posthog.host ?? "https://us.i.posthog.com")}});${POSTHOG_SPA_PAGEVIEWS}`
|
|
47
|
-
: null;
|
|
48
|
-
|
|
49
|
-
// Cloudflare Web Analytics (manual setup): the beacon script keyed by the
|
|
50
|
-
// site token, exactly as the dashboard's snippet renders it. It tracks
|
|
51
|
-
// history changes itself, so client-router navigations need no extra hook.
|
|
52
|
-
const cloudflareBeacon =
|
|
53
|
-
enabled && analytics?.cloudflare
|
|
54
|
-
? JSON.stringify({ token: analytics.cloudflare.token })
|
|
55
|
-
: null;
|
|
56
|
-
|
|
57
|
-
// Custom scripts: any other provider. Each is either external (`src`) or inline
|
|
58
|
-
// (`content`). Explicit fields win over spread `attributes`.
|
|
59
|
-
const customScripts = enabled ? (analytics?.scripts ?? []) : [];
|
|
60
|
-
const externalScripts = customScripts
|
|
61
|
-
.filter((script) => script.src)
|
|
62
|
-
.map((script) => ({
|
|
63
|
-
...script.attributes,
|
|
64
|
-
...(script.strategy === "async" ? { async: true } : {}),
|
|
65
|
-
...(script.strategy === "defer" ? { defer: true } : {}),
|
|
66
|
-
src: script.src,
|
|
67
|
-
}));
|
|
68
|
-
const inlineScripts = customScripts
|
|
69
|
-
.filter((script) => script.content)
|
|
70
|
-
.map((script) => ({ attributes: script.attributes ?? {}, content: script.content }));
|
|
18
|
+
const nodes = analyticsHead(import.meta.env.PROD ? (analytics ?? []) : []);
|
|
71
19
|
---
|
|
72
20
|
|
|
73
|
-
{vercelEnabled && <VercelAnalytics />}
|
|
74
|
-
{
|
|
75
|
-
cloudflareBeacon && (
|
|
76
|
-
<script
|
|
77
|
-
is:inline
|
|
78
|
-
defer
|
|
79
|
-
src="https://static.cloudflareinsights.com/beacon.min.js"
|
|
80
|
-
data-cf-beacon={cloudflareBeacon}
|
|
81
|
-
/>
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
{posthogSnippet && <script is:inline set:html={posthogSnippet} />}
|
|
85
|
-
{externalScripts.map((attrs) => <script is:inline {...attrs} />)}
|
|
86
21
|
{
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
22
|
+
nodes.map((node) => {
|
|
23
|
+
if (node.type === "vercel") {
|
|
24
|
+
return <VercelAnalytics {...node.props} />;
|
|
25
|
+
}
|
|
26
|
+
return node.content === null ? (
|
|
27
|
+
<script is:inline {...node.attributes} />
|
|
28
|
+
) : (
|
|
29
|
+
<script is:inline set:html={node.content} {...node.attributes} />
|
|
30
|
+
);
|
|
31
|
+
})
|
|
90
32
|
}
|
|
@@ -34,7 +34,9 @@ const b = { ...EN_UI.banner, ...strings };
|
|
|
34
34
|
data-banner-key={banner.key}
|
|
35
35
|
data-blume-banner
|
|
36
36
|
>
|
|
37
|
-
|
|
37
|
+
{/* The message is authored in one language, whatever the page's
|
|
38
|
+
direction: `dir="auto"` keeps its punctuation where it was typed. */}
|
|
39
|
+
<span dir="auto">{banner.content}</span>
|
|
38
40
|
{banner.link && (
|
|
39
41
|
<a
|
|
40
42
|
class="inline-flex items-center gap-1 font-medium underline underline-offset-2"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { DiscoveryHeadLinks } from "../../core/data.ts";
|
|
3
|
+
import { withBase } from "../islands/base-path.ts";
|
|
4
|
+
// Emits the agent-discovery <link>s for the document <head>, on every page and
|
|
5
|
+
// not just the root: an agent that enters on a deep page (a search result, a
|
|
6
|
+
// shared link) never sees the homepage HTTP `Link` header (see
|
|
7
|
+
// `ai/link-headers.ts`), so the head carries the same `describedby` resources,
|
|
8
|
+
// the AI Catalog / ARD manifest pair, and — when the page has one — its own
|
|
9
|
+
// raw-Markdown mirror as an `alternate`. This also reaches hosts where Blume
|
|
10
|
+
// can't set response headers. Every shell (RootLayout, PageLayout,
|
|
11
|
+
// ReferenceLayout) renders this one partial, so the "every page's head"
|
|
12
|
+
// promise has a single definition. Both `describedby` and `alternate` are
|
|
13
|
+
// IANA-registered relations.
|
|
14
|
+
interface Props {
|
|
15
|
+
/**
|
|
16
|
+
* Which resources exist, from the `blume:data` snapshot; `null` drops every
|
|
17
|
+
* link this partial renders, the Markdown alternate included (a page opting
|
|
18
|
+
* out of the agent-facing surface).
|
|
19
|
+
*/
|
|
20
|
+
discovery?: DiscoveryHeadLinks | null;
|
|
21
|
+
/**
|
|
22
|
+
* This page's raw-Markdown mirror (already under the deployment base), or
|
|
23
|
+
* `null` when the route has none — only content routes and the homepage do
|
|
24
|
+
* (see `markdownRoutePaths`). Advertised only while `discovery` is set.
|
|
25
|
+
*/
|
|
26
|
+
markdownMirror?: string | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const { discovery, markdownMirror } = Astro.props;
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
discovery?.agentReadability && (
|
|
34
|
+
<link
|
|
35
|
+
href={withBase("/agent-readability.json")}
|
|
36
|
+
rel="describedby"
|
|
37
|
+
type="application/json"
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
{
|
|
42
|
+
discovery?.llmsTxt && (
|
|
43
|
+
<link href={withBase("/llms.txt")} rel="describedby" type="text/plain" />
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
{/* The AI Catalog / ARD manifest under both relations its two specs define:
|
|
47
|
+
`ai-catalog` (ai-catalog spec) and `ard` (ARD v0.91), each pointing at that
|
|
48
|
+
spec's own well-known path. */}
|
|
49
|
+
{
|
|
50
|
+
discovery?.aiCatalog && (
|
|
51
|
+
<>
|
|
52
|
+
<link
|
|
53
|
+
href={withBase("/.well-known/ai-catalog.json")}
|
|
54
|
+
rel="ai-catalog"
|
|
55
|
+
type="application/ai-catalog+json"
|
|
56
|
+
/>
|
|
57
|
+
<link
|
|
58
|
+
href={withBase("/.well-known/ard.json")}
|
|
59
|
+
rel="ard"
|
|
60
|
+
type="application/json"
|
|
61
|
+
/>
|
|
62
|
+
</>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
{
|
|
66
|
+
discovery && markdownMirror && (
|
|
67
|
+
<link href={markdownMirror} rel="alternate" type="text/markdown" />
|
|
68
|
+
)
|
|
69
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import Ask from "blume:ask";
|
|
3
3
|
import data from "blume:data";
|
|
4
4
|
import { withBase } from "../islands/base-path.ts";
|
|
5
|
-
import {
|
|
5
|
+
import { NEW_TAB_ATTRS, newTabAttrs } from "../../core/new-tab.ts";
|
|
6
6
|
import type { ComponentOverride } from "../../core/define-components.ts";
|
|
7
7
|
import { EN_UI } from "../../core/i18n-ui.ts";
|
|
8
8
|
import type { UIStrings } from "../../core/i18n-ui.ts";
|
|
@@ -33,6 +33,11 @@ interface Props {
|
|
|
33
33
|
navigation: Navigation;
|
|
34
34
|
route: string;
|
|
35
35
|
searchEnabled: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Active locale of the page, forwarded to the `Logo` slot so the brand link
|
|
38
|
+
* resolves to the locale's root like the tabs beside it.
|
|
39
|
+
*/
|
|
40
|
+
locale?: string;
|
|
36
41
|
/**
|
|
37
42
|
* Whether the search modal offers an "Ask AI" hand-off. Defaults to whether
|
|
38
43
|
* Ask AI is configured, so no page has to pass it; a layout can still opt a
|
|
@@ -71,6 +76,12 @@ interface Props {
|
|
|
71
76
|
* the whole header.
|
|
72
77
|
*/
|
|
73
78
|
layout?: Record<string, ComponentOverride>;
|
|
79
|
+
/**
|
|
80
|
+
* Start the header see-through, with its chrome in white, so it can sit over
|
|
81
|
+
* a dark hero at the top of the page; it returns to the frosted bar as soon
|
|
82
|
+
* as the page scrolls (`PageLayout`'s `transparentHeader`).
|
|
83
|
+
*/
|
|
84
|
+
transparent?: boolean;
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
const {
|
|
@@ -79,6 +90,7 @@ const {
|
|
|
79
90
|
navigation,
|
|
80
91
|
route,
|
|
81
92
|
searchEnabled,
|
|
93
|
+
locale,
|
|
82
94
|
// `config.ask` is null whenever Ask AI is off, so the header is the one place
|
|
83
95
|
// that has to know — the Ask trigger below and the search modal's hand-off to
|
|
84
96
|
// it both switch on this, and every page gets both for free.
|
|
@@ -94,6 +106,7 @@ const {
|
|
|
94
106
|
searchLocale,
|
|
95
107
|
searchVersion = null,
|
|
96
108
|
layout = {},
|
|
109
|
+
transparent = false,
|
|
97
110
|
} = Astro.props;
|
|
98
111
|
|
|
99
112
|
// Merge over the English defaults so a label missing from a translation (or
|
|
@@ -143,6 +156,12 @@ const ctaClass = [
|
|
|
143
156
|
// for the swap (next-themes' disableTransitionOnChange trick), force a
|
|
144
157
|
// synchronous style flush, then restore them on the next tick.
|
|
145
158
|
//
|
|
159
|
+
// Both the theme toggle and the banner dismiss change the page first and only
|
|
160
|
+
// then remember the choice: localStorage throws where storage is blocked
|
|
161
|
+
// (Safari "Block All Cookies", sandboxed iframes), and a throw before the DOM
|
|
162
|
+
// change would leave the toggle dead with transitions switched off for good.
|
|
163
|
+
// There the choice simply isn't remembered.
|
|
164
|
+
//
|
|
146
165
|
// The mobile drawer sits below the sticky header, but the banner above the
|
|
147
166
|
// header has no fixed height (its text wraps), so the drawer's top offset can't
|
|
148
167
|
// be static: on open we measure the header's on-screen bottom edge into
|
|
@@ -150,16 +169,31 @@ const ctaClass = [
|
|
|
150
169
|
// so the offset can't drift while open, and re-measure when a banner dismiss or
|
|
151
170
|
// a resize/rotation moves the header. Crossing into the desktop breakpoint
|
|
152
171
|
// (64rem, Tailwind `lg`) closes the drawer so the scroll lock can't outlive it.
|
|
153
|
-
|
|
172
|
+
// The rest of the drawer's behavior — the toggle's `aria-expanded`, Escape to
|
|
173
|
+
// close, and the inert page behind it — follows the same attribute from the
|
|
174
|
+
// layouts' drawer-inert.ts.
|
|
175
|
+
// Transparent header: flag the bar as scrolled once the page moves off the
|
|
176
|
+
// top so the stylesheet below can swap it back to the frosted look. `sync`
|
|
177
|
+
// re-queries the header each time, so the one listener a real load installs
|
|
178
|
+
// keeps working across client-router swaps (and no-ops on pages without it).
|
|
179
|
+
// The router re-runs this inline script on every swap into a transparent-header
|
|
180
|
+
// page, so it syncs that page each time but installs the listeners only once
|
|
181
|
+
// per real load, behind a window flag.
|
|
182
|
+
const transparentScript = `(()=>{const sync=()=>{const h=document.querySelector("[data-blume-header-transparent]");if(h){h.toggleAttribute("data-blume-header-scrolled",scrollY>8);}};sync();if(window.__blumeTransparentHeader){return;}window.__blumeTransparentHeader=true;addEventListener("scroll",sync,{passive:true});document.addEventListener("astro:after-swap",sync);})();`;
|
|
183
|
+
|
|
184
|
+
const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-blume-header]");if(h){document.documentElement.style.setProperty("--blume-drawer-top",h.getBoundingClientRect().bottom+"px");}};const save=(k,v)=>{try{localStorage.setItem(k,v);}catch{}};document.addEventListener("click",(e)=>{const t=e.target.closest("[data-blume-theme-toggle]");if(t){const d=document.documentElement;const next=d.dataset.theme==="dark"?"light":"dark";const s=document.createElement("style");s.appendChild(document.createTextNode("*,*::before,*::after{transition:none!important}"));document.head.appendChild(s);d.dataset.theme=next;window.getComputedStyle(d).opacity;setTimeout(()=>document.head.removeChild(s),1);save("blume-theme",next);}const n=e.target.closest("[data-blume-nav-toggle]");if(n){const d=document.documentElement;const open=d.toggleAttribute("data-blume-nav-open");if(open){dr();}}const b=e.target.closest("[data-blume-banner-dismiss]");if(b){document.documentElement.setAttribute("data-blume-banner-hidden","");requestAnimationFrame(dr);const bar=b.closest("[data-blume-banner]");const k=bar&&bar.getAttribute("data-banner-key");if(k){save("blume-banner:"+k,"1");}}});addEventListener("resize",()=>{const d=document.documentElement;if(!d.hasAttribute("data-blume-nav-open")){return;}if(matchMedia("(min-width:64rem)").matches){d.removeAttribute("data-blume-nav-open");}else{dr();}});})();`;
|
|
154
185
|
---
|
|
155
186
|
|
|
156
187
|
<header
|
|
157
188
|
class="sticky top-0 z-40 flex h-16 items-center gap-3 bg-background/90 px-4 backdrop-blur md:px-6"
|
|
158
189
|
data-blume-header
|
|
190
|
+
data-blume-header-transparent={transparent ? "" : undefined}
|
|
159
191
|
>
|
|
160
192
|
{
|
|
161
193
|
showNavToggle && (
|
|
162
194
|
<button
|
|
195
|
+
aria-controls="blume-nav-drawer"
|
|
196
|
+
aria-expanded="false"
|
|
163
197
|
aria-label={n.toggleNavigation}
|
|
164
198
|
class={`${iconButton} lg:hidden`}
|
|
165
199
|
data-blume-nav-toggle
|
|
@@ -169,7 +203,7 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
|
|
|
169
203
|
</button>
|
|
170
204
|
)
|
|
171
205
|
}
|
|
172
|
-
<LogoSlot logo={logo} site={site} />
|
|
206
|
+
<LogoSlot locale={locale} logo={logo} site={site} />
|
|
173
207
|
{
|
|
174
208
|
navigation.selectors.length > 0 && (
|
|
175
209
|
<div class="flex items-center gap-1.5">
|
|
@@ -229,27 +263,22 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
|
|
|
229
263
|
{
|
|
230
264
|
/* Plain links first, then the one filled button: the reader's eye lands
|
|
231
265
|
on the button because nothing beside it competes. */
|
|
232
|
-
(navigation.actions ?? []).map((action) =>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
{action.label}
|
|
242
|
-
</a>
|
|
243
|
-
);
|
|
244
|
-
})
|
|
266
|
+
(navigation.actions ?? []).map((action) => (
|
|
267
|
+
<a
|
|
268
|
+
class={actionClass}
|
|
269
|
+
href={withBase(action.href)}
|
|
270
|
+
{...newTabAttrs(action.href)}
|
|
271
|
+
>
|
|
272
|
+
{action.label}
|
|
273
|
+
</a>
|
|
274
|
+
))
|
|
245
275
|
}
|
|
246
276
|
{
|
|
247
277
|
navigation.cta && (
|
|
248
278
|
<a
|
|
249
279
|
class={ctaClass}
|
|
250
280
|
href={withBase(navigation.cta.href)}
|
|
251
|
-
|
|
252
|
-
target={isExternalUrl(navigation.cta.href) ? "_blank" : undefined}
|
|
281
|
+
{...newTabAttrs(navigation.cta.href)}
|
|
253
282
|
>
|
|
254
283
|
{navigation.cta.label}
|
|
255
284
|
<Icon name="chevron-right" size={14} />
|
|
@@ -262,8 +291,7 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
|
|
|
262
291
|
aria-label={n.githubRepository}
|
|
263
292
|
class={iconButton}
|
|
264
293
|
href={navigation.repoUrl}
|
|
265
|
-
|
|
266
|
-
target="_blank"
|
|
294
|
+
{...NEW_TAB_ATTRS}
|
|
267
295
|
>
|
|
268
296
|
<svg
|
|
269
297
|
aria-hidden="true"
|
|
@@ -290,3 +318,38 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
|
|
|
290
318
|
</div>
|
|
291
319
|
</header>
|
|
292
320
|
<script is:inline set:html={clickScript} />
|
|
321
|
+
{transparent && <script is:inline set:html={transparentScript} />}
|
|
322
|
+
|
|
323
|
+
<style is:global>
|
|
324
|
+
/* Transparent header (PageLayout `transparentHeader`): at the top of the
|
|
325
|
+
page the bar has no background and its chrome renders in white so it can
|
|
326
|
+
sit over a dark hero; once scrolled it is the frosted bar again. The color
|
|
327
|
+
tokens are re-declared on the header so every utility inside follows, and
|
|
328
|
+
the search dialog gets the page's own values back so it isn't inverted. */
|
|
329
|
+
:root {
|
|
330
|
+
--blume-header-background: var(--blume-background);
|
|
331
|
+
--blume-header-foreground: var(--blume-foreground);
|
|
332
|
+
--blume-header-muted: var(--blume-muted);
|
|
333
|
+
--blume-header-muted-foreground: var(--blume-muted-foreground);
|
|
334
|
+
--blume-header-border: var(--blume-border);
|
|
335
|
+
}
|
|
336
|
+
[data-blume-header-transparent] {
|
|
337
|
+
transition: background-color 200ms;
|
|
338
|
+
}
|
|
339
|
+
[data-blume-header-transparent]:not([data-blume-header-scrolled]) {
|
|
340
|
+
--blume-background: transparent;
|
|
341
|
+
--blume-foreground: #fff;
|
|
342
|
+
--blume-muted: rgb(255 255 255 / 0.12);
|
|
343
|
+
--blume-muted-foreground: rgb(255 255 255 / 0.75);
|
|
344
|
+
--blume-border: rgb(255 255 255 / 0.25);
|
|
345
|
+
background-color: transparent;
|
|
346
|
+
backdrop-filter: none;
|
|
347
|
+
}
|
|
348
|
+
[data-blume-header-transparent]:not([data-blume-header-scrolled]) dialog {
|
|
349
|
+
--blume-background: var(--blume-header-background);
|
|
350
|
+
--blume-foreground: var(--blume-header-foreground);
|
|
351
|
+
--blume-muted: var(--blume-header-muted);
|
|
352
|
+
--blume-muted-foreground: var(--blume-header-muted-foreground);
|
|
353
|
+
--blume-border: var(--blume-header-border);
|
|
354
|
+
}
|
|
355
|
+
</style>
|
|
@@ -11,6 +11,9 @@ interface Props {
|
|
|
11
11
|
|
|
12
12
|
const { options, label, untranslatedLabel } = Astro.props;
|
|
13
13
|
const current = options.find((option) => option.current);
|
|
14
|
+
// The accessible name carries the visible language name too (WCAG 2.5.3,
|
|
15
|
+
// label in name), so a voice-control user can say "English" to open it.
|
|
16
|
+
const summaryLabel = current ? `${label}: ${current.label}` : label;
|
|
14
17
|
|
|
15
18
|
const iconButton =
|
|
16
19
|
"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";
|
|
@@ -22,7 +25,7 @@ const menuRowClass =
|
|
|
22
25
|
options.length > 1 && (
|
|
23
26
|
<details class="group relative" data-blume-dropdown>
|
|
24
27
|
<summary
|
|
25
|
-
aria-label={
|
|
28
|
+
aria-label={summaryLabel}
|
|
26
29
|
class={`${iconButton} list-none [&::-webkit-details-marker]:hidden`}
|
|
27
30
|
>
|
|
28
31
|
<Icon name="globe" size={16} />
|
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
---
|
|
2
|
+
import data from "blume:data";
|
|
2
3
|
import { withBase } from "../islands/base-path.ts";
|
|
3
4
|
// The site brand: the logo mark (inline SVG so a `currentColor` mark follows the
|
|
4
5
|
// theme, or light/dark `<img>` variants) followed by the site title, wrapped in
|
|
5
6
|
// a link to the brand href. Extracted from the header so it can be replaced on
|
|
6
7
|
// its own through the `Logo` layout slot (`defineComponents({ layout: { Logo } })`).
|
|
7
8
|
import type { BlumeLogo } from "../../core/data.ts";
|
|
9
|
+
import { localizeInternalPath } from "../../core/i18n.ts";
|
|
8
10
|
|
|
9
11
|
interface Props {
|
|
10
12
|
site: { title: string };
|
|
11
13
|
logo?: BlumeLogo | null;
|
|
14
|
+
/**
|
|
15
|
+
* Active locale of the page. The brand link follows it the way the header
|
|
16
|
+
* tabs do (`/` -> `/en` under a prefixed locale), so clicking the logo never
|
|
17
|
+
* drops a reader out of the language they were reading. Absent, the link is
|
|
18
|
+
* emitted as configured.
|
|
19
|
+
*/
|
|
20
|
+
locale?: string;
|
|
12
21
|
}
|
|
13
22
|
|
|
14
|
-
const { site, logo } = Astro.props;
|
|
23
|
+
const { site, logo, locale } = Astro.props;
|
|
15
24
|
|
|
16
25
|
// The logo is resolved upstream: an inline `svg` (so a currentColor mark follows
|
|
17
26
|
// the theme) or image URL(s) for an <img>.
|
|
@@ -21,7 +30,19 @@ const logoDark = logo?.dark ?? logo?.light;
|
|
|
21
30
|
const logoLightDimensions = logo?.dimensions?.light;
|
|
22
31
|
const logoDarkDimensions = logo?.dimensions?.dark ?? logo?.dimensions?.light;
|
|
23
32
|
const logoAlt = logo?.alt ?? "";
|
|
24
|
-
|
|
33
|
+
// The configured `logo.href` (default `/`) is authored in the default locale's
|
|
34
|
+
// path space, like a tab path; localize it for the page's locale. The locale's
|
|
35
|
+
// navigation carries it resolved against the routes the build serves (a custom
|
|
36
|
+
// home page exists only at `/`, so it isn't moved to `/fr`). External and
|
|
37
|
+
// protocol-relative hrefs pass through, and `withBase` layers the deployment
|
|
38
|
+
// base on afterwards, so the locale prefix sits inside the base like every
|
|
39
|
+
// other localized route.
|
|
40
|
+
const configuredHref = logo?.href ?? "/";
|
|
41
|
+
const brandHref =
|
|
42
|
+
locale === undefined
|
|
43
|
+
? configuredHref
|
|
44
|
+
: (data.navigationByLocale[locale]?.brandHref ??
|
|
45
|
+
localizeInternalPath(configuredHref, locale, data.config.i18n));
|
|
25
46
|
// Wordmark beside the mark: the configured `logo.text`, or the site title when
|
|
26
47
|
// it's omitted. An explicit `""` hides it (an image-only logo whose mark already
|
|
27
48
|
// carries the wordmark).
|
|
@@ -33,6 +33,12 @@ const active =
|
|
|
33
33
|
.toSorted((a, b) => b.path.length - a.path.length)[0] ??
|
|
34
34
|
selector.items[0];
|
|
35
35
|
|
|
36
|
+
// The active label rides in the trigger on every screen when it's short (a
|
|
37
|
+
// version like "v2" or "Latest"): on a phone a bare chevron doesn't say what
|
|
38
|
+
// it switches. Longer product names still collapse to the icon there.
|
|
39
|
+
const label = active?.label ?? selector.label;
|
|
40
|
+
const labelClass = label.length <= 6 ? undefined : "max-sm:hidden";
|
|
41
|
+
|
|
36
42
|
const iconButton =
|
|
37
43
|
"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";
|
|
38
44
|
const menuRowClass =
|
|
@@ -47,7 +53,7 @@ const menuRowClass =
|
|
|
47
53
|
class={`${iconButton} list-none [&::-webkit-details-marker]:hidden`}
|
|
48
54
|
>
|
|
49
55
|
{active?.icon && <Icon name={active.icon} size={16} />}
|
|
50
|
-
<span class=
|
|
56
|
+
<span class={labelClass}>{label}</span>
|
|
51
57
|
<Icon
|
|
52
58
|
class="transition-transform group-open:rotate-180"
|
|
53
59
|
name="chevron-down"
|
|
@@ -55,7 +61,8 @@ const menuRowClass =
|
|
|
55
61
|
/>
|
|
56
62
|
</summary>
|
|
57
63
|
<div
|
|
58
|
-
class={`absolute z-50 mt-2 min-w-56 rounded-blume border border-border bg-background p-1 shadow-xl ${align === "end" ? "end-0" : "start-0"}`}
|
|
64
|
+
class={`absolute z-50 mt-2 min-w-56 max-w-[calc(100vw-1rem)] rounded-blume border border-border bg-background p-1 shadow-xl ${align === "end" ? "end-0" : "start-0"}`}
|
|
65
|
+
data-blume-dropdown-panel
|
|
59
66
|
>
|
|
60
67
|
{selector.items.map((item) => (
|
|
61
68
|
<a
|
|
@@ -89,8 +96,12 @@ const menuRowClass =
|
|
|
89
96
|
|
|
90
97
|
<script>
|
|
91
98
|
import { installDropdownDismiss } from "../dropdown-dismiss.ts";
|
|
99
|
+
import { installDropdownClamp } from "./dropdown-clamp.ts";
|
|
92
100
|
|
|
93
101
|
// Outside-click / Escape / focus-out dismissal, shared with the language
|
|
94
102
|
// switcher and the page actions.
|
|
95
103
|
installDropdownDismiss();
|
|
104
|
+
// On a phone the trigger sits mid-header, so an edge-anchored panel can
|
|
105
|
+
// run off the screen; shift it back inside when it opens.
|
|
106
|
+
installDropdownClamp();
|
|
96
107
|
</script>
|
|
@@ -8,6 +8,7 @@ import { withBase } from "../islands/base-path.ts";
|
|
|
8
8
|
import Self from "./NavTree.astro";
|
|
9
9
|
import NavTreeCache from "./NavTreeCache.astro";
|
|
10
10
|
import NavTreeScript from "./NavTreeScript.astro";
|
|
11
|
+
import { isGroupRowCurrent } from "./nav-utils.ts";
|
|
11
12
|
|
|
12
13
|
interface PagePanel {
|
|
13
14
|
id: string;
|
|
@@ -180,7 +181,11 @@ const initialId =
|
|
|
180
181
|
<Icon class="rtl:-scale-x-100" name="arrow-left" size={16} />
|
|
181
182
|
</button>
|
|
182
183
|
<a
|
|
183
|
-
aria-current={
|
|
184
|
+
aria-current={
|
|
185
|
+
isGroupRowCurrent(panel.node, currentRoute)
|
|
186
|
+
? "page"
|
|
187
|
+
: undefined
|
|
188
|
+
}
|
|
184
189
|
class="flex-1 truncate rounded-[0.65rem] px-1 py-1 font-semibold text-foreground text-sm transition-colors hover:bg-muted"
|
|
185
190
|
href={withBase(panel.route)}
|
|
186
191
|
>
|
|
@@ -329,7 +334,9 @@ const initialId =
|
|
|
329
334
|
{item.route ? (
|
|
330
335
|
<a
|
|
331
336
|
aria-current={
|
|
332
|
-
item
|
|
337
|
+
isGroupRowCurrent(item, currentRoute)
|
|
338
|
+
? "page"
|
|
339
|
+
: undefined
|
|
333
340
|
}
|
|
334
341
|
class="blume-nav-summary-link"
|
|
335
342
|
href={withBase(item.route)}
|
|
@@ -412,7 +419,9 @@ const initialId =
|
|
|
412
419
|
<p class="blume-nav-heading">
|
|
413
420
|
{item.route ? (
|
|
414
421
|
<a
|
|
415
|
-
aria-current={
|
|
422
|
+
aria-current={
|
|
423
|
+
isGroupRowCurrent(item, currentRoute) ? "page" : undefined
|
|
424
|
+
}
|
|
416
425
|
class="blume-nav-heading-link"
|
|
417
426
|
href={withBase(item.route)}
|
|
418
427
|
>
|
|
@@ -77,7 +77,12 @@
|
|
|
77
77
|
}
|
|
78
78
|
const slot = deferredIn(details.querySelector(":scope > [data-nav-src]"));
|
|
79
79
|
if (slot) {
|
|
80
|
-
|
|
80
|
+
// A fragment that can't load (offline, a deploy that dropped it)
|
|
81
|
+
// closes the group again instead of leaving it open and empty; the
|
|
82
|
+
// slot keeps its `data-nav-src`, so the next open retries.
|
|
83
|
+
fillDeferred(slot).catch(() => {
|
|
84
|
+
details.open = false;
|
|
85
|
+
});
|
|
81
86
|
}
|
|
82
87
|
},
|
|
83
88
|
true
|
|
@@ -159,8 +164,17 @@
|
|
|
159
164
|
if (!next) {
|
|
160
165
|
return;
|
|
161
166
|
}
|
|
162
|
-
// A deferred panel loads its contents before it slides in.
|
|
163
|
-
|
|
167
|
+
// A deferred panel loads its contents before it slides in. When its
|
|
168
|
+
// fragment can't load (offline, a deploy that dropped it), the drill-in
|
|
169
|
+
// follows the section's own page link — the panel's title — instead of
|
|
170
|
+
// leaving the click dead. A section with no page stays put, and the next
|
|
171
|
+
// drill-in retries the fetch.
|
|
172
|
+
try {
|
|
173
|
+
await fillDeferred(next);
|
|
174
|
+
} catch {
|
|
175
|
+
next.querySelector<HTMLAnchorElement>("a[href]")?.click();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
164
178
|
const prev = this.active;
|
|
165
179
|
if (prev === next) {
|
|
166
180
|
return;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { EN_UI } from "../../core/i18n-ui.ts";
|
|
3
3
|
import type { UIStrings } from "../../core/i18n-ui.ts";
|
|
4
|
+
import { NEW_TAB_ATTRS } from "../../core/new-tab.ts";
|
|
4
5
|
import { openInChatProviders } from "../../core/open-in-chat.ts";
|
|
5
6
|
import type { OpenInChatProvider } from "../../core/open-in-chat.ts";
|
|
6
7
|
import { GITHUB_MARK } from "../github-mark.ts";
|
|
@@ -112,7 +113,7 @@ const menuRowClass =
|
|
|
112
113
|
>
|
|
113
114
|
{
|
|
114
115
|
editUrl && (
|
|
115
|
-
<a class={rowClass} href={editUrl}
|
|
116
|
+
<a class={rowClass} href={editUrl} {...NEW_TAB_ATTRS}>
|
|
116
117
|
<span set:html={GITHUB_LOGO} />
|
|
117
118
|
{a.edit}
|
|
118
119
|
</a>
|
|
@@ -192,8 +193,7 @@ const menuRowClass =
|
|
|
192
193
|
<a
|
|
193
194
|
class={menuRowClass}
|
|
194
195
|
data-open-in={provider.key}
|
|
195
|
-
|
|
196
|
-
target="_blank"
|
|
196
|
+
{...NEW_TAB_ATTRS}
|
|
197
197
|
>
|
|
198
198
|
<span set:html={LOGOS[provider.key]} />
|
|
199
199
|
<span class="flex-1">{provider.label}</span>
|