blume 0.3.0 → 0.4.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.
Files changed (81) hide show
  1. package/dist/cli/index.js +747 -471
  2. package/dist/cli/index.js.map +45 -38
  3. package/dist/types/core/schema.d.ts +289 -278
  4. package/dist/types/migrate/mintlify/assets.d.ts +8 -0
  5. package/docs/01-quickstart.mdx +5 -16
  6. package/docs/02-deployment.mdx +21 -54
  7. package/docs/advanced/api-reference.mdx +10 -37
  8. package/docs/advanced/blog.mdx +9 -25
  9. package/docs/advanced/changelog.mdx +10 -33
  10. package/docs/advanced/custom-pages.mdx +21 -78
  11. package/docs/configuration/ai.mdx +42 -103
  12. package/docs/configuration/analytics.mdx +20 -38
  13. package/docs/configuration/customization.mdx +40 -73
  14. package/docs/configuration/export.mdx +9 -34
  15. package/docs/configuration/index.mdx +67 -87
  16. package/docs/configuration/search.mdx +17 -54
  17. package/docs/configuration/seo.mdx +17 -48
  18. package/docs/configuration/theming.mdx +20 -42
  19. package/docs/content/components.mdx +42 -101
  20. package/docs/content/i18n.mdx +21 -72
  21. package/docs/content/index.mdx +18 -48
  22. package/docs/content/islands.mdx +25 -52
  23. package/docs/content/meta.mdx +23 -50
  24. package/docs/content/navigation.mdx +23 -62
  25. package/docs/content/sources.mdx +20 -83
  26. package/docs/content/syntax.mdx +37 -105
  27. package/docs/index.mdx +11 -40
  28. package/docs/reference/cli.mdx +18 -29
  29. package/docs/reference/frontmatter.mdx +2 -5
  30. package/package.json +1 -1
  31. package/src/astro/integration.ts +26 -3
  32. package/src/astro/islands.ts +6 -2
  33. package/src/astro/markdown-negotiation.ts +17 -3
  34. package/src/astro/pages.ts +6 -1
  35. package/src/astro/static-assets.ts +117 -0
  36. package/src/astro/templates.ts +48 -26
  37. package/src/cli/args.ts +23 -0
  38. package/src/cli/commands/build.ts +23 -0
  39. package/src/cli/commands/dev.ts +11 -2
  40. package/src/cli/commands/doctor.ts +10 -1
  41. package/src/cli/commands/eject.ts +3 -1
  42. package/src/cli/commands/init.ts +21 -1
  43. package/src/cli/commands/preview.ts +2 -1
  44. package/src/cli/commands/validate.ts +12 -1
  45. package/src/cli/dev-lock.ts +84 -0
  46. package/src/cli/log.ts +11 -0
  47. package/src/components/BlumePage.astro +2 -0
  48. package/src/components/content/YouTube.astro +35 -0
  49. package/src/components/content/youtube.ts +46 -0
  50. package/src/components/islands/ask-ai.tsx +14 -14
  51. package/src/components/props.ts +3 -0
  52. package/src/core/assets.ts +31 -0
  53. package/src/core/bridge.ts +10 -0
  54. package/src/core/builtin-tags.ts +1 -0
  55. package/src/core/diagnostics.ts +6 -1
  56. package/src/core/gitignore.ts +30 -0
  57. package/src/core/links.ts +60 -19
  58. package/src/core/schema.ts +7 -0
  59. package/src/core/sources/mdx-remote.ts +54 -8
  60. package/src/core/sources/normalize.ts +6 -1
  61. package/src/core/sources/notion.ts +49 -5
  62. package/src/core/sources/sanity.ts +5 -1
  63. package/src/deploy/rss.ts +1 -8
  64. package/src/deploy/sitemap.ts +20 -1
  65. package/src/deploy/xml.ts +8 -0
  66. package/src/markdown/directives.ts +15 -7
  67. package/src/markdown/package-commands.ts +26 -4
  68. package/src/migrate/fumadocs/content.ts +14 -1
  69. package/src/migrate/fumadocs/groups.ts +7 -0
  70. package/src/migrate/fumadocs/index.ts +5 -2
  71. package/src/migrate/mintlify/assets.ts +46 -0
  72. package/src/migrate/mintlify/index.ts +53 -45
  73. package/src/migrate/shared.ts +12 -27
  74. package/src/og/card.ts +14 -2
  75. package/src/registry/eject.ts +13 -3
  76. package/src/registry/registry.ts +6 -0
  77. package/src/registry/rewrite-imports.ts +31 -19
  78. package/src/search/documents.ts +23 -5
  79. package/src/search/sync/algolia.ts +5 -1
  80. package/src/search/sync/typesense.ts +24 -16
  81. package/src/theme/palette.ts +26 -7
