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.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +142 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
- package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
- package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
- package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
- package/dist/cli/chunk-313vnn40.js.map +10 -0
- package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
- package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
- package/dist/cli/chunk-3x6x3pph.js.map +10 -0
- package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
- package/dist/cli/chunk-42t4jxdx.js.map +12 -0
- package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
- package/dist/cli/chunk-54ztw1nj.js.map +10 -0
- package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
- package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
- package/dist/cli/chunk-66w9j7p6.js +322 -0
- package/dist/cli/chunk-66w9j7p6.js.map +14 -0
- package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
- package/dist/cli/chunk-7ppf1rva.js.map +10 -0
- package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
- package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
- package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
- package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
- package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
- package/dist/cli/chunk-cfyg47zg.js.map +10 -0
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
- package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
- package/dist/cli/chunk-e6atmn4h.js.map +36 -0
- package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
- package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
- package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
- package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
- package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
- package/dist/cli/chunk-ehweg4fr.js.map +218 -0
- package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
- package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
- package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
- package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
- package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
- package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
- package/dist/cli/chunk-gb420vvz.js.map +17 -0
- package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
- package/dist/cli/chunk-hebn0tpx.js.map +14 -0
- package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
- package/dist/cli/chunk-htrwgabr.js.map +15 -0
- package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
- package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
- package/dist/cli/chunk-j134vrp2.js +65 -0
- package/dist/cli/chunk-j134vrp2.js.map +10 -0
- package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
- package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
- package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
- package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
- package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
- package/dist/cli/chunk-ncj7w596.js.map +35 -0
- package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
- package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
- package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
- package/dist/cli/chunk-nrns10mj.js.map +10 -0
- package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
- package/dist/cli/chunk-t2m5j4pr.js +104 -0
- package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
- package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
- package/dist/cli/chunk-tphac74f.js +126 -0
- package/dist/cli/chunk-tphac74f.js.map +11 -0
- package/dist/cli/chunk-w1r4vase.js +18 -0
- package/dist/cli/chunk-w1r4vase.js.map +10 -0
- package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
- package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
- package/dist/cli/index.js +31 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +26 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +16 -0
- package/dist/types/astro/integration.d.ts +9 -0
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +62 -0
- package/dist/types/components/content/api-page.d.ts +100 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +158 -0
- package/dist/types/components/openapi/security.d.ts +95 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +217 -23
- package/dist/types/core/data.d.ts +53 -4
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/i18n-ui.d.ts +88 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/probe.d.ts +2 -0
- package/dist/types/core/project-graph.d.ts +6 -0
- package/dist/types/core/redirect-patterns.d.ts +152 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +670 -56
- package/dist/types/core/sources/cache.d.ts +3 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
- package/dist/types/core/sources/contentful.d.ts +17 -1
- package/dist/types/core/sources/lexical.d.ts +5 -0
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/remote.d.ts +37 -10
- package/dist/types/core/sources/sanity.d.ts +1 -1
- package/dist/types/core/types.d.ts +18 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/adapter-output.d.ts +2 -1
- package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
- package/dist/types/deploy/adapters/node.d.ts +58 -23
- package/dist/types/deploy/adapters/registry.d.ts +10 -0
- package/dist/types/deploy/adapters/types.d.ts +3 -2
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/node.d.ts +3 -1
- package/dist/types/deploy/platforms/types.d.ts +18 -7
- package/dist/types/deploy/platforms/vercel.d.ts +26 -1
- package/dist/types/deploy/redirects.d.ts +55 -11
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/features.d.ts +3 -2
- package/dist/types/narration/build.d.ts +70 -0
- package/dist/types/narration/provider.d.ts +26 -0
- package/dist/types/narration/script.d.ts +154 -0
- package/dist/types/openapi/checks.d.ts +27 -0
- package/dist/types/openapi/graphql.d.ts +6 -0
- package/dist/types/openapi/model.d.ts +27 -10
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +16 -0
- package/dist/types/openapi/references.d.ts +30 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +119 -0
- package/dist/types/ratelimit/upstash.d.ts +46 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +89 -11
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +82 -6
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +144 -36
- package/dist/types/search/adapters/registry.d.ts +3 -0
- package/dist/types/search/adapters/typesense.d.ts +14 -4
- package/dist/types/search/build.d.ts +3 -1
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +13 -9
- package/dist/types/search/sync/algolia.d.ts +5 -2
- package/dist/types/search/sync/index.d.ts +3 -1
- package/dist/types/search/sync/typesense.d.ts +11 -7
- package/dist/types/seo/metatags.d.ts +20 -0
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +54 -0
- package/dist/types/sources/shared.d.ts +3 -0
- package/dist/types/sources/strapi.d.ts +2 -0
- package/docs/01-quickstart.mdx +4 -2
- package/docs/02-deployment.mdx +71 -17
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/advanced/changelog.mdx +13 -2
- package/docs/advanced/skills.mdx +15 -1
- package/docs/cli/audit.mdx +51 -8
- package/docs/cli/doctor.mdx +5 -1
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/assistant.mdx +194 -38
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +8 -6
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +64 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +90 -0
- package/docs/configuration/search.mdx +63 -12
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +108 -2
- package/docs/content/frontmatter.mdx +80 -2
- package/docs/content/i18n.mdx +39 -4
- package/docs/content/includes.mdx +16 -0
- package/docs/content/meta.mdx +1 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +32 -10
- package/docs/content/sources/contentful.mdx +35 -0
- package/docs/content/sources/custom.mdx +43 -0
- package/docs/content/sources/github-releases.mdx +39 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +31 -0
- package/docs/content/sources/remote-mdx.mdx +44 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +32 -0
- package/docs/content/syntax.mdx +69 -4
- package/docs/content/variables.mdx +41 -0
- package/docs/discoverability/agent-discovery.mdx +29 -2
- package/docs/discoverability/index.mdx +2 -2
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +2 -2
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +4 -2
- package/docs/references/graphql.mdx +14 -2
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +148 -7
- package/docs/references/scalar.mdx +3 -1
- package/package.json +43 -8
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +7 -7
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +10 -7
- package/skills/blume-migrate/references/starlight.md +11 -8
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +6 -3
- package/src/ai/ask-context.ts +103 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +76 -1
- package/src/ai/cors.ts +14 -3
- package/src/ai/index.ts +12 -0
- package/src/ai/llms.ts +6 -2
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +36 -6
- package/src/ai/relative-links.ts +4 -38
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +35 -2
- package/src/ai/write-skill.ts +97 -0
- package/src/astro/generate.ts +210 -66
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +42 -4
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +9 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/templates.ts +406 -108
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +38 -3
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +19 -13
- package/src/audit/checks/network.ts +110 -6
- package/src/audit/checks/redirects.ts +6 -4
- package/src/audit/checks/robots.ts +58 -2
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +5 -0
- package/src/audit/types.ts +4 -1
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +12 -1
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +67 -28
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/init/scaffold.ts +3 -3
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +72 -30
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +66 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/FileTree.astro +1 -0
- package/src/components/content/GithubInfo.astro +1 -0
- package/src/components/content/Panel.astro +1 -0
- package/src/components/content/ParamField.astro +25 -0
- package/src/components/content/RequestExample.astro +17 -0
- package/src/components/content/ResponseExample.astro +17 -0
- package/src/components/content/ResponseField.astro +32 -0
- package/src/components/content/Step.astro +1 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +103 -0
- package/src/components/content/api-page.ts +248 -0
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/content/view-switcher.ts +71 -0
- package/src/components/index.ts +2 -0
- package/src/components/islands/Assistant.astro +10 -1
- package/src/components/islands/assistant.tsx +104 -14
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +136 -21
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +6 -2
- package/src/components/layout/ConsentBanner.astro +62 -0
- package/src/components/layout/ConsentHead.astro +38 -0
- package/src/components/layout/Directory.astro +94 -0
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +122 -80
- package/src/components/layout/LanguageSwitcher.astro +48 -15
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +33 -7
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +71 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +318 -47
- package/src/components/layout/Search.astro +47 -19
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +126 -0
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +32 -0
- package/src/components/layout/search/typesense.ts +19 -3
- package/src/components/openapi/AsyncApiOperation.astro +14 -7
- package/src/components/openapi/Authorization.astro +10 -0
- package/src/components/openapi/GraphqlOperation.astro +5 -0
- package/src/components/openapi/Operation.astro +184 -13
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +24 -5
- package/src/components/openapi/RequestPanel.astro +59 -7
- package/src/components/openapi/Responses.astro +7 -4
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +65 -9
- package/src/components/openapi/async.ts +123 -29
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/graphql-helpers.ts +35 -12
- package/src/components/openapi/helpers.ts +36 -2
- package/src/components/openapi/message-model.ts +54 -11
- package/src/components/openapi/message.ts +14 -4
- package/src/components/openapi/operation-model.ts +16 -7
- package/src/components/openapi/playground-client.ts +24 -5
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +16 -3
- package/src/components/openapi/snippets.ts +873 -10
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/components/props.ts +6 -0
- package/src/consent/client.ts +95 -0
- package/src/consent/clients.ts +19 -0
- package/src/consent/ethyca.ts +71 -0
- package/src/consent/head.ts +24 -0
- package/src/consent/index.ts +37 -0
- package/src/consent/init.ts +29 -0
- package/src/consent/native.ts +36 -0
- package/src/consent/osano.ts +59 -0
- package/src/consent/schema.ts +30 -0
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/client-address.ts +19 -0
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +225 -23
- package/src/core/data.ts +46 -4
- package/src/core/diagnostics.ts +8 -2
- package/src/core/footer.ts +26 -0
- package/src/core/graph.ts +39 -36
- package/src/core/i18n-ui.ts +84 -2
- package/src/core/includes.ts +21 -4
- package/src/core/links.ts +63 -19
- package/src/core/localizable.ts +26 -0
- package/src/core/navigation.ts +43 -12
- package/src/core/page-modes.ts +56 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +163 -16
- package/src/core/redirect-patterns.ts +520 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +339 -66
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/contentful-rich-text.ts +29 -6
- package/src/core/sources/contentful.ts +135 -25
- package/src/core/sources/filesystem.ts +26 -4
- package/src/core/sources/github-releases.ts +12 -1
- package/src/core/sources/lexical.ts +15 -10
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +228 -41
- package/src/core/sources/notion.ts +7 -1
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/remote.ts +72 -15
- package/src/core/sources/resolve.ts +11 -1
- package/src/core/sources/sanity.ts +43 -25
- package/src/core/sources/strapi.ts +2 -2
- package/src/core/types.ts +19 -1
- package/src/core/ui-packs/ar.ts +44 -0
- package/src/core/ui-packs/bg.ts +46 -0
- package/src/core/ui-packs/bn.ts +44 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +45 -0
- package/src/core/ui-packs/da.ts +46 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +46 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +46 -0
- package/src/core/ui-packs/fi.ts +46 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +44 -0
- package/src/core/ui-packs/hi.ts +45 -0
- package/src/core/ui-packs/hr.ts +46 -0
- package/src/core/ui-packs/hu.ts +45 -0
- package/src/core/ui-packs/id.ts +46 -0
- package/src/core/ui-packs/it.ts +46 -0
- package/src/core/ui-packs/ja.ts +46 -0
- package/src/core/ui-packs/ko.ts +45 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +45 -0
- package/src/core/ui-packs/pl.ts +46 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +46 -0
- package/src/core/ui-packs/ro.ts +46 -0
- package/src/core/ui-packs/ru.ts +46 -0
- package/src/core/ui-packs/sk.ts +45 -0
- package/src/core/ui-packs/sr.ts +46 -0
- package/src/core/ui-packs/sv.ts +45 -0
- package/src/core/ui-packs/th.ts +44 -0
- package/src/core/ui-packs/tr.ts +46 -0
- package/src/core/ui-packs/uk.ts +46 -0
- package/src/core/ui-packs/vi.ts +46 -0
- package/src/core/ui-packs/zh-tw.ts +44 -0
- package/src/core/ui-packs/zh.ts +44 -0
- package/src/core/variables.ts +103 -0
- package/src/deploy/adapter-output.ts +7 -2
- package/src/deploy/adapters/cloudflare.ts +7 -5
- package/src/deploy/adapters/node.ts +47 -9
- package/src/deploy/adapters/types.ts +7 -3
- package/src/deploy/artifacts.ts +79 -9
- package/src/deploy/cloudflare-negotiation.ts +35 -5
- package/src/deploy/headers.ts +2 -1
- package/src/deploy/node-headers.ts +63 -9
- package/src/deploy/platforms/cloudflare.ts +45 -9
- package/src/deploy/platforms/netlify.ts +35 -2
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +149 -17
- package/src/deploy/redirects.ts +151 -24
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +326 -102
- package/src/eval/agents.ts +18 -1
- package/src/eval/prompts.ts +6 -3
- package/src/eval/report.ts +34 -13
- package/src/eval/run.ts +5 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/features.ts +3 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +28 -5
- package/src/markdown/math.ts +4 -4
- package/src/markdown/relative-links.ts +3 -2
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +7 -6
- package/src/openapi/checks.ts +273 -0
- package/src/openapi/graphql-build.ts +21 -0
- package/src/openapi/graphql.ts +11 -0
- package/src/openapi/model.ts +72 -27
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +182 -4
- package/src/openapi/references.ts +64 -8
- package/src/openapi/render-mdx.ts +5 -1
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +40 -15
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +247 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +60 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +20 -3
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +80 -8
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +23 -5
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/locale-scope.ts +30 -0
- package/src/search/adapters/typesense.ts +14 -4
- package/src/search/build.ts +21 -3
- package/src/search/documents.ts +26 -2
- package/src/search/orama-index.ts +191 -34
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +111 -10
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +76 -26
- package/src/seo/metatags.ts +67 -0
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/shared.ts +3 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +85 -6
- package/src/theme/palette.ts +121 -45
- package/src/translate/prompts.ts +1 -0
- package/src/translate/validate.ts +31 -3
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
- package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
- package/dist/cli/chunk-35d4wj9f.js.map +0 -15
- package/dist/cli/chunk-364znk6q.js +0 -75
- package/dist/cli/chunk-364znk6q.js.map +0 -11
- package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
- package/dist/cli/chunk-8ktnccpt.js.map +0 -10
- package/dist/cli/chunk-9t7a85s3.js.map +0 -10
- package/dist/cli/chunk-b07cmahc.js +0 -145
- package/dist/cli/chunk-b07cmahc.js.map +0 -11
- package/dist/cli/chunk-c8chx29p.js.map +0 -36
- package/dist/cli/chunk-e04dxsz1.js +0 -39
- package/dist/cli/chunk-e04dxsz1.js.map +0 -10
- package/dist/cli/chunk-j85vccga.js.map +0 -36
- package/dist/cli/chunk-p3v96n38.js.map +0 -10
- package/dist/cli/chunk-pehfxfta.js.map +0 -10
- package/dist/cli/chunk-pv29h0wf.js.map +0 -190
- package/dist/cli/chunk-q58y5e6a.js.map +0 -10
- package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
- package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
- package/dist/cli/chunk-yfyb25rh.js.map +0 -14
- package/docs/content/sources.mdx +0 -334
- /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
- /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
- /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
- /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
- /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
- /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
- /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
- /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
|
@@ -15,7 +15,7 @@ Throughout this skill (including the `references/` files), **`<skill>` means the
|
|
|
15
15
|
|
|
16
16
|
- **Target idiomatic Blume, not a mechanical port.** Prefer filesystem-derived navigation over an exhaustive explicit `navigation.sidebar`. Prefer `:::` directives over JSX callouts. Prefer Blume defaults over restating them in config.
|
|
17
17
|
- **Every field has a default; `{}` is a valid config.** Map only what the source _declares_. If the source uses a framework default, don't write it.
|
|
18
|
-
- **Drop chrome that has no Blume equivalent — and say so.** Navbar CTAs, footer
|
|
18
|
+
- **Drop chrome that has no Blume equivalent — and say so.** Navbar CTAs, footer copyright text, custom theming, conditional redirects, and unmappable icons get reported to the user, not silently discarded or faked.
|
|
19
19
|
- **Convert, don't preserve.** Blume's page frontmatter schema is **strict** — unknown keys are build errors. A source-only frontmatter key must be mapped to a Blume key or removed (and reported), never left to "maybe validate."
|
|
20
20
|
|
|
21
21
|
## Migration workflow
|
|
@@ -44,7 +44,7 @@ The single biggest shift for most sources — especially Mintlify — is that **
|
|
|
44
44
|
|
|
45
45
|
- **Folders become groups, files become pages.** A page's sidebar label is its frontmatter `title`; a group's label is the humanized folder name.
|
|
46
46
|
- **Ordering resolves highest-priority-first:** an explicit `navigation.sidebar` (replaces the whole tree) → a folder's `meta.ts` `pages` array → a page's frontmatter `sidebar.order` → the filesystem (`index` first, then numeric filename prefix like `01-`, then alphabetical).
|
|
47
|
-
- **`meta.ts` refines one folder** (`defineMeta({ title, icon, order, collapsed, pages, display })`). The `pages` array lists children by slug (numeric prefix and parentheses stripped); children you omit fall back to their own `sidebar.order`, then filesystem order (`index` still sorts first) — so a partial `pages` list is safe, but list every child when the source declared a complete order.
|
|
47
|
+
- **`meta.ts` refines one folder** (`defineMeta({ title, icon, order, collapsed, pages, display, directory })`). The `pages` array lists children by slug (numeric prefix and parentheses stripped); children you omit fall back to their own `sidebar.order`, then filesystem order (`index` still sorts first) — so a partial `pages` list is safe, but list every child when the source declared a complete order.
|
|
48
48
|
- **Sidebar render mode: a global default with per-folder overrides.** `navigation.sidebar.display` in `blume.config.ts` is `"flat"` (default), `"group"` (collapsible), or `"page"` (drill-in sub-panel) and sets the mode for every group at once. A folder can override its **own** group: `display` in its `meta.ts`, or — sugar when the folder has an `index` page — `sidebar.display` in that index page's frontmatter. Precedence: index frontmatter → `meta.ts` → global config → `flat`; an override applies to that one group only (nested subgroups resolve their own chain). So a source's per-category collapse/drill-in modes migrate per folder — only reach for the global mode when the whole sidebar changes. Under an explicit `navigation.sidebar`, the config item's own `display` field is the only per-group control (frontmatter/meta `display` is ignored there, with a `BLUME_SIDEBAR_DISPLAY_IGNORED` warning).
|
|
49
49
|
- **An explicit `navigation.sidebar` replaces filesystem generation entirely.** Use it only for a nav shape files can't express. Its items are a page route string, a group (`{ label, items }`), or a link (`{ label, href }`).
|
|
50
50
|
- **Config-declared nesting has no on-disk counterpart — materialize it or it flattens silently.** When a source (Mintlify `groups`, Nextra `_meta`, a Docusaurus sidebar…) declares a nested group, its pages usually sit **flat in one folder** and the grouping lives only in config. Filesystem-derived nav sees the flat folder and drops the inner group. To keep the nesting you must **either** move those pages into a real subfolder (`meta.ts` for label/`collapsed`) — which changes their URLs, so add `redirects` — **or** declare the group in an explicit `navigation.sidebar`, which nests the existing routes without moving a file. Walk config `pages`/nav arrays **recursively** during inventory and record where config nesting depth exceeds on-disk depth; that gap is exactly what gets lost.
|
|
@@ -69,7 +69,7 @@ The single biggest shift for most sources — especially Mintlify — is that **
|
|
|
69
69
|
- **`content`:** `root` (default `"docs"`, relative to the project dir where `blume` runs), `include`/`exclude` (arrays of globs **relative to `content.root`**; defaults `["**/*.{md,mdx}"]` / `["**/_*", "**/.*"]`), `sources` (an array of **adapters imported from `blume/sources`**: `filesystem({ root, include, exclude })`, `obsidian({ vault })`, `githubReleases({ owner, repo })`, `notion({ database })`, `sanity({ projectId, dataset, query })`, `contentful({ space, contentType })`, `payload({ url, collection })`, `strapi({ url, contentType })`, `mdxRemote({ github })`, `custom(source)`; every factory with an options object also takes `prefix` and `pollInterval`, while `custom(source)` takes a `ContentSource` instance that sets its own `prefix`. The 1.x `{ type: "…" }` objects were removed — rename `type` to the factory call and pass the other fields as its options — except `{ type: "custom", source }`, which becomes `custom(source)` with the instance as the only argument. `root`/`include`/`exclude` are shorthand for a single `filesystem()` and are **rejected beside `sources`** — move them into the `filesystem()` entry. OpenAPI/AsyncAPI/GraphQL are **not** among these; they're adapters in the top-level `reference` list), `pages` (custom `.astro` dir), `defaultType`. When docs sit directly under the project dir (no `docs/` subfolder), set `root` there and **scope `include` to the real content folders** instead of scanning everything — `references/monorepo.md` §1.
|
|
70
70
|
- **`basePath`** (top-level): a site-wide mount point (e.g. `"/docs"`) prepended to **every** route while staying invisible to the sidebar (no wrapper group). This is the right target for a source that served all docs under a prefix (Docusaurus `routeBasePath`, a Fumadocs `baseUrl` of `/docs`) — distinct from a per-source `prefix` (which adds a nav group) and from `deployment.base` (host subdirectory).
|
|
71
71
|
- **`navigation`:** `tabs`, `selectors`, `actions` and `cta` (header links and the one filled button), `featured` (links pinned above the sidebar on every route), `sidebar` (`{ display, items }` — `display` is the global render mode above; `items` is an explicit tree), `repo` (`true`/`false`, or an absolute GitHub URL for the header mark when the docs repo is private and `github` must stay unset). **Avoid an explicit `navigation.sidebar` unless you have to** — lean on the filesystem-derived sidebar. It only works when the file tree roughly matches the intended sidebar layout, so reshape folders to match first; reach for `sidebar.items` only for a shape files genuinely can't express (see "Config-declared nesting" above).
|
|
72
|
-
- **`search`** — an adapter imported from `blume/search`: `orama()` (default, so omit `search` entirely for it), `flexsearch()`, `pagefind()`, `algolia({ appId, apiKey, indexName })`, `oramaCloud({ endpoint, apiKey, indexId? })`, `typesense({ host, collection, apiKey })`, `mixedbread({ storeId })`, or `false` to disable. Pass the adapter directly (`search: algolia({…})`) or as `search: { provider, popular, indexing }` when you also set curated links or indexing options. **Blume 1.x's `search.provider` string and its `search.algolia`/`oramaCloud`/`typesense`/`mixedbread` credential blocks are gone** — when a source config (or an older `blume.config.ts`) has `provider: "algolia", algolia: { appId, indexName, searchApiKey }`, rewrite it as `search: algolia({ appId, indexName, apiKey: searchApiKey })` (the search-only key is now `apiKey` in every adapter that takes one; admin keys stay in env vars). **`ai`** (the assistant, Open in chat — `ai.assistant.provider` takes an **adapter descriptor** imported from `blume/ai`: `gateway({ model })` (the default, `openai/gpt-5.5`), `
|
|
72
|
+
- **`search`** — an adapter imported from `blume/search`: `orama()` (default, so omit `search` entirely for it), `flexsearch()`, `pagefind()`, `algolia({ appId, apiKey, indexName })`, `oramaCloud({ endpoint, apiKey, indexId? })`, `typesense({ host, collection, apiKey })`, `mixedbread({ storeId })`, or `false` to disable. Pass the adapter directly (`search: algolia({…})`) or as `search: { provider, popular, indexing }` when you also set curated links or indexing options. **Blume 1.x's `search.provider` string and its `search.algolia`/`oramaCloud`/`typesense`/`mixedbread` credential blocks are gone** — when a source config (or an older `blume.config.ts`) has `provider: "algolia", algolia: { appId, indexName, searchApiKey }`, rewrite it as `search: algolia({ appId, indexName, apiKey: searchApiKey })` (the search-only key is now `apiKey` in every adapter that takes one; admin keys stay in env vars). **`ai`** (the assistant, Open in chat — `ai.assistant.provider` takes an **adapter descriptor** imported from `blume/ai`: `gateway({ model })` (the default, `openai/gpt-5.5`), `openai({ model })` (or `openai({ baseUrl, name, model, apiKeyEnv })` for any OpenAI-compatible endpoint), `anthropic({ model })`, `gemini({ model })`, `grok({ model })`, `openrouter({ model, reasoning })`, `llmgateway({ model })`, or `inkeep({ model })`. Every adapter takes `model`, `apiKeyEnv`, `headers`, and a verbatim `providerOptions` passthrough (`headers` values are written into the generated route source as-is, so they are for non-secret static headers only — a bearer token or any other credential belongs in the env var `apiKeyEnv` names, never in `headers`). Every adapter except `inkeep()` also takes `reasoning`: Inkeep runs its own answer pipeline, so `inkeep({ reasoning })` fails validation with an unrecognized key — drop a source's reasoning setting there and report it. There are **no** flat `provider`/`model`/`apiKeyEnv`/`baseUrl`/`headers`/`reasoning` fields on `ai.assistant` — a source that configured an AI assistant that way (Blume < 2.0 included) maps onto one adapter call. `enabled`, `instructions`, `retrieval`, `suggestions`, `cors`, and `endpoint` sit on `ai.assistant` itself; there is **no** `ai.ask` — Blume 2.0.0 and earlier used that name, so an older `blume.config.ts` moves the whole block to `ai.assistant`), **`agents`** (llms.txt, the JSON API, the MCP server, published skills, discovery manifests, robots content signals), **`reference`** (a list of adapters imported from `blume/reference` — `openapi({ spec | sources, route, … })`, `asyncapi({ … })`, `graphql({ spec, endpoint, … })` — never the 1.x `openapi`/`asyncapi`/`graphql` blocks), **`redirects`**, **`seo`**, **`markdown`**, **`analytics`** (a list of adapters imported from `blume/analytics` — one factory per provider (`posthog({ key, host })`, `googleAnalytics({ id })`, `plausible({ domain, host })`, `mixpanel({ token, region })`, `segment({ key })`, …; the docs page lists them all), `vercel()`, and `script({ src | content, strategy, attributes })` for anything without one — never an object keyed by provider), **`deployment`**, **`i18n`**, **`toc`**, **`lastModified`**, **`github`** (`{ owner, repo, branch?, dir?, host?, api? }` — set `host` whenever the source's edit URL is on a GitHub Enterprise origin rather than `github.com`).
|
|
73
73
|
- **`deployment`** is a host adapter from `blume/deploy` — `vercel()`, `netlify()`, `cloudflare()`, or `node()` — or a plain `{ site, base }` for a static build on any host (the default is a static build). Naming a host adapter switches the build to **server output** on that host (pass `output: "static"` to stay static there); `site`, `base`, and `output` are the named options, and anything else is forwarded verbatim to the underlying `@astrojs/*` adapter. There is **no** `deployment.adapter` string and **no** `deployment.output` field: a source that needs server rendering (the assistant, the MCP server, Mixedbread search, the API playground proxy) gets `import { vercel } from "blume/deploy"` and `deployment: vercel()`; a static source gets nothing — unless it served its docs under a subpath, which becomes `deployment: { base: "/docs" }` (see below for when to add `site`). Note that `cloudflare` and `vercel` are also exported from `blume/analytics` — alias one (`import { cloudflare as cloudflareDeploy } from "blume/deploy"`) when a config uses both.
|
|
74
74
|
- **Keep the source's site URL as `deployment.site` unless the target host is one Blume auto-detects.** Blume fills `site` in from the platform's build environment only on **Vercel, Netlify, and Cloudflare Pages**, and uses the dev server's `localhost` URL during `blume dev`; on those three hosts leave it unset and let detection pick the deployed URL. Everywhere else — GitHub Pages, S3 or another static host, a custom CDN, Cloudflare Workers, a `node()` server — nothing detects it, and an unset `site` silently drops the sitemap, OG images, RSS feeds, the AI catalog, and absolute canonical URLs. So when the source config had a `url`/`site` field and the target isn't one of those three hosts, carry it over: `deployment: { site: "https://…" }` for a static build, or the `site` option of a host adapter (`node({ site })`). If you can't tell where the site will deploy, keep it and say so in the report.
|
|
75
75
|
- **Favicon is a filename convention, not config.** Drop `icon.{svg,png,ico}` or `favicon.{svg,png,ico}` (and `apple-icon.png`) in the project root or `public/` — Blume auto-detects it. There is **no** `favicon` config field. A source favicon given as `{ light, dark }` maps to a filename pair: copy the light file to a conventional name (e.g. `public/icon.png`) and the dark file to its `-dark` sibling — same directory and extension, `-dark` before the extension (`public/icon-dark.png`). If the two files have different formats, convert one so the extensions match; only an exact sibling of the resolved icon is picked up.
|
|
@@ -116,7 +116,7 @@ Also valid: `date`/`authors` (blog/changelog feeds), `changelog` (changelog meta
|
|
|
116
116
|
- **Callouts as directives:** `:::note`, `:::tip`, `:::warning`, `:::danger`, `:::info`, `:::success`, with an optional title in brackets: `:::warning[Heads up]`. Aliases `caution`→warning, `error`→danger, `important`→note, `warn`→warning.
|
|
117
117
|
- **No-import MDX components:** `Callout`, `Card`/`CardGroup`, `Columns`/`Column`, `Steps`/`Step`, `Tabs`/`Tab`, `Accordion`/`AccordionItem`, `Expandable`, `FileTree`, `Tree`/`Tree.Folder`/`Tree.File`, `CodeGroup`, `Frame`, `Panel`, `Tooltip`, `Tile`, `Badge`, `Icon`, `TypeTable`/`AutoTypeTable`, `Color`, `YouTube`, `Visibility`, `GithubInfo`, `Component`, `CodeBlock`, `Diff`, `Prompt`, `Math`. (**Not** shipped — convert away: `<Warning>` → the `:::warning` directive, and the `ParamField`/`ResponseField`/`RequestField` field family → `TypeTable` rows or the OpenAPI reference. See the reference files for targets.)
|
|
118
118
|
- **Fenced-code superpowers:** ` ```package-install ` → package-manager tabs; ` ```mermaid ` → a rendered diagram; code-block titles (` ```ts server.ts `), line numbers (`lineNumbers`), and highlighting (`{1,4-5}`, `// [!code ++]`).
|
|
119
|
-
- **Math:**
|
|
119
|
+
- **Math:** `$$…$$` renders in `.mdx` with **no config** (there is no `markdown.math` field) — as a block on lines of its own, or inline within a sentence. A single `$` always stays literal text, so convert each inline `$…$` to `$$…$$` in place, inside its sentence (not onto a line of its own), checking every pair is math and not currency or a shell variable.
|
|
120
120
|
|
|
121
121
|
### OpenAPI
|
|
122
122
|
|
|
@@ -162,13 +162,13 @@ content: {
|
|
|
162
162
|
|
|
163
163
|
### Redirects are static
|
|
164
164
|
|
|
165
|
-
A `redirects: [{ from, to, status? }]` array **in `blume.config.ts`** maps old URLs when you restructure routes — Blume serves these itself, so any reorganization that moves a page (folder-per-tab, materialized nested groups, renamed slugs, index promotion) is fixed by adding an entry there; no host config needed. **Restructuring is the main source of these:** every page you moved in step 4 (folder-per-tab, renamed slugs, index promotion) needs an entry, or old URLs 404. `status` defaults to **301 (permanent — browsers cache it indefinitely)**; that's correct for genuine moves, but never use 301/308 for redirects you might reverse.
|
|
165
|
+
A `redirects: [{ from, to, status? }]` array **in `blume.config.ts`** maps old URLs when you restructure routes — Blume serves these itself, so any reorganization that moves a page (folder-per-tab, materialized nested groups, renamed slugs, index promotion) is fixed by adding an entry there; no host config needed. **Restructuring is the main source of these:** every page you moved in step 4 (folder-per-tab, renamed slugs, index promotion) needs an entry, or old URLs 404. `status` defaults to **301 (permanent — browsers cache it indefinitely)**; that's correct for genuine moves, but never use 301/308 for redirects you might reverse. Patterns carry over as written: `:name` for one segment, `:name*` or a trailing `*` for the rest of the path (`{ from: "/beta/:slug*", to: "/v2/:slug*" }`). A pattern can't also match a page, so the build fails (`BLUME_REDIRECT_MATCHES_PAGE`) if one covers a page you kept; narrow it. Rules a pattern can't express (regex params, header or cookie conditions) move to host-level config (`_redirects`, `vercel.json`); report them.
|
|
166
166
|
|
|
167
167
|
## Verification & reporting
|
|
168
168
|
|
|
169
169
|
1. Run **`blume build`** — it validates the frontmatter schema, duplicate routes, and config, and fails on any error diagnostic by default (**don't pass `--no-strict`**: that builds anyway and silently drops invalid pages). Then run **`blume validate --strict`** — links, heading anchors, and assets live here, not in `build` (add `--external` to also check outbound HTTP links). OpenAPI operation pages are real routes to `validate`, so dead links to them are caught too. Iterate until both are clean.
|
|
170
170
|
2. Run `blume dev` and review the site visually — nav structure, tabs, theme, rendered components.
|
|
171
|
-
3. **Write a migration summary** covering: what was migrated (config, N pages, nav, API references), what was **dropped** (navbar CTAs,
|
|
171
|
+
3. **Write a migration summary** covering: what was migrated (config, N pages, nav, API references), what was **dropped** (navbar CTAs, footer copyright text, custom theming, conditional redirects, unmappable icons, unsupported components), and suggested follow-ups (`blume eject` for full control, `blume add` to vendor a component for customization).
|
|
172
172
|
|
|
173
173
|
## Full documentation
|
|
174
174
|
|
|
@@ -18,7 +18,7 @@ Read `themeConfig`, `presets`, and `plugins`:
|
|
|
18
18
|
| `tagline` | `description` |
|
|
19
19
|
| `themeConfig.navbar.title` / `.logo` | `title` / `logo` (move the image into `public/`) |
|
|
20
20
|
| `themeConfig.navbar.items` (doc items) | `navigation.tabs` (for section links) |
|
|
21
|
-
| `themeConfig.navbar.items` (external/utility links — Blog, Discord…) | **`navigation.actions`** (`[{ label, href }]`, plain header links) to keep them in the header, or **`navigation.featured`** (`{ label, href, icon? }`, pinned above the sidebar on every route) if they should survive on phones; the GitHub link → the `github` config instead |
|
|
21
|
+
| `themeConfig.navbar.items` (external/utility links — Blog, Discord…) | **`navigation.actions`** (`[{ label, href }]`, plain header links) to keep them in the header, or **`navigation.featured`** (`{ label, href, icon? }`, pinned above the sidebar on every route) if they should survive on phones; the GitHub link → the `github` config instead (it renders in the footer) |
|
|
22
22
|
| `themeConfig.navbar.items` (a `className`-styled button — "Get started", "Sign up") | **`navigation.cta`** (`{ label, href }`, the header's one filled button; a route the docs don't serve must be an absolute URL) |
|
|
23
23
|
| `themeConfig.colorMode.defaultMode` | `theme.mode` (`respectPrefersColorScheme: true` → `"system"`) |
|
|
24
24
|
| `themeConfig.prism.theme` / `.darkTheme` | `markdown.code.theme: { light, dark }` (map Prism theme names to Shiki themes, e.g. `github`/`github-dark`) |
|
|
@@ -26,7 +26,7 @@ Read `themeConfig`, `presets`, and `plugins`:
|
|
|
26
26
|
| `url` + `baseUrl` | **`url` → `deployment.site`**, unless the target host is Vercel, Netlify, or Cloudflare Pages, which Blume auto-detects (see SKILL.md — GitHub Pages, a common Docusaurus host, is not one of them); `baseUrl` (when not `/`) → `deployment: { base: "/…" }`, or the `base` option of a host adapter (`vercel({ base })`) when the site also needs one |
|
|
27
27
|
| preset `docs.routeBasePath` — **including the default!** | Docusaurus serves docs at **`/docs/…` by default**; the "map only declared fields" rule does **not** apply here because the _URLs_ are load-bearing. Either keep them with top-level **`basePath: "/docs"`** (invisible to the sidebar), or intentionally move to root and emit a `redirects` entry per page. Decide explicitly and say which. (`routeBasePath: '/'` = docs-only mode — nothing to do.) |
|
|
28
28
|
| preset `docs.editUrl` | `github` (owner/repo/branch; a path after the branch → `github.dir`; **an origin other than `https://github.com` → `github.host`** — a GitHub Enterprise repo's edit links and header mark point at the public site without it) |
|
|
29
|
-
| `themeConfig.footer` | drop
|
|
29
|
+
| `themeConfig.footer` | `footer.links`, one row of `{ label, href }`: every column's items flatten into it in order (an item's `to`, a route, is its `href`); column `title`s, `copyright`, `logo`, and `style` drop (report), or keep the whole footer as a Footer override (`defineComponents` layout slot) |
|
|
30
30
|
| `themeConfig.announcementBar` | `banner` (`{ content, dismissible, id }` — `isCloseable` → `dismissible`; colors drop) |
|
|
31
31
|
| `i18n.locales` / `defaultLocale` | `i18n` — translated files live at `i18n/<locale>/docusaurus-plugin-content-docs/current/…`; move them to `<locale>/…` under `content.root` |
|
|
32
32
|
| `themeConfig.algolia` | drop — Blume ships built-in search (Orama); remove the Algolia dep. To keep the index, `search: algolia({ appId, apiKey, indexName })` from `blume/search` (the DocSearch `apiKey` is the search-only key) |
|
|
@@ -34,7 +34,7 @@ Read `themeConfig`, `presets`, and `plugins`:
|
|
|
34
34
|
| `@docusaurus/theme-mermaid` | delete the dep — ` ```mermaid ` renders natively (in `.mdx`) |
|
|
35
35
|
| OpenAPI doc plugins (`docusaurus-plugin-openapi-docs`, `redocusaurus`) | delete the plugin **and its generated pages** — add `openapi({ spec })` (from `blume/reference`) to the top-level `reference` list; `redocusaurus` `specs[].route` → the adapter's `route`, one `openapi()` entry (or source) per spec (see SKILL.md "OpenAPI") |
|
|
36
36
|
| GraphQL doc generators (`@graphql-markdown/docusaurus`, `@edno/docusaurus2-graphql-doc-generator`) | delete the plugin **and its generated pages** — add `graphql({ spec, endpoint })` (from `blume/reference`) to the top-level `reference` list instead (see SKILL.md "GraphQL") |
|
|
37
|
-
| `remark-math` + `rehype-katex` | delete —
|
|
37
|
+
| `remark-math` + `rehype-katex` | delete — `$$…$$` renders in `.mdx` with no config (no `markdown.math` field exists), as a block or inline within a sentence; a single `$` stays literal, so convert each inline `$…$` to `$$…$$` inside its sentence |
|
|
38
38
|
| Multi-instance docs plugins (`plugin-content-docs` with `id`) | one folder (and usually one `navigation.tabs` entry) per instance |
|
|
39
39
|
|
|
40
40
|
## Static assets — required move
|
|
@@ -45,7 +45,7 @@ Every Docusaurus repo serves **`static/`** at the site root (`static/img/foo.png
|
|
|
45
45
|
|
|
46
46
|
- **Autogenerated sidebar** (`{ type: 'autogenerated', dirName: '...' }`) → Blume's default filesystem navigation. Docusaurus strips numeric prefixes (`01-`) exactly like Blume, so the convention round-trips; no config needed.
|
|
47
47
|
- **Explicit sidebar** (arrays of doc IDs, categories, links) → restructure into folders where possible; use `navigation.sidebar` only for shapes files can't express. A category `{ type: 'category', label, items }` → a folder (label → `meta.ts` `title`); `collapsed` → `meta.ts` `collapsed`, and collapsible rendering → that folder's `meta.ts` `display: "group"` (or `navigation.sidebar.display: "group"` once in config when every category collapses).
|
|
48
|
-
- **`_category_.json`** (also `.yml`) (`{ label, position, collapsed, collapsible, link, className, customProps }`) → a folder `meta.ts`: `label`→`title`, `position`→`order`, `collapsed`→`collapsed`. `link.type: 'generated-index'` → an `index` page in the folder — **and the old URL was `/docs/category/<slug>`**, so add a redirect and rewrite inbound links. `link.type: 'doc'` → make that doc the folder's `index`. `collapsible: false` → that folder's `meta.ts` `display: "flat"`, so it stays a plain heading even under a global `"group"` mode. `className`/`customProps` → drop (report).
|
|
48
|
+
- **`_category_.json`** (also `.yml`) (`{ label, position, collapsed, collapsible, link, className, customProps }`) → a folder `meta.ts`: `label`→`title`, `position`→`order`, `collapsed`→`collapsed`. `link.type: 'generated-index'` → an `index` page in the folder (its `title`/`description` from `link.title`/`link.description`) plus `directory: "card"` in the folder's `meta.ts`, which lists the folder's pages below it as the generated index did — **and the old URL was `/docs/category/<slug>`**, so add a redirect and rewrite inbound links. `link.type: 'doc'` → make that doc the folder's `index`. `collapsible: false` → that folder's `meta.ts` `display: "flat"`, so it stays a plain heading even under a global `"group"` mode. `className`/`customProps` → drop (report).
|
|
49
49
|
- **`src/pages/` — inventory, don't nuke.** Nearly every repo has a React landing page (`src/pages/index.tsx`) and often extra Markdown pages. Markdown pages → content pages; the React home page → rebuild as a docs index or a custom `.astro` page under `content.pages` — report either way.
|
|
50
50
|
|
|
51
51
|
## Versioned docs
|
|
@@ -61,7 +61,7 @@ A Docusaurus `blog/` → Blume `type: blog` pages. **Dates come from filenames/f
|
|
|
61
61
|
- **`.md` vs `.mdx` — both majors need renames, for opposite reasons.** Blume parses `.md` as plain Markdown: no directives, no JSX, no `$$` math, no mermaid/package-install fences. **v3** treats `.md` as MDX (so a `.md` with imports/JSX/`{}` renders them as literal text in Blume); **v2** content is looser MDX v1. Rule: **rename any `.md` that contains admonitions, JSX, imports, or math to `.mdx`** — for typical Docusaurus repos that is most files.
|
|
62
62
|
- **Admonitions are directives — but check the version.** v3: `:::note`, `:::tip`, `:::info`, `:::warning`, `:::danger` pass through; `:::caution` → `:::warning` (or rely on Blume's alias); titles `:::note[Title]` work. **v2:** titles are space-separated (`:::note Your Title`) — rewrite to brackets or the title is silently lost; and v2's `:::warning` rendered **red/danger** — audit whether it should become `:::danger`.
|
|
63
63
|
- **Tabs:** `<Tabs>`/`<TabItem label="…" value="…">` → `<Tabs>`/`<Tab title="…">`. Drop `groupId`/`queryString`/`value`; strip the `@theme/Tabs` imports.
|
|
64
|
-
- **Theme JSX in content:** `<DocCardList/>` (standard on category index pages) →
|
|
64
|
+
- **Theme JSX in content:** `<DocCardList/>` (standard on category index pages) → delete it and set `directory: "card"` in that folder's `meta.ts`: Blume then lists the folder's pages as cards below the `index` page's content and keeps the list current (nested folders inherit the setting; give one `directory: "none"` to opt out). A hand-written `CardGroup` is only for a curated subset; `<TOCInline/>` → drop (report); `<CodeBlock>` JSX → a fenced code block; `<Admonition>` → the matching directive; `<details>`/`<summary>` → `<Accordion>`/`<AccordionItem>` or leave as raw HTML.
|
|
65
65
|
- **`@theme/*` / `@site/*` imports** — strip `@theme/*` (Blume injects components globally); rewrite `@site/` asset/module paths to `/public` URLs or inline. **MDX partials** (`_partial.mdx` imports) → inline the partial's body (Blume's default `**/_*` exclude already hides the partial files themselves).
|
|
66
66
|
- **Code blocks:** `title="file.js"` → works as-is; `showLineNumbers` → `lineNumbers`; **magic comments** (`// highlight-next-line`, `highlight-start`/`end`) → `{ranges}` or `// [!code highlight]` — unconverted they ship as literal comments in every sample; ` ```bash npm2yarn ` → ` ```package-install `.
|
|
67
67
|
- **MDX v1 (v2 sources) pitfalls:** unescaped `<`/`{` in prose, HTML comments `<!-- -->` (→ `{/* */}`), string `style="…"` attributes (→ objects). Fix as build errors surface.
|
|
@@ -71,7 +71,7 @@ A Docusaurus `blog/` → Blume `type: blog` pages. **Dates come from filenames/f
|
|
|
71
71
|
| Docusaurus | Blume |
|
|
72
72
|
| --- | --- |
|
|
73
73
|
| `title` / `description` | pass through |
|
|
74
|
-
| `id` |
|
|
74
|
+
| `id` | **not a safe drop** — Docusaurus builds a doc's URL from its ID, so `id: part1` in `guides/hello.md` serves `/docs/guides/part1`. Where the `id` differs from the filename (and no `slug` is set), replace it with `slug: guides/part1` (the folder path plus the id) or rename the file to match; otherwise drop it. Sidebar and `link.type: 'doc'` references name docs by this ID too |
|
|
75
75
|
| `slug` | `slug` as a **full path from the content root**: Blume's `slug` replaces the page's whole route, while Docusaurus resolves a relative slug (no leading `/`) against the doc's folder. So `guides/intro.md` with `slug: start` → `slug: guides/start`; an absolute slug (`/start`) is already a full path |
|
|
76
76
|
| `sidebar_label` | `sidebar.label` |
|
|
77
77
|
| `sidebar_position` | `sidebar.order` |
|
|
@@ -95,4 +95,4 @@ Remove `@docusaurus/*` and Algolia deps; delete `docusaurus.config.*`, `sidebars
|
|
|
95
95
|
|
|
96
96
|
## Dropped — report these
|
|
97
97
|
|
|
98
|
-
Custom/swizzled theme components (layout slots or `blume eject`), footer
|
|
98
|
+
Custom/swizzled theme components (layout slots or `blume eject`), the footer's copyright, logo, and HTML items, the blog's generated tag, author, and archive pages, Algolia config, `sidebar_custom_props` and the other dropped frontmatter keys, `createRedirects` functions (→ host rules), React pages under `src/pages/`, `<TOCInline>`, per-category `className`/`customProps`, and any `@theme/*` component with no Blume equivalent.
|
|
@@ -6,21 +6,22 @@ Fumadocs is code-first: navigation comes from the folder tree + per-folder `meta
|
|
|
6
6
|
|
|
7
7
|
- Content under **`content/docs/`** (the Fumadocs convention).
|
|
8
8
|
- Per-folder **`meta.json`** files.
|
|
9
|
-
- `fumadocs-ui` / `fumadocs-core` / `fumadocs-mdx` deps and a `source.config.ts
|
|
10
|
-
- A `loader({ baseUrl
|
|
9
|
+
- `fumadocs-ui` / `fumadocs-core` / `fumadocs-mdx` deps, and collections declared either in a `source.config.ts` (the Config API) or, in newer scaffolds, with `defineDocs` from `fumadocs-mdx/macro` inside `lib/source.ts` (no `source.config.ts` at all).
|
|
10
|
+
- A `loader({ baseUrl })` call in `lib/source.ts` (or `app/source.ts`, `src/lib/source.ts`, `source.ts`). Newer scaffolds pass a constant (`baseUrl: docsRoute`) defined in `lib/shared.ts` — resolve it there.
|
|
11
11
|
|
|
12
12
|
## Config
|
|
13
13
|
|
|
14
|
-
Fumadocs declares
|
|
14
|
+
Fumadocs declares little Blume needs — read the loader and the shared layout options:
|
|
15
15
|
|
|
16
|
-
- **Title** — read `package.json` `name`, prettified (drop scope, split on `-_`, Title-Case)
|
|
16
|
+
- **Title** — the header title: `nav.title` in `baseOptions` (`lib/layout.shared.tsx`, or `app/layout.config.tsx` in older scaffolds; often the `appName` constant from `lib/shared.ts`; extract the text if it's JSX). Without one, read `package.json` `name`, prettified (drop scope, split on `-_`, Title-Case); for a generic monorepo name (`web`, `app`, `docs`…), use the repo-root directory name instead.
|
|
17
|
+
- **Header settings** (the same `baseOptions`): `githubUrl` → `github: { owner, repo }` (the repository and edit links; when it's built from a `gitConfig` constant in `lib/shared.ts`, `{ user, repo, branch }` → `{ owner: user, repo, branch }`); `links` entries → `navigation.actions` (`{ label: text, href: url }`), except a `type: "icon"` link to a platform `footer.socials` knows (Discord, X, …), which goes there instead. Menus, custom items, and JSX in `nav` → report.
|
|
17
18
|
- **Route prefix** — the `baseUrl` in the source loader (required in Fumadocs, so it's always declared). If it's a real prefix (e.g. `/docs`), set top-level **`basePath: "/docs"`** — it prefixes every route while staying invisible to the sidebar, which matches Fumadocs' behavior. (A `content.sources` `prefix` also works but adds a wrapping nav group — only use it when you _want_ the group.) If `baseUrl` is `"/"`, serve from the site root (nothing to set).
|
|
18
19
|
|
|
19
|
-
Everything else is
|
|
20
|
+
Everything else is Blume defaults.
|
|
20
21
|
|
|
21
|
-
**Also read `source.config.ts` `mdxOptions
|
|
22
|
+
**Also read the MDX options** — remark/rehype plugins live in `source.config.ts` `mdxOptions`, or, with the macro API, in the collection options passed to `defineDocs` (a macro project may still keep a `source.config.ts` for global options):
|
|
22
23
|
|
|
23
|
-
- `remark-math`/`rehype-katex` → nothing to configure:
|
|
24
|
+
- `remark-math`/`rehype-katex` → nothing to configure: `$$…$$` renders in `.mdx` out of the box (there is **no** `markdown.math` field), as a block or inline within a sentence. A single `$` stays literal, so convert each inline `$…$` to `$$…$$` inside its sentence.
|
|
24
25
|
- A Twoslash transformer → Blume supports the `twoslash` fence meta natively; drop the plugin.
|
|
25
26
|
- Custom Shiki transformers/themes or other plugins → report.
|
|
26
27
|
|
|
@@ -39,14 +40,17 @@ Everything else is `defineConfig({ title })`.
|
|
|
39
40
|
| `description` | **drop** (folders have no description) |
|
|
40
41
|
| `collapsible: false` | that folder's `display: "flat"` (a plain heading, even under a global `"group"` mode) |
|
|
41
42
|
|
|
42
|
-
`meta.ts` accepts **only** `title`, `icon`, `order`, `collapsed`, `pages`, `display
|
|
43
|
+
`meta.ts` accepts **only** `title`, `icon`, `order`, `collapsed`, `pages`, `display`, `directory` (`"card"`/`"accordion"` lists the folder's pages below its `index` page — the replacement for a hand-written card list of the folder's children). Render mode is per-folder or global: a folder that needs collapsible rendering sets its own `meta.ts` `display: "group"` (drill-in is `"page"`); when the whole sidebar should collapse, set `navigation.sidebar.display: "group"` once in `blume.config.ts` instead of repeating it per folder.
|
|
44
|
+
|
|
45
|
+
**Numeric filename prefixes move URLs.** Fumadocs builds slugs from the file path as written, so `01-intro.mdx` serves `/docs/01-intro`; Blume reads a `01-` prefix on a file or folder as sort order and drops it from the route (`/docs/intro`). Add a `redirects` entry for every prefixed file or folder (or pin the old path with frontmatter `slug`, a full path from the content root), and write `pages` entries without the prefix (`"intro"`, not `"01-intro"`).
|
|
43
46
|
|
|
44
47
|
**`root: true` folders are Fumadocs' tab mechanism** — Fumadocs UI renders them as layout tabs and scopes the sidebar to the active one. That is exactly Blume's `navigation.tabs`: add `{ label, path, icon? }` per root folder (label/icon from its `meta.json`), pointing at the folder's route. Blume then scopes the sidebar by URL prefix the same way. Don't try to model root folders inside `meta.ts`.
|
|
45
48
|
|
|
46
49
|
Handle the `pages` array items:
|
|
47
50
|
|
|
48
51
|
- **`"..."`** (rest marker) / `""` → drop; Blume appends unlisted pages automatically. **`"z...a"`** (reversed rest) → no equivalent; list the pages explicitly in the intended order.
|
|
49
|
-
-
|
|
52
|
+
- **A `pages` list with no `"..."`** → Fumadocs shows **only** the listed items; every page and folder it leaves out is hidden from the sidebar (still served by URL). Blume appends unlisted children, so each one **resurfaces** — set `sidebar.hidden: true` in each left-out page's frontmatter (for a left-out folder, in every page under it — a folder with no visible page drops out of the sidebar).
|
|
53
|
+
- **`"!page"`** (exclusion from `"..."`) → the same trap: Blume _appends_ unlisted pages, so a dropped `!page` **resurfaces in the sidebar**. Set that page's frontmatter `sidebar.hidden: true` instead.
|
|
50
54
|
- **`"---Section---"`** (separator; also the `---[Icon]Label---` variant) → Blume has no flat separator. Turn each section into a **`(Section)/` group folder** (route-transparent — the `(…)` segment is stripped from URLs), and move the section's pages into it. If a section wraps a single existing folder, leave it in place and set that folder's `meta.ts` `title` instead.
|
|
51
55
|
- **`"...folder"`** (extract) → Blume can't flatten a folder inline; keep it as a normal group at that ordering position and report it.
|
|
52
56
|
- **`"[Text](url)"`** (link; also `[Icon][Text](url)` and `external:` variants) → a top-level/utility link belongs in **`navigation.featured`** (`{ label, href, icon? }` — pinned above the sidebar on every route). A link buried deep in one folder has no folder-meta home — drop and report (or model that one folder via an explicit `navigation.sidebar`).
|
|
@@ -54,7 +58,7 @@ Handle the `pages` array items:
|
|
|
54
58
|
|
|
55
59
|
## Frontmatter
|
|
56
60
|
|
|
57
|
-
Fumadocs' core frontmatter (`title`, `description`, `icon`) matches Blume — but **convert `icon` casing** (see Icons).
|
|
61
|
+
Fumadocs' core frontmatter (`title`, `description`, `icon`) matches Blume — but **convert `icon` casing** (see Icons). **`full: true`** (full width, TOC folded into a popover) → `mode: wide` (full column width, no TOC — the closest match; report); **`_openapi`** marks a generated API stub — delete the whole page (see OpenAPI). Any other non-schema key is a build error, so drop and report.
|
|
58
62
|
|
|
59
63
|
## Icons: lucide-react names → kebab-case
|
|
60
64
|
|
|
@@ -71,7 +75,7 @@ Fumadocs icons are strings resolved by the repo's own `icon` handler in `loader(
|
|
|
71
75
|
- **`<Banner>`** (layout-mounted, not per-page) → the `banner` config field (`{ content, link: { href, text }, dismissible, id }`).
|
|
72
76
|
- **`<include>./partial.mdx</include>`** — Blume uses the same include syntax. **Pass through unchanged**: paths resolve relative to the including file, a leading `/` resolves from the content root, and nested includes work. Keep partials in `_`-prefixed files or folders so they stay out of routing and the sidebar.
|
|
73
77
|
- **No equivalent — report:** `<DynamicCodeBlock>`, `<ImageZoom>` (Blume zooms content images by default), `<InlineTOC>`.
|
|
74
|
-
- **Strip or convert every import** — not just `fumadocs-*`: `lucide-react` imports (icon JSX → string names), `next/image`/`next/link` (→ Markdown image/link), and local components. **Inventory
|
|
78
|
+
- **Strip or convert every import** — not just `fumadocs-*`: `lucide-react` imports (icon JSX → string names), `next/image`/`next/link` (→ Markdown image/link), and local components. **Inventory the MDX components file before deleting it** — `components/mdx.tsx` (`getMDXComponents`) in newer scaffolds, `mdx-components.tsx` in older ones; components registered there are used import-free in MDX bodies; port or inline each usage first.
|
|
75
79
|
|
|
76
80
|
## Headings
|
|
77
81
|
|
|
@@ -96,8 +100,8 @@ A `loader({ i18n })` setup (locale-suffixed files or locale dirs) → Blume `i18
|
|
|
96
100
|
|
|
97
101
|
## Package.json & teardown
|
|
98
102
|
|
|
99
|
-
Repoint scripts (`dev`→`blume dev`, `build`→`blume build`, `start`→`blume preview`), remove the `fumadocs-*`/`@fumadocs/*` deps and the host framework's deps (`next`, `react-router`, `@tanstack/*`…), add `blume`. Safe to delete after harvesting (see above for what to read first): `source.config.*`, `mdx-components.tsx`, the app/route dir, and host-framework config (`next.config.*`, `next-env.d.ts`, the `next` tsconfig plugin — or the React Router/TanStack equivalents).
|
|
103
|
+
Repoint scripts (`dev`→`blume dev`, `build`→`blume build`, `start`→`blume preview`), remove the `fumadocs-*`/`@fumadocs/*` deps and the host framework's deps (`next`, `react-router`, `@tanstack/*`…), add `blume`. Safe to delete after harvesting (see above for what to read first): `source.config.*`, `lib/source.ts`, `lib/shared.ts`, `lib/layout.shared.tsx` (or `app/layout.config.tsx`), `components/mdx.tsx` / `mdx-components.tsx`, the app/route dir, and host-framework config (`next.config.*`, `next-env.d.ts`, the `next` tsconfig plugin — or the React Router/TanStack equivalents).
|
|
100
104
|
|
|
101
105
|
## Dropped — report these
|
|
102
106
|
|
|
103
|
-
Folder `description` and `collapsible: false`; reversed rest (`z...a`) ordering; the extract (`...folder`) flatten semantics; deep-folder sidebar links; frontmatter `full
|
|
107
|
+
Folder `description` and `collapsible: false`; reversed rest (`z...a`) ordering; the extract (`...folder`) flatten semantics; deep-folder sidebar links; frontmatter `full` (approximated as `mode: wide`); header settings from `lib/layout.shared.tsx` with no Blume home; `<DynamicCodeBlock>`/`<InlineTOC>`; custom Shiki transformers; any icon with no Lucide equivalent after casing conversion.
|
|
@@ -29,12 +29,12 @@ Resolve `$ref` includes first (Mintlify splits config across files). Map only wh
|
|
|
29
29
|
| `background.decoration` | **drop** | no Blume equivalent |
|
|
30
30
|
| `fonts.family` / `fonts.{heading,body}.family` | `theme.fonts.{display,body}` | a curated slug (kebab-case, e.g. `space-grotesk`) maps directly; any other Google family maps to the object form `{ name: "Family Name" }`; a self-hosted font (`fonts.*.src` URLs) maps to `{ name, variants: [{ src, weight }] }` after downloading the files into the project |
|
|
31
31
|
| `banner` | `banner` (`{ content, dismissible, id, link: { href, text } }`) | **only** those keys — drop `banner.color`/`banner.type` |
|
|
32
|
-
| `styling.latex: true` | **drop the field** — block math `$$…$$` renders in `.mdx` with no config | there is **no** `markdown.math` field; inline
|
|
32
|
+
| `styling.latex: true` | **drop the field** — block math `$$…$$` renders in `.mdx` with no config | there is **no** `markdown.math` field; Blume writes inline math with two dollar signs too — convert each inline `$…$` to `$$…$$` inside the sentence, checking every pair is math and not currency or a shell variable |
|
|
33
33
|
| `styling.codeblocks.theme` | `markdown.code.theme` (`{ light, dark }`) | |
|
|
34
34
|
| `search.prompt` | **drop** | no equivalent |
|
|
35
|
-
| `seo.metatags` |
|
|
35
|
+
| `seo.metatags` | `seo.metatags`, minus the tags Blume writes itself | keep verification tokens, `theme-color`, and the like as written; Blume refuses `description`, `robots`, `og:title`/`og:description`/`og:image`/`og:url`/`og:type`/`og:site_name`, `twitter:*` card tags, and `article:*` dates, so move those to their settings (`og:image` → `seo.og` or a page's `seo.image`, `twitter:site` → `seo.x.handle`) and drop the rest. `seo.paths` (folder tags) has no equivalent: set per-page `seo` frontmatter |
|
|
36
36
|
| `seo.indexing: "all"` | `search.indexing.includeHiddenPages: true` | |
|
|
37
|
-
| `variables` (`{{name}}`) |
|
|
37
|
+
| `variables` (`{{name}}`) | `variables` | same syntax and names (letters, digits, `_`, `-`); pages keep their `{{name}}` references unchanged |
|
|
38
38
|
| `integrations.posthog` (`{ apiKey, apiHost, sessionRecording }`) | `posthog({ key, host })` in the `analytics` list | preserve the host verbatim (e.g. `us.posthog.com` — Blume's default is `us.i.posthog.com`); `sessionRecording: false` → `disable_session_recording: true`; every adapter is imported from `blume/analytics` |
|
|
39
39
|
| `integrations.ga4` (`{ measurementId }`) | `googleAnalytics({ id })` | |
|
|
40
40
|
| `integrations.gtm` (`{ tagId }`) | `googleTagManager({ id })` | |
|
|
@@ -52,8 +52,15 @@ Resolve `$ref` includes first (Mintlify splits config across files). Map only wh
|
|
|
52
52
|
| `integrations.clearbit` (`{ publicApiKey }`) | `clearbit({ key })` | |
|
|
53
53
|
| `integrations.adobe` (`{ launchUrl }`) | `adobe({ url })` | |
|
|
54
54
|
| any other `integrations` script | `script({ src, strategy, attributes })` / `vercel()` in the `analytics` list | one `script()` adapter per provider without a factory |
|
|
55
|
+
| `telemetry` (`{ enabled: false }`) | `feedback: false` | Mintlify's switch also turned off its feedback widgets; Blume sends no telemetry of its own, so only the rating needs turning off |
|
|
56
|
+
| Feedback toggles in the Mintlify dashboard (not in `docs.json`) | `feedback: { comments: true }` for contextual (written) feedback | ask whether the site collected written feedback; Blume sends comments through the `analytics` adapters as `feedback_comment` events. Code-snippet feedback, edit suggestions, and raise-issue have no equivalent: report them |
|
|
57
|
+
| `integrations.cookies` (`{ key, value }`), or a content-folder `.js` file that injects Osano or Ethyca/Fides | `consent`, imported from `blume/consent`: `osano({ customerId, configId })` (both IDs from the `cmp.osano.com/<customerId>/<configId>/osano.js` URL), `ethyca({ privacyCenter })` (the origin that serves `fides.js`), or `native()` for Blume's own banner | Mintlify's `cookies` pair only switched off its own telemetry for readers whose localStorage lacked the value; under `consent`, every `analytics` adapter waits for the reader instead. Delete the injector script. Another consent manager (Transcend, OneTrust, …) has no adapter: report it |
|
|
58
|
+
| A root `skill.md`, or `.mintlify/skills/<name>/SKILL.md` | move each into a `skills/<name>/` folder and set `agents.skills: "./skills"`; drop Mintlify-only frontmatter (`groups`) | Blume already generates a skill for the site at `/skill.md` (`agents.skillMd`, on when `deployment.site` is set); a root `skill.md` replaces it only if its `name` matches the site's title slug (`Acme Docs` → `acme-docs`), so set that name |
|
|
55
59
|
| `contextual` (`["copy","chatgpt","claude",…]`) | **mostly free** | Copy-as-Markdown and Open-in-chat are default page actions; `mcp` needs `agents.mcp.enabled` + server output (report as a follow-up) |
|
|
56
|
-
| `
|
|
60
|
+
| `footer` (`{ socials, links }`) | `footer: { socials, links }` | `socials` keeps its keys, except `twitter`/`x-twitter` → `x` and `earth-americas` → `website`; a key outside Blume's list drops (report); `links` is one row of `{ label, href }`: every column's `items` flatten into it in order, and each column's `header` drops (report) |
|
|
61
|
+
| `api.mdx` (`{ server, auth: { method, name } }`) | `api: { server, auth: { method, name } }` | the defaults for `api`-frontmatter pages |
|
|
62
|
+
| `api.playground` (`{ display, proxy }`) | `api: { playground }` | `display: "none"` → `playground: false`; `"simple"` has no site-wide form, so set `playground: simple` in each page's frontmatter; `proxy` (on by default in Mintlify) → `playground: { proxy: true }`, which needs a server-output adapter, or leave it off to send directly |
|
|
63
|
+
| `redirects` (`{ source, destination, permanent }`) | `redirects: [{ from, to, status }]` | `source` → `from`, `destination` → `to` as written, patterns included (`/beta/:slug*`, `/old/article-*`); `permanent: false` → `status: 307`, otherwise `status: 308` |
|
|
57
64
|
| `navigation.languages` | `i18n` | see i18n below |
|
|
58
65
|
|
|
59
66
|
A minimal result is often just `defineConfig({ title, logo, theme: { accent } })`.
|
|
@@ -92,13 +99,13 @@ The codemod touches **only frontmatter**. Icons in MDX **body** (`<Icon icon="
|
|
|
92
99
|
| `life-ring` | `life-buoy` | | `shield-halved` | `shield` |
|
|
93
100
|
| `rocket`/`book`/`book-open`/`code`/`terminal`/`key`/`lock`/`user`/`users`/`database`/`server`/`cloud`/`bell`/`calendar`/`star`/`heart`/`tag`/`folder`/`globe`/`link`/`download`/`upload`/`check`/`copy`/`play`/`filter` | _(same name — verify)_ |
|
|
94
101
|
|
|
95
|
-
**Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*` — github, discord, x, slack, linkedin…) mostly have **no** Lucide equivalent: for GitHub use the `github` config (renders the
|
|
102
|
+
**Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*` — github, discord, x, slack, linkedin…) mostly have **no** Lucide equivalent: for GitHub use the `github` config (renders the footer's repo link); for other socials, use `footer.socials`. Where no Lucide counterpart exists, **drop the icon and report it**. The build won't catch a wrong name for you: an unknown icon renders nothing, and it's only a warning (`BLUME_UNKNOWN_ICON`) for navigation icons — an icon prop on a component like `<Card>` fails silently — so check every name.
|
|
96
103
|
|
|
97
104
|
## Navigation: `docs.json` `navigation` → filesystem + tabs
|
|
98
105
|
|
|
99
106
|
Mintlify's `navigation` object (`tabs`/`anchors`/`dropdowns`/`products`/`versions`/`languages`/`groups`/`pages`) is fully config-declared. **Prefer restructuring content into folders**, not porting the config verbatim:
|
|
100
107
|
|
|
101
|
-
- **`groups`** (`{ group, pages: [...] }`) → a folder per group. The `group` name → the folder's humanized name or a `meta.ts` `title`. Nested groups → nested folders. `expanded: false` → `meta.ts` `collapsed: true` (inverted). `tag` → the folder/page `sidebar.badge`. **Folder metadata is a `meta.ts` module** (`export default defineMeta({ title, icon, order, collapsed, pages, display })`), a TypeScript file — **not** JSON. Blume does not read a `meta.json`, so any folder-level config you carry over from the source (or hand-write to preserve a group's label/order/collapse) must be authored as `meta.ts`. (Render mode — flat/group/page — defaults to the global `navigation.sidebar.display` in `blume.config.ts`; a folder overrides its own group with `meta.ts` `display`, or `sidebar.display` in its `index` page's frontmatter.)
|
|
108
|
+
- **`groups`** (`{ group, pages: [...] }`) → a folder per group. The `group` name → the folder's humanized name or a `meta.ts` `title`. Nested groups → nested folders. `expanded: false` → `meta.ts` `collapsed: true` (inverted). `tag` → the folder/page `sidebar.badge`. `directory` (`card`/`accordion`/`none`, on a group, tab, or the navigation itself) → `meta.ts` `directory` on that folder, or on the content root's `meta.ts` for the whole navigation; it inherits down the tree the same way, and lists the pages on the group's `root`/`index` page. **Folder metadata is a `meta.ts` module** (`export default defineMeta({ title, icon, order, collapsed, pages, display, directory })`), a TypeScript file — **not** JSON. Blume does not read a `meta.json`, so any folder-level config you carry over from the source (or hand-write to preserve a group's label/order/collapse) must be authored as `meta.ts`. (Render mode — flat/group/page — defaults to the global `navigation.sidebar.display` in `blume.config.ts`; a folder overrides its own group with `meta.ts` `display`, or `sidebar.display` in its `index` page's frontmatter.)
|
|
102
109
|
- **Config-only nested groups don't exist on disk — you must materialize them, or they flatten silently.** A nested `{ group, pages }` almost never has a matching subfolder: its pages sit **flat in the parent directory** (e.g. `platform/analytics/getting-started.mdx`, `…/quick-reference.mdx`) and the grouping lives **only** in the `docs.json` `pages` array. If you leave the files where they are, filesystem-derived nav sees one flat folder and the inner group vanishes — Mintlify's `Analytics → Reference → {…}` becomes a flat `Analytics → {…}`. To preserve it you must **either** move those pages into a real subfolder (`platform/analytics/reference/`, with a `meta.ts` for the label/`collapsed`), **or** declare the shape in an explicit `navigation.sidebar`. Walk **every** `pages` array recursively and treat any nested `group` object as a folder-move to plan, not files already in place. When inventorying the nav (workflow step 2), record the config nesting depth separately from the on-disk depth — they diverge exactly here.
|
|
103
110
|
- **This is the canonical case for `navigation.sidebar` over folders.** Materializing a purely-presentational nested group as a subfolder changes URLs (`/platform/analytics/getting-started` → `/platform/analytics/reference/getting-started`) for no reason other than a visual grouping, forcing a `redirects` entry per page. When you want to keep the nesting **and** the URLs, an explicit `navigation.sidebar` group (`{ label, items }`) is the better trade — it nests the existing routes without moving any file. Pick per group; don't reflexively flatten.
|
|
104
111
|
- **`pages`** entries are page refs (paths without extension) → files at the corresponding path. An entry that's `"GET /path"` is an OpenAPI endpoint stub → **delete it** (Blume generates these; see OpenAPI).
|
|
@@ -110,7 +117,7 @@ Mintlify's `navigation` object (`tabs`/`anchors`/`dropdowns`/`products`/`version
|
|
|
110
117
|
|
|
111
118
|
- **`dropdowns`/`products`/`versions`** → `navigation.selectors` (`{ kind, label, items: [{ label, path, icon?, description?, tag? }] }`). Use `kind` `dropdown`/`product`/`version` accordingly.
|
|
112
119
|
- **`anchors` / `navigation.global.anchors`** (persistent sidebar-top links — Blog, Changelog, Community, Contact/Support) → **`navigation.featured`** (`{ label, href, icon? }`). These pin to the **top of the sidebar, above every section, on every route** (not tab-scoped) — the right home for Mintlify's always-visible utility links. An external `href` opens in a new tab; an internal one (`/contact`) is build-time validated against your pages. Convert the FontAwesome `icon` to Lucide as usual. (This replaces the old "drop and report" for anchors.)
|
|
113
|
-
- **`navbar.links`** (plain header links — Log in, Status, Support) → **`navigation.actions`** (`[{ label, href }]`), rendered in the header left of the icon buttons. A GitHub link → the `github` config (or `navigation.repo` as a URL when the docs repo is private) instead. Header links hide on phones; a link that must survive there belongs in `featured`.
|
|
120
|
+
- **`navbar.links`** (plain header links — Log in, Status, Support) → **`navigation.actions`** (`[{ label, href }]`), rendered in the header left of the icon buttons. A GitHub link → the `github` config (or `navigation.repo` as a URL when the docs repo is private) instead; it renders in the footer, the only place Blume links a repository. Header links hide on phones; a link that must survive there belongs in `featured`.
|
|
114
121
|
- **`navbar.primary`** (the header **CTA button** — "Get Started"/"Sign Up", `type: "button"`) → **`navigation.cta`** (`{ label, href }`, singular: Blume renders exactly one filled button). A `type: "github"` primary → the `github` config instead. A route the docs don't serve (the product's own `/signup`) must be an absolute URL, or it raises `BLUME_NAV_MISSING_PAGE`.
|
|
115
122
|
- **`languages`** → `i18n`, not a selector (see below).
|
|
116
123
|
- Only fall back to an explicit `navigation.sidebar` for a shape the filesystem genuinely can't express.
|
|
@@ -123,16 +130,18 @@ Rewrite each page's MDX:
|
|
|
123
130
|
|
|
124
131
|
- **Callouts → directives** (directives are **MDX-only** — Mintlify content is already `.mdx`, so this just works; never rename a page to `.md`): `<Note>`→`:::note`, `<Tip>`→`:::tip`, `<Warning>`→`:::warning`, `<Info>`→`:::info`, `<Check>`→`:::success`, `<Danger>`/`<Error>`→`:::danger`. `<Callout type="x">` maps by type (`caution`→warning, `check`→success). A `title` attr → `:::type[Title]`. Drop `icon`/color props.
|
|
125
132
|
- **Accordions — container/item inversion!** Mintlify nests `<Accordion title="…">` inside `<AccordionGroup>`. Blume inverts: `<AccordionGroup>`→`<Accordion>` (container), and each Mintlify `<Accordion title="…">`→`<AccordionItem title="…">` (item).
|
|
126
|
-
- **`<RequestExample>`/`<ResponseExample>`** → `<CodeGroup>` (titled-fence tabs).
|
|
127
133
|
- **`<Tabs>` → `<Tabs inline>`.** Mintlify renders tabs **borderless** — a strip on a full-width rule with the content flowing beneath as prose — while Blume's `<Tabs>` defaults to a bordered box. Add `inline` to each `<Tabs>` to preserve Mintlify's appearance; every child `<Tab title="…">` is unchanged. Don't add `param` — Mintlify tabs switch in place and don't deep-link to the URL, so plain `inline` is the faithful mapping.
|
|
128
|
-
- **These pass through — Blume ships them natively:** `<Columns>`/`<Column>`, `<Expandable>`, `<Tooltip>`, `<Frame>`, `<Panel>`, `<Card>`/`<CardGroup>`, `<Tab>`, `<Steps>`/`<Step
|
|
129
|
-
- **
|
|
134
|
+
- **These pass through — Blume ships them natively:** `<Columns>`/`<Column>`, `<Expandable>`, `<Tooltip>`, `<Frame>`, `<Panel>`, `<Card>`/`<CardGroup>`, `<Tab>`, `<Steps>`/`<Step>`, `<View>` (its `title` becomes an option in the page's view picker, as on Mintlify; remap its `icon` with the table below and drop `iconType`). Keep them as-is.
|
|
135
|
+
- **Multi-word code-block titles need quotes.** Mintlify reads everything after the language as the title (` ```ts Acme SDK `); Blume reads one bare word, so write ` ```ts title="Acme SDK" `. One-word titles (` ```bash cURL `) stay as they are.
|
|
136
|
+
- **`<RequestExample>`/`<ResponseExample>` pass through.** Top-level ones pin to a column beside the page on wide screens, request above response, as on Mintlify; `dropdown` works the same.
|
|
137
|
+
- **Hand-written endpoint pages pass through.** `api: "POST /v1/users"` frontmatter, with `authMethod` (`bearer`/`basic`/`key`/`none`) and `playground` (`interactive`/`simple`/`none`), works as on Mintlify: the page's `<ParamField>`s build its Try it panel and request samples. Keep them as written.
|
|
138
|
+
- **API fields pass through.** `<ParamField>` (`path`/`query`/`header`/`body`, `type`, `required`, `deprecated`, `default`, `placeholder`) and `<ResponseField>` (`name`, `type`, `required`, `deprecated`, `default`, `pre`, `post`) render natively, nested `<Expandable>` fields included. Keep them as written. An older `<RequestField>` isn't supported: rewrite it as a `<ParamField>`.
|
|
130
139
|
- **`<Update>`** (a Mintlify changelog entry) has no component form → convert to a `type: changelog` page, or use the `githubReleases()` source.
|
|
131
|
-
- **Snippets
|
|
140
|
+
- **Snippets become includes.** Blume has no `/snippets` import mechanism; its reuse is `<include>`. Move each snippet into the content folder as a `_`-prefixed partial (`_snippets/x.mdx`, which never renders as a page), and replace `import X from "/snippets/x.mdx"` + `<X prop="v" />` with `<include prop="v">./_snippets/x.mdx</include>` on its own line. In the partial, rewrite each `{prop}` placeholder to `{{prop}}`: include attributes are props read with the variables syntax. Named string imports (`import { foo } from "/snippets/vars.mdx"`) → a site-wide `variables` entry read as `{{foo}}`, or inline the value.
|
|
132
141
|
|
|
133
142
|
## Frontmatter
|
|
134
143
|
|
|
135
|
-
Mintlify page frontmatter → Blume's strict schema. **`scripts/mintlify-codemod.mjs --write` does the mechanical rows automatically** (rename, drop, icon-remap) and flags the judgment rows (`openapi`/`asyncapi
|
|
144
|
+
Mintlify page frontmatter → Blume's strict schema. **`scripts/mintlify-codemod.mjs --write` does the mechanical rows automatically** (rename, drop, icon-remap) and flags the judgment rows (`openapi`/`asyncapi`) for you — see [Icons](#icons-fontawesome--lucide-required) for the invocation. The table is both the mapping reference and a description of exactly what the codemod does:
|
|
136
145
|
|
|
137
146
|
| Mintlify | Blume | Codemod |
|
|
138
147
|
| --- | --- | --- |
|
|
@@ -143,17 +152,25 @@ Mintlify page frontmatter → Blume's strict schema. **`scripts/mintlify-codemod
|
|
|
143
152
|
| `canonical` | `seo.canonical` | renames |
|
|
144
153
|
| `og:image` | `seo.image` | renames |
|
|
145
154
|
| `hidden: true` | valid top-level in Blume — **kept as-is**; add `noindex: true` yourself if the page must also leave the search index | left (do by hand) |
|
|
146
|
-
| `openapi`/`asyncapi
|
|
147
|
-
| `
|
|
155
|
+
| `openapi`/`asyncapi` | usually an endpoint stub → **delete the page** (Blume generates operation pages); else drop the key and keep it as a normal page | **flags** for review — never auto-deletes a page |
|
|
156
|
+
| `api`, `authMethod`, `playground` | kept as written (a hand-written endpoint page, see above) | left |
|
|
157
|
+
| `related` (a list) | kept as written: root-relative paths, URLs, and `{ Title: link }` entries render as Related pages cards | left; `related: true` has no equivalent (Blume has no automatic related pages), so drop it (report) |
|
|
158
|
+
| `mode` | `mode`, as written | `default`, `wide`, `center`, `custom`, and `frame` carry over; `assistant` has no equivalent → drop (report) |
|
|
159
|
+
| `hideFooterPagination: true` | `pagination: false` | renames (`false` drops, since the links show by default) |
|
|
160
|
+
| `keywords`, `boost` | `search.keywords`, `search.boost` | renames |
|
|
161
|
+
| `searchable: false` | `search.exclude: true` | renames (`searchable: true` drops, since pages are searchable by default) |
|
|
162
|
+
| `public`, `rss`, `groups`, `hideApiMarker`, `iconType` | **drop** (report) | drops |
|
|
148
163
|
|
|
149
164
|
The codemod leaves the source key in place and reports a conflict rather than clobbering data when a rename target already exists (e.g. a page already has `sidebar.label`) or the value is too structured to move safely — resolve those by hand. Remove any duplicate H1 in the body — `title` renders the H1. (The codemod only edits frontmatter; it never touches the body.)
|
|
150
165
|
|
|
151
166
|
## OpenAPI
|
|
152
167
|
|
|
153
|
-
Top-level `openapi`, `api.openapi`, or a per-group/per-tab `openapi` → `reference: [openapi({ sources: [{ spec, label?, route? }] })]`, with `openapi` imported from `blume/reference` (`spec` alone is the single-source shorthand; several per-tab specs become several sources, or several `openapi()` entries when they need different routes; a spec the source embedded with Scalar becomes a `scalar({ spec })` entry). A Mintlify `{ source, directory }` object: `directory` → the source's `route`. An `asyncapi` field maps the same way to `asyncapi({ … })` in the list. **Delete every per-endpoint stub page** (frontmatter `openapi: "GET /path"` or a `"GET /path"` nav entry) — Blume's native renderer generates one real page per operation. **Add a `navigation.tabs` entry pointing at the reference `route` yourself** (Mintlify's API tab maps to it); the reference does not create a header tab automatically.
|
|
168
|
+
Top-level `openapi`, `api.openapi`, or a per-group/per-tab `openapi` → `reference: [openapi({ sources: [{ spec, label?, route? }] })]`, with `openapi` imported from `blume/reference` (`spec` alone is the single-source shorthand; several per-tab specs become several sources, or several `openapi()` entries when they need different routes; a spec the source embedded with Scalar becomes a `scalar({ spec })` entry). A Mintlify `{ source, directory }` object: `directory` → the source's `route`. An `asyncapi` field maps the same way to `asyncapi({ … })` in the list. **Delete every per-endpoint stub page** (frontmatter `openapi: "GET /path"`, `openapi: "spec.json webhook name"`, or a `"GET /path"` nav entry) — Blume's native renderer generates one real page per operation and per webhook, and shows callbacks on their operation's page. **Add a `navigation.tabs` entry pointing at the reference `route` yourself** (Mintlify's API tab maps to it); the reference does not create a header tab automatically.
|
|
154
169
|
|
|
155
170
|
- **Vendor the spec.** Mintlify usually points at a spec **URL**. Copying that straight into `spec:` makes every build fetch it at build time — a single point of failure in CI/offline/behind a proxy, and a failed fetch silently drops the reference (leaving the tab pointing at a route that 404s). Prefer downloading it into the repo (`curl … -o openapi/<name>.json`) and pointing `spec` at that local path. If you keep the URL, report the dependency and consider a `prebuild` refresh-with-fallback.
|
|
156
171
|
- **Fix endpoint links.** Blume operation routes are `<route>/<slugified-tag>/<slugified-operationId>` (tag `Models` + id `listModels` → `/api-reference/models/list-models`: a camelCase id is split into kebab-case, not just lowercased — see SKILL.md "OpenAPI") — this differs from Mintlify's endpoint URLs, so **rewrite every inbound link to an operation**. `blume validate` resolves operation pages like any other route and flags the ones you miss.
|
|
172
|
+
- **Overlays carry over.** An `openapi: { source, overlays: [...] }` object → that source's `overlays` (`openapi({ spec, overlays })`, or `overlays` on each entry in `sources`), in the same order; Blume applies Overlay 1.0 and 1.1 the same way. An overlay Mintlify found only through its `extends` field (auto-discovered, not listed in `docs.json`) must be listed explicitly: Blume doesn't scan for overlays.
|
|
173
|
+
- **Code samples carry over.** `api.examples.languages` → `openapi({ codeSamples: [...] })`; Blume generates the same 18 languages and accepts Mintlify's keys and aliases (`bash`, `javascript`, `node`, `csharp`, `dotnet`, `c++`, …) as written. `api.examples.autogenerate: false` → `codeSamples: false`. `x-codeSamples` in the spec needs nothing: Blume renders them ahead of the generated samples.
|
|
157
174
|
- **Keep the "Introduction" page.** Mintlify commonly has a written intro/auth page in an "Introduction" group beside the "Endpoints" (openapi) group in the same tab. Keep it: a normal content page placed under the `openapi()` adapter's `route` (e.g. `<root>/api-reference/introduction.mdx`) merges into the reference tab's sidebar alongside the generated operations. Delete only the per-endpoint stubs, not the conceptual pages.
|
|
158
175
|
|
|
159
176
|
## Assets
|
|
@@ -164,9 +181,10 @@ Mintlify serves every top-level dir (e.g. `/images`) at the site root. Blume ser
|
|
|
164
181
|
|
|
165
182
|
`navigation.languages` (≥2) → `i18n: { defaultLocale, locales: [{ code, label }] }`. The `default: true` language → `defaultLocale`. Translated content already lives in ISO-code directories, which match Blume's `dir` parser — no file moves. Remove any language selector; language switching is handled by i18n.
|
|
166
183
|
|
|
184
|
+
Per-language `banner`, `navbar`, and `footer` (on `navigation.languages[]`) merge into the one site-wide config, with each label as a map of language code to that language's text: `banner: { content: { en: "…", fr: "…" } }` (and `link.text`), `navigation.actions`/`cta` labels, and `footer` link labels. Hrefs stay single — Blume moves an internal link into the reader's language itself. A language without an entry shows the default language's text. Report what doesn't merge: a banner or link set for only some languages, or one whose href differs per language.
|
|
185
|
+
|
|
167
186
|
## Dropped — report these
|
|
168
187
|
|
|
169
|
-
-
|
|
170
|
-
- **
|
|
171
|
-
-
|
|
172
|
-
- **`<Update>`** changelog components, `iconType`, `background.decoration`, `search.prompt`, `seo.metatags`.
|
|
188
|
+
- **A group's `boost`** (on a `navigation` group, inherited by its pages) → no inherited boost; set `search.boost` on the pages that need it.
|
|
189
|
+
- **Authentication** (password or SSO, set in the Mintlify dashboard) → Blume has none of its own; point the user at host-level protection (Vercel Deployment Protection, Netlify password protection, Cloudflare Access), per the deployment docs' **Private docs** section. It covers the whole site, so a mix of public and private pages needs two sites.
|
|
190
|
+
- **`<Update>`** changelog components, `iconType`, `background.decoration`, `search.prompt`.
|
|
@@ -15,9 +15,9 @@ Nextra (on Next.js) declares navigation and per-page labels in `_meta` files —
|
|
|
15
15
|
|
|
16
16
|
None of it maps automatically — read the config surface for the generation by hand and reconstruct in `blume.config.ts`:
|
|
17
17
|
|
|
18
|
-
- **v2/v3 — `theme.config.*`:** `logo` (JSX — extract text/image) → `logo`; `project.link` → `github` (renders the
|
|
18
|
+
- **v2/v3 — `theme.config.*`:** `logo` (JSX — extract text/image) → `logo`; `project.link` → `github` (renders the footer's repo link); `docsRepositoryBase` → `github` (owner/repo/branch — and any trailing sub-path → `github.dir`; if its origin is not `https://github.com`, set `github.host` to that origin — with `host` omitted, Blume builds the repository and edit links against public GitHub); `banner.text`/`banner.key` → `banner.content`/`banner.id` (`dismissible` maps); `primaryHue`/`primarySaturation` → pick an equivalent `theme.accent` color; `footer` → drop (report); `faviconGlyph` → drop (Blume's favicon is a file convention); `useNextSeoProps`/head → per-page `seo` frontmatter or drop.
|
|
19
19
|
- **v4 — `app/layout.*` props:** the same facts moved: `<Navbar logo projectLink>`, `<Layout docsRepositoryBase editLink sidebar={{…}} toc={{…}}>`, `<Banner>`, `<Footer>`. Map them the same way; sidebar/TOC tuning mostly drops (Blume's `toc` config covers min/max heading levels).
|
|
20
|
-
- **`next.config.*`:** harvest **`redirects()`** — static entries become Blume `redirects: [{ from, to }]
|
|
20
|
+
- **`next.config.*`:** harvest **`redirects()`** — static entries and `:param`/`:path*` patterns become Blume `redirects: [{ from, to }]` as written (`permanent: true` → `status: 308`, `false` → `307`); ones with regex params (`:slug(\d+)`) or `has`/`missing` conditions move to host config (report). A `latex: true` flag means math is in play (see Math below). Then delete the file.
|
|
21
21
|
- Root `_meta` entries with **`type: "page"`** → `navigation.tabs` (`{ label, path }`, where `path` is `/` for `index`, else `/<slug>`). `type: "page"` only maps at the **root**.
|
|
22
22
|
|
|
23
23
|
## Navigation: `_meta` → `meta.ts` + frontmatter
|
|
@@ -35,14 +35,17 @@ For each `_meta` entry (`key` = slug, value = string title or `{ title, type, di
|
|
|
35
35
|
| `href` (external link) | root-level → **`navigation.actions`** (`[{ label, href }]`, plain header links, matching Nextra's navbar placement) or **`navigation.featured`** (`{ label, href, icon? }` — pinned above the sidebar on every route, survives on phones); only drop deep-nested ones (report) |
|
|
36
36
|
| `type: "page"` (subfolder, not root) | drop (only root → tabs) |
|
|
37
37
|
| `theme: { collapsed }` on a folder | `meta.ts` `collapsed` |
|
|
38
|
-
| `theme: { layout: "full"
|
|
38
|
+
| `theme: { layout: "full" }` on a page | that page's frontmatter `mode: wide` (full column width, no table of contents — the closest match; report) |
|
|
39
|
+
| other `theme` keys (`sidebar: false`, `toc: false`, `typesetting`, …) | drop (report — no per-page switches for them) |
|
|
39
40
|
| `"*"` wildcard entry | apply its value as the default for unlisted siblings, then drop |
|
|
40
41
|
|
|
41
42
|
Write each folder's `meta.ts` with its `pages` order (from its own `_meta`) and its `title` (inherited from the parent's `_meta`). A v4 **`_meta.global.*`** file holds the whole tree in one place (folder entries carry `items`) — split it into per-folder `meta.ts` files with the same rules.
|
|
42
43
|
|
|
44
|
+
**Keep the order with `display: "group"`.** Nextra draws folders as collapsible rows and keeps pages and folders interleaved as `_meta` lists them. Blume's default `flat` display draws a folder as a plain section header, so it lists each level's pages above its subfolders — a page `_meta` puts after a folder jumps above it. Set `navigation.sidebar.display: "group"` (or `display: "group"` in the `meta.ts` of every subfolder at a level whose order must hold — one flat sibling folder reorders the level) to keep the authored order in nested folders. Groups then start closed unless they hold the current page, while Nextra opens every folder shallower than its `defaultMenuCollapseLevel` (default `2`: the top-level folders), so add `collapsed: false` to those folders' `meta.ts`. The top level (and each tab's top level) lists loose pages before folders in every display mode, so a root `_meta` that puts a page after a folder can't be matched — report it.
|
|
45
|
+
|
|
43
46
|
## Frontmatter & titles — synthesize, don't just pass through
|
|
44
47
|
|
|
45
|
-
Most Nextra pages have **no frontmatter
|
|
48
|
+
Most Nextra pages have **no frontmatter**. Nextra keeps two titles apart: the **sidebar label** falls back `_meta` title → `sidebarTitle` → `title` → first body H1 → filename, while the **heading readers see** is the body H1. Blume renders frontmatter `title` as the page H1, so for **every page**: set frontmatter `title` from the body H1 (else frontmatter `title`, else the `_meta` title, else a humanized filename), **remove the body H1**, and set `sidebar.label` to the `_meta` title (else `sidebarTitle`) wherever it differs from `title`. Don't take the `_meta` label as `title` — that renames the page's heading. `asIndexPage: true` (v4 folder-index marker) → make the file the folder's `index.mdx` and drop the key. Drop any other non-schema key and report it.
|
|
46
49
|
|
|
47
50
|
## Components
|
|
48
51
|
|
|
@@ -60,12 +63,12 @@ Nextra's fence meta differs from Blume's — rewrite it: `filename="app.js"` →
|
|
|
60
63
|
|
|
61
64
|
## Math
|
|
62
65
|
|
|
63
|
-
Nextra enables math via `nextra({ latex: true })` (KaTeX or MathJax). In Blume, block math `$$…$$` renders in `.mdx` with **no config** (there is no `markdown.math` field). Convert Nextra's ` ```math ` fences → `$$…$$` blocks (they render as plain code blocks otherwise). Inline
|
|
66
|
+
Nextra enables math via `nextra({ latex: true })` (KaTeX or MathJax). In Blume, block math `$$…$$` renders in `.mdx` with **no config** (there is no `markdown.math` field). Convert Nextra's ` ```math ` fences → `$$…$$` blocks (they render as plain code blocks otherwise). Inline math is `$$…$$` too: a single `$` stays literal, so convert each inline `$…$` to `$$…$$` inside its sentence. MathJax-specific macros → report.
|
|
64
67
|
|
|
65
68
|
## i18n
|
|
66
69
|
|
|
67
70
|
- **v2/v3:** locale **file suffixes** (`index.en.mdx`, `index.zh.mdx`) + `i18n` in `next.config` → match Blume's `dot` parser as-is, default-locale suffix included: `i18n: { defaultLocale, locales: [{ code, label }], parser: "dot" }`, no file moves. Page titles land in each file's own frontmatter, so they stay per-locale, but under `dot` a folder's `meta.ts` serves every locale — build it from the default locale's `_meta` and report translated folder titles from the other locales' `_meta` files.
|
|
68
|
-
- **v4:** `content/<lang>/`
|
|
71
|
+
- **v4:** every locale has a `content/<lang>/` dir, the default included, and Nextra serves every locale under its prefix (`/en/…`). Blume's `dir` parser takes the other locales' dirs as-is, but the default locale lives **at the content root**: a `content/en/` dir is ordinary content that publishes at `/en/…` and warns `BLUME_I18N_DEFAULT_LOCALE_FOLDER`. Move the default locale's files (and `_meta`-derived `meta.ts` files) up one level, and set `i18n.hideDefaultLocalePrefix: false` to keep serving them at `/en/…` as Nextra did — or keep Blume's unprefixed default and add a `redirects` entry per page.
|
|
69
72
|
|
|
70
73
|
## Package.json & teardown
|
|
71
74
|
|
|
@@ -73,4 +76,4 @@ Repoint `dev`/`build`/`start` scripts to the Blume CLI; remove `next`/`nextra`/`
|
|
|
73
76
|
|
|
74
77
|
## Dropped — report these
|
|
75
78
|
|
|
76
|
-
Footer content; `primaryHue`-style theming beyond an accent color; `faviconGlyph`; `_meta` separators, menus, `newWindow`; per-page `theme` layout
|
|
79
|
+
Footer content; `primaryHue`-style theming beyond an accent color; `faviconGlyph`; `_meta` separators, menus, `newWindow`; per-page `theme` switches (and `layout: "full"` approximated as `mode: wide`); root-level pages `_meta` ordered after a folder; `<Bleed>`; MathJax macros; word-highlight/copy fence meta; any icon you can't reconstruct as a Lucide name.
|
|
@@ -21,17 +21,17 @@ Keep content where it is — set `content.root: "src/content/docs"`.
|
|
|
21
21
|
| `logo` (`{ src }` or `{ light, dark, alt }`) | `logo` — move the referenced file into `public/` |
|
|
22
22
|
| `logo.replacesTitle` | `logo: { text: "" }` (renders the mark alone) |
|
|
23
23
|
| `favicon` | copy the file into `public/` (drop the config field — Blume auto-detects) |
|
|
24
|
-
| `social` (array of `{ label, icon, href }`; pre-0.33 legacy: `{ github: url }` object) | derive **`github: { owner, repo }`** from the GitHub entry; other socials drop (report) |
|
|
24
|
+
| `social` (array of `{ label, icon, href }`; pre-0.33 legacy: `{ github: url }` object) | derive **`github: { owner, repo }`** from the GitHub entry; every other entry whose platform Blume knows → **`footer.socials`** (`{ discord: href, bluesky: href, … }`; the `x.com`/`twitter` icon → `x`; the platform list is under `footer` in `docs/configuration/index.mdx`); the rest (`mastodon`, `gitlab`, `rss`, …) drop (report) |
|
|
25
25
|
| `editLink.baseUrl` (`…/edit/<branch>/<subdir?>`) | `github: { owner, repo, branch }` — **and any repo sub-path after the branch → `github.dir`** (a docs-in-subfolder repo breaks every edit link without it); **an origin other than `https://github.com` → `github.host`** (a GitHub Enterprise repo otherwise links to the public site) |
|
|
26
26
|
| `sidebar` (array) | filesystem nav / `navigation.sidebar` (see below) |
|
|
27
27
|
| `tableOfContents` (`false` or `{ minHeadingLevel, maxHeadingLevel }`) | `toc` — identical shape, 1:1 |
|
|
28
28
|
| `markdown.headingLinks: false` | `markdown.headingAnchors: false` |
|
|
29
29
|
| `expressiveCode.themes` | `markdown.code.theme: { light, dark }` — EC assigns by theme _type_, so match each theme by its darkness, not by array position |
|
|
30
30
|
| `expressiveCode.styleOverrides` | drop → restyle via a root `theme.css` file |
|
|
31
|
-
| `head` |
|
|
31
|
+
| `head` | per entry: a `meta` tag → **`seo.metatags`** (`{ [attrs.name ?? attrs.property]: attrs.content }` — verification tokens, `theme-color`, and the like), minus the tags Blume writes itself (`description`, `robots`, `og:title`/`og:description`/`og:image`/`og:url`/`og:type`/`og:site_name`, `twitter:*` card tags, `article:*` dates — the build refuses them and names the setting that owns each, e.g. `og:image` → `seo.og`, `twitter:site` → `seo.x.handle`); an analytics `<script>` → one `script()` adapter each in the `analytics` list (from `blume/analytics`): `attrs.src` → `src`, an `async`/`defer` attr → `strategy`, every other `attrs` key → `attributes`, and an inline body (`content`) → `content`; anything else (`link`, `style`, other scripts) → drop and report |
|
|
32
32
|
| `lastUpdated: true` | `lastModified: "git"` |
|
|
33
33
|
| `customCss` | drop → move into a root **`theme.css`** file (auto-picked-up; not a config field) |
|
|
34
|
-
| `components` (overrides) | Blume's layout slots via `defineComponents({ layout: { Header
|
|
34
|
+
| `components` (overrides) | Blume's layout slots via `defineComponents({ layout: { … } })` in a root `components.ts`: `Header`, `Search`, `Sidebar`, `TableOfContents`, `Pagination` keep their names; `SiteTitle` → `Logo`; **`Footer` → `PageFooter`**, not Blume's `Footer` (that slot is the site footer; Starlight's `Footer` is the page-end last-updated date, pagination, and edit link, which Blume renders itself, so keep only what the override added). Other overrides (`Banner`, `PageTitle`, `Hero`, `EditLink`, `SocialIcons`, …) have no slot — fold their additions into `PageHeader`/`PageFooter`, or `blume eject`; a Starlight name left under `layout` matches no slot and does nothing. Rewrite reads of `Astro.locals.starlightRoute` against the slot's props |
|
|
35
35
|
| `plugins` | **map, don't blanket-drop** — see Plugins below |
|
|
36
36
|
| `pagination: false`, `pagefind`/Pagefind options, `titleDelimiter`, `credits`, `disable404Route`, `routeMiddleware` | drop (report) |
|
|
37
37
|
| `locales` / `defaultLocale` | `i18n` (see below) |
|
|
@@ -40,7 +40,7 @@ Keep content where it is — set `content.root: "src/content/docs"`.
|
|
|
40
40
|
|
|
41
41
|
Starlight's `sidebar` array → prefer letting Blume generate from the filesystem; use `navigation.sidebar` only for shapes files can't express:
|
|
42
42
|
|
|
43
|
-
- `{ label, autogenerate: { directory: "d" } }` → **structure the folder and rely on filesystem nav** (label → the folder's `meta.ts` `title`). Do **not** map it to a sidebar item with `root:` — in an explicit Blume sidebar that renders a single page link, not the directory's children.
|
|
43
|
+
- `{ label, items: [{ autogenerate: { directory: "d" } }] }` (0.39 and later; before 0.39 the group held it directly, `{ label, autogenerate: { directory: "d" } }`) → **structure the folder and rely on filesystem nav** (label → the folder's `meta.ts` `title`; `autogenerate.collapsed` → `collapsed: true` in each subfolder's `meta.ts`). Do **not** map it to a sidebar item with `root:` — in an explicit Blume sidebar that renders a single page link, not the directory's children. Since 0.39 a group's `items` can mix manual entries with an `autogenerate` entry; move those manual pages into the folder (route change → `redirects`) so the folder holds the whole group.
|
|
44
44
|
- string `"guides/intro"` → `"/guides/intro"`; `{ label?, slug }` → `/<slug>`.
|
|
45
45
|
- `{ label, items: [...] }` → `{ label, items: [...] }` (recursive) — or better, a real folder.
|
|
46
46
|
- `{ label?, link }` → `{ label, href: link }`.
|
|
@@ -57,8 +57,10 @@ Starlight's `sidebar` array → prefer letting Blume generate from the filesyste
|
|
|
57
57
|
| `pagefind: false` | `search.exclude: true` |
|
|
58
58
|
| `lastUpdated` (date/string) | `lastModified` |
|
|
59
59
|
| `lastUpdated: false` (boolean) | **remove** (Blume's `lastModified` takes a date; a boolean is a build error) |
|
|
60
|
-
| `prev`
|
|
61
|
-
| `
|
|
60
|
+
| `prev: false` **and** `next: false` | `pagination: false` (hides both links) |
|
|
61
|
+
| `prev` / `next` otherwise (one side, or a label/link) | **drop** (report — the links can only be hidden together, and their labels come from the linked pages) |
|
|
62
|
+
| `template: splash` | `mode: center` (no sidebar, a wider centered column — the closest layout; report) |
|
|
63
|
+
| `hero` | **no key** — its tagline → a paragraph, its actions → `<Card>`s or links, its image → a Markdown image (report); for a designed landing page, rebuild it as a custom `.astro` page under `content.pages` (`pages/index.astro` on `PageLayout` wins over the content page) |
|
|
62
64
|
| `banner`, `tableOfContents`, `editUrl`, `head` | drop (report) |
|
|
63
65
|
|
|
64
66
|
## Asides → directives (and the `.md` trap)
|
|
@@ -82,7 +84,8 @@ Starlight content is full of Expressive Code fence meta; Blume understands some
|
|
|
82
84
|
- `title="file.js"` → works as-is (or use the space-title shorthand). Line ranges `{2-3}` → work as-is.
|
|
83
85
|
- `ins=`/`del=` line marks → `// [!code ++]` / `// [!code --]` comments; `mark=` → `{ranges}` or `// [!code highlight]`.
|
|
84
86
|
- `showLineNumbers` → `lineNumbers`.
|
|
85
|
-
-
|
|
87
|
+
- `wrap` / `wrap=true` → a bare `wrap` (that block's long lines wrap); a site-wide `expressiveCode.defaultProps.wrap: true` → `markdown.code.wrap: true`.
|
|
88
|
+
- **Drop:** `frame="terminal"`, `collapse=`, `wrap=false`, `preserveIndent`/`hangingIndent`, `"string"` and `/regex/` text markers (report if they carried meaning).
|
|
86
89
|
- ` ```diff lang="js" ` → a normal ` ```js ` fence with `[!code ++]`/`[!code --]` markers.
|
|
87
90
|
|
|
88
91
|
## Plugins — map, don't drop
|
|
@@ -113,4 +116,4 @@ Remove `@astrojs/starlight` (and plugin deps) from deps, delete the Starlight bi
|
|
|
113
116
|
|
|
114
117
|
## Dropped — report these
|
|
115
118
|
|
|
116
|
-
|
|
119
|
+
Socials on a platform `footer.socials` lacks, badge variants, sidebar/item `attrs` + `translations`, `customCss` beyond `theme.css`, `head` entries other than meta tags and analytics scripts, a page's frontmatter `head`, `routeMiddleware`, splash layouts approximated with `mode: center` and hero blocks rebuilt as content, override components with no Blume slot, starlight-blog's tag and author pages, aside custom icons, EC frames/collapse/text markers, prev/next toggles, unmapped plugins, any `<Icon>` name with no Lucide equivalent.
|