blume 2.0.3 → 2.1.1

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.
Files changed (607) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +142 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
  5. package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
  6. package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
  7. package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
  8. package/dist/cli/chunk-150jk7km.js +52 -0
  9. package/dist/cli/chunk-150jk7km.js.map +10 -0
  10. package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
  11. package/dist/cli/chunk-313vnn40.js.map +10 -0
  12. package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
  13. package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
  14. package/dist/cli/chunk-3x6x3pph.js.map +10 -0
  15. package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
  16. package/dist/cli/chunk-42t4jxdx.js.map +12 -0
  17. package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
  18. package/dist/cli/chunk-54ztw1nj.js.map +10 -0
  19. package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
  20. package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
  21. package/dist/cli/chunk-66w9j7p6.js +322 -0
  22. package/dist/cli/chunk-66w9j7p6.js.map +14 -0
  23. package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
  24. package/dist/cli/chunk-7ppf1rva.js.map +10 -0
  25. package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
  26. package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
  27. package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
  28. package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
  29. package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
  30. package/dist/cli/chunk-cfyg47zg.js.map +10 -0
  31. package/dist/cli/chunk-cm89scdv.js +443 -0
  32. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  33. package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
  34. package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
  35. package/dist/cli/chunk-e6atmn4h.js.map +36 -0
  36. package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
  37. package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
  38. package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
  39. package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
  40. package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
  41. package/dist/cli/chunk-ehweg4fr.js.map +218 -0
  42. package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
  43. package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
  44. package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
  45. package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
  46. package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
  47. package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
  48. package/dist/cli/chunk-gb420vvz.js.map +17 -0
  49. package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
  50. package/dist/cli/chunk-hebn0tpx.js.map +14 -0
  51. package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
  52. package/dist/cli/chunk-htrwgabr.js.map +15 -0
  53. package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
  54. package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
  55. package/dist/cli/chunk-j134vrp2.js +65 -0
  56. package/dist/cli/chunk-j134vrp2.js.map +10 -0
  57. package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
  58. package/dist/cli/chunk-kwrg63tm.js +31 -0
  59. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  60. package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
  61. package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
  62. package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
  63. package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
  64. package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
  65. package/dist/cli/chunk-ncj7w596.js.map +35 -0
  66. package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
  67. package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
  68. package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
  69. package/dist/cli/chunk-nrns10mj.js.map +10 -0
  70. package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
  71. package/dist/cli/chunk-t2m5j4pr.js +104 -0
  72. package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
  73. package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
  74. package/dist/cli/chunk-tphac74f.js +126 -0
  75. package/dist/cli/chunk-tphac74f.js.map +11 -0
  76. package/dist/cli/chunk-w1r4vase.js +18 -0
  77. package/dist/cli/chunk-w1r4vase.js.map +10 -0
  78. package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
  79. package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
  80. package/dist/cli/index.js +31 -20
  81. package/dist/cli/index.js.map +5 -5
  82. package/dist/types/ai/agent-surface.d.ts +8 -7
  83. package/dist/types/ai/ai-catalog.d.ts +7 -0
  84. package/dist/types/ai/ask-context.d.ts +26 -0
  85. package/dist/types/ai/ask.d.ts +271 -58
  86. package/dist/types/ai/component-markdown.d.ts +2 -0
  87. package/dist/types/ai/index.d.ts +2 -2
  88. package/dist/types/ai/openapi-components.d.ts +4 -1
  89. package/dist/types/ai/site-skill.d.ts +26 -0
  90. package/dist/types/ai/skills.d.ts +16 -0
  91. package/dist/types/astro/integration.d.ts +9 -0
  92. package/dist/types/astro/markdown-negotiation.d.ts +3 -0
  93. package/dist/types/astro/pages.d.ts +10 -0
  94. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  95. package/dist/types/captcha/index.d.ts +28 -0
  96. package/dist/types/captcha/schema.d.ts +29 -0
  97. package/dist/types/captcha/turnstile.d.ts +28 -0
  98. package/dist/types/cli/init/scaffold.d.ts +1 -1
  99. package/dist/types/components/content/api-field.d.ts +62 -0
  100. package/dist/types/components/content/api-page.d.ts +100 -0
  101. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  102. package/dist/types/components/openapi/code-samples.d.ts +29 -0
  103. package/dist/types/components/openapi/helpers.d.ts +158 -0
  104. package/dist/types/components/openapi/security.d.ts +95 -0
  105. package/dist/types/components/openapi/snippets.d.ts +60 -0
  106. package/dist/types/consent/ethyca.d.ts +48 -0
  107. package/dist/types/consent/index.d.ts +37 -0
  108. package/dist/types/consent/native.d.ts +28 -0
  109. package/dist/types/consent/osano.d.ts +42 -0
  110. package/dist/types/consent/schema.d.ts +110 -0
  111. package/dist/types/core/changelog-index.d.ts +8 -0
  112. package/dist/types/core/config-input.d.ts +217 -23
  113. package/dist/types/core/data.d.ts +53 -4
  114. package/dist/types/core/footer.d.ts +8 -0
  115. package/dist/types/core/i18n-ui.d.ts +88 -0
  116. package/dist/types/core/includes.d.ts +8 -2
  117. package/dist/types/core/links.d.ts +8 -0
  118. package/dist/types/core/localizable.d.ts +7 -0
  119. package/dist/types/core/page-modes.d.ts +29 -0
  120. package/dist/types/core/probe.d.ts +2 -0
  121. package/dist/types/core/project-graph.d.ts +6 -0
  122. package/dist/types/core/redirect-patterns.d.ts +152 -0
  123. package/dist/types/core/related.d.ts +40 -0
  124. package/dist/types/core/schema.d.ts +670 -56
  125. package/dist/types/core/sources/cache.d.ts +3 -0
  126. package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
  127. package/dist/types/core/sources/contentful.d.ts +17 -1
  128. package/dist/types/core/sources/lexical.d.ts +5 -0
  129. package/dist/types/core/sources/normalize.d.ts +20 -1
  130. package/dist/types/core/sources/read.d.ts +5 -0
  131. package/dist/types/core/sources/remote.d.ts +37 -10
  132. package/dist/types/core/sources/sanity.d.ts +1 -1
  133. package/dist/types/core/types.d.ts +18 -1
  134. package/dist/types/core/variables.d.ts +42 -0
  135. package/dist/types/deploy/adapter-output.d.ts +2 -1
  136. package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
  137. package/dist/types/deploy/adapters/node.d.ts +58 -23
  138. package/dist/types/deploy/adapters/registry.d.ts +10 -0
  139. package/dist/types/deploy/adapters/types.d.ts +3 -2
  140. package/dist/types/deploy/node-headers.d.ts +13 -2
  141. package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
  142. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  143. package/dist/types/deploy/platforms/node.d.ts +3 -1
  144. package/dist/types/deploy/platforms/types.d.ts +18 -7
  145. package/dist/types/deploy/platforms/vercel.d.ts +26 -1
  146. package/dist/types/deploy/redirects.d.ts +55 -11
  147. package/dist/types/deploy/sitemap.d.ts +2 -1
  148. package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
  149. package/dist/types/markdown/code-title.d.ts +17 -0
  150. package/dist/types/markdown/features.d.ts +3 -2
  151. package/dist/types/narration/build.d.ts +70 -0
  152. package/dist/types/narration/provider.d.ts +26 -0
  153. package/dist/types/narration/script.d.ts +154 -0
  154. package/dist/types/openapi/checks.d.ts +27 -0
  155. package/dist/types/openapi/graphql.d.ts +6 -0
  156. package/dist/types/openapi/model.d.ts +27 -10
  157. package/dist/types/openapi/overlay.d.ts +54 -0
  158. package/dist/types/openapi/parse.d.ts +16 -0
  159. package/dist/types/openapi/references.d.ts +30 -4
  160. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  161. package/dist/types/ratelimit/index.d.ts +27 -0
  162. package/dist/types/ratelimit/memory.d.ts +36 -0
  163. package/dist/types/ratelimit/schema.d.ts +119 -0
  164. package/dist/types/ratelimit/upstash.d.ts +46 -0
  165. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  166. package/dist/types/reference/asyncapi.d.ts +10 -10
  167. package/dist/types/reference/graphql.d.ts +89 -11
  168. package/dist/types/reference/index.d.ts +1 -1
  169. package/dist/types/reference/openapi.d.ts +33 -12
  170. package/dist/types/reference/options.d.ts +82 -6
  171. package/dist/types/reference/scalar.d.ts +13 -0
  172. package/dist/types/reference/schema.d.ts +144 -36
  173. package/dist/types/search/adapters/registry.d.ts +3 -0
  174. package/dist/types/search/adapters/typesense.d.ts +14 -4
  175. package/dist/types/search/build.d.ts +3 -1
  176. package/dist/types/search/documents.d.ts +12 -1
  177. package/dist/types/search/orama-index.d.ts +13 -9
  178. package/dist/types/search/sync/algolia.d.ts +5 -2
  179. package/dist/types/search/sync/index.d.ts +3 -1
  180. package/dist/types/search/sync/typesense.d.ts +11 -7
  181. package/dist/types/seo/metatags.d.ts +20 -0
  182. package/dist/types/sources/contentful.d.ts +16 -0
  183. package/dist/types/sources/github-releases.d.ts +8 -1
  184. package/dist/types/sources/payload.d.ts +2 -0
  185. package/dist/types/sources/registry.d.ts +54 -0
  186. package/dist/types/sources/shared.d.ts +3 -0
  187. package/dist/types/sources/strapi.d.ts +2 -0
  188. package/docs/01-quickstart.mdx +4 -2
  189. package/docs/02-deployment.mdx +71 -17
  190. package/docs/03-upgrading.mdx +4 -4
  191. package/docs/04-migrating.mdx +1 -1
  192. package/docs/advanced/changelog.mdx +13 -2
  193. package/docs/advanced/skills.mdx +15 -1
  194. package/docs/cli/audit.mdx +51 -8
  195. package/docs/cli/doctor.mdx +5 -1
  196. package/docs/cli/evals.mdx +4 -4
  197. package/docs/cli/index.mdx +1 -0
  198. package/docs/cli/translate.mdx +1 -0
  199. package/docs/cli/validate.mdx +4 -3
  200. package/docs/configuration/analytics.mdx +3 -1
  201. package/docs/configuration/assistant.mdx +194 -38
  202. package/docs/configuration/consent.mdx +100 -0
  203. package/docs/configuration/customization.mdx +8 -6
  204. package/docs/configuration/export.mdx +5 -3
  205. package/docs/configuration/index.mdx +64 -5
  206. package/docs/configuration/meta.ts +3 -0
  207. package/docs/configuration/narration.mdx +119 -0
  208. package/docs/configuration/rate-limiting.mdx +90 -0
  209. package/docs/configuration/search.mdx +63 -12
  210. package/docs/configuration/theming.mdx +3 -1
  211. package/docs/content/components.mdx +108 -2
  212. package/docs/content/frontmatter.mdx +80 -2
  213. package/docs/content/i18n.mdx +39 -4
  214. package/docs/content/includes.mdx +16 -0
  215. package/docs/content/meta.mdx +1 -0
  216. package/docs/content/meta.ts +1 -0
  217. package/docs/content/navigation.mdx +32 -10
  218. package/docs/content/sources/contentful.mdx +35 -0
  219. package/docs/content/sources/custom.mdx +43 -0
  220. package/docs/content/sources/github-releases.mdx +39 -0
  221. package/docs/content/sources/index.mdx +91 -0
  222. package/docs/content/sources/meta.ts +16 -0
  223. package/docs/content/sources/notion.mdx +32 -0
  224. package/docs/content/sources/obsidian.mdx +37 -0
  225. package/docs/content/sources/payload.mdx +31 -0
  226. package/docs/content/sources/remote-mdx.mdx +44 -0
  227. package/docs/content/sources/sanity.mdx +29 -0
  228. package/docs/content/sources/strapi.mdx +32 -0
  229. package/docs/content/syntax.mdx +69 -4
  230. package/docs/content/variables.mdx +41 -0
  231. package/docs/discoverability/agent-discovery.mdx +29 -2
  232. package/docs/discoverability/index.mdx +2 -2
  233. package/docs/discoverability/json-api.mdx +2 -0
  234. package/docs/discoverability/llms-txt.mdx +2 -2
  235. package/docs/discoverability/markdown.mdx +3 -1
  236. package/docs/discoverability/mcp.mdx +4 -0
  237. package/docs/discoverability/metadata.mdx +17 -0
  238. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  239. package/docs/references/api-pages.mdx +74 -0
  240. package/docs/references/asyncapi.mdx +4 -2
  241. package/docs/references/graphql.mdx +14 -2
  242. package/docs/references/meta.ts +1 -1
  243. package/docs/references/openapi.mdx +148 -7
  244. package/docs/references/scalar.mdx +3 -1
  245. package/package.json +43 -8
  246. package/skills/blume/SKILL.md +3 -0
  247. package/skills/blume-migrate/SKILL.md +6 -6
  248. package/skills/blume-migrate/references/docusaurus.md +7 -7
  249. package/skills/blume-migrate/references/fumadocs.md +17 -13
  250. package/skills/blume-migrate/references/mintlify.md +37 -19
  251. package/skills/blume-migrate/references/nextra.md +10 -7
  252. package/skills/blume-migrate/references/starlight.md +11 -8
  253. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
  254. package/skills/blume-write-skill/SKILL.md +82 -0
  255. package/src/ai/agent-readability.ts +2 -1
  256. package/src/ai/agent-surface.ts +9 -7
  257. package/src/ai/ai-catalog.ts +6 -3
  258. package/src/ai/ask-context.ts +103 -20
  259. package/src/ai/ask-data.ts +6 -0
  260. package/src/ai/ask-limits.ts +13 -0
  261. package/src/ai/ask-tools.ts +142 -0
  262. package/src/ai/ask.ts +354 -76
  263. package/src/ai/changelog-markdown.ts +11 -6
  264. package/src/ai/component-markdown.ts +76 -1
  265. package/src/ai/cors.ts +14 -3
  266. package/src/ai/index.ts +12 -0
  267. package/src/ai/llms.ts +6 -2
  268. package/src/ai/markdown.ts +2 -1
  269. package/src/ai/mcp/data.ts +6 -0
  270. package/src/ai/mcp/query.ts +14 -6
  271. package/src/ai/openapi-components.ts +36 -6
  272. package/src/ai/relative-links.ts +4 -38
  273. package/src/ai/site-skill.ts +274 -0
  274. package/src/ai/skills.ts +35 -2
  275. package/src/ai/write-skill.ts +97 -0
  276. package/src/astro/generate.ts +210 -66
  277. package/src/astro/index.ts +1 -0
  278. package/src/astro/integration.ts +42 -4
  279. package/src/astro/markdown-negotiation.ts +3 -0
  280. package/src/astro/module-types.ts +9 -1
  281. package/src/astro/pages.ts +23 -0
  282. package/src/astro/templates.ts +406 -108
  283. package/src/astro/variables.ts +31 -0
  284. package/src/audit/catalog.ts +38 -3
  285. package/src/audit/checks/contrast.ts +183 -0
  286. package/src/audit/checks/i18n.ts +2 -3
  287. package/src/audit/checks/indexability.ts +2 -3
  288. package/src/audit/checks/links.ts +19 -13
  289. package/src/audit/checks/network.ts +110 -6
  290. package/src/audit/checks/redirects.ts +6 -4
  291. package/src/audit/checks/robots.ts +58 -2
  292. package/src/audit/checks/sitemap.ts +2 -3
  293. package/src/audit/redirects.ts +46 -15
  294. package/src/audit/run.ts +5 -0
  295. package/src/audit/types.ts +4 -1
  296. package/src/audit/url.ts +14 -5
  297. package/src/blume-modules.d.ts +12 -1
  298. package/src/captcha/client.ts +152 -0
  299. package/src/captcha/hcaptcha.ts +36 -0
  300. package/src/captcha/index.ts +28 -0
  301. package/src/captcha/schema.ts +32 -0
  302. package/src/captcha/turnstile.ts +38 -0
  303. package/src/captcha/verify.ts +71 -0
  304. package/src/cli/args.ts +51 -0
  305. package/src/cli/build-failure.ts +23 -0
  306. package/src/cli/command-meta.ts +5 -0
  307. package/src/cli/commands/audit.ts +10 -1
  308. package/src/cli/commands/dev.ts +18 -2
  309. package/src/cli/commands/doctor.ts +67 -28
  310. package/src/cli/commands/eval.ts +36 -4
  311. package/src/cli/commands/init.ts +6 -4
  312. package/src/cli/commands/skill.ts +96 -0
  313. package/src/cli/commands/validate.ts +10 -1
  314. package/src/cli/index.ts +5 -0
  315. package/src/cli/init/scaffold.ts +3 -3
  316. package/src/cli/prepare.ts +6 -3
  317. package/src/cli/required-secrets.ts +72 -30
  318. package/src/components/BlumePage.astro +2 -0
  319. package/src/components/content/ApiEndpoint.astro +18 -0
  320. package/src/components/content/ApiField.astro +79 -0
  321. package/src/components/content/ApiPlayground.astro +66 -0
  322. package/src/components/content/ApiRail.astro +19 -0
  323. package/src/components/content/Color.astro +1 -0
  324. package/src/components/content/FileTree.astro +1 -0
  325. package/src/components/content/GithubInfo.astro +1 -0
  326. package/src/components/content/Panel.astro +1 -0
  327. package/src/components/content/ParamField.astro +25 -0
  328. package/src/components/content/RequestExample.astro +17 -0
  329. package/src/components/content/ResponseExample.astro +17 -0
  330. package/src/components/content/ResponseField.astro +32 -0
  331. package/src/components/content/Step.astro +1 -0
  332. package/src/components/content/Tile.astro +1 -0
  333. package/src/components/content/Tooltip.astro +1 -0
  334. package/src/components/content/Tree.astro +1 -0
  335. package/src/components/content/TypeTable.astro +4 -1
  336. package/src/components/content/View.astro +21 -0
  337. package/src/components/content/ViewSwitcher.astro +168 -0
  338. package/src/components/content/api-field.ts +103 -0
  339. package/src/components/content/api-page.ts +248 -0
  340. package/src/components/content/mermaid-element.ts +15 -1
  341. package/src/components/content/view-switcher.ts +71 -0
  342. package/src/components/index.ts +2 -0
  343. package/src/components/islands/Assistant.astro +10 -1
  344. package/src/components/islands/assistant.tsx +104 -14
  345. package/src/components/islands/code-question.ts +62 -0
  346. package/src/components/islands/hooks.ts +136 -21
  347. package/src/components/islands/support-link.ts +68 -0
  348. package/src/components/layout/Analytics.astro +11 -2
  349. package/src/components/layout/Banner.astro +14 -10
  350. package/src/components/layout/Breadcrumbs.astro +6 -2
  351. package/src/components/layout/ConsentBanner.astro +62 -0
  352. package/src/components/layout/ConsentHead.astro +38 -0
  353. package/src/components/layout/Directory.astro +94 -0
  354. package/src/components/layout/DrawerSwitchers.astro +51 -0
  355. package/src/components/layout/Empty.astro +2 -2
  356. package/src/components/layout/Header.astro +122 -80
  357. package/src/components/layout/LanguageSwitcher.astro +48 -15
  358. package/src/components/layout/NarrationPlayer.astro +1085 -0
  359. package/src/components/layout/NavSelector.astro +33 -7
  360. package/src/components/layout/PageActions.astro +139 -24
  361. package/src/components/layout/PageFeedback.astro +54 -49
  362. package/src/components/layout/PageLayout.astro +71 -3
  363. package/src/components/layout/ReferenceLayout.astro +17 -6
  364. package/src/components/layout/RelatedPages.astro +42 -0
  365. package/src/components/layout/RootLayout.astro +318 -47
  366. package/src/components/layout/Search.astro +47 -19
  367. package/src/components/layout/SiteFooter.astro +124 -0
  368. package/src/components/layout/SiteMetatags.astro +16 -0
  369. package/src/components/layout/TableOfContents.astro +24 -17
  370. package/src/components/layout/consent/native.ts +79 -0
  371. package/src/components/layout/consent/types.ts +37 -0
  372. package/src/components/layout/footer-links.ts +53 -0
  373. package/src/components/layout/footer-socials.ts +87 -0
  374. package/src/components/layout/head-scripts.ts +6 -1
  375. package/src/components/layout/locale-redirect.ts +107 -0
  376. package/src/components/layout/nav-utils.ts +83 -0
  377. package/src/components/layout/page-feedback.ts +96 -0
  378. package/src/components/layout/search/algolia.ts +10 -1
  379. package/src/components/layout/search/analytics.ts +126 -0
  380. package/src/components/layout/search/endpoint.ts +48 -5
  381. package/src/components/layout/search/flexsearch.ts +17 -5
  382. package/src/components/layout/search/orama-cloud.ts +26 -14
  383. package/src/components/layout/search/pagefind.ts +114 -5
  384. package/src/components/layout/search/types.ts +32 -0
  385. package/src/components/layout/search/typesense.ts +19 -3
  386. package/src/components/openapi/AsyncApiOperation.astro +14 -7
  387. package/src/components/openapi/Authorization.astro +10 -0
  388. package/src/components/openapi/GraphqlOperation.astro +5 -0
  389. package/src/components/openapi/Operation.astro +184 -13
  390. package/src/components/openapi/ParametersTable.astro +8 -4
  391. package/src/components/openapi/Playground.astro +7 -1
  392. package/src/components/openapi/RequestBody.astro +24 -5
  393. package/src/components/openapi/RequestPanel.astro +59 -7
  394. package/src/components/openapi/Responses.astro +7 -4
  395. package/src/components/openapi/SchemaTable.astro +15 -3
  396. package/src/components/openapi/async-snippets.ts +65 -9
  397. package/src/components/openapi/async.ts +123 -29
  398. package/src/components/openapi/code-samples.ts +97 -0
  399. package/src/components/openapi/graphql-helpers.ts +35 -12
  400. package/src/components/openapi/helpers.ts +36 -2
  401. package/src/components/openapi/message-model.ts +54 -11
  402. package/src/components/openapi/message.ts +14 -4
  403. package/src/components/openapi/operation-model.ts +16 -7
  404. package/src/components/openapi/playground-client.ts +24 -5
  405. package/src/components/openapi/playground-schema.ts +1 -1
  406. package/src/components/openapi/schema-tree.ts +44 -14
  407. package/src/components/openapi/security.ts +16 -3
  408. package/src/components/openapi/snippets.ts +873 -10
  409. package/src/components/openapi/validate-json.ts +4 -3
  410. package/src/components/props.ts +6 -0
  411. package/src/consent/client.ts +95 -0
  412. package/src/consent/clients.ts +19 -0
  413. package/src/consent/ethyca.ts +71 -0
  414. package/src/consent/head.ts +24 -0
  415. package/src/consent/index.ts +37 -0
  416. package/src/consent/init.ts +29 -0
  417. package/src/consent/native.ts +36 -0
  418. package/src/consent/osano.ts +59 -0
  419. package/src/consent/schema.ts +30 -0
  420. package/src/core/builtin-tags.ts +5 -0
  421. package/src/core/changelog-index.ts +31 -1
  422. package/src/core/client-address.ts +19 -0
  423. package/src/core/component-diagnostics.ts +53 -0
  424. package/src/core/component-overrides.ts +32 -0
  425. package/src/core/config-input.ts +225 -23
  426. package/src/core/data.ts +46 -4
  427. package/src/core/diagnostics.ts +8 -2
  428. package/src/core/footer.ts +26 -0
  429. package/src/core/graph.ts +39 -36
  430. package/src/core/i18n-ui.ts +84 -2
  431. package/src/core/includes.ts +21 -4
  432. package/src/core/links.ts +63 -19
  433. package/src/core/localizable.ts +26 -0
  434. package/src/core/navigation.ts +43 -12
  435. package/src/core/page-modes.ts +56 -0
  436. package/src/core/probe.ts +26 -6
  437. package/src/core/project-graph.ts +163 -16
  438. package/src/core/redirect-patterns.ts +520 -0
  439. package/src/core/related.ts +131 -0
  440. package/src/core/schema.ts +339 -66
  441. package/src/core/sources/cache.ts +6 -0
  442. package/src/core/sources/contentful-rich-text.ts +29 -6
  443. package/src/core/sources/contentful.ts +135 -25
  444. package/src/core/sources/filesystem.ts +26 -4
  445. package/src/core/sources/github-releases.ts +12 -1
  446. package/src/core/sources/lexical.ts +15 -10
  447. package/src/core/sources/mdx-remote.ts +62 -10
  448. package/src/core/sources/normalize.ts +228 -41
  449. package/src/core/sources/notion.ts +7 -1
  450. package/src/core/sources/obsidian.ts +16 -3
  451. package/src/core/sources/payload.ts +38 -15
  452. package/src/core/sources/read.ts +8 -3
  453. package/src/core/sources/remote.ts +72 -15
  454. package/src/core/sources/resolve.ts +11 -1
  455. package/src/core/sources/sanity.ts +43 -25
  456. package/src/core/sources/strapi.ts +2 -2
  457. package/src/core/types.ts +19 -1
  458. package/src/core/ui-packs/ar.ts +44 -0
  459. package/src/core/ui-packs/bg.ts +46 -0
  460. package/src/core/ui-packs/bn.ts +44 -0
  461. package/src/core/ui-packs/ca.ts +47 -0
  462. package/src/core/ui-packs/cs.ts +45 -0
  463. package/src/core/ui-packs/da.ts +46 -0
  464. package/src/core/ui-packs/de.ts +47 -0
  465. package/src/core/ui-packs/el.ts +46 -0
  466. package/src/core/ui-packs/es.ts +47 -0
  467. package/src/core/ui-packs/fa.ts +46 -0
  468. package/src/core/ui-packs/fi.ts +46 -0
  469. package/src/core/ui-packs/fr.ts +47 -0
  470. package/src/core/ui-packs/he.ts +44 -0
  471. package/src/core/ui-packs/hi.ts +45 -0
  472. package/src/core/ui-packs/hr.ts +46 -0
  473. package/src/core/ui-packs/hu.ts +45 -0
  474. package/src/core/ui-packs/id.ts +46 -0
  475. package/src/core/ui-packs/it.ts +46 -0
  476. package/src/core/ui-packs/ja.ts +46 -0
  477. package/src/core/ui-packs/ko.ts +45 -0
  478. package/src/core/ui-packs/nl.ts +47 -0
  479. package/src/core/ui-packs/no.ts +45 -0
  480. package/src/core/ui-packs/pl.ts +46 -0
  481. package/src/core/ui-packs/pt-br.ts +47 -0
  482. package/src/core/ui-packs/pt.ts +46 -0
  483. package/src/core/ui-packs/ro.ts +46 -0
  484. package/src/core/ui-packs/ru.ts +46 -0
  485. package/src/core/ui-packs/sk.ts +45 -0
  486. package/src/core/ui-packs/sr.ts +46 -0
  487. package/src/core/ui-packs/sv.ts +45 -0
  488. package/src/core/ui-packs/th.ts +44 -0
  489. package/src/core/ui-packs/tr.ts +46 -0
  490. package/src/core/ui-packs/uk.ts +46 -0
  491. package/src/core/ui-packs/vi.ts +46 -0
  492. package/src/core/ui-packs/zh-tw.ts +44 -0
  493. package/src/core/ui-packs/zh.ts +44 -0
  494. package/src/core/variables.ts +103 -0
  495. package/src/deploy/adapter-output.ts +7 -2
  496. package/src/deploy/adapters/cloudflare.ts +7 -5
  497. package/src/deploy/adapters/node.ts +47 -9
  498. package/src/deploy/adapters/types.ts +7 -3
  499. package/src/deploy/artifacts.ts +79 -9
  500. package/src/deploy/cloudflare-negotiation.ts +35 -5
  501. package/src/deploy/headers.ts +2 -1
  502. package/src/deploy/node-headers.ts +63 -9
  503. package/src/deploy/platforms/cloudflare.ts +45 -9
  504. package/src/deploy/platforms/netlify.ts +35 -2
  505. package/src/deploy/platforms/node.ts +12 -2
  506. package/src/deploy/platforms/types.ts +21 -7
  507. package/src/deploy/platforms/vercel.ts +149 -17
  508. package/src/deploy/redirects.ts +151 -24
  509. package/src/deploy/rss.ts +3 -1
  510. package/src/deploy/sitemap.ts +39 -5
  511. package/src/deploy/vercel-negotiation.ts +326 -102
  512. package/src/eval/agents.ts +18 -1
  513. package/src/eval/prompts.ts +6 -3
  514. package/src/eval/report.ts +34 -13
  515. package/src/eval/run.ts +5 -0
  516. package/src/markdown/api-rail.ts +259 -0
  517. package/src/markdown/code-title.ts +35 -9
  518. package/src/markdown/features.ts +3 -2
  519. package/src/markdown/fence-meta.ts +2 -0
  520. package/src/markdown/include.ts +11 -1
  521. package/src/markdown/index.ts +28 -5
  522. package/src/markdown/math.ts +4 -4
  523. package/src/markdown/relative-links.ts +3 -2
  524. package/src/markdown/variables.ts +56 -0
  525. package/src/markdown/views.ts +82 -0
  526. package/src/narration/build.ts +412 -0
  527. package/src/narration/player.ts +249 -0
  528. package/src/narration/provider.ts +29 -0
  529. package/src/narration/script.ts +592 -0
  530. package/src/og/card.ts +7 -6
  531. package/src/openapi/checks.ts +273 -0
  532. package/src/openapi/graphql-build.ts +21 -0
  533. package/src/openapi/graphql.ts +11 -0
  534. package/src/openapi/model.ts +72 -27
  535. package/src/openapi/overlay.ts +256 -0
  536. package/src/openapi/parse.ts +182 -4
  537. package/src/openapi/references.ts +64 -8
  538. package/src/openapi/render-mdx.ts +5 -1
  539. package/src/openapi/scalar.ts +40 -6
  540. package/src/openapi/source.ts +40 -15
  541. package/src/ratelimit/cloudflare.ts +54 -0
  542. package/src/ratelimit/index.ts +30 -0
  543. package/src/ratelimit/memory.ts +45 -0
  544. package/src/ratelimit/runtime.ts +247 -0
  545. package/src/ratelimit/schema.ts +28 -0
  546. package/src/ratelimit/upstash.ts +60 -0
  547. package/src/ratelimit/wrangler.ts +70 -0
  548. package/src/reference/asyncapi.ts +2 -2
  549. package/src/reference/graphql.ts +20 -3
  550. package/src/reference/index.ts +1 -0
  551. package/src/reference/openapi.ts +21 -7
  552. package/src/reference/options.ts +80 -8
  553. package/src/reference/scalar.ts +33 -8
  554. package/src/registry/eject.ts +23 -5
  555. package/src/registry/registry.ts +7 -0
  556. package/src/search/adapters/locale-scope.ts +30 -0
  557. package/src/search/adapters/typesense.ts +14 -4
  558. package/src/search/build.ts +21 -3
  559. package/src/search/documents.ts +26 -2
  560. package/src/search/orama-index.ts +191 -34
  561. package/src/search/pagefind-ranking.ts +39 -0
  562. package/src/search/source-pages.ts +29 -0
  563. package/src/search/sync/algolia.ts +111 -10
  564. package/src/search/sync/index.ts +52 -13
  565. package/src/search/sync/orama-cloud.ts +3 -0
  566. package/src/search/sync/typesense.ts +76 -26
  567. package/src/seo/metatags.ts +67 -0
  568. package/src/sources/contentful.ts +12 -0
  569. package/src/sources/github-releases.ts +7 -1
  570. package/src/sources/shared.ts +3 -0
  571. package/src/theme/chrome-icons.ts +1 -0
  572. package/src/theme/color.ts +500 -0
  573. package/src/theme/entry.ts +85 -6
  574. package/src/theme/palette.ts +121 -45
  575. package/src/translate/prompts.ts +1 -0
  576. package/src/translate/validate.ts +31 -3
  577. package/src/upgrade/upgrade.ts +4 -171
  578. package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
  579. package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
  580. package/dist/cli/chunk-35d4wj9f.js.map +0 -15
  581. package/dist/cli/chunk-364znk6q.js +0 -75
  582. package/dist/cli/chunk-364znk6q.js.map +0 -11
  583. package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
  584. package/dist/cli/chunk-8ktnccpt.js.map +0 -10
  585. package/dist/cli/chunk-9t7a85s3.js.map +0 -10
  586. package/dist/cli/chunk-b07cmahc.js +0 -145
  587. package/dist/cli/chunk-b07cmahc.js.map +0 -11
  588. package/dist/cli/chunk-c8chx29p.js.map +0 -36
  589. package/dist/cli/chunk-e04dxsz1.js +0 -39
  590. package/dist/cli/chunk-e04dxsz1.js.map +0 -10
  591. package/dist/cli/chunk-j85vccga.js.map +0 -36
  592. package/dist/cli/chunk-p3v96n38.js.map +0 -10
  593. package/dist/cli/chunk-pehfxfta.js.map +0 -10
  594. package/dist/cli/chunk-pv29h0wf.js.map +0 -190
  595. package/dist/cli/chunk-q58y5e6a.js.map +0 -10
  596. package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
  597. package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
  598. package/dist/cli/chunk-yfyb25rh.js.map +0 -14
  599. package/docs/content/sources.mdx +0 -334
  600. /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
  601. /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
  602. /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
  603. /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
  604. /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
  605. /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
  606. /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
  607. /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
@@ -2,12 +2,15 @@
2
2
  import IconSprite from "./IconSprite.astro";
3
3
  import { createIconSprite } from "../icon-sprite.ts";
4
4
  import data from "blume:data";
5
+ import { relatedLinks } from "../../core/related.ts";
6
+ import type { RelatedEntry } from "../../core/related.ts";
5
7
  import { EN_UI } from "../../core/i18n-ui.ts";
6
8
  import type { UIStrings } from "../../core/i18n-ui.ts";
7
9
  import { resolveDateFormatOptions } from "../../core/date-format.ts";
8
10
  import type { ResolvedDateFormat } from "../../core/schema.ts";
9
11
  import type { OpenInChatProvider } from "../../core/open-in-chat.ts";
10
12
  import type {
13
+ BlumeBanner,
11
14
  BlumeClientData,
12
15
  BlumeDataConfig,
13
16
  BlumeFavicon,
@@ -40,14 +43,28 @@ import {
40
43
  import { buildStructuredData, toIso } from "../../seo/jsonld.ts";
41
44
  import { normalizeXHandle } from "../../seo/x-handle.ts";
42
45
  import { withBase, withMountedBase } from "../islands/base-path.ts";
46
+ import { routeSetFor } from "../../core/locale-links.ts";
47
+ import {
48
+ KEYWORDS_ATTRIBUTE,
49
+ pagefindRanking,
50
+ } from "../../search/pagefind-ranking.ts";
51
+ import {
52
+ browserLanguageTargets,
53
+ LOCALE_REDIRECT_SCRIPT,
54
+ } from "./locale-redirect.ts";
43
55
  import { isExternalUrl } from "../../core/base-path.ts";
44
56
  import { NEW_TAB_HINT_ID, newTabAttrs } from "../../core/new-tab.ts";
45
57
  import Analytics from "./Analytics.astro";
58
+ import ConsentBanner from "./ConsentBanner.astro";
59
+ import ConsentHead from "./ConsentHead.astro";
46
60
  import WebMcp from "./WebMcp.astro";
47
61
  import Banner from "./Banner.astro";
48
62
  import Breadcrumbs from "./Breadcrumbs.astro";
49
63
  import Empty from "./Empty.astro";
64
+ import Directory from "./Directory.astro";
65
+ import RelatedPages from "./RelatedPages.astro";
50
66
  import DiscoveryLinks from "./DiscoveryLinks.astro";
67
+ import DrawerSwitchers from "./DrawerSwitchers.astro";
51
68
  import Favicon from "./Favicon.astro";
52
69
  import Fonts from "./Fonts.astro";
53
70
  import {
@@ -62,6 +79,7 @@ import {
62
79
  currentTabForRoute,
63
80
  findBreadcrumbs,
64
81
  flattenPages,
82
+ directoryGroupForRoute,
65
83
  getPagination,
66
84
  navGroupIds,
67
85
  sidebarForRoute,
@@ -69,10 +87,14 @@ import {
69
87
  import NavTabMenu from "./NavTabMenu.astro";
70
88
  import NavTree from "./NavTree.astro";
71
89
  import { resolveSlot } from "./overrides.ts";
90
+ import { pageModeLayout } from "../../core/page-modes.ts";
91
+ import type { PageMode } from "../../core/page-modes.ts";
72
92
  import { pageDirection, pageLocale } from "./page-locale.ts";
73
93
  import { searchLocaleFor } from "./search-locale.ts";
74
94
  import PageActions from "./PageActions.astro";
75
95
  import PageFeedback from "./PageFeedback.astro";
96
+ import SiteFooter from "./SiteFooter.astro";
97
+ import SiteMetatags from "./SiteMetatags.astro";
76
98
  import Pagination from "./Pagination.astro";
77
99
  import TableOfContents from "./TableOfContents.astro";
78
100
  import VersionBanner from "./VersionBanner.astro";
@@ -89,12 +111,7 @@ interface Props {
89
111
  } | null;
90
112
  favicon?: BlumeFavicon | null;
91
113
  appleIcon?: BlumeFavicon | null;
92
- banner?: {
93
- content: string;
94
- link?: { text: string; href: string };
95
- dismissible: boolean;
96
- key: string;
97
- } | null;
114
+ banner?: BlumeBanner | null;
98
115
  analytics?: BlumeDataConfig["analytics"] | null;
99
116
  navigation: Navigation;
100
117
  mcp?: { name: string; route: string } | null;
@@ -129,6 +146,17 @@ interface Props {
129
146
  assistantEnabled?: boolean;
130
147
  /** Show the "Was this page helpful?" rating below the content. */
131
148
  feedback?: boolean;
149
+ /** Ask for a written comment after the rating. */
150
+ feedbackComments?: boolean;
151
+ /** Show the previous/next links at the foot of the page. */
152
+ pagination?: boolean;
153
+ /** The page's `related` frontmatter: pages to suggest at its foot. */
154
+ related?: RelatedEntry[] | false;
155
+ /**
156
+ * The page's `search.boost` and `search.keywords`, for Pagefind, which
157
+ * reads them from the built page (see search/pagefind-ranking.ts).
158
+ */
159
+ search?: { boost?: number; keywords?: string[] };
132
160
  exportPdf?: boolean;
133
161
  exportEpub?: boolean;
134
162
  /**
@@ -149,6 +177,14 @@ interface Props {
149
177
  discovery?: DiscoveryHeadLinks | null;
150
178
  siteUrl?: string | null;
151
179
  pageType?: string;
180
+ /**
181
+ * The page pins `<RequestExample>`/`<ResponseExample>` to a column beside
182
+ * its content (see `markdown/api-rail.ts`): it takes the API layout, with
183
+ * no table of contents, and the article makes room for the column.
184
+ */
185
+ apiRail?: boolean;
186
+ /** The page's `mode` frontmatter: what it shows around its content (see `core/page-modes.ts`). */
187
+ pageMode?: PageMode;
152
188
  published?: string | Date | null;
153
189
  lastModified?: string | null;
154
190
  noindex?: boolean;
@@ -201,9 +237,10 @@ interface Props {
201
237
  * User layout-slot overrides from `components.ts` (`defineComponents`). Each
202
238
  * key replaces the matching built-in; unknown keys are ignored. Wired slots:
203
239
  * `Header`, `Logo`, `Search`, `Sidebar`, `MobileNav`, `Breadcrumbs`,
204
- * `TableOfContents`, `Pagination`, `Feedback`, plus the content-injection slots
205
- * `PageHeader`, `PageFooter`, and `Footer` (which have no built-in and render
206
- * only when overridden). `Layout` (replacing this whole component) is wired in
240
+ * `TableOfContents`, `Pagination`, `Feedback`, `Footer` (the built-in renders
241
+ * only when `footer` is configured), plus the content-injection slots
242
+ * `PageHeader` and `PageFooter` (which have no built-in and render only when
243
+ * overridden). `Layout` (replacing this whole component) is wired in
207
244
  * the generated page templates, not here.
208
245
  */
209
246
  layout?: Record<string, ComponentOverride>;
@@ -251,6 +288,10 @@ const {
251
288
  editUrl,
252
289
  assistantEnabled,
253
290
  feedback = false,
291
+ feedbackComments = false,
292
+ pagination = true,
293
+ related,
294
+ search,
254
295
  exportPdf,
255
296
  exportEpub,
256
297
  openInChat,
@@ -258,6 +299,8 @@ const {
258
299
  discovery = data.config.discovery,
259
300
  siteUrl,
260
301
  pageType,
302
+ apiRail = false,
303
+ pageMode,
261
304
  published,
262
305
  lastModified,
263
306
  noindex,
@@ -304,15 +347,21 @@ const PaginationSlot = resolveSlot(layout.Pagination, Pagination);
304
347
  const MobileNavSlot = layout.MobileNav
305
348
  ? resolveSlot(layout.MobileNav, NavTree)
306
349
  : null;
350
+ // The site footer renders nothing when `footer` is unset.
351
+ const FooterSlot = resolveSlot(layout.Footer, SiteFooter);
307
352
  // Content-injection slots with no built-in: the `Empty` fallback renders nothing
308
353
  // when unconfigured, so these are safe to render unconditionally.
309
- const FooterSlot = resolveSlot(layout.Footer, Empty);
310
354
  const PageHeaderSlot = resolveSlot(layout.PageHeader, Empty);
311
355
  const PageFooterSlot = resolveSlot(layout.PageFooter, Empty);
312
356
  // The "Was this page helpful?" rating (rendered only when `feedback` is on).
313
357
  const FeedbackSlot = resolveSlot(layout.Feedback, PageFeedback);
314
358
 
315
359
  const strings = ui ?? EN_UI;
360
+ // The consent adapter (`consent`), site-wide: analytics waits for the reader.
361
+ const consent = data.config.consent;
362
+ // Code blocks get an Ask button when the assistant is on (same default as the
363
+ // header's trigger).
364
+ const assistantOn = assistantEnabled ?? Boolean(data.config.assistant);
316
365
  // Merge the groups this layout reads directly over the English defaults so a
317
366
  // key missing from a translation (or from a not-yet-regenerated snapshot)
318
367
  // still renders instead of coming out blank — the PageActions pattern.
@@ -328,11 +377,19 @@ const searchLocale = searchLocaleFor(data.config.i18n, locale);
328
377
  // API operation pages own a two-column body (docs + request panel) and their own
329
378
  // right rail, so they drop the table of contents and widen the content column.
330
379
  const isApiOperation = pageType === "openapi-operation";
380
+ // A hand-written API page lays out like one: its example column replaces the
381
+ // table of contents.
382
+ const isApiLayout = isApiOperation || apiRail;
331
383
  // A "bare" page (the changelog index) is a standalone landing: no sidebar, no
332
384
  // TOC, just a wider centered column of content.
333
385
  const isBare = contentLayout === "bare";
334
- const showSidebar = !isBare;
335
- const showToc = !(isApiOperation || isBare);
386
+ // The page's `mode`: which of the sidebar, TOC, and its own chrome it keeps.
387
+ const modeLayout = pageModeLayout(pageMode);
388
+ const showSidebar = !isBare && modeLayout.sidebar;
389
+ const showToc = !(isApiLayout || isBare) && modeLayout.toc;
390
+ // Breadcrumbs, page-end links, and the site footer; `custom` and `frame`
391
+ // pages bring their own.
392
+ const showChrome = modeLayout.chrome;
336
393
  const tocHeadings =
337
394
  toc.enabled && showToc
338
395
  ? headings.filter((h) => h.depth >= toc.minLevel && h.depth <= toc.maxLevel)
@@ -342,15 +399,21 @@ const tocHeadings =
342
399
  const hasToc = tocHeadings.length > 0;
343
400
  let gridClass =
344
401
  "lg:grid-cols-[17.5rem_minmax(0,1fr)] xl:grid-cols-[17.5rem_minmax(0,1fr)_17.5rem]";
345
- if (isBare) {
402
+ if (!showSidebar) {
346
403
  gridClass = "";
347
- } else if (isApiOperation) {
404
+ } else if (!showToc) {
348
405
  gridClass = "lg:grid-cols-[17.5rem_minmax(0,1fr)]";
349
406
  }
350
407
  let articleClass = "prose mx-auto max-w-content";
351
- if (isBare) {
408
+ if (isBare || modeLayout.width === "center") {
352
409
  articleClass = "prose mx-auto max-w-[54rem]";
353
- } else if (isApiOperation) {
410
+ } else if (apiRail) {
411
+ // Room at `xl` for the example column (28rem plus the 2.5rem gap an
412
+ // operation page keeps), which `ApiRail.astro` positions in it, and a
413
+ // viewport's height so the column's capped panel never overhangs the page.
414
+ articleClass =
415
+ "prose max-w-none xl:relative xl:min-h-[calc(100dvh-7.25rem)] xl:pe-[30.5rem]";
416
+ } else if (isApiOperation || modeLayout.width === "full") {
354
417
  articleClass = "prose max-w-none";
355
418
  }
356
419
  // A page titled like the site (a home page often is) takes the bare site title
@@ -435,6 +498,17 @@ const activeTab = currentTabForRoute(
435
498
  navigation.root
436
499
  );
437
500
  const crumbs = findBreadcrumbs(sidebar, page.route);
501
+ // A group's own page lists the group's pages below its content when the
502
+ // group asks for a directory. Looked up in the full tree: a tab's own page
503
+ // is not in its scoped sidebar.
504
+ const directoryGroup = directoryGroupForRoute(navigation.sidebar, page.route);
505
+ // The page's `related` links, resolved to served routes in this locale.
506
+ const relatedItems = relatedLinks(related, {
507
+ basePath: data.config.basePath,
508
+ i18n: data.config.i18n,
509
+ locale,
510
+ routes: data.routes,
511
+ });
438
512
  const { prev, next } = getPagination(flattenPages(sidebar), page.route);
439
513
 
440
514
  // Structured data is skipped when disabled or for pages we ask crawlers not to
@@ -466,6 +540,27 @@ const bannerKey = banner?.dismissible ? banner.key : null;
466
540
  // Start the page's icon sprite before anything renders an icon (see
467
541
  // icon-sprite.ts); <IconSprite /> at the end of the body emits it.
468
542
  createIconSprite(Astro.locals);
543
+
544
+ const pagefind = pagefindRanking(search ?? {});
545
+
546
+ // A visitor landing on the default language's home page goes to their
547
+ // browser's language (`i18n.routeByBrowserLanguage`, see locale-redirect.ts).
548
+ const localeTargets = browserLanguageTargets({
549
+ basePath: data.config.basePath,
550
+ i18n: data.config.i18n,
551
+ route: page.route,
552
+ routes: routeSetFor(data.routes),
553
+ });
554
+ const localeRedirect = localeTargets
555
+ ? JSON.stringify(
556
+ Object.fromEntries(
557
+ Object.entries(localeTargets).map(([code, path]) => [
558
+ code,
559
+ withMountedBase(path),
560
+ ])
561
+ )
562
+ )
563
+ : null;
469
564
  ---
470
565
 
471
566
  <!doctype html>
@@ -473,6 +568,16 @@ createIconSprite(Astro.locals);
473
568
  <head>
474
569
  <meta charset="utf-8" />
475
570
  <meta name="viewport" content="width=device-width, initial-scale=1" />
571
+ {
572
+ localeRedirect && (
573
+ <script
574
+ data-default={data.config.i18n?.defaultLocale}
575
+ data-targets={localeRedirect}
576
+ is:inline
577
+ set:html={LOCALE_REDIRECT_SCRIPT}
578
+ />
579
+ )
580
+ }
476
581
  {/* Client-side navigation: same-origin link clicks swap the DOM in place
477
582
  instead of tearing the document down, so no browser ever paints a blank
478
583
  frame between pages (Firefox has no cross-document paint holding and
@@ -537,6 +642,7 @@ createIconSprite(Astro.locals);
537
642
  {description && <meta name="twitter:description" content={description} />}
538
643
  {xSite && <meta name="twitter:site" content={xSite} />}
539
644
  {xCreator && <meta name="twitter:creator" content={xCreator} />}
645
+ <SiteMetatags tags={data.config.metatags} />
540
646
  {
541
647
  feeds?.map((feed) => (
542
648
  <link
@@ -563,16 +669,21 @@ createIconSprite(Astro.locals);
563
669
  )
564
670
  }
565
671
  <script data-mode={themeMode} is:inline set:html={THEME_INIT_SCRIPT} />
672
+ {consent && <ConsentHead consent={consent} />}
566
673
  <Analytics analytics={analytics} />
567
674
  </head>
568
675
  <body
569
676
  class="bg-background font-sans text-foreground antialiased"
677
+ data-blume-code-ask={assistantOn ? "" : undefined}
570
678
  data-blume-code-copy=""
571
679
  data-blume-code-wrap={codeWrap ? "" : undefined}
572
680
  data-blume-image-zoom={imageZoom ? "" : undefined}
681
+ data-i18n-ask-code={assistantOn ? actionStrings.askAboutCode : undefined}
573
682
  data-i18n-copied={actionStrings.copied}
574
683
  data-i18n-copy-code={actionStrings.copyCode}
575
684
  data-i18n-diagram-error={contentStrings.diagramError}
685
+ data-i18n-show-less={contentStrings.showLess}
686
+ data-i18n-show-more={contentStrings.showMore}
576
687
  >
577
688
  <a
578
689
  class="absolute start-[-999px] top-0 z-[100] bg-accent px-4 py-2 text-accent-foreground focus:start-0"
@@ -616,6 +727,13 @@ createIconSprite(Astro.locals);
616
727
  !showSidebar && "lg:hidden",
617
728
  ]}
618
729
  >
730
+ <DrawerSwitchers
731
+ localeSwitch={localeSwitch}
732
+ route={page.route}
733
+ selectors={navigation.selectors}
734
+ switcherStrings={strings.languageSwitcher}
735
+ versionSelector={versionSelector}
736
+ />
619
737
  {
620
738
  // Pinned links (blog, changelog, contact…) sit above every section on
621
739
  // all breakpoints, outside the tab-scoped sidebar so they never change
@@ -740,18 +858,30 @@ createIconSprite(Astro.locals);
740
858
  </aside>
741
859
  <script is:inline set:html={SIDEBAR_SCROLL_INIT_SCRIPT} />
742
860
  <main class="px-6 pt-6 pb-10 lg:px-8 xl:px-10" id="blume-content">
743
- <BreadcrumbsSlot
744
- crumbs={crumbs}
745
- strings={navStrings}
746
- wide={isApiOperation}
747
- />
748
861
  {
749
- hasToc && (
862
+ showChrome && (
863
+ <BreadcrumbsSlot
864
+ crumbs={crumbs}
865
+ strings={navStrings}
866
+ centered={modeLayout.width === "center"}
867
+ wide={isApiLayout || modeLayout.width === "full"}
868
+ />
869
+ )
870
+ }
871
+ {/* Below `xl`, where the rail is hidden, the page actions ride in
872
+ the "On this page" dropdown, so it renders wherever the rail
873
+ would, with or without headings. They render once, in the rail:
874
+ the dropdown gets an empty mount the actions script moves them
875
+ into (see PageActions.astro). */}
876
+ {
877
+ showToc && (
750
878
  <TableOfContentsSlot
751
879
  headings={tocHeadings}
752
880
  title={strings.toc.title}
753
881
  variant="mobile"
754
- />
882
+ >
883
+ <div data-blume-page-actions-mount />
884
+ </TableOfContentsSlot>
755
885
  )
756
886
  }
757
887
  <PageHeaderSlot headings={tocHeadings} page={page} route={page.route} />
@@ -764,14 +894,34 @@ createIconSprite(Astro.locals);
764
894
  <article
765
895
  class:list={[articleClass]}
766
896
  data-pagefind-body={indexable && !isBare ? "" : undefined}
897
+ data-pagefind-weight={pagefind.weight}
767
898
  dir={contentDir}
768
899
  lang={articleLang}
769
900
  >
901
+ {pagefind.keywords && (
902
+ <span
903
+ data-pagefind-index-attrs={KEYWORDS_ATTRIBUTE}
904
+ {...{ [KEYWORDS_ATTRIBUTE]: pagefind.keywords }}
905
+ hidden
906
+ />
907
+ )}
770
908
  <slot />
771
909
  </article>
772
910
  {
773
- !isApiOperation && (
774
- <>
911
+ !isApiOperation && showChrome && (
912
+ <div
913
+ class:list={[
914
+ // Aligned with the content column, not centered under the
915
+ // prose measure: a rail page's, a wide page's, or a center
916
+ // page's wider one.
917
+ apiRail && "xl:pe-[30.5rem]",
918
+ (apiRail || modeLayout.width === "full") && "[&>*]:max-w-none",
919
+ modeLayout.width === "center" && "[&>*]:max-w-[54rem]",
920
+ ]}
921
+ data-blume-page-end
922
+ >
923
+ {directoryGroup && <Directory group={directoryGroup} />}
924
+ <RelatedPages links={relatedItems} title={strings.page.related} />
775
925
  <PageFooterSlot
776
926
  headings={tocHeadings}
777
927
  page={page}
@@ -782,9 +932,16 @@ createIconSprite(Astro.locals);
782
932
  {strings.page.lastUpdated} {formattedLastModified}
783
933
  </p>
784
934
  )}
785
- {feedback && <FeedbackSlot strings={strings.feedback} />}
786
- <PaginationSlot next={next} prev={prev} strings={strings.page} />
787
- </>
935
+ {feedback && (
936
+ <FeedbackSlot
937
+ comments={feedbackComments}
938
+ strings={strings.feedback}
939
+ />
940
+ )}
941
+ {pagination && (
942
+ <PaginationSlot next={next} prev={prev} strings={strings.page} />
943
+ )}
944
+ </div>
788
945
  )
789
946
  }
790
947
  </main>
@@ -817,7 +974,17 @@ createIconSprite(Astro.locals);
817
974
  )
818
975
  }
819
976
  </div>
820
- <FooterSlot navigation={navigation} site={site} ui={strings} />
977
+ {
978
+ showChrome && (
979
+ <FooterSlot
980
+ footer={data.config.footer}
981
+ locale={locale}
982
+ navigation={navigation}
983
+ site={site}
984
+ ui={strings}
985
+ />
986
+ )
987
+ }
821
988
  {
822
989
  clientDataJson && (
823
990
  <script
@@ -954,6 +1121,24 @@ createIconSprite(Astro.locals);
954
1121
  const copiedLabel =
955
1122
  document.body.getAttribute("data-i18n-copied") || "Copied!";
956
1123
 
1124
+ // A block's code as the reader sees it. Twoslash nests each hover
1125
+ // popup's type signature and docs inside the <code>; its textContent
1126
+ // verbatim would interleave them with the source, so the popups are
1127
+ // stripped from a clone first.
1128
+ const codeText = (pre: Element | null): string => {
1129
+ const code = pre?.querySelector("code");
1130
+ if (!code?.querySelector(".twoslash-popup-container")) {
1131
+ return code?.textContent ?? "";
1132
+ }
1133
+ const clone = code.cloneNode(true) as HTMLElement;
1134
+ for (const popup of clone.querySelectorAll(
1135
+ ".twoslash-popup-container"
1136
+ )) {
1137
+ popup.remove();
1138
+ }
1139
+ return clone.textContent ?? "";
1140
+ };
1141
+
957
1142
  // `placement` is the extra class set for an overlay button (empty for
958
1143
  // one hosted by a tab strip); `readPre` resolves the block to copy at
959
1144
  // click time, since a strip button follows the active panel.
@@ -989,27 +1174,91 @@ createIconSprite(Astro.locals);
989
1174
  };
990
1175
  const flash = createCopyFlash(setChecked, copiedLabel);
991
1176
  button.addEventListener("click", async () => {
992
- const code = readPre()?.querySelector("code");
993
- let text = code?.textContent ?? "";
994
- // Twoslash nests each hover popup's type signature and docs inside
995
- // the <code>; copying textContent verbatim would interleave them
996
- // with the source. Strip the popups from a clone first.
997
- if (code?.querySelector(".twoslash-popup-container")) {
998
- const clone = code.cloneNode(true) as HTMLElement;
999
- for (const popup of clone.querySelectorAll(
1000
- ".twoslash-popup-container"
1001
- )) {
1002
- popup.remove();
1003
- }
1004
- text = clone.textContent ?? "";
1005
- }
1006
- if (await copyText(text)) {
1177
+ if (await copyText(codeText(readPre()))) {
1007
1178
  flash();
1008
1179
  }
1009
1180
  });
1010
1181
  return button;
1011
1182
  };
1012
1183
 
1184
+ // A code block's Ask button, when the assistant is on: it opens the
1185
+ // panel with the block attached (see islands/code-question.ts).
1186
+ const askEnabled = document.body.hasAttribute("data-blume-code-ask");
1187
+ const askLabel =
1188
+ document.body.getAttribute("data-i18n-ask-code") ||
1189
+ "Ask about this code";
1190
+ const createAskButton = (
1191
+ placement: string,
1192
+ readPre: () => Element | null
1193
+ ) => {
1194
+ const button = document.createElement("button");
1195
+ button.type = "button";
1196
+ button.className = `${buttonClass} ${idleClasses.join(" ")} ${placement}`;
1197
+ button.setAttribute("data-blume-ask", "");
1198
+ button.setAttribute("aria-label", askLabel);
1199
+ button.title = askLabel;
1200
+ button.innerHTML = svg("sparkles");
1201
+ button.addEventListener("click", () => {
1202
+ const pre = readPre();
1203
+ if (!(pre instanceof HTMLElement)) {
1204
+ return;
1205
+ }
1206
+ window.dispatchEvent(
1207
+ new CustomEvent("blume:open-assistant", {
1208
+ detail: {
1209
+ code: {
1210
+ language: pre.dataset.blumeLanguage ?? "",
1211
+ source: codeText(pre),
1212
+ title: pre.dataset.title,
1213
+ },
1214
+ },
1215
+ })
1216
+ );
1217
+ });
1218
+ return button;
1219
+ };
1220
+
1221
+ // An `expandable` block (```ts expandable) opens and closes from a
1222
+ // toggle under its code. The theme only collapses the block where
1223
+ // scripting runs, so the toggle is added on the same terms.
1224
+ const showMoreLabel =
1225
+ document.body.getAttribute("data-i18n-show-more") || "Show more";
1226
+ const showLessLabel =
1227
+ document.body.getAttribute("data-i18n-show-less") || "Show less";
1228
+ const expandToggle = (pre: HTMLElement) => {
1229
+ const button = document.createElement("button");
1230
+ button.type = "button";
1231
+ button.setAttribute("data-blume-code-expand", "");
1232
+ button.innerHTML = svg("chevron-down");
1233
+ const label = document.createElement("span");
1234
+ button.prepend(label);
1235
+ const setExpanded = (expanded: boolean) => {
1236
+ pre.toggleAttribute("data-expanded", expanded);
1237
+ button.setAttribute("aria-expanded", String(expanded));
1238
+ label.textContent = expanded ? showLessLabel : showMoreLabel;
1239
+ };
1240
+ setExpanded(false);
1241
+ button.addEventListener("click", () => {
1242
+ const expanded = !pre.hasAttribute("data-expanded");
1243
+ setExpanded(expanded);
1244
+ // Collapsing a long block can leave the reader below it; bring
1245
+ // its top back into view.
1246
+ if (!expanded && pre.getBoundingClientRect().top < 0) {
1247
+ pre.scrollIntoView({ block: "start" });
1248
+ }
1249
+ });
1250
+ return button;
1251
+ };
1252
+ if (matchMedia("(scripting: enabled)").matches) {
1253
+ for (const pre of document.querySelectorAll<HTMLElement>(
1254
+ ".prose pre[data-expandable]"
1255
+ )) {
1256
+ if (!pre.querySelector(":scope > [data-blume-code-expand]")) {
1257
+ pre.appendChild(expandToggle(pre));
1258
+ }
1259
+ }
1260
+ }
1261
+
1013
1262
  for (const pre of document.querySelectorAll(".prose pre")) {
1014
1263
  if (pre.querySelector("[data-blume-copy]")) {
1015
1264
  continue;
@@ -1021,6 +1270,11 @@ createIconSprite(Astro.locals);
1021
1270
  }
1022
1271
  const language = pre.getAttribute("data-language");
1023
1272
  if (language) {
1273
+ // The fence's own language id, for a question about the code; the
1274
+ // attribute itself becomes the header's display label.
1275
+ if (pre instanceof HTMLElement) {
1276
+ pre.dataset.blumeLanguage = language;
1277
+ }
1024
1278
  pre.setAttribute(
1025
1279
  "data-language",
1026
1280
  languageLabels[language.toLowerCase()] ?? language
@@ -1042,9 +1296,11 @@ createIconSprite(Astro.locals);
1042
1296
  // One button per code switcher, reading whichever panel shows.
1043
1297
  if (!actions.querySelector("[data-blume-copy]")) {
1044
1298
  const tabs = actions.closest("blume-tabs");
1045
- actions.appendChild(
1046
- createCopyButton("", () => (tabs ? activeCodePre(tabs) : null))
1047
- );
1299
+ const readActive = () => (tabs ? activeCodePre(tabs) : null);
1300
+ if (askEnabled) {
1301
+ actions.appendChild(createAskButton("", readActive));
1302
+ }
1303
+ actions.appendChild(createCopyButton("", readActive));
1048
1304
  }
1049
1305
  continue;
1050
1306
  }
@@ -1053,6 +1309,13 @@ createIconSprite(Astro.locals);
1053
1309
  const topClass = pre.closest("blume-tabs, .not-prose")
1054
1310
  ? "top-2.5"
1055
1311
  : "top-2";
1312
+ if (askEnabled) {
1313
+ // Beside the copy button: its 0.75rem inset, its 1.875rem width,
1314
+ // and a quarter-rem gap.
1315
+ pre.appendChild(
1316
+ createAskButton(`absolute right-[2.875rem] z-[2] ${topClass}`, () => pre)
1317
+ );
1318
+ }
1056
1319
  pre.appendChild(
1057
1320
  createCopyButton(`${overlayClass} ${topClass}`, () => pre)
1058
1321
  );
@@ -1123,6 +1386,14 @@ createIconSprite(Astro.locals);
1123
1386
  }
1124
1387
  </style>
1125
1388
  <WebMcp />
1389
+ {
1390
+ consent?.kind === "native" && (
1391
+ <ConsentBanner
1392
+ policy={consent.options.policy}
1393
+ strings={strings.consent}
1394
+ />
1395
+ )
1396
+ }
1126
1397
  <IconSprite />
1127
1398
  </body>
1128
1399
  </html>