@@ -3,16 +3,11 @@ title: Components
3
3
  description: The built-in JSX components — cards, columns, steps, tabs, accordions, badges, code groups, frames, trees, tooltips, type tables, live component previews, diffs, and a GitHub card — usable in any MDX page.
4
4
  ---
5
5
 
6
- Blume ships an accessible, themeable component set available in any `.mdx` page
7
- with **no imports**. Each one is shown below with a live preview and its source.
8
- Components are vanilla and React-free; React only switches on if you add your own
9
- island.
6
+ Blume ships an accessible, themeable component set available in any `.mdx` page with **no imports**. Each one is shown below with a live preview and its source. Components are vanilla and React-free; React only switches on if you add your own island.
10
7
 
11
8
  ## Card and CardGroup
12
9
 
13
- Cards link to a destination with an icon, title, and short blurb. Group them with
14
- `CardGroup` for a responsive grid. Reach for them on landing pages, section
15
- indexes, and “next steps” — anywhere you’re guiding the reader onward.
10
+ Cards link to a destination with an icon, title, and short blurb. Group them with `CardGroup` for a responsive grid. Reach for them on landing pages, section indexes, and “next steps” — anywhere you’re guiding the reader onward.
16
11
 
17
12
  <CardGroup cols={2}>
18
13
  <Card title="Quickstart" href="/docs/quickstart" icon="rocket">
@@ -34,13 +29,11 @@ indexes, and “next steps” — anywhere you’re guiding the reader onward.
34
29
  </CardGroup>
35
30
  ```
36
31
 
37
- `Card` takes `title`, an optional `href` (omit it for a non-clickable card), and
38
- an `icon` from Blume's built-in icon set. `CardGroup` takes `cols` (default `2`).
32
+ `Card` takes `title`, an optional `href` (omit it for a non-clickable card), and an `icon` from Blume's built-in icon set. `CardGroup` takes `cols` (default `2`).
39
33
 
40
34
  ## Steps
41
35
 
42
- A numbered vertical sequence for ordered instructions — installs, setup flows,
43
- and tutorials where the order matters. Each `Step` takes a `title`.
36
+ A numbered vertical sequence for ordered instructions — installs, setup flows, and tutorials where the order matters. Each `Step` takes a `title`.
44
37
 
45
38
  <Steps>
46
39
  <Step title="Install Blume">Add the package to your project.</Step>
@@ -62,9 +55,7 @@ and tutorials where the order matters. Each `Step` takes a `title`.
62
55
 
63
56
  ## Tabs
64
57
 
65
- Switch between equivalent content in place — language variants, OS-specific
66
- commands, or alternative approaches — without stacking everything on the page.
67
- Each `Tab` takes a `title`.
58
+ Switch between equivalent content in place — language variants, OS-specific commands, or alternative approaches — without stacking everything on the page. Each `Tab` takes a `title`.
68
59
 
69
60
  <Tabs>
70
61
  <Tab title="macOS">Use Homebrew to install the toolchain.</Tab>
@@ -80,8 +71,7 @@ Each `Tab` takes a `title`.
80
71
 
81
72
  ## Badge
82
73
 
83
- A small inline label for status or metadata — version tags, “new” or “beta”
84
- markers, stability levels. The `variant` tunes the color to the meaning.
74
+ A small inline label for status or metadata — version tags, “new” or “beta” markers, stability levels. The `variant` tunes the color to the meaning.
85
75
 
86
76
  ### Default
87
77
 
@@ -135,9 +125,7 @@ A negative or breaking state, such as a deprecation.
135
125
 
136
126
  ## Icon
137
127
 
138
- Render an icon from Blume's built-in set by name — the same set the `icon` props
139
- on cards, tiles, tabs, and sidebar entries draw from. Names are lowercase and
140
- kebab-cased (`rocket`, `book-open`, `chevron-right`).
128
+ Render an icon from Blume's built-in set by name — the same set the `icon` props on cards, tiles, tabs, and sidebar entries draw from. Names are lowercase and kebab-cased (`rocket`, `book-open`, `chevron-right`).
141
129
 
142
130
  <Icon icon="rocket" size={20} />
143
131
 
@@ -145,16 +133,11 @@ kebab-cased (`rocket`, `book-open`, `chevron-right`).
145
133
  <Icon icon="rocket" size={20} />
146
134
  ```
147
135
 
148
- `icon` is the icon name; `size` sets the pixel size (default `16`) and `color`
149
- tints it (any CSS color; defaults to `currentColor`). Pass a raw `<svg>` string,
150
- an image URL, or a local image path in place of a name to render your own art,
151
- and add a `label` to expose it to assistive tech — without one, the icon is
152
- decorative.
136
+ `icon` is the icon name; `size` sets the pixel size (default `16`) and `color` tints it (any CSS color; defaults to `currentColor`). Pass a raw `<svg>` string, an image URL, or a local image path in place of a name to render your own art, and add a `label` to expose it to assistive tech — without one, the icon is decorative.
153
137
 
154
138
  ## File tree
155
139
 
156
- Illustrate a project or folder layout. Wrap a normal Markdown list and Blume
157
- styles it as a tree — handy for explaining structure in setup and config guides.
140
+ Illustrate a project or folder layout. Wrap a normal Markdown list and Blume styles it as a tree — handy for explaining structure in setup and config guides.
158
141
 
159
142
  <FileTree>
160
143
 
@@ -180,10 +163,7 @@ styles it as a tree — handy for explaining structure in setup and config guide
180
163
 
181
164
  ## Accordion
182
165
 
183
- Stack related collapsibles in a single bordered container with dividers between
184
- them — FAQs, optional steps, or long examples. Each child is an `AccordionItem`
185
- (`title`, optional `icon`, `description`, `defaultOpen`). For a single standalone
186
- disclosure, use [Expandable](#expandable).
166
+ Stack related collapsibles in a single bordered container with dividers between them — FAQs, optional steps, or long examples. Each child is an `AccordionItem` (`title`, optional `icon`, `description`, `defaultOpen`). For a single standalone disclosure, use [Expandable](#expandable).
187
167
 
188
168
  <Accordion>
189
169
  <AccordionItem title="Does it support MDX?">
@@ -207,9 +187,7 @@ disclosure, use [Expandable](#expandable).
207
187
 
208
188
  ## Expandable
209
189
 
210
- A lightweight inline disclosure for nested detail — expanding a field's
211
- sub-properties or an optional aside. `title` labels the toggle (defaults to
212
- “Show more”); set `defaultOpen` to start expanded.
190
+ A lightweight inline disclosure for nested detail — expanding a field's sub-properties or an optional aside. `title` labels the toggle (defaults to “Show more”); set `defaultOpen` to start expanded.
213
191
 
214
192
  <Expandable title="Show advanced options">
215
193
  These settings are optional and rarely need changing.
@@ -223,8 +201,7 @@ sub-properties or an optional aside. `title` labels the toggle (defaults to
223
201
 
224
202
  ## Columns
225
203
 
226
- Lay cards or blocks out in a responsive grid of equal columns that reflows on
227
- mobile. `Columns` takes `cols`; wrap each cell in a `Column`.
204
+ Lay cards or blocks out in a responsive grid of equal columns that reflows on mobile. `Columns` takes `cols`; wrap each cell in a `Column`.
228
205
 
229
206
  <Columns cols={2}>
230
207
  <Column>
@@ -256,9 +233,7 @@ mobile. `Columns` takes `cols`; wrap each cell in a `Column`.
256
233
 
257
234
  ## CodeGroup
258
235
 
259
- Group several code blocks into one tabbed switcher — a tab per language or file.
260
- The tab label is each block's title (the text after the language). Add `dropdown`
261
- to switch with a menu instead of a tab bar.
236
+ Group several code blocks into one tabbed switcher — a tab per language or file. The tab label is each block's title (the text after the language). Add `dropdown` to switch with a menu instead of a tab bar.
262
237
 
263
238
  <CodeGroup>
264
239
 
@@ -302,8 +277,7 @@ fn greet(name: &str) -> String {
302
277
 
303
278
  ## Frame
304
279
 
305
- Wrap an image or any visual in a centered, bordered frame with an optional
306
- `caption` (rendered as Markdown) and `hint`.
280
+ Wrap an image or any visual in a centered, bordered frame with an optional `caption` (rendered as Markdown) and `hint`.
307
281
 
308
282
  <Frame
309
283
  caption="A **framed** illustration."
@@ -329,12 +303,20 @@ Wrap an image or any visual in a centered, bordered frame with an optional
329
303
  </Frame>
330
304
  ```
331
305
 
306
+ ## YouTube
307
+
308
+ Embed a YouTube video in a responsive, privacy-friendly (`youtube-nocookie.com`) 16:9 frame that ships no client JavaScript. Pass a video `id` or a full `url`, plus an optional `title` (for accessibility) and a `start` time in seconds.
309
+
310
+ <YouTube id="aqz-KE-bpKQ" title="Big Buck Bunny" />
311
+
312
+ ```astro lineNumbers
313
+ <YouTube id="aqz-KE-bpKQ" title="Big Buck Bunny" />
314
+ <YouTube url="https://youtu.be/aqz-KE-bpKQ" start={30} />
315
+ ```
316
+
332
317
  ## Color
333
318
 
334
- Show color swatches with copyable hex values — useful for documenting a palette
335
- or brand colors. Use `variant="compact"` for a swatch list, or `variant="table"`
336
- with `Color.Row` to group them. Each `Color.Item` takes a `name` and a `value`
337
- (a hex string, or `{ light, dark }` for theme-aware colors).
319
+ Show color swatches with copyable hex values — useful for documenting a palette or brand colors. Use `variant="compact"` for a swatch list, or `variant="table"` with `Color.Row` to group them. Each `Color.Item` takes a `name` and a `value` (a hex string, or `{ light, dark }` for theme-aware colors).
338
320
 
339
321
  <Color variant="compact">
340
322
  <Color.Item name="blue-500" value="#3B82F6" />
@@ -352,10 +334,7 @@ with `Color.Row` to group them. Each `Color.Item` takes a `name` and a `value`
352
334
 
353
335
  ## Tree
354
336
 
355
- Render a hierarchical file/folder structure with expandable folders. (For a
356
- quick, list-driven version see [File tree](#file-tree); `Tree` gives per-folder
357
- control.) Use `Tree.Folder` (`name`, optional `defaultOpen`, `openable`) and
358
- `Tree.File` (`name`).
337
+ Render a hierarchical file/folder structure with expandable folders. (For a quick, list-driven version see [File tree](#file-tree); `Tree` gives per-folder control.) Use `Tree.Folder` (`name`, optional `defaultOpen`, `openable`) and `Tree.File` (`name`).
359
338
 
360
339
  <Tree>
361
340
  <Tree.Folder name="src" defaultOpen>
@@ -395,8 +374,7 @@ A titled container for supplementary, set-aside content. `title` is optional.
395
374
 
396
375
  ## Tooltip
397
376
 
398
- Reveal a definition or hint on hover for an inline term. `tip` is the hover text;
399
- add an optional `headline` and a `cta` + `href` for a follow-up link.
377
+ Reveal a definition or hint on hover for an inline term. `tip` is the hover text; add an optional `headline` and a `cta` + `href` for a follow-up link.
400
378
 
401
379
  Hover the <Tooltip tip="A set of protocols software uses to communicate." headline="API" cta="Read the guide" href="/docs/quickstart">API</Tooltip> term to learn more.
402
380
 
@@ -406,9 +384,7 @@ Hover the <Tooltip tip="A set of protocols software uses to communicate." headli
406
384
 
407
385
  ## Tile
408
386
 
409
- A clickable preview that leads with a visual — an icon or image — above a title
410
- and description. Good for galleries and showcases. Takes `title`, `description`,
411
- and `href`; the child is the visual.
387
+ A clickable preview that leads with a visual — an icon or image — above a title and description. Good for galleries and showcases. Takes `title`, `description`, and `href`; the child is the visual.
412
388
 
413
389
  <Tile
414
390
  title="Quickstart"
@@ -430,10 +406,7 @@ and `href`; the child is the visual.
430
406
 
431
407
  ## Prompt
432
408
 
433
- A single row with a label and a copy button. The `description` (Markdown) is the
434
- visible label; the body is the prompt itself — hidden, and copied to the
435
- clipboard when the **Copy prompt** button is pressed. `actions` controls the
436
- buttons (e.g. `["copy", "cursor"]`).
409
+ A single row with a label and a copy button. The `description` (Markdown) is the visible label; the body is the prompt itself — hidden, and copied to the clipboard when the **Copy prompt** button is pressed. `actions` controls the buttons (e.g. `["copy", "cursor"]`).
437
410
 
438
411
  <Prompt
439
412
  description="Ask the model to **document** an endpoint."
@@ -453,8 +426,7 @@ buttons (e.g. `["copy", "cursor"]`).
453
426
 
454
427
  ## Visibility
455
428
 
456
- Show or hide content by audience. `for="web"` renders only on the site;
457
- `for="agents"` targets the generated Markdown (`llms.txt`) that AI agents read.
429
+ Show or hide content by audience. `for="web"` renders only on the site; `for="agents"` targets the generated Markdown (`llms.txt`) that AI agents read.
458
430
 
459
431
  <Visibility for="web">
460
432
  This note appears on the website but is omitted from the agent-facing
@@ -468,17 +440,11 @@ Show or hide content by audience. `for="web"` renders only on the site;
468
440
 
469
441
  ## Type tables
470
442
 
471
- Tables for documenting an object's properties — its props, types, and defaults.
472
- Write the rows by hand with `TypeTable`, or generate them straight from a
473
- TypeScript interface or type alias with `AutoTypeTable`.
443
+ Tables for documenting an object's properties — its props, types, and defaults. Write the rows by hand with `TypeTable`, or generate them straight from a TypeScript interface or type alias with `AutoTypeTable`.
474
444
 
475
445
  ### Type table
476
446
 
477
- A **Prop / Type** grid where each row expands to reveal its description and
478
- details. Pass a `type` map keyed by property name; each entry takes a `type`,
479
- plus an optional `description`, `default`, `required` flag, `typeDescription`,
480
- and `typeDescriptionLink`. Optional props (`required` unset) show a `?` after the
481
- name.
447
+ A **Prop / Type** grid where each row expands to reveal its description and details. Pass a `type` map keyed by property name; each entry takes a `type`, plus an optional `description`, `default`, `required` flag, `typeDescription`, and `typeDescriptionLink`. Optional props (`required` unset) show a `?` after the name.
482
448
 
483
449
  <TypeTable
484
450
  type={{
@@ -516,17 +482,13 @@ name.
516
482
 
517
483
  ### Auto type table
518
484
 
519
- Generate a type table from a TypeScript type so the docs stay in sync with the
520
- source. Point `AutoTypeTable` at a file with `path` (resolved from your project
521
- root) and a type `name`. Descriptions come from JSDoc comments, defaults from
522
- `@default` tags, and optional properties (`?`) are marked accordingly.
485
+ Generate a type table from a TypeScript type so the docs stay in sync with the source. Point `AutoTypeTable` at a file with `path` (resolved from your project root) and a type `name`. Descriptions come from JSDoc comments, defaults from `@default` tags, and optional properties (`?`) are marked accordingly.
523
486
 
524
487
  ```astro
525
488
  <AutoTypeTable path="./src/button.ts" name="ButtonProps" />
526
489
  ```
527
490
 
528
- You can also pass the type inline with `type` instead of a `path` — handy for
529
- small examples:
491
+ You can also pass the type inline with `type` instead of a `path` — handy for small examples:
530
492
 
531
493
  <AutoTypeTable
532
494
  name="ButtonProps"
@@ -566,11 +528,7 @@ export interface ButtonProps {
566
528
 
567
529
  ## GitHub info
568
530
 
569
- A card linking to a GitHub repository with its live star and fork counts.
570
- Counts are fetched at build time — no client JavaScript — and the card still
571
- renders if the API is unreachable. Pass `owner` and `repo`, or omit them to use
572
- the repository from your `blume.config`. Set a `GITHUB_TOKEN` environment
573
- variable to lift the API rate limit.
531
+ A card linking to a GitHub repository with its live star and fork counts. Counts are fetched at build time — no client JavaScript — and the card still renders if the API is unreachable. Pass `owner` and `repo`, or omit them to use the repository from your `blume.config`. Set a `GITHUB_TOKEN` environment variable to lift the API rate limit.
574
532
 
575
533
  <GithubInfo owner="withastro" repo="astro" />
576
534
 
@@ -584,16 +542,9 @@ variable to lift the API rate limit.
584
542
 
585
543
  ## Component
586
544
 
587
- `Component` renders an example file from your project's `examples/` directory as
588
- a live preview alongside its highlighted source, in tabs. Point it at a file with
589
- `path` — its location under `examples/`, without the extension (so
590
- `examples/counter.tsx` is `path="counter"`). React, Vue, Svelte, and Astro
591
- examples are all supported; framework examples hydrate, Astro ones render
592
- statically. It keeps the preview and the code in sync from a single file.
545
+ `Component` renders an example file from your project's `examples/` directory as a live preview alongside its highlighted source, in tabs. Point it at a file with `path` — its location under `examples/`, without the extension (so `examples/counter.tsx` is `path="counter"`). React, Vue, Svelte, and Astro examples are all supported; framework examples hydrate, Astro ones render statically. It keeps the preview and the code in sync from a single file.
593
546
 
594
- The directory is configurable — set `examples` in `blume.config.ts` when your
595
- examples live elsewhere (e.g. a registry layout). `path` is always relative to
596
- it:
547
+ The directory is configurable — set `examples` in `blume.config.ts` when your examples live elsewhere (e.g. a registry layout). `path` is always relative to it:
597
548
 
598
549
  ```ts
599
550
  // blume.config.ts
@@ -607,11 +558,7 @@ export default defineConfig({
607
558
  <Component path="file-list/basic" />
608
559
  ```
609
560
 
610
- `examples` can also be a glob (anything with `*`, `?`, `[]`, `{}`, or `!`). Only
611
- matching files are discovered, and `path` is relative to the glob's static prefix
612
- (the part before the first wildcard). This is for a registry that colocates each
613
- component's source with its example — point at just the examples so the sources,
614
- which have no default export to preview, aren't swept in:
561
+ `examples` can also be a glob (anything with `*`, `?`, `[]`, `{}`, or `!`). Only matching files are discovered, and `path` is relative to the glob's static prefix (the part before the first wildcard). This is for a registry that colocates each component's source with its example — point at just the examples so the sources, which have no default export to preview, aren't swept in:
615
562
 
616
563
  ```ts
617
564
  // blume.config.ts
@@ -640,9 +587,7 @@ An Astro example renders live with no client JavaScript:
640
587
 
641
588
  ## CodeBlock
642
589
 
643
- `CodeBlock` highlights a code string with the same Shiki theme and transformers
644
- as your fenced code — including the light/dark swap — for places a fence can't
645
- go, like a landing page or a custom component. Pass `code` and a `lang`:
590
+ `CodeBlock` highlights a code string with the same Shiki theme and transformers as your fenced code — including the light/dark swap — for places a fence can't go, like a landing page or a custom component. Pass `code` and a `lang`:
646
591
 
647
592
  <CodeBlock
648
593
  lang="ts"
@@ -658,8 +603,7 @@ import CodeBlock from "blume/components/content/CodeBlock.astro";
658
603
  <CodeBlock lang="ts" code={source} />
659
604
  ```
660
605
 
661
- To highlight to an HTML string yourself (e.g. inside your own component), import
662
- the underlying helper from `blume/markdown`:
606
+ To highlight to an HTML string yourself (e.g. inside your own component), import the underlying helper from `blume/markdown`:
663
607
 
664
608
  ```ts
665
609
  import { highlightCode } from "blume/markdown";
@@ -669,10 +613,7 @@ const html = await highlightCode(source, "ts");
669
613
 
670
614
  ## Diff
671
615
 
672
- `Diff` renders a git-style diff, highlighted with the same Shiki theme as your
673
- code blocks and produced entirely at build time — no client JavaScript. Give it
674
- two inline strings (`old` / `new`), two file paths (`before` / `after`), or a
675
- unified patch (an inline `patch` string or a `src` file).
616
+ `Diff` renders a git-style diff, highlighted with the same Shiki theme as your code blocks and produced entirely at build time — no client JavaScript. Give it two inline strings (`old` / `new`), two file paths (`before` / `after`), or a unified patch (an inline `patch` string or a `src` file).
676
617
 
677
618
  <Diff
678
619
  lang="ts"
@@ -3,10 +3,7 @@ title: Internationalization
3
3
  description: Serve your docs in multiple languages with locale-aware routing, per-language navigation, translated UI, and SEO — all convention-first.
4
4
  ---
5
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.
6
+ Blume serves one project in many languages. Drop translated files into the right place and Blume wires up routing, the language switcher, per-locale navigation, and SEO for you — there's no separate routing layer to maintain. It's opt-in: without an `i18n` block, your site stays single-language exactly as before.
10
7
 
11
8
  ## Enable it
12
9
 
@@ -23,20 +20,13 @@ i18n: {
23
20
  }
24
21
  ```
25
22
 
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).
23
+ Each locale has a `code` (used in URLs), a `label` (shown in the language switcher), and an optional `dir` for right-to-left scripts (`"ltr"` by default).
28
24
 
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
- :::
25
+ :::tip Migrating from Mintlify? `blume migrate mintlify` reads `navigation.languages[]` and writes the `i18n` block for you — the `default: true` language becomes `defaultLocale`, and translated folders already match Blume's layout. :::
35
26
 
36
27
  ## Organize translated content
37
28
 
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:
29
+ The default locale lives at your content root. Every other locale is a top-level folder named by its `code`, mirroring the default structure:
40
30
 
41
31
  ```txt
42
32
  docs/
@@ -55,13 +45,11 @@ docs/
55
45
  | `docs/guides/quickstart.mdx` | `/guides/quickstart` |
56
46
  | `docs/fr/guides/quickstart.mdx` | `/fr/guides/quickstart` |
57
47
 
58
- You only translate the files you want — everything else falls back automatically
59
- (see [Fallbacks](#fallbacks)).
48
+ You only translate the files you want — everything else falls back automatically (see [Fallbacks](#fallbacks)).
60
49
 
61
50
  ### Filename suffixes
62
51
 
63
- Prefer to keep translations next to the original? Set `parser: "dot"` and name
64
- files with a locale suffix instead of using folders:
52
+ Prefer to keep translations next to the original? Set `parser: "dot"` and name files with a locale suffix instead of using folders:
65
53
 
66
54
  ```txt
67
55
  docs/
@@ -69,13 +57,11 @@ docs/
69
57
  guides/quickstart.fr.mdx -> /fr/guides/quickstart (French)
70
58
  ```
71
59
 
72
- Good for sparse translations — colocate the few pages you've translated without
73
- mirroring the whole tree.
60
+ Good for sparse translations — colocate the few pages you've translated without mirroring the whole tree.
74
61
 
75
62
  ### Shared files
76
63
 
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:
64
+ For content that's the same in every language — a changelog, a status page — add a `$` marker so one file serves all locales without duplication:
79
65
 
80
66
  ```txt
81
67
  docs/changelog.$.mdx -> /changelog and /fr/changelog (same content)
@@ -86,9 +72,7 @@ A locale-specific `meta.ts` still overrides the shared one for that language.
86
72
 
87
73
  ## Default-locale URLs
88
74
 
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:
75
+ By default the default locale has no URL prefix (`/`, `/guides/quickstart`) while other locales are prefixed (`/fr/…`). This keeps your primary language's URLs clean. To prefix every locale, including the default:
92
76
 
93
77
  ```ts blume.config.ts lineNumbers
94
78
  i18n: {
@@ -99,17 +83,11 @@ i18n: {
99
83
 
100
84
  ## Per-locale navigation
101
85
 
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.
86
+ Each language gets its own sidebar, built from that locale's files — so translations can diverge in structure, ordering, or labels. Folder [`meta.ts`](/docs/content/meta) files resolve per locale, too: put a `meta.ts` under `fr/guides/` to order the French group independently. Everything else about [navigation](/docs/content/navigation) works the same, per language.
107
87
 
108
88
  ## Fallbacks
109
89
 
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`:
90
+ When a page isn't translated yet, Blume renders the fallback locale's content at the localized URL — so the link works, the page is fully pre-rendered, and search engines aren't sent to a dead end. The fallback defaults to your `defaultLocale`:
113
91
 
114
92
  ```ts blume.config.ts lineNumbers
115
93
  i18n: {
@@ -118,40 +96,21 @@ i18n: {
118
96
  }
119
97
  ```
120
98
 
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.
99
+ Fallback pages are excluded from the search index and aren't advertised as real translations in `hreflang`, so untranslated content doesn't compete for ranking. They still appear in that locale's sidebar, so navigation stays complete — a reader can reach every page in any language.
125
100
 
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
- :::
101
+ :::tip Start by translating your most important pages — the homepage, quickstart, and top guides — and let the rest fall back. You can fill in translations over time without breaking any links. :::
131
102
 
132
103
  ## The language switcher
133
104
 
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.
105
+ When i18n is on, a language switcher appears in the header automatically, generated from your `locales`. For each page it links the matching translation in every language; where a translation is missing it links the fallback page and marks it as not translated. There's nothing to configure.
138
106
 
139
107
  ## Translated UI
140
108
 
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.**
109
+ Blume ships built-in translations for its own interface chrome — “On this page”, “Search”, “Edit on GitHub”, and the rest — so a locale with a built-in pack gets translated UI out of the box. **You only translate your content.**
144
110
 
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.
111
+ Packs ship for 36 languages — Arabic, Bengali, Bulgarian, Catalan, Chinese (Simplified and Traditional), Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Norwegian, Persian, Polish, Portuguese (and Brazilian Portuguese), Romanian, Russian, Serbian, Slovak, Spanish, Swedish, Thai, Turkish, Ukrainian, and Vietnamese. They're community-maintained — open a PR to add a locale or sharpen a translation.
152
112
 
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:
113
+ Missing or unshipped strings fall back to the default locale, then to English. To override a string or supply your own language, set `i18n.ui`, keyed by locale:
155
114
 
156
115
  ```ts blume.config.ts lineNumbers
157
116
  i18n: {
@@ -170,28 +129,18 @@ i18n: {
170
129
  Localized SEO is handled for you — no per-page metadata to write:
171
130
 
172
131
  - `<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.
132
+ - `hreflang` alternates link every real translation of a page, plus an `x-default` pointing at the default locale.
175
133
  - Canonical URLs are locale-correct, and JSON-LD carries `inLanguage`.
176
134
 
177
- Set [`deployment.site`](/docs/deployment) so these can be emitted as absolute
178
- URLs.
135
+ Set [`deployment.site`](/docs/deployment) so these can be emitted as absolute URLs.
179
136
 
180
137
  ## Search
181
138
 
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.
139
+ Search is scoped to the active language: on a `/fr/…` page the dialog returns French results, with an **All languages** toggle to search across every locale at once. The default (Orama) and FlexSearch indexes filter in the browser; hosted providers carry a `locale` facet on each record.
186
140
 
187
141
  ## Right-to-left
188
142
 
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.
143
+ Set `dir: "rtl"` on a locale and Blume mirrors the whole interface — the sidebar, header, table of contents, pagination, search, and menus — and sets `<html dir>` to match. Two things deliberately stay left-to-right: **code blocks** (code reads LTR in any language) and **fallback content** — an untranslated page keeps the direction of the language it's actually written in, so English shown under an RTL locale still reads correctly while the surrounding chrome mirrors.
195
144
 
196
145
  ## Where to next
197
146
 
@@ -3,24 +3,18 @@ title: Pages
3
3
  description: How files in your content folder become pages, and how to organize them.
4
4
  ---
5
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.
6
+ Your docs are just a folder of Markdown and MDX files. Blume turns each file into a page — routing, navigation, and metadata are inferred from the file system, so there's no manifest to keep in sync.
9
7
 
10
- Content lives under your **content root** (`docs/` by default; change it with
11
- `content.root` in [`blume.config.ts`](/docs/configuration)).
8
+ Content lives under your **content root** (`docs/` by default; change it with `content.root` in [`blume.config.ts`](/docs/configuration)).
12
9
 
13
10
  ## Markdown and MDX
14
11
 
15
12
  Blume renders two kinds of file:
16
13
 
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).
14
+ - **`.md`** — Markdown for plain prose: GFM, frontmatter, smart punctuation, and super/subscript.
15
+ - **`.mdx`** — everything `.md` has, plus [components](/docs/content/components) and the MDX-only [directives, package installs, and math](/docs/content/syntax).
21
16
 
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.
17
+ Reach for `.md` when a page is just prose, and `.mdx` when it needs components or directives. Switching is as simple as renaming the file.
24
18
 
25
19
  ## Files and routes
26
20
 
@@ -33,26 +27,22 @@ Each file maps to a route by its path under the content root:
33
27
  | `docs/guides/theming.mdx` | `/guides/theming` |
34
28
  | `docs/guides/index.mdx` | `/guides` |
35
29
 
36
- Nested folders become nested routes, and an `index.mdx` inside a folder becomes
37
- that folder's own page.
30
+ Nested folders become nested routes, and an `index.mdx` inside a folder becomes that folder's own page.
38
31
 
39
32
  ## Ordering with numeric prefixes
40
33
 
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:
34
+ Prefix a file or folder with a number to control its order in the sidebar. The prefix is stripped from the URL, so you can reorder pages without breaking links:
43
35
 
44
36
  ```txt
45
37
  01-introduction.mdx -> /introduction
46
38
  02-installation.mdx -> /installation
47
39
  ```
48
40
 
49
- Ordering has several layers — see [Navigation](/docs/content/navigation) for the full
50
- precedence rules.
41
+ Ordering has several layers — see [Navigation](/docs/content/navigation) for the full precedence rules.
51
42
 
52
43
  ## Group folders
53
44
 
54
- Wrap a folder name in parentheses to group its pages in the sidebar **without**
55
- adding a URL segment:
45
+ Wrap a folder name in parentheses to group its pages in the sidebar **without** adding a URL segment:
56
46
 
57
47
  ```txt
58
48
  docs/(internal)/security.mdx -> /security
@@ -62,8 +52,7 @@ The pages share an “Internal” sidebar group but keep flat, parenthesis-free
62
52
 
63
53
  ## Drafts
64
54
 
65
- Mark a page as a draft to keep it out of production builds while still previewing
66
- it in `blume dev`:
55
+ Mark a page as a draft to keep it out of production builds while still previewing it in `blume dev`:
67
56
 
68
57
  ```yaml lineNumbers
69
58
  ---
@@ -76,9 +65,7 @@ draft: true
76
65
 
77
66
  ## Content types
78
67
 
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).
68
+ Every page has a **type**, set with the `type` frontmatter field (default `doc`). Types let Blume treat groups of pages differently — most importantly, `blog` and `changelog` pages are collected into [feeds](#feeds).
82
69
 
83
70
  ```yaml lineNumbers
84
71
  ---
@@ -91,25 +78,18 @@ changelog:
91
78
  ---
92
79
  ```
93
80
 
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.
81
+ The type is independent of where the file lives, but by convention blog posts go under `blog/` and changelog entries under `changelog/`. Both get an RSS feed automatically, and changelog entries are also collected into a generated [`/changelog` timeline](/docs/advanced/changelog). See [Blog](/docs/advanced/blog) and [Changelog](/docs/advanced/changelog) for authoring each.
99
82
 
100
83
  ## Feeds
101
84
 
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`:
85
+ Blume generates an RSS feed automatically for each content type listed in [`rss.types`](/docs/configuration/seo#rss-feeds) — `blog` and `changelog` by default — as long as it has at least one page. Feeds are served at `/<type>/rss.xml`:
105
86
 
106
87
  | Type | Feed |
107
88
  | ----------- | -------------------- |
108
89
  | `blog` | `/blog/rss.xml` |
109
90
  | `changelog` | `/changelog/rss.xml` |
110
91
 
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:
92
+ Give each entry a `date` so items sort newest-first and carry a `pubDate`. An unquoted YAML date is fine — Blume normalizes it:
113
93
 
114
94
  ```yaml lineNumbers
115
95
  ---
@@ -120,25 +100,15 @@ description: Why we built a markdown-first docs framework.
120
100
  ---
121
101
  ```
122
102
 
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.
103
+ Feeds need an absolute site URL, so set [`deployment.site`](/docs/deployment). Blume adds `<link rel="alternate">` tags to every page so browsers and feed readers discover them automatically. See [Blog](/docs/advanced/blog) and [Changelog](/docs/advanced/changelog) for authoring each content type.
127
104
 
128
105
  ## On this page
129
106
 
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.
107
+ Every page gets an automatic table of contents, built from its headings. On wide screens it sits in a sticky sidebar beside your content; on narrower screens it collapses into an **On this page** panel above the page. As you scroll, the entry for the section you're reading is highlighted, so you always know where you are in a long page.
135
108
 
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`).
109
+ Blume slugifies each heading into an anchor, so every entry links straight to its section — and you can deep-link to any heading by appending its slug to the URL (`.../my-page#getting-started`).
139
110
 
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.
111
+ The contents list your `##` and `###` headings (H2 and H3). A page with no headings at that level simply has no table of contents.
142
112
 
143
113
  ## Where to next
144
114