blume 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/blume.mjs +18 -0
- package/dist/cli/index.js +11989 -0
- package/dist/cli/index.js.map +141 -0
- package/docs/01-quickstart.mdx +99 -0
- package/docs/02-deployment.mdx +129 -0
- package/docs/advanced/api-reference.mdx +114 -0
- package/docs/advanced/blog.mdx +121 -0
- package/docs/advanced/changelog.mdx +113 -0
- package/docs/advanced/custom-pages.mdx +187 -0
- package/docs/advanced/meta.ts +7 -0
- package/docs/changelog/v0-1-0.mdx +12 -0
- package/docs/changelog/v0-2-0.mdx +16 -0
- package/docs/configuration/ai.mdx +228 -0
- package/docs/configuration/analytics.mdx +98 -0
- package/docs/configuration/customization.mdx +91 -0
- package/docs/configuration/export.mdx +70 -0
- package/docs/configuration/index.mdx +271 -0
- package/docs/configuration/meta.ts +15 -0
- package/docs/configuration/search.mdx +172 -0
- package/docs/configuration/seo.mdx +196 -0
- package/docs/configuration/theming.mdx +178 -0
- package/docs/content/components.mdx +565 -0
- package/docs/content/i18n.mdx +205 -0
- package/docs/content/index.mdx +161 -0
- package/docs/content/islands.mdx +94 -0
- package/docs/content/meta.mdx +119 -0
- package/docs/content/meta.ts +15 -0
- package/docs/content/navigation.mdx +168 -0
- package/docs/content/sources.mdx +216 -0
- package/docs/content/syntax.mdx +445 -0
- package/docs/index.mdx +112 -0
- package/docs/reference/cli.mdx +43 -0
- package/docs/reference/frontmatter.mdx +74 -0
- package/docs/reference/meta.ts +7 -0
- package/package.json +140 -6
- package/src/ai/ask.ts +93 -0
- package/src/ai/llms.ts +65 -0
- package/src/ai/markdown.ts +31 -0
- package/src/ai/mcp/data.ts +74 -0
- package/src/ai/mcp/discovery.ts +49 -0
- package/src/ai/mcp/server.ts +225 -0
- package/src/ai/mcp/tools.ts +47 -0
- package/src/assets/icon.png +0 -0
- package/src/astro/generate.ts +878 -0
- package/src/astro/index.ts +4 -0
- package/src/astro/integration.ts +74 -0
- package/src/astro/islands.ts +131 -0
- package/src/astro/markdown-negotiation.ts +68 -0
- package/src/astro/pages.ts +28 -0
- package/src/astro/templates.ts +1199 -0
- package/src/cli/commands/add.ts +81 -0
- package/src/cli/commands/build.ts +103 -0
- package/src/cli/commands/dev.ts +108 -0
- package/src/cli/commands/doctor.ts +74 -0
- package/src/cli/commands/eject.ts +57 -0
- package/src/cli/commands/init.ts +98 -0
- package/src/cli/commands/migrate.ts +39 -0
- package/src/cli/commands/preview.ts +39 -0
- package/src/cli/commands/sync.ts +52 -0
- package/src/cli/commands/validate.ts +60 -0
- package/src/cli/index.ts +35 -0
- package/src/cli/log.ts +37 -0
- package/src/cli/prepare.ts +80 -0
- package/src/components/Icon.astro +99 -0
- package/src/components/content/Accordion.astro +8 -0
- package/src/components/content/AccordionItem.astro +121 -0
- package/src/components/content/AutoTypeTable.astro +51 -0
- package/src/components/content/Badge.astro +124 -0
- package/src/components/content/Callout.astro +73 -0
- package/src/components/content/Card.astro +104 -0
- package/src/components/content/CardGroup.astro +14 -0
- package/src/components/content/CodeGroup.astro +13 -0
- package/src/components/content/Color.astro +15 -0
- package/src/components/content/ColorItem.astro +87 -0
- package/src/components/content/ColorRow.astro +10 -0
- package/src/components/content/Column.astro +6 -0
- package/src/components/content/Columns.astro +9 -0
- package/src/components/content/Expandable.astro +11 -0
- package/src/components/content/FileTree.astro +8 -0
- package/src/components/content/Frame.astro +70 -0
- package/src/components/content/GithubInfo.astro +110 -0
- package/src/components/content/Math.astro +24 -0
- package/src/components/content/Panel.astro +20 -0
- package/src/components/content/Prompt.astro +129 -0
- package/src/components/content/Step.astro +34 -0
- package/src/components/content/Steps.astro +20 -0
- package/src/components/content/Tab.astro +40 -0
- package/src/components/content/Tabs.astro +273 -0
- package/src/components/content/Tile.astro +42 -0
- package/src/components/content/Tooltip.astro +68 -0
- package/src/components/content/Tree.astro +300 -0
- package/src/components/content/TreeFile.astro +15 -0
- package/src/components/content/TreeFolder.astro +62 -0
- package/src/components/content/TypeTable.astro +106 -0
- package/src/components/content/Update.astro +66 -0
- package/src/components/content/Visibility.astro +12 -0
- package/src/components/content/Warning.astro +9 -0
- package/src/components/content/auto-type-table.ts +141 -0
- package/src/components/content/github-info.ts +79 -0
- package/src/components/content/mermaid-element.ts +68 -0
- package/src/components/github-mark.ts +9 -0
- package/src/components/index.ts +14 -0
- package/src/components/islands/AskAI.astro +12 -0
- package/src/components/islands/ask-ai.tsx +156 -0
- package/src/components/layout/Analytics.astro +63 -0
- package/src/components/layout/Banner.astro +50 -0
- package/src/components/layout/Breadcrumbs.astro +31 -0
- package/src/components/layout/Favicon.astro +15 -0
- package/src/components/layout/Fonts.astro +14 -0
- package/src/components/layout/Header.astro +188 -0
- package/src/components/layout/LanguageSwitcher.astro +56 -0
- package/src/components/layout/NavTree.astro +462 -0
- package/src/components/layout/PageActions.astro +438 -0
- package/src/components/layout/PageFeedback.astro +58 -0
- package/src/components/layout/Pagination.astro +56 -0
- package/src/components/layout/ReferenceLayout.astro +102 -0
- package/src/components/layout/RootLayout.astro +533 -0
- package/src/components/layout/Search.astro +608 -0
- package/src/components/layout/TableOfContents.astro +68 -0
- package/src/components/layout/analytics-client.ts +38 -0
- package/src/components/layout/nav-utils.ts +87 -0
- package/src/components/layout/overrides.ts +32 -0
- package/src/components/layout/search/algolia.ts +43 -0
- package/src/components/layout/search/endpoint.ts +22 -0
- package/src/components/layout/search/flexsearch.ts +52 -0
- package/src/components/layout/search/orama-cloud.ts +41 -0
- package/src/components/layout/search/orama.ts +26 -0
- package/src/components/layout/search/pagefind.ts +43 -0
- package/src/components/layout/search/types.ts +163 -0
- package/src/components/layout/search/typesense.ts +60 -0
- package/src/components/layout/toc-element.ts +108 -0
- package/src/core/bridge.ts +92 -0
- package/src/core/config.ts +112 -0
- package/src/core/content.ts +50 -0
- package/src/core/define-components.ts +34 -0
- package/src/core/define-meta.ts +20 -0
- package/src/core/deployment-env.ts +73 -0
- package/src/core/diagnostics.ts +104 -0
- package/src/core/graph.ts +128 -0
- package/src/core/i18n-ui.ts +171 -0
- package/src/core/i18n.ts +169 -0
- package/src/core/last-modified.ts +88 -0
- package/src/core/links.ts +336 -0
- package/src/core/load-module.ts +15 -0
- package/src/core/manifest.ts +126 -0
- package/src/core/meta.ts +97 -0
- package/src/core/navigation.ts +392 -0
- package/src/core/package-root.ts +37 -0
- package/src/core/project-graph.ts +153 -0
- package/src/core/project.ts +56 -0
- package/src/core/schema.ts +1057 -0
- package/src/core/server-features.ts +23 -0
- package/src/core/sources/assets.ts +77 -0
- package/src/core/sources/cache.ts +122 -0
- package/src/core/sources/filesystem.ts +99 -0
- package/src/core/sources/mdx-remote.ts +216 -0
- package/src/core/sources/mintlify.ts +161 -0
- package/src/core/sources/normalize.ts +227 -0
- package/src/core/sources/notion.ts +440 -0
- package/src/core/sources/portable-text.ts +143 -0
- package/src/core/sources/read.ts +36 -0
- package/src/core/sources/resolve.ts +158 -0
- package/src/core/sources/sanity.ts +218 -0
- package/src/core/sources/types.ts +105 -0
- package/src/core/types.ts +261 -0
- package/src/core/ui-packs/ar.ts +47 -0
- package/src/core/ui-packs/bg.ts +47 -0
- package/src/core/ui-packs/bn.ts +47 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +47 -0
- package/src/core/ui-packs/da.ts +47 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +47 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +47 -0
- package/src/core/ui-packs/fi.ts +47 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +47 -0
- package/src/core/ui-packs/hi.ts +47 -0
- package/src/core/ui-packs/hr.ts +47 -0
- package/src/core/ui-packs/hu.ts +47 -0
- package/src/core/ui-packs/id.ts +47 -0
- package/src/core/ui-packs/index.ts +87 -0
- package/src/core/ui-packs/it.ts +47 -0
- package/src/core/ui-packs/ja.ts +47 -0
- package/src/core/ui-packs/ko.ts +47 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +47 -0
- package/src/core/ui-packs/pl.ts +47 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +47 -0
- package/src/core/ui-packs/ro.ts +47 -0
- package/src/core/ui-packs/ru.ts +47 -0
- package/src/core/ui-packs/sk.ts +47 -0
- package/src/core/ui-packs/sr.ts +47 -0
- package/src/core/ui-packs/sv.ts +47 -0
- package/src/core/ui-packs/th.ts +47 -0
- package/src/core/ui-packs/tr.ts +47 -0
- package/src/core/ui-packs/uk.ts +47 -0
- package/src/core/ui-packs/vi.ts +47 -0
- package/src/core/ui-packs/zh-tw.ts +47 -0
- package/src/core/ui-packs/zh.ts +47 -0
- package/src/core/version.ts +23 -0
- package/src/deploy/robots.ts +20 -0
- package/src/deploy/rss.ts +128 -0
- package/src/deploy/sitemap.ts +28 -0
- package/src/index.ts +27 -0
- package/src/markdown/code-title.ts +71 -0
- package/src/markdown/directives.ts +83 -0
- package/src/markdown/heading-anchors.ts +137 -0
- package/src/markdown/index.ts +159 -0
- package/src/markdown/inline-code.ts +108 -0
- package/src/markdown/language-icon.ts +172 -0
- package/src/markdown/math.ts +32 -0
- package/src/markdown/mdast.ts +48 -0
- package/src/markdown/mermaid.ts +37 -0
- package/src/markdown/package-commands.ts +159 -0
- package/src/markdown/package-install.ts +40 -0
- package/src/migrate/fumadocs/config.ts +106 -0
- package/src/migrate/fumadocs/content.ts +365 -0
- package/src/migrate/fumadocs/frontmatter.ts +18 -0
- package/src/migrate/fumadocs/index.ts +252 -0
- package/src/migrate/fumadocs/meta.ts +114 -0
- package/src/migrate/migrate.ts +53 -0
- package/src/migrate/mintlify/config.ts +1040 -0
- package/src/migrate/mintlify/content.ts +98 -0
- package/src/migrate/mintlify/frontmatter.ts +126 -0
- package/src/migrate/mintlify/i18n.ts +51 -0
- package/src/migrate/mintlify/icons.ts +128 -0
- package/src/migrate/mintlify/index.ts +266 -0
- package/src/migrate/mintlify/snippets.ts +305 -0
- package/src/migrate/mintlify/transform.ts +81 -0
- package/src/migrate/nextra/content.ts +46 -0
- package/src/migrate/nextra/frontmatter.ts +40 -0
- package/src/migrate/nextra/index.ts +374 -0
- package/src/migrate/nextra/meta.ts +266 -0
- package/src/migrate/shared.ts +623 -0
- package/src/migrate/starlight/config.ts +459 -0
- package/src/migrate/starlight/content.ts +78 -0
- package/src/migrate/starlight/frontmatter.ts +111 -0
- package/src/migrate/starlight/i18n.ts +54 -0
- package/src/migrate/starlight/index.ts +131 -0
- package/src/og/card.ts +92 -0
- package/src/og/index.ts +2 -0
- package/src/openapi/scalar.ts +246 -0
- package/src/registry/eject.ts +263 -0
- package/src/registry/registry.ts +100 -0
- package/src/registry/rewrite-imports.ts +39 -0
- package/src/runtime/index.ts +14 -0
- package/src/search/build.ts +23 -0
- package/src/search/documents.ts +165 -0
- package/src/search/orama-index.ts +66 -0
- package/src/search/providers.ts +91 -0
- package/src/search/sync/algolia.ts +30 -0
- package/src/search/sync/index.ts +50 -0
- package/src/search/sync/orama-cloud.ts +40 -0
- package/src/search/sync/typesense.ts +65 -0
- package/src/seo/jsonld.ts +113 -0
- package/src/theme/entry.ts +608 -0
- package/src/theme/fonts.ts +198 -0
- package/src/theme/icons.ts +184 -0
- package/src/theme/palette.ts +143 -0
- package/src/theme/twoslash.ts +81 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Internationalization
|
|
3
|
+
description: Serve your docs in multiple languages with locale-aware routing, per-language navigation, translated UI, and SEO — all convention-first.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Blume serves one project in many languages. Drop translated files into the right
|
|
7
|
+
place and Blume wires up routing, the language switcher, per-locale navigation,
|
|
8
|
+
and SEO for you — there's no separate routing layer to maintain. It's opt-in:
|
|
9
|
+
without an `i18n` block, your site stays single-language exactly as before.
|
|
10
|
+
|
|
11
|
+
## Enable it
|
|
12
|
+
|
|
13
|
+
Add an `i18n` block listing your locales and which one is the default:
|
|
14
|
+
|
|
15
|
+
```ts blume.config.ts lineNumbers
|
|
16
|
+
i18n: {
|
|
17
|
+
defaultLocale: "en",
|
|
18
|
+
locales: [
|
|
19
|
+
{ code: "en", label: "English" },
|
|
20
|
+
{ code: "fr", label: "Français" },
|
|
21
|
+
{ code: "ar", label: "العربية", dir: "rtl" },
|
|
22
|
+
],
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Each locale has a `code` (used in URLs), a `label` (shown in the language
|
|
27
|
+
switcher), and an optional `dir` for right-to-left scripts (`"ltr"` by default).
|
|
28
|
+
|
|
29
|
+
:::tip
|
|
30
|
+
Migrating from Mintlify? `blume migrate mintlify` reads
|
|
31
|
+
`navigation.languages[]` and writes the `i18n` block for you — the `default: true`
|
|
32
|
+
language becomes `defaultLocale`, and translated folders already match Blume's
|
|
33
|
+
layout.
|
|
34
|
+
:::
|
|
35
|
+
|
|
36
|
+
## Organize translated content
|
|
37
|
+
|
|
38
|
+
The default locale lives at your content root. Every other locale is a top-level
|
|
39
|
+
folder named by its `code`, mirroring the default structure:
|
|
40
|
+
|
|
41
|
+
```txt
|
|
42
|
+
docs/
|
|
43
|
+
index.mdx -> /
|
|
44
|
+
guides/quickstart.mdx -> /guides/quickstart
|
|
45
|
+
fr/
|
|
46
|
+
index.mdx -> /fr
|
|
47
|
+
guides/quickstart.mdx -> /fr/guides/quickstart
|
|
48
|
+
ar/
|
|
49
|
+
index.mdx -> /ar
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| File | Route |
|
|
53
|
+
| ------------------------------- | ----------------------- |
|
|
54
|
+
| `docs/index.mdx` | `/` |
|
|
55
|
+
| `docs/guides/quickstart.mdx` | `/guides/quickstart` |
|
|
56
|
+
| `docs/fr/guides/quickstart.mdx` | `/fr/guides/quickstart` |
|
|
57
|
+
|
|
58
|
+
You only translate the files you want — everything else falls back automatically
|
|
59
|
+
(see [Fallbacks](#fallbacks)).
|
|
60
|
+
|
|
61
|
+
### Filename suffixes
|
|
62
|
+
|
|
63
|
+
Prefer to keep translations next to the original? Set `parser: "dot"` and name
|
|
64
|
+
files with a locale suffix instead of using folders:
|
|
65
|
+
|
|
66
|
+
```txt
|
|
67
|
+
docs/
|
|
68
|
+
guides/quickstart.mdx -> /guides/quickstart (default)
|
|
69
|
+
guides/quickstart.fr.mdx -> /fr/guides/quickstart (French)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Good for sparse translations — colocate the few pages you've translated without
|
|
73
|
+
mirroring the whole tree.
|
|
74
|
+
|
|
75
|
+
### Shared files
|
|
76
|
+
|
|
77
|
+
For content that's the same in every language — a changelog, a status page — add
|
|
78
|
+
a `$` marker so one file serves all locales without duplication:
|
|
79
|
+
|
|
80
|
+
```txt
|
|
81
|
+
docs/changelog.$.mdx -> /changelog and /fr/changelog (same content)
|
|
82
|
+
docs/guides/meta.$.ts (folder meta applied to every locale)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
A locale-specific `meta.ts` still overrides the shared one for that language.
|
|
86
|
+
|
|
87
|
+
## Default-locale URLs
|
|
88
|
+
|
|
89
|
+
By default the default locale has no URL prefix (`/`, `/guides/quickstart`) while
|
|
90
|
+
other locales are prefixed (`/fr/…`). This keeps your primary language's URLs
|
|
91
|
+
clean. To prefix every locale, including the default:
|
|
92
|
+
|
|
93
|
+
```ts blume.config.ts lineNumbers
|
|
94
|
+
i18n: {
|
|
95
|
+
// …
|
|
96
|
+
hideDefaultLocalePrefix: false, // /en/…, /fr/…
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Per-locale navigation
|
|
101
|
+
|
|
102
|
+
Each language gets its own sidebar, built from that locale's files — so
|
|
103
|
+
translations can diverge in structure, ordering, or labels. Folder
|
|
104
|
+
[`meta.ts`](/docs/content/meta) files resolve per locale, too: put a `meta.ts`
|
|
105
|
+
under `fr/guides/` to order the French group independently. Everything else about
|
|
106
|
+
[navigation](/docs/content/navigation) works the same, per language.
|
|
107
|
+
|
|
108
|
+
## Fallbacks
|
|
109
|
+
|
|
110
|
+
When a page isn't translated yet, Blume renders the fallback locale's content at
|
|
111
|
+
the localized URL — so the link works, the page is fully pre-rendered, and search
|
|
112
|
+
engines aren't sent to a dead end. The fallback defaults to your `defaultLocale`:
|
|
113
|
+
|
|
114
|
+
```ts blume.config.ts lineNumbers
|
|
115
|
+
i18n: {
|
|
116
|
+
// …
|
|
117
|
+
fallbackLocale: "en", // default; set to null to 404 instead
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Fallback pages are excluded from the search index and aren't advertised as real
|
|
122
|
+
translations in `hreflang`, so untranslated content doesn't compete for ranking.
|
|
123
|
+
They still appear in that locale's sidebar, so navigation stays complete — a
|
|
124
|
+
reader can reach every page in any language.
|
|
125
|
+
|
|
126
|
+
:::tip
|
|
127
|
+
Start by translating your most important pages — the homepage, quickstart, and
|
|
128
|
+
top guides — and let the rest fall back. You can fill in translations over time
|
|
129
|
+
without breaking any links.
|
|
130
|
+
:::
|
|
131
|
+
|
|
132
|
+
## The language switcher
|
|
133
|
+
|
|
134
|
+
When i18n is on, a language switcher appears in the header automatically,
|
|
135
|
+
generated from your `locales`. For each page it links the matching translation in
|
|
136
|
+
every language; where a translation is missing it links the fallback page and
|
|
137
|
+
marks it as not translated. There's nothing to configure.
|
|
138
|
+
|
|
139
|
+
## Translated UI
|
|
140
|
+
|
|
141
|
+
Blume ships built-in translations for its own interface chrome — “On this page”,
|
|
142
|
+
“Search”, “Edit on GitHub”, and the rest — so a locale with a built-in pack gets
|
|
143
|
+
translated UI out of the box. **You only translate your content.**
|
|
144
|
+
|
|
145
|
+
Packs ship for 36 languages — Arabic, Bengali, Bulgarian, Catalan, Chinese
|
|
146
|
+
(Simplified and Traditional), Croatian, Czech, Danish, Dutch, Finnish, French,
|
|
147
|
+
German, Greek, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean,
|
|
148
|
+
Norwegian, Persian, Polish, Portuguese (and Brazilian Portuguese), Romanian,
|
|
149
|
+
Russian, Serbian, Slovak, Spanish, Swedish, Thai, Turkish, Ukrainian, and
|
|
150
|
+
Vietnamese. They're community-maintained — open a PR to add a locale or sharpen a
|
|
151
|
+
translation.
|
|
152
|
+
|
|
153
|
+
Missing or unshipped strings fall back to the default locale, then to English.
|
|
154
|
+
To override a string or supply your own language, set `i18n.ui`, keyed by locale:
|
|
155
|
+
|
|
156
|
+
```ts blume.config.ts lineNumbers
|
|
157
|
+
i18n: {
|
|
158
|
+
// …
|
|
159
|
+
ui: {
|
|
160
|
+
fr: {
|
|
161
|
+
search: { button: "Rechercher", placeholder: "Rechercher…" },
|
|
162
|
+
page: { previous: "Précédent", next: "Suivant" },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## SEO
|
|
169
|
+
|
|
170
|
+
Localized SEO is handled for you — no per-page metadata to write:
|
|
171
|
+
|
|
172
|
+
- `<html lang>` and `dir` are set from the active locale.
|
|
173
|
+
- `hreflang` alternates link every real translation of a page, plus an
|
|
174
|
+
`x-default` pointing at the default locale.
|
|
175
|
+
- Canonical URLs are locale-correct, and JSON-LD carries `inLanguage`.
|
|
176
|
+
|
|
177
|
+
Set [`deployment.site`](/docs/deployment) so these can be emitted as absolute
|
|
178
|
+
URLs.
|
|
179
|
+
|
|
180
|
+
## Search
|
|
181
|
+
|
|
182
|
+
Search is scoped to the active language: on a `/fr/…` page the dialog returns
|
|
183
|
+
French results, with an **All languages** toggle to search across every locale at
|
|
184
|
+
once. The default (Orama) and FlexSearch indexes filter in the browser; hosted
|
|
185
|
+
providers carry a `locale` facet on each record.
|
|
186
|
+
|
|
187
|
+
## Right-to-left
|
|
188
|
+
|
|
189
|
+
Set `dir: "rtl"` on a locale and Blume mirrors the whole interface — the sidebar,
|
|
190
|
+
header, table of contents, pagination, search, and menus — and sets `<html dir>`
|
|
191
|
+
to match. Two things deliberately stay left-to-right: **code blocks** (code reads
|
|
192
|
+
LTR in any language) and **fallback content** — an untranslated page keeps the
|
|
193
|
+
direction of the language it's actually written in, so English shown under an RTL
|
|
194
|
+
locale still reads correctly while the surrounding chrome mirrors.
|
|
195
|
+
|
|
196
|
+
## Where to next
|
|
197
|
+
|
|
198
|
+
<CardGroup cols={2}>
|
|
199
|
+
<Card title="Navigation" href="/docs/content/navigation" icon="menu">
|
|
200
|
+
Shape each locale's sidebar, ordering, and tabs.
|
|
201
|
+
</Card>
|
|
202
|
+
<Card title="SEO" href="/docs/configuration/seo" icon="rocket">
|
|
203
|
+
Sitemaps, Open Graph, and structured data.
|
|
204
|
+
</Card>
|
|
205
|
+
</CardGroup>
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pages
|
|
3
|
+
description: How files in your content folder become pages, and how to organize them.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Your docs are just a folder of Markdown and MDX files. Blume turns each file into
|
|
7
|
+
a page — routing, navigation, and metadata are inferred from the file system, so
|
|
8
|
+
there's no manifest to keep in sync.
|
|
9
|
+
|
|
10
|
+
Content lives under your **content root** (`docs/` by default; change it with
|
|
11
|
+
`content.root` in [`blume.config.ts`](/docs/configuration)).
|
|
12
|
+
|
|
13
|
+
## Markdown and MDX
|
|
14
|
+
|
|
15
|
+
Blume renders two kinds of file:
|
|
16
|
+
|
|
17
|
+
- **`.md`** — Markdown for plain prose: GFM, frontmatter, smart punctuation, and
|
|
18
|
+
super/subscript.
|
|
19
|
+
- **`.mdx`** — everything `.md` has, plus [components](/docs/content/components) and
|
|
20
|
+
the MDX-only [directives, package installs, and math](/docs/content/syntax).
|
|
21
|
+
|
|
22
|
+
Reach for `.md` when a page is just prose, and `.mdx` when it needs components or
|
|
23
|
+
directives. Switching is as simple as renaming the file.
|
|
24
|
+
|
|
25
|
+
## Files and routes
|
|
26
|
+
|
|
27
|
+
Each file maps to a route by its path under the content root:
|
|
28
|
+
|
|
29
|
+
| File | Route |
|
|
30
|
+
| ------------------------- | ----------------- |
|
|
31
|
+
| `docs/index.mdx` | `/` |
|
|
32
|
+
| `docs/quickstart.mdx` | `/quickstart` |
|
|
33
|
+
| `docs/guides/theming.mdx` | `/guides/theming` |
|
|
34
|
+
| `docs/guides/index.mdx` | `/guides` |
|
|
35
|
+
|
|
36
|
+
Nested folders become nested routes, and an `index.mdx` inside a folder becomes
|
|
37
|
+
that folder's own page.
|
|
38
|
+
|
|
39
|
+
## Ordering with numeric prefixes
|
|
40
|
+
|
|
41
|
+
Prefix a file or folder with a number to control its order in the sidebar. The
|
|
42
|
+
prefix is stripped from the URL, so you can reorder pages without breaking links:
|
|
43
|
+
|
|
44
|
+
```txt
|
|
45
|
+
01-introduction.mdx -> /introduction
|
|
46
|
+
02-installation.mdx -> /installation
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Ordering has several layers — see [Navigation](/docs/content/navigation) for the full
|
|
50
|
+
precedence rules.
|
|
51
|
+
|
|
52
|
+
## Group folders
|
|
53
|
+
|
|
54
|
+
Wrap a folder name in parentheses to group its pages in the sidebar **without**
|
|
55
|
+
adding a URL segment:
|
|
56
|
+
|
|
57
|
+
```txt
|
|
58
|
+
docs/(internal)/security.mdx -> /security
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The pages share an “Internal” sidebar group but keep flat, parenthesis-free URLs.
|
|
62
|
+
|
|
63
|
+
## Drafts
|
|
64
|
+
|
|
65
|
+
Mark a page as a draft to keep it out of production builds while still previewing
|
|
66
|
+
it in `blume dev`:
|
|
67
|
+
|
|
68
|
+
```yaml lineNumbers
|
|
69
|
+
---
|
|
70
|
+
title: Work in progress
|
|
71
|
+
draft: true
|
|
72
|
+
---
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`blume build` skips drafts; `blume dev` renders them so you can work in the open.
|
|
76
|
+
|
|
77
|
+
## Content types
|
|
78
|
+
|
|
79
|
+
Every page has a **type**, set with the `type` frontmatter field (default
|
|
80
|
+
`doc`). Types let Blume treat groups of pages differently — most importantly,
|
|
81
|
+
`blog` and `changelog` pages are collected into [feeds](#feeds).
|
|
82
|
+
|
|
83
|
+
```yaml lineNumbers
|
|
84
|
+
---
|
|
85
|
+
title: v1.2.0
|
|
86
|
+
type: changelog
|
|
87
|
+
date: 2026-06-20
|
|
88
|
+
changelog:
|
|
89
|
+
version: 1.2.0
|
|
90
|
+
category: Features
|
|
91
|
+
---
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The type is independent of where the file lives, but by convention blog posts
|
|
95
|
+
go under `blog/` and changelog entries under `changelog/`. Both get an RSS feed
|
|
96
|
+
automatically, and changelog entries are also collected into a generated
|
|
97
|
+
[`/changelog` timeline](/docs/advanced/changelog). See [Blog](/docs/advanced/blog) and
|
|
98
|
+
[Changelog](/docs/advanced/changelog) for authoring each.
|
|
99
|
+
|
|
100
|
+
## Feeds
|
|
101
|
+
|
|
102
|
+
Blume generates an RSS feed automatically for each content type listed in
|
|
103
|
+
[`rss.types`](/docs/configuration/seo#rss-feeds) — `blog` and `changelog` by default —
|
|
104
|
+
as long as it has at least one page. Feeds are served at `/<type>/rss.xml`:
|
|
105
|
+
|
|
106
|
+
| Type | Feed |
|
|
107
|
+
| ----------- | -------------------- |
|
|
108
|
+
| `blog` | `/blog/rss.xml` |
|
|
109
|
+
| `changelog` | `/changelog/rss.xml` |
|
|
110
|
+
|
|
111
|
+
Give each entry a `date` so items sort newest-first and carry a `pubDate`. An
|
|
112
|
+
unquoted YAML date is fine — Blume normalizes it:
|
|
113
|
+
|
|
114
|
+
```yaml lineNumbers
|
|
115
|
+
---
|
|
116
|
+
title: Introducing Blume
|
|
117
|
+
type: blog
|
|
118
|
+
date: 2026-06-22
|
|
119
|
+
description: Why we built a markdown-first docs framework.
|
|
120
|
+
---
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Feeds need an absolute site URL, so set [`deployment.site`](/docs/deployment). Blume
|
|
124
|
+
adds `<link rel="alternate">` tags to every page so browsers and feed readers
|
|
125
|
+
discover them automatically. See [Blog](/docs/advanced/blog) and
|
|
126
|
+
[Changelog](/docs/advanced/changelog) for authoring each content type.
|
|
127
|
+
|
|
128
|
+
## On this page
|
|
129
|
+
|
|
130
|
+
Every page gets an automatic table of contents, built from its headings. On wide
|
|
131
|
+
screens it sits in a sticky sidebar beside your content; on narrower screens it
|
|
132
|
+
collapses into an **On this page** panel above the page. As you scroll, the entry
|
|
133
|
+
for the section you're reading is highlighted, so you always know where you are in
|
|
134
|
+
a long page.
|
|
135
|
+
|
|
136
|
+
Blume slugifies each heading into an anchor, so every entry links straight to its
|
|
137
|
+
section — and you can deep-link to any heading by appending its slug to the URL
|
|
138
|
+
(`.../my-page#getting-started`).
|
|
139
|
+
|
|
140
|
+
The contents list your `##` and `###` headings (H2 and H3). A page with no
|
|
141
|
+
headings at that level simply has no table of contents.
|
|
142
|
+
|
|
143
|
+
## Where to next
|
|
144
|
+
|
|
145
|
+
<CardGroup cols={2}>
|
|
146
|
+
<Card title="Frontmatter" href="/docs/reference/frontmatter" icon="file">
|
|
147
|
+
Page metadata: title, description, sidebar, SEO, and search.
|
|
148
|
+
</Card>
|
|
149
|
+
<Card title="Syntax" href="/docs/content/syntax" icon="book-open">
|
|
150
|
+
Every Markdown and MDX feature you can write.
|
|
151
|
+
</Card>
|
|
152
|
+
<Card title="Components" href="/docs/content/components" icon="folder">
|
|
153
|
+
The JSX components available in any MDX page.
|
|
154
|
+
</Card>
|
|
155
|
+
<Card title="Navigation" href="/docs/content/navigation" icon="menu">
|
|
156
|
+
Shape the sidebar, ordering, and tabs.
|
|
157
|
+
</Card>
|
|
158
|
+
<Card title="Folder meta" href="/docs/content/meta" icon="panel-left">
|
|
159
|
+
Configure a sidebar group with a `meta.ts` file.
|
|
160
|
+
</Card>
|
|
161
|
+
</CardGroup>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Islands
|
|
3
|
+
description: Drop an interactive component into islands/ and use it in any MDX page — hydrated automatically, no per-page import.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Blume renders your docs as static HTML with **zero JavaScript** by default. When
|
|
7
|
+
you need something interactive — a live demo, a chart, a playground — you add an
|
|
8
|
+
**island**: a framework component that ships JS only for itself, only on the
|
|
9
|
+
pages that use it.
|
|
10
|
+
|
|
11
|
+
## The `islands/` convention
|
|
12
|
+
|
|
13
|
+
Drop a component into an `islands/` folder at your project root. Its filename
|
|
14
|
+
becomes a component you can use in **any** `.mdx` page, with no import:
|
|
15
|
+
|
|
16
|
+
```tsx islands/Counter.tsx lineNumbers
|
|
17
|
+
import { useState } from "react";
|
|
18
|
+
|
|
19
|
+
export default function Counter() {
|
|
20
|
+
const [count, setCount] = useState(0);
|
|
21
|
+
return <button onClick={() => setCount(count + 1)}>Clicked {count}</button>;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```mdx page.mdx
|
|
26
|
+
Here's a live counter: <Counter />
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The filename is the component name, so it **must be PascalCase**
|
|
30
|
+
(`Counter.tsx` → `<Counter />`). Lowercase filenames and two islands that
|
|
31
|
+
resolve to the same name are skipped with a build warning.
|
|
32
|
+
|
|
33
|
+
:::note
|
|
34
|
+
Islands are for **interactive** UI. For a static component you reuse across
|
|
35
|
+
pages (a styled callout, a pricing table), use an [MDX
|
|
36
|
+
override](/docs/configuration/customization) instead — it ships no JavaScript.
|
|
37
|
+
:::
|
|
38
|
+
|
|
39
|
+
## Hydration
|
|
40
|
+
|
|
41
|
+
By default an island uses `client:visible`: it hydrates when the reader scrolls
|
|
42
|
+
it into view, so a page full of islands still loads instantly. Opt into a
|
|
43
|
+
different strategy with an `export const client` in the island file:
|
|
44
|
+
|
|
45
|
+
```tsx islands/Chart.tsx lineNumbers
|
|
46
|
+
// Skip server rendering entirely — for components that touch the DOM/window.
|
|
47
|
+
export const client = "only";
|
|
48
|
+
|
|
49
|
+
export default function Chart() {
|
|
50
|
+
/* ... */
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| `client` value | Hydrates | Use it for |
|
|
55
|
+
| ----------------------- | ---------------------------------- | --------------------------------------------------------- |
|
|
56
|
+
| `"visible"` _(default)_ | When scrolled into view | Most islands |
|
|
57
|
+
| `"load"` | Immediately on page load | Above-the-fold, must-be-instant UI |
|
|
58
|
+
| `"idle"` | When the main thread is idle | Non-urgent interactivity |
|
|
59
|
+
| `"only"` | Client only, never server-rendered | Libraries that need `window`/`document` (charts, editors) |
|
|
60
|
+
|
|
61
|
+
## Frameworks
|
|
62
|
+
|
|
63
|
+
**React works out of the box** — Blume turns it on automatically the moment your
|
|
64
|
+
project contains a `.tsx`/`.jsx` island.
|
|
65
|
+
|
|
66
|
+
**Vue and Svelte** are supported too; install the matching Astro integration and
|
|
67
|
+
Blume wires up the renderer when it sees a `.vue` or `.svelte` island:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Vue
|
|
71
|
+
npm install @astrojs/vue vue
|
|
72
|
+
|
|
73
|
+
# Svelte
|
|
74
|
+
npm install @astrojs/svelte svelte
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```vue islands/Toggle.vue lineNumbers
|
|
78
|
+
<script setup>
|
|
79
|
+
import { ref } from "vue";
|
|
80
|
+
const on = ref(false);
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<template>
|
|
84
|
+
<button @click="on = !on">{{ on ? "On" : "Off" }}</button>
|
|
85
|
+
</template>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Props you pass in MDX (`<Counter start={5} />`) are forwarded to the component,
|
|
89
|
+
and children (`<Counter>label</Counter>`) arrive as the default slot.
|
|
90
|
+
|
|
91
|
+
:::tip
|
|
92
|
+
Islands hydrate on the client, so anything you pass as a prop must be
|
|
93
|
+
serializable — strings, numbers, plain objects, not functions.
|
|
94
|
+
:::
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Folder meta
|
|
3
|
+
description: Configure a sidebar group — its title, icon, order, display mode, and page order — with a meta.ts file.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Every folder in your content tree becomes a sidebar group. Drop a `meta.ts`
|
|
7
|
+
beside its pages to control how that group looks and how its children are
|
|
8
|
+
ordered. It's entirely optional: without one, the group's label is the humanized
|
|
9
|
+
folder name and its pages sort by [index, numeric prefix, then
|
|
10
|
+
alphabetically](/docs/content/navigation#ordering).
|
|
11
|
+
|
|
12
|
+
## Defining meta
|
|
13
|
+
|
|
14
|
+
Export a `defineMeta` object for a fully typed config. Place the file at the root
|
|
15
|
+
of the folder it configures — `guides/meta.ts` configures the **Guides** group:
|
|
16
|
+
|
|
17
|
+
```ts meta.ts lineNumbers
|
|
18
|
+
import { defineMeta } from "blume";
|
|
19
|
+
|
|
20
|
+
export default defineMeta({
|
|
21
|
+
title: "Guides",
|
|
22
|
+
icon: "book-open",
|
|
23
|
+
order: 2,
|
|
24
|
+
display: "flat",
|
|
25
|
+
collapsed: false,
|
|
26
|
+
pages: ["configuration", "theming", "deployment"],
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Every field is optional — set only what you want to override.
|
|
31
|
+
|
|
32
|
+
## Fields
|
|
33
|
+
|
|
34
|
+
| Field | Type | Description |
|
|
35
|
+
| ----------- | ----------------------------- | -------------------------------------------------------------------------------------- |
|
|
36
|
+
| `title` | `string` | The group's label. Defaults to the humanized folder name. |
|
|
37
|
+
| `icon` | `string` | Icon shown next to the label. |
|
|
38
|
+
| `order` | `number` | Position among sibling groups and pages. Lower numbers sort first. |
|
|
39
|
+
| `display` | `"flat" \| "group" \| "page"` | How the group renders in the sidebar. Defaults to `flat`. See [below](#display-modes). |
|
|
40
|
+
| `collapsed` | `boolean` | For `display: "group"`, whether the group starts collapsed. |
|
|
41
|
+
| `pages` | `string[]` | Explicit order for the group's children, by slug. |
|
|
42
|
+
|
|
43
|
+
The `pages` array lists children by slug — the folder or file name with its
|
|
44
|
+
numeric prefix and any parentheses stripped (so `01-quickstart.mdx` is
|
|
45
|
+
`"quickstart"`). Children you leave out still appear, after the listed ones.
|
|
46
|
+
|
|
47
|
+
## Display modes
|
|
48
|
+
|
|
49
|
+
`display` controls how a group and its items appear in the sidebar:
|
|
50
|
+
|
|
51
|
+
- **`flat`** (default) — a non-collapsible header with its pages listed beneath.
|
|
52
|
+
- **`group`** — a collapsible `<details>` disclosure. Pair it with `collapsed`
|
|
53
|
+
to set the initial state; a group containing the current page always starts
|
|
54
|
+
open.
|
|
55
|
+
- **`page`** — a single row that, when clicked, slides the sidebar into a
|
|
56
|
+
sub-panel showing only that group's items, with a back arrow at the top. The
|
|
57
|
+
panel is route-aware, so landing directly on a page inside the group opens
|
|
58
|
+
straight to it.
|
|
59
|
+
|
|
60
|
+
:::tip
|
|
61
|
+
`page` mode keeps deep sections tidy — reach for it when a group has many
|
|
62
|
+
children and you'd rather drill into it than scroll past it.
|
|
63
|
+
:::
|
|
64
|
+
|
|
65
|
+
`display` works the same on a group in an [explicit
|
|
66
|
+
sidebar](/docs/content/navigation#explicit-sidebar) config.
|
|
67
|
+
|
|
68
|
+
## Computed meta
|
|
69
|
+
|
|
70
|
+
Because `meta.ts` is a real module, you can compute the meta — pass a function
|
|
71
|
+
(sync or `async`) instead of an object to build it at scan time. Handy for
|
|
72
|
+
ordering pages from an external source:
|
|
73
|
+
|
|
74
|
+
```ts meta.ts
|
|
75
|
+
import { defineMeta } from "blume";
|
|
76
|
+
|
|
77
|
+
export default defineMeta(async () => ({
|
|
78
|
+
title: "Guides",
|
|
79
|
+
pages: await orderFromCms(),
|
|
80
|
+
}));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Ordering within a group
|
|
84
|
+
|
|
85
|
+
The `pages` array sets the order of a group's children. Anything it omits falls
|
|
86
|
+
back to each page's frontmatter `sidebar.order`, then the file system (an `index`
|
|
87
|
+
page first, then numeric prefixes, then alphabetical). For the full sidebar
|
|
88
|
+
precedence — including an explicit config sidebar — see [Navigation ›
|
|
89
|
+
Ordering](/docs/content/navigation#ordering).
|
|
90
|
+
|
|
91
|
+
To group pages _without_ adding a URL segment, you don't need a `meta.ts` at all:
|
|
92
|
+
use a parenthesized folder name — see [Pages › Group
|
|
93
|
+
folders](/docs/content#group-folders).
|
|
94
|
+
|
|
95
|
+
## Internationalization
|
|
96
|
+
|
|
97
|
+
Under [i18n](/docs/content/i18n), folder meta resolves per locale: put a
|
|
98
|
+
`meta.ts` under `fr/guides/` to order the French group independently.
|
|
99
|
+
|
|
100
|
+
For folder meta that's identical in every language, add a `$` marker so one file
|
|
101
|
+
serves all locales without duplication:
|
|
102
|
+
|
|
103
|
+
```txt
|
|
104
|
+
docs/guides/meta.$.ts (folder meta applied to every locale)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
A locale-specific `meta.ts` still overrides the shared `meta.$.ts` for that
|
|
108
|
+
language.
|
|
109
|
+
|
|
110
|
+
## Where to next
|
|
111
|
+
|
|
112
|
+
<CardGroup cols={2}>
|
|
113
|
+
<Card title="Navigation" href="/docs/content/navigation" icon="menu">
|
|
114
|
+
How the sidebar, breadcrumbs, and tabs are built.
|
|
115
|
+
</Card>
|
|
116
|
+
<Card title="Frontmatter" href="/docs/reference/frontmatter" icon="file">
|
|
117
|
+
Per-page metadata, including the `sidebar` overrides.
|
|
118
|
+
</Card>
|
|
119
|
+
</CardGroup>
|