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
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  import data from "blume:data";
3
+ import type { BlumeBanner } from "../../core/data.ts";
3
4
  import { EN_UI } from "../../core/i18n-ui.ts";
4
5
  import type { UIStrings } from "../../core/i18n-ui.ts";
6
+ import { resolveLocalizable } from "../../core/localizable.ts";
5
7
  import { withBase } from "../islands/base-path.ts";
6
8
  import Icon from "../Icon.astro";
7
9
 
@@ -9,14 +11,11 @@ import Icon from "../Icon.astro";
9
11
  // every shell shows the same bar. The pre-paint hide for a dismissed banner and
10
12
  // the dismiss click handler live in the layout/Header, not here.
11
13
  interface Props {
12
- banner:
13
- | {
14
- content: string;
15
- link?: { text: string; href: string };
16
- dismissible: boolean;
17
- key: string;
18
- }
19
- | null;
14
+ /**
15
+ * The banner. Its `content` and link `text` may be per-locale maps, shown
16
+ * in `locale` (else the default locale, else the map's first entry).
17
+ */
18
+ banner: BlumeBanner | null;
20
19
  /** Localized banner labels. */
21
20
  strings?: UIStrings["banner"];
22
21
  /**
@@ -40,6 +39,11 @@ const b = { ...EN_UI.banner, ...strings };
40
39
  const navigation =
41
40
  (locale === undefined ? undefined : data.navigationByLocale[locale]) ??
42
41
  data.navigation;
42
+ const defaultLocale = data.config.i18n?.defaultLocale;
43
+ const content =
44
+ banner && resolveLocalizable(banner.content, locale, defaultLocale);
45
+ const linkText =
46
+ banner?.link && resolveLocalizable(banner.link.text, locale, defaultLocale);
43
47
  const linkHref =
44
48
  banner?.link && banner.link.href === data.config.banner?.link?.href
45
49
  ? (navigation.bannerHref ?? banner.link.href)
@@ -55,13 +59,13 @@ const linkHref =
55
59
  >
56
60
  {/* The message is authored in one language, whatever the page's
57
61
  direction: `dir="auto"` keeps its punctuation where it was typed. */}
58
- <span dir="auto">{banner.content}</span>
62
+ <span dir="auto">{content}</span>
59
63
  {banner.link && linkHref && (
60
64
  <a
61
65
  class="inline-flex items-center gap-1 font-medium underline underline-offset-2"
62
66
  href={withBase(linkHref)}
63
67
  >
64
- {banner.link.text}
68
+ {linkText}
65
69
  <Icon class="rtl:-scale-x-100" name="arrow-right" size={14} />
66
70
  </a>
67
71
  )}
@@ -11,9 +11,11 @@ interface Props {
11
11
  strings?: UIStrings["nav"];
12
12
  /** Left-align full width (for the wide API layout) instead of the prose measure. */
13
13
  wide?: boolean;
14
+ /** Match a `center` page's wider centered column instead of the prose measure. */
15
+ centered?: boolean;
14
16
  }
15
17
 
16
- const { crumbs, strings, wide = false } = Astro.props;
18
+ const { crumbs, strings, wide = false, centered = false } = Astro.props;
17
19
 
18
20
  // Merge over the English defaults so a label missing from a translation (or
19
21
  // from a not-yet-regenerated snapshot) still renders instead of coming out
@@ -31,7 +33,9 @@ const eyebrowCrumb = crumbs.length > 1 ? crumbs[crumbs.length - 2] : null;
31
33
  aria-label={n.breadcrumb}
32
34
  class:list={[
33
35
  "mb-2 text-muted-foreground text-sm",
34
- wide ? "max-w-none" : "mx-auto max-w-content",
36
+ wide
37
+ ? "max-w-none"
38
+ : ["mx-auto", centered ? "max-w-[54rem]" : "max-w-content"],
35
39
  ]}
36
40
  >
37
41
  {eyebrowCrumb.route ? (
@@ -0,0 +1,62 @@
1
+ ---
2
+ import { EN_UI } from "../../core/i18n-ui.ts";
3
+ import type { UIStrings } from "../../core/i18n-ui.ts";
4
+ import { newTabAttrs } from "../../core/new-tab.ts";
5
+ import { withBase } from "../islands/base-path.ts";
6
+
7
+ // The `native()` consent banner: a card at the foot of the viewport asking to
8
+ // use analytics cookies. It renders hidden, and the consent runtime
9
+ // (`consent/client.ts`) shows it until the reader answers, stores the answer,
10
+ // and shows it again from the footer's Cookie settings link. Accept and
11
+ // Decline carry the same weight, so declining is as easy as accepting.
12
+ interface Props {
13
+ /** The privacy policy link: a page route or a URL. */
14
+ policy?: string;
15
+ /** Localized banner labels. */
16
+ strings?: UIStrings["consent"];
17
+ }
18
+
19
+ const { policy, strings } = Astro.props;
20
+ const c = { ...EN_UI.consent, ...strings };
21
+ const buttonClass =
22
+ "flex-1 rounded-blume border border-border px-4 py-2 text-foreground text-sm transition-colors hover:border-foreground";
23
+ ---
24
+
25
+ <div
26
+ aria-label={c.label}
27
+ class="fixed inset-x-4 bottom-4 z-50 rounded-blume border border-border bg-background p-4 shadow-lg sm:start-auto sm:end-4 sm:w-96"
28
+ data-blume-consent-banner
29
+ hidden
30
+ role="region"
31
+ >
32
+ <p class="text-foreground text-sm">
33
+ {c.message}{" "}
34
+ {
35
+ policy && (
36
+ <a
37
+ class="text-muted-foreground underline underline-offset-2 transition-colors hover:text-foreground"
38
+ href={withBase(policy)}
39
+ {...newTabAttrs(policy)}
40
+ >
41
+ {c.policy}
42
+ </a>
43
+ )
44
+ }
45
+ </p>
46
+ <div class="mt-3 flex gap-2">
47
+ <button
48
+ class={buttonClass}
49
+ data-blume-consent-choice="decline"
50
+ type="button"
51
+ >
52
+ {c.decline}
53
+ </button>
54
+ <button
55
+ class={buttonClass}
56
+ data-blume-consent-choice="accept"
57
+ type="button"
58
+ >
59
+ {c.accept}
60
+ </button>
61
+ </div>
62
+ </div>
@@ -0,0 +1,38 @@
1
+ ---
2
+ import { consentHead } from "../../consent/head.ts";
3
+ import { CONSENT_INIT_SCRIPT } from "../../consent/init.ts";
4
+ import type { BlumeDataConfig } from "../../core/data.ts";
5
+
6
+ // The consent layer's <head> output, rendered ahead of `Analytics.astro` by
7
+ // every layout when `consent` is configured: the inline script that creates
8
+ // `window.blumeConsent` (`consent/init.ts`), the adapter's own tags — a
9
+ // hosted consent manager's loader and the bridge that reports its answers —
10
+ // and the runtime that runs the held analytics (`consent/client.ts`), which
11
+ // starts the adapter's browser module, if it has one (`blume:consent-client`,
12
+ // see `consent/clients.ts`). Like analytics, a hosted manager loads in
13
+ // production builds only; a browser module (`native()`'s banner) works in
14
+ // `blume dev` too.
15
+ interface Props {
16
+ consent: NonNullable<BlumeDataConfig["consent"]>;
17
+ }
18
+
19
+ const { consent } = Astro.props;
20
+ const tags = import.meta.env.PROD ? consentHead(consent) : [];
21
+ ---
22
+
23
+ <script data-kind={consent.kind} is:inline set:html={CONSENT_INIT_SCRIPT} />
24
+ {
25
+ tags.map((tag) =>
26
+ tag.content === null ? (
27
+ <script is:inline {...tag.attributes} />
28
+ ) : (
29
+ <script is:inline set:html={tag.content} {...tag.attributes} />
30
+ )
31
+ )
32
+ }
33
+ <script>
34
+ import { startConsentClient } from "blume:consent-client";
35
+ import { startConsent } from "../../consent/client.ts";
36
+
37
+ startConsent(startConsentClient);
38
+ </script>
@@ -0,0 +1,94 @@
1
+ ---
2
+ import AccordionItem from "../content/AccordionItem.astro";
3
+ import Card from "../content/Card.astro";
4
+ import CardGroup from "../content/CardGroup.astro";
5
+ import Icon from "../Icon.astro";
6
+ import { directoryEntries } from "./nav-utils.ts";
7
+ import type { NavGroup } from "./nav-utils.ts";
8
+
9
+ /**
10
+ * A group page's directory: the group's other pages listed below the page's
11
+ * content, as cards or as an accordion whose subgroups open to their pages
12
+ * (the group's `directory`, see `core/schema.ts`).
13
+ */
14
+ interface Props {
15
+ group: NavGroup;
16
+ }
17
+
18
+ const { group } = Astro.props;
19
+ const entries = directoryEntries(group);
20
+ ---
21
+
22
+ {
23
+ entries.length > 0 && (
24
+ <nav
25
+ aria-label={group.label}
26
+ class="mx-auto mt-6 max-w-content"
27
+ data-blume-directory={group.directory}
28
+ >
29
+ {group.directory === "card" ? (
30
+ <CardGroup>
31
+ {entries.map((entry) => (
32
+ <Card href={entry.href} icon={entry.icon} title={entry.label}>
33
+ {entry.description}
34
+ </Card>
35
+ ))}
36
+ </CardGroup>
37
+ ) : (
38
+ <div class="not-prose my-6 divide-y divide-border overflow-hidden rounded-blume border border-border">
39
+ {entries.map((entry, index) =>
40
+ entry.pages ? (
41
+ <AccordionItem
42
+ description={entry.description}
43
+ icon={entry.icon}
44
+ id={`blume-directory-${index + 1}`}
45
+ title={entry.label}
46
+ >
47
+ <ul class="grid gap-2 text-sm">
48
+ {entry.pages.map((page) => (
49
+ <li>
50
+ <a
51
+ class="text-muted-foreground no-underline transition-colors hover:text-foreground"
52
+ href={page.route}
53
+ >
54
+ {page.label}
55
+ </a>
56
+ </li>
57
+ ))}
58
+ </ul>
59
+ </AccordionItem>
60
+ ) : (
61
+ <a
62
+ class="flex items-center justify-between gap-4 p-4 font-medium text-foreground no-underline transition-colors hover:bg-muted/40"
63
+ href={entry.href}
64
+ >
65
+ <span class="flex items-start gap-2">
66
+ {entry.icon && (
67
+ <Icon
68
+ class="mt-0.5 shrink-0 text-muted-foreground"
69
+ name={entry.icon}
70
+ size={16}
71
+ />
72
+ )}
73
+ <span>
74
+ <span class="block">{entry.label}</span>
75
+ {entry.description && (
76
+ <span class="block font-normal text-muted-foreground text-sm">
77
+ {entry.description}
78
+ </span>
79
+ )}
80
+ </span>
81
+ </span>
82
+ <Icon
83
+ class="shrink-0 text-muted-foreground rtl:-scale-x-100"
84
+ name="arrow-right"
85
+ size={16}
86
+ />
87
+ </a>
88
+ )
89
+ )}
90
+ </div>
91
+ )}
92
+ </nav>
93
+ )
94
+ }
@@ -0,0 +1,51 @@
1
+ ---
2
+ // The header's selectors, version selector, and language switcher, as a row
3
+ // at the top of the nav drawer. Below `lg` the sidebar is this drawer, and the
4
+ // header has no room for them beside the logo, tabs, search, and icon
5
+ // buttons, so it hides them whenever there's a drawer to open and this row
6
+ // takes over; from `lg` up the row hides and the header shows them again.
7
+ import type { UIStrings } from "../../core/i18n-ui.ts";
8
+ import type {
9
+ LocaleSwitchOption,
10
+ NavSelector as NavSelectorConfig,
11
+ } from "../../core/types.ts";
12
+ import LanguageSwitcher from "./LanguageSwitcher.astro";
13
+ import NavSelector from "./NavSelector.astro";
14
+
15
+ interface Props {
16
+ selectors: NavSelectorConfig[];
17
+ versionSelector?: NavSelectorConfig | null;
18
+ localeSwitch?: LocaleSwitchOption[];
19
+ route: string;
20
+ switcherStrings?: UIStrings["languageSwitcher"];
21
+ }
22
+
23
+ const { selectors, versionSelector, localeSwitch, route, switcherStrings } =
24
+ Astro.props;
25
+ const hasLocales = (localeSwitch?.length ?? 0) > 1;
26
+ ---
27
+
28
+ {
29
+ (selectors.length > 0 || versionSelector || hasLocales) && (
30
+ <div class="mb-4 flex flex-col gap-2 border-border border-b pb-4 lg:hidden">
31
+ {selectors.map((selector) => (
32
+ <NavSelector route={route} selector={selector} variant="drawer" />
33
+ ))}
34
+ {versionSelector && (
35
+ <NavSelector
36
+ route={route}
37
+ selector={versionSelector}
38
+ variant="drawer"
39
+ />
40
+ )}
41
+ {localeSwitch && hasLocales && (
42
+ <LanguageSwitcher
43
+ label={switcherStrings?.label ?? "Language"}
44
+ options={localeSwitch}
45
+ untranslatedLabel={switcherStrings?.untranslated ?? "Not translated"}
46
+ variant="drawer"
47
+ />
48
+ )}
49
+ </div>
50
+ )
51
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  // A no-op layout slot: renders nothing regardless of props. Used as the built-in
3
- // fallback for the content-injection slots (Footer, PageHeader, PageFooter) that
4
- // have no default, so an unconfigured slot renders empty while `resolveSlot`
3
+ // fallback for the content-injection slots (PageHeader, PageFooter) that have
4
+ // no default, so an unconfigured slot renders empty while `resolveSlot`
5
5
  // still returns a valid component and the generated pages stay type-safe.
6
6
  ---
@@ -2,7 +2,7 @@
2
2
  import Ask from "blume:ask";
3
3
  import data from "blume:data";
4
4
  import { withBase, withMountedBase } from "../islands/base-path.ts";
5
- import { NEW_TAB_ATTRS, newTabAttrs } from "../../core/new-tab.ts";
5
+ import { 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";
@@ -11,7 +11,6 @@ import type {
11
11
  Navigation,
12
12
  NavSelector as NavSelectorConfig,
13
13
  } from "../../core/types.ts";
14
- import { GITHUB_MARK } from "../github-mark.ts";
15
14
  import Icon from "../Icon.astro";
16
15
  import LanguageSwitcher from "./LanguageSwitcher.astro";
17
16
  import Logo from "./Logo.astro";
@@ -129,11 +128,19 @@ const activeTab = currentTabForRoute(navigation.tabs, route, navigation.root);
129
128
  // mobile nav below `lg`, so the inline tabs wait until `lg` to avoid duplicating
130
129
  // the drawer's links between `md` and `lg`.
131
130
  const tabsNavClass = hasSidebar
132
- ? "hidden gap-1 md:flex"
133
- : "hidden gap-1 lg:flex";
131
+ ? "hidden shrink-0 gap-1 md:flex"
132
+ : "hidden shrink-0 gap-1 lg:flex";
134
133
 
135
134
  const iconButton =
136
- "inline-flex size-9 cursor-pointer items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground";
135
+ "inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground";
136
+
137
+ // Below `lg`, where the sidebar is a drawer, the selectors, version selector,
138
+ // and language switcher move into a row at the top of it (see
139
+ // DrawerSwitchers.astro): they scope what the sidebar lists, and beside the
140
+ // logo, tabs, search, and icon buttons they'd overflow a phone or tablet
141
+ // header. With no drawer to open they have nowhere else to go, so they stay.
142
+ // Nothing in the header shrinks except the logo, whose title truncates.
143
+ const switcherClass = showNavToggle ? "hidden shrink-0 lg:block" : "shrink-0";
137
144
 
138
145
  // Header links: plain actions are secondary and hide below `sm`, where the
139
146
  // header has room for the logo and the drawer toggle and nothing else. The one
@@ -186,37 +193,44 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
186
193
  ---
187
194
 
188
195
  <header
189
- class="sticky top-0 z-40 flex h-16 items-center gap-3 bg-background/90 px-4 backdrop-blur md:px-6"
196
+ class="sticky top-0 z-40 flex h-16 items-center gap-2 bg-background/90 px-4 backdrop-blur sm:gap-3 md:px-6 lg:grid lg:grid-cols-[minmax(0,1fr)_auto_minmax(max-content,1fr)]"
190
197
  data-blume-header
191
198
  data-blume-header-transparent={transparent ? "" : undefined}
192
199
  >
193
- {
194
- showNavToggle && (
195
- <button
196
- aria-controls="blume-nav-drawer"
197
- aria-expanded="false"
198
- aria-label={n.toggleNavigation}
199
- class={`${iconButton} lg:hidden`}
200
- data-blume-nav-toggle
201
- type="button"
202
- >
203
- <Icon name="menu" size={20} />
204
- </button>
205
- )
206
- }
207
- <LogoSlot locale={locale} logo={logo} site={site} />
208
- {
209
- navigation.selectors.length > 0 && (
210
- <div class="flex items-center gap-1.5">
211
- {navigation.selectors.map((selector) => (
212
- <NavSelector route={route} selector={selector} />
213
- ))}
214
- </div>
215
- )
216
- }
200
+ {/* From `lg` the header is three columns, so the tabs sit at its center:
201
+ the logo side and the controls side share the rest equally. The logo
202
+ side may shrink to nothing (its title truncates, as on phones); the
203
+ controls never shrink, so when they need more than half, the tabs move
204
+ over rather than overlap. Below `lg` it's one row, tabs after the logo. */}
205
+ <div class="flex min-w-0 items-center gap-2 sm:gap-3 lg:col-start-1">
206
+ {
207
+ showNavToggle && (
208
+ <button
209
+ aria-controls="blume-nav-drawer"
210
+ aria-expanded="false"
211
+ aria-label={n.toggleNavigation}
212
+ class={`${iconButton} lg:hidden`}
213
+ data-blume-nav-toggle
214
+ type="button"
215
+ >
216
+ <Icon name="menu" size={20} />
217
+ </button>
218
+ )
219
+ }
220
+ <LogoSlot locale={locale} logo={logo} site={site} />
221
+ {
222
+ navigation.selectors.length > 0 && (
223
+ <div class:list={["flex items-center gap-1.5", switcherClass]}>
224
+ {navigation.selectors.map((selector) => (
225
+ <NavSelector route={route} selector={selector} />
226
+ ))}
227
+ </div>
228
+ )
229
+ }
230
+ </div>
217
231
  {
218
232
  navigation.tabs.length > 0 && (
219
- <nav aria-label={n.sections} class={tabsNavClass}>
233
+ <nav aria-label={n.sections} class:list={[tabsNavClass, "lg:col-start-2"]}>
220
234
  {navigation.tabs.map((tab) =>
221
235
  tab.items && tab.items.length > 0 ? (
222
236
  <NavTabMenu
@@ -241,38 +255,31 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
241
255
  </nav>
242
256
  )
243
257
  }
244
- <div class="flex-1"></div>
245
- {
246
- /* Right-aligned next to the language switcher: the spacer absorbs its
247
- width, so pages without a version selector (blog, generated references)
248
- keep the logo, tabs, and the rest of this cluster in place — no layout
249
- shift when crossing into the docs. */
250
- versionSelector && (
251
- <NavSelector align="end" route={route} selector={versionSelector} />
252
- )
253
- }
254
- {
255
- localeSwitch && localeSwitch.length > 1 && (
256
- <LanguageSwitcher
257
- label={switcherStrings?.label ?? "Language"}
258
- options={localeSwitch}
259
- untranslatedLabel={switcherStrings?.untranslated ?? "Not translated"}
260
- />
261
- )
262
- }
263
- {
264
- searchEnabled && (
265
- <SearchSlot
266
- assistantEnabled={assistantEnabled}
267
- locale={searchLocale}
268
- navigation={navigation}
269
- popularPages={data.config.search.popular}
270
- strings={searchStrings}
271
- version={searchVersion}
272
- />
273
- )
274
- }
275
- <div class="flex items-center gap-2">
258
+ <div class="flex-1 lg:hidden"></div>
259
+ {/* Everything on the right sits in one group with a tight gap: the version
260
+ and language pickers, the header links, and the icon buttons. Below `lg`
261
+ the spacer absorbs its width, so pages without a version selector (blog,
262
+ generated references) keep the logo and tabs in place — no layout shift
263
+ when crossing into the docs. */}
264
+ <div class="flex shrink-0 items-center gap-1 lg:col-start-3 lg:justify-self-end">
265
+ {
266
+ versionSelector && (
267
+ <div class={switcherClass}>
268
+ <NavSelector align="end" route={route} selector={versionSelector} />
269
+ </div>
270
+ )
271
+ }
272
+ {
273
+ localeSwitch && localeSwitch.length > 1 && (
274
+ <div class={switcherClass}>
275
+ <LanguageSwitcher
276
+ label={switcherStrings?.label ?? "Language"}
277
+ options={localeSwitch}
278
+ untranslatedLabel={switcherStrings?.untranslated ?? "Not translated"}
279
+ />
280
+ </div>
281
+ )
282
+ }
276
283
  {
277
284
  /* Plain links first, then the one filled button: the reader's eye lands
278
285
  on the button because nothing beside it competes. */
@@ -299,29 +306,24 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
299
306
  )
300
307
  }
301
308
  {
302
- navigation.repoUrl && (
303
- <a
304
- aria-label={n.githubRepository}
305
- class={iconButton}
306
- href={navigation.repoUrl}
307
- {...NEW_TAB_ATTRS}
308
- >
309
- <svg
310
- aria-hidden="true"
311
- fill="currentColor"
312
- height="18"
313
- set:html={GITHUB_MARK}
314
- viewBox="0 0 16 16"
315
- width="18"
316
- xmlns="http://www.w3.org/2000/svg"
317
- />
318
- </a>
309
+ /* The icon buttons, each named by a tooltip. The site's repository and
310
+ social profiles live in the footer. */
311
+ searchEnabled && (
312
+ <SearchSlot
313
+ assistantEnabled={assistantEnabled}
314
+ locale={searchLocale}
315
+ navigation={navigation}
316
+ popularPages={data.config.search.popular}
317
+ strings={searchStrings}
318
+ version={searchVersion}
319
+ />
319
320
  )
320
321
  }
321
322
  <button
322
323
  aria-label={n.toggleTheme}
323
324
  class={iconButton}
324
325
  data-blume-theme-toggle
326
+ data-blume-tooltip={n.toggleTheme}
325
327
  type="button"
326
328
  >
327
329
  <span class="inline-flex dark:hidden"><Icon name="sun" size={18} /></span>
@@ -334,6 +336,46 @@ const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-b
334
336
  {transparent && <script is:inline set:html={transparentScript} />}
335
337
 
336
338
  <style is:global>
339
+ /* The header's icon buttons are named by a tooltip below them, shown on hover
340
+ (where there is one) and on keyboard focus. It hangs from the button's end
341
+ edge, so the last button's tooltip never runs past the viewport, and it
342
+ keeps the page's own colors under a transparent header. */
343
+ [data-blume-tooltip] {
344
+ position: relative;
345
+ }
346
+ [data-blume-tooltip]::after {
347
+ content: attr(data-blume-tooltip);
348
+ position: absolute;
349
+ top: calc(100% + 0.375rem);
350
+ inset-inline-end: 0;
351
+ z-index: 50;
352
+ padding: 0.25rem 0.5rem;
353
+ border-radius: 0.375rem;
354
+ background-color: var(--blume-header-foreground);
355
+ color: var(--blume-header-background);
356
+ font-size: 0.75rem;
357
+ font-weight: 500;
358
+ line-height: 1rem;
359
+ white-space: nowrap;
360
+ pointer-events: none;
361
+ opacity: 0;
362
+ visibility: hidden;
363
+ transition:
364
+ opacity 120ms ease,
365
+ visibility 0s linear 120ms;
366
+ }
367
+ [data-blume-tooltip]:focus-visible::after {
368
+ opacity: 1;
369
+ visibility: visible;
370
+ transition: opacity 120ms ease;
371
+ }
372
+ @media (hover: hover) {
373
+ [data-blume-tooltip]:hover::after {
374
+ opacity: 1;
375
+ visibility: visible;
376
+ transition: opacity 120ms ease 400ms;
377
+ }
378
+ }
337
379
  /* Transparent header (PageLayout `transparentHeader`): at the top of the
338
380
  page the bar has no background and its chrome renders in white so it can
339
381
  sit over a dark hero; once scrolled it is the frosted bar again. The color