blume 0.6.7 → 0.8.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/CHANGELOG.md +618 -0
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/cli/index.js +2609 -1041
- package/dist/cli/index.js.map +110 -103
- package/dist/types/ai/component-markdown.d.ts +34 -0
- package/dist/types/components/content/youtube.d.ts +18 -0
- package/dist/types/core/base-path.d.ts +47 -0
- package/dist/types/core/config-input.d.ts +110 -12
- package/dist/types/core/config.d.ts +6 -4
- package/dist/types/core/data.d.ts +4 -0
- package/dist/types/core/i18n-ui.d.ts +477 -135
- package/dist/types/core/schema.d.ts +309 -195
- package/dist/types/core/sources/types.d.ts +2 -0
- package/dist/types/core/types.d.ts +6 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/openapi/references.d.ts +60 -0
- package/docs/01-quickstart.mdx +5 -2
- package/docs/02-deployment.mdx +24 -9
- package/docs/03-faq.mdx +46 -16
- package/docs/advanced/custom-pages.mdx +1 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/configuration/ai.mdx +49 -10
- package/docs/configuration/customization.mdx +11 -0
- package/docs/configuration/index.mdx +33 -3
- package/docs/configuration/seo.mdx +2 -2
- package/docs/content/components.mdx +30 -3
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/islands.mdx +8 -0
- package/docs/content/navigation.mdx +3 -3
- package/docs/content/sources.mdx +1 -1
- package/docs/content/syntax.mdx +17 -2
- package/docs/index.mdx +2 -2
- package/docs/reference/cli.mdx +8 -6
- package/package.json +15 -4
- package/skills/blume/SKILL.md +5 -3
- package/skills/blume-update-docs/SKILL.md +3 -2
- package/src/ai/agent-readability.ts +11 -5
- package/src/ai/ask-context.ts +7 -2
- package/src/ai/ask-data.ts +3 -0
- package/src/ai/ask.ts +12 -7
- package/src/ai/component-markdown.ts +461 -0
- package/src/ai/llms.ts +143 -23
- package/src/ai/markdown.ts +35 -6
- package/src/ai/mcp/data.ts +33 -8
- package/src/ai/mcp/discovery.ts +10 -3
- package/src/ai/mcp/server.ts +24 -7
- package/src/ai/visibility.ts +74 -0
- package/src/astro/component-slots.ts +16 -4
- package/src/astro/examples.ts +12 -7
- package/src/astro/generate.ts +393 -189
- package/src/astro/index.ts +5 -1
- package/src/astro/integration.ts +9 -5
- package/src/astro/islands.ts +11 -5
- package/src/astro/markdown-negotiation.ts +2 -2
- package/src/astro/pages.ts +89 -22
- package/src/astro/templates.ts +259 -25
- package/src/blume-modules.d.ts +8 -0
- package/src/cli/commands/build.ts +131 -38
- package/src/cli/commands/check.ts +1 -1
- package/src/cli/commands/dev.ts +71 -17
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/eject.ts +47 -19
- package/src/cli/commands/init.ts +120 -180
- package/src/cli/commands/preview.ts +4 -1
- package/src/cli/commands/validate.ts +44 -2
- package/src/cli/dev-lock.ts +34 -19
- package/src/cli/eject-scripts.ts +72 -0
- package/src/cli/env.ts +15 -5
- package/src/cli/init/questions.ts +158 -0
- package/src/cli/init/scaffold.ts +380 -0
- package/src/cli/required-secrets.ts +2 -1
- package/src/components/content/AccordionItem.astro +23 -4
- package/src/components/content/Badge.astro +3 -1
- package/src/components/content/Card.astro +4 -2
- package/src/components/content/CodeBlock.astro +3 -0
- package/src/components/content/Component.astro +30 -16
- package/src/components/content/Diff.astro +3 -1
- package/src/components/content/Step.astro +10 -1
- package/src/components/content/Tabs.astro +15 -3
- package/src/components/content/Tile.astro +2 -1
- package/src/components/content/Tooltip.astro +3 -1
- package/src/components/content/Update.astro +9 -2
- package/src/components/content/auto-type-table.ts +25 -9
- package/src/components/content/base-href.ts +33 -0
- package/src/components/content/changelog-element.ts +9 -2
- package/src/components/content/diff.ts +12 -6
- package/src/components/content/mermaid-element.ts +10 -2
- package/src/components/index.ts +23 -1
- package/src/components/islands/AskAI.astro +5 -2
- package/src/components/islands/ask-ai.tsx +68 -12
- package/src/components/islands/base-path.ts +28 -0
- package/src/components/islands/hooks.ts +44 -9
- package/src/components/layout/Banner.astro +12 -3
- package/src/components/layout/Breadcrumbs.astro +2 -1
- package/src/components/layout/Favicon.astro +3 -2
- package/src/components/layout/Header.astro +15 -5
- package/src/components/layout/LanguageSwitcher.astro +2 -1
- package/src/components/layout/Logo.astro +13 -4
- package/src/components/layout/NavSelector.astro +2 -1
- package/src/components/layout/NavTree.astro +22 -7
- package/src/components/layout/PageActions.astro +25 -10
- package/src/components/layout/PageFeedback.astro +4 -1
- package/src/components/layout/PageLayout.astro +51 -9
- package/src/components/layout/Pagination.astro +3 -2
- package/src/components/layout/ReferenceLayout.astro +8 -1
- package/src/components/layout/RootLayout.astro +74 -13
- package/src/components/layout/Search.astro +107 -27
- package/src/components/layout/nav-utils.ts +18 -10
- package/src/components/layout/search/algolia.ts +11 -2
- package/src/components/layout/search/endpoint.ts +11 -5
- package/src/components/layout/search/orama-cloud.ts +8 -2
- package/src/components/layout/search/pagefind.ts +3 -0
- package/src/components/layout/search/types.ts +5 -1
- package/src/components/layout/search/typesense.ts +4 -1
- package/src/components/layout/toc-element.ts +8 -2
- package/src/components/openapi/ApiTagOperations.astro +2 -1
- package/src/components/openapi/Operation.astro +47 -40
- package/src/components/openapi/RequestPanel.astro +8 -2
- package/src/components/openapi/helpers.ts +71 -3
- package/src/components/openapi/panel.ts +1 -1
- package/src/components/openapi/snippets.ts +25 -11
- package/src/core/base-path.ts +94 -0
- package/src/core/builtin-tags.ts +2 -0
- package/src/core/component-overrides.ts +103 -74
- package/src/core/config-input.ts +118 -17
- package/src/core/config.ts +8 -5
- package/src/core/content.ts +2 -0
- package/src/core/data.ts +4 -0
- package/src/core/diagnostics.ts +54 -34
- package/src/core/gitignore.ts +4 -1
- package/src/core/graph.ts +166 -88
- package/src/core/i18n-ui.ts +63 -3
- package/src/core/last-modified.ts +15 -6
- package/src/core/links.ts +69 -25
- package/src/core/manifest.ts +62 -45
- package/src/core/nav-diagnostics.ts +1 -1
- package/src/core/navigation.ts +144 -58
- package/src/core/package-json.ts +17 -2
- package/src/core/project-graph.ts +25 -15
- package/src/core/schema.ts +605 -620
- package/src/core/sources/assets.ts +6 -1
- package/src/core/sources/filesystem.ts +4 -0
- package/src/core/sources/github-releases.ts +2 -1
- package/src/core/sources/mdx-remote.ts +76 -63
- package/src/core/sources/normalize.ts +236 -91
- package/src/core/sources/notion.ts +27 -18
- package/src/core/sources/types.ts +2 -0
- package/src/core/tsconfig-aliases.ts +59 -30
- package/src/core/types.ts +6 -1
- package/src/core/ui-packs/ar.ts +1 -0
- package/src/core/ui-packs/bg.ts +1 -0
- package/src/core/ui-packs/bn.ts +1 -0
- package/src/core/ui-packs/ca.ts +1 -0
- package/src/core/ui-packs/cs.ts +1 -0
- package/src/core/ui-packs/da.ts +1 -0
- package/src/core/ui-packs/de.ts +1 -0
- package/src/core/ui-packs/el.ts +1 -0
- package/src/core/ui-packs/es.ts +1 -0
- package/src/core/ui-packs/fa.ts +1 -0
- package/src/core/ui-packs/fi.ts +1 -0
- package/src/core/ui-packs/fr.ts +2 -1
- package/src/core/ui-packs/he.ts +1 -0
- package/src/core/ui-packs/hi.ts +1 -0
- package/src/core/ui-packs/hr.ts +1 -0
- package/src/core/ui-packs/hu.ts +1 -0
- package/src/core/ui-packs/id.ts +1 -0
- package/src/core/ui-packs/it.ts +1 -0
- package/src/core/ui-packs/ja.ts +1 -0
- package/src/core/ui-packs/ko.ts +1 -0
- package/src/core/ui-packs/nl.ts +1 -0
- package/src/core/ui-packs/no.ts +1 -0
- package/src/core/ui-packs/pl.ts +1 -0
- package/src/core/ui-packs/pt-br.ts +1 -0
- package/src/core/ui-packs/pt.ts +1 -0
- package/src/core/ui-packs/ro.ts +1 -0
- package/src/core/ui-packs/ru.ts +1 -0
- package/src/core/ui-packs/sk.ts +1 -0
- package/src/core/ui-packs/sr.ts +1 -0
- package/src/core/ui-packs/sv.ts +1 -0
- package/src/core/ui-packs/th.ts +1 -0
- package/src/core/ui-packs/tr.ts +1 -0
- package/src/core/ui-packs/uk.ts +1 -0
- package/src/core/ui-packs/vi.ts +1 -0
- package/src/core/ui-packs/zh-tw.ts +1 -0
- package/src/core/ui-packs/zh.ts +1 -0
- package/src/deploy/adapter-output.ts +18 -8
- package/src/deploy/redirects.ts +25 -2
- package/src/deploy/robots.ts +6 -1
- package/src/deploy/rss.ts +10 -3
- package/src/deploy/sitemap.ts +59 -13
- package/src/index.ts +5 -0
- package/src/markdown/base-links.ts +60 -0
- package/src/markdown/code-title.ts +11 -14
- package/src/markdown/index.ts +46 -9
- package/src/markdown/inline-code.ts +14 -4
- package/src/markdown/package-commands.ts +10 -4
- package/src/markdown/themes.ts +24 -0
- package/src/openapi/model.ts +15 -5
- package/src/openapi/parse.ts +21 -0
- package/src/openapi/references.ts +75 -21
- package/src/openapi/render-mdx.ts +11 -6
- package/src/openapi/scalar.ts +32 -16
- package/src/openapi/source.ts +59 -10
- package/src/registry/eject.ts +247 -19
- package/src/registry/registry.ts +0 -3
- package/src/search/build.ts +3 -0
- package/src/search/documents.ts +36 -4
- package/src/search/sync/typesense.ts +6 -4
- package/src/seo/jsonld.ts +28 -17
- package/src/theme/entry.ts +85 -20
|
@@ -108,6 +108,8 @@ export interface NormalizeContext {
|
|
|
108
108
|
prefix?: string;
|
|
109
109
|
staged: boolean;
|
|
110
110
|
};
|
|
111
|
+
/** Site-wide route mount point (`""` or `/seg`), prepended to every route. */
|
|
112
|
+
basePath?: string;
|
|
111
113
|
defaultType: string;
|
|
112
114
|
i18n?: ResolvedI18nConfig;
|
|
113
115
|
}
|
|
@@ -162,10 +162,14 @@ export interface NavSelectorItem {
|
|
|
162
162
|
icon?: string;
|
|
163
163
|
tag?: string;
|
|
164
164
|
}
|
|
165
|
+
/** Context-partition selector kinds (a versioned/localized/multi-product site). */
|
|
166
|
+
type NavSelectorContextKind = "product" | "version";
|
|
167
|
+
/** What a top-level partition selector switches between. */
|
|
168
|
+
type NavSelectorKind = "dropdown" | "language" | NavSelectorContextKind;
|
|
165
169
|
/** Top-level partition selectors (products, versions, languages). */
|
|
166
170
|
export interface NavSelector {
|
|
167
171
|
label: string;
|
|
168
|
-
kind:
|
|
172
|
+
kind: NavSelectorKind;
|
|
169
173
|
items: NavSelectorItem[];
|
|
170
174
|
}
|
|
171
175
|
/** A pinned link rendered above the sidebar sections (external or internal). */
|
|
@@ -252,3 +256,4 @@ export interface BlumeManifest {
|
|
|
252
256
|
output: ResolvedConfig["deployment"]["output"];
|
|
253
257
|
routes: RouteManifestEntry[];
|
|
254
258
|
}
|
|
259
|
+
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type { ComponentMarkdown, ComponentMarkdownChild, ComponentMarkdownContext, } from "./ai/component-markdown.ts";
|
|
1
2
|
export { defineConfig } from "./core/config.ts";
|
|
2
3
|
export type { BlumeBanner, BlumeData, BlumeDataConfig, BlumeDataI18n, BlumeDataLocale, BlumeFavicon, BlumeFeed, BlumeLogo, BlumeRoute, } from "./core/data.ts";
|
|
3
4
|
export { defineComponents } from "./core/define-components.ts";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ResolvedConfig } from "../core/schema.ts";
|
|
2
|
+
import type { NavTab } from "../core/types.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Pure resolution of the configured API reference blocks into concrete routes,
|
|
5
|
+
* labels, and a renderer choice — no file IO, so the content source, the nav
|
|
6
|
+
* tabs, the Scalar page generator, and the `blume:openapi` data module all share
|
|
7
|
+
* one source of truth. Kept free of any Astro/template imports so `core` can
|
|
8
|
+
* depend on it without a cycle.
|
|
9
|
+
*/
|
|
10
|
+
export type ReferenceKind = "openapi" | "asyncapi";
|
|
11
|
+
/** Who renders a reference: Blume's own UI, or the embedded Scalar SPA. */
|
|
12
|
+
export type ReferenceRenderer = "blume" | "scalar";
|
|
13
|
+
/** Per-block display options for the Blume renderer. */
|
|
14
|
+
export interface ReferenceDisplay {
|
|
15
|
+
/** Code-sample languages shown per operation. */
|
|
16
|
+
codeSamples: string[];
|
|
17
|
+
/** Whether nested schema rows start expanded. */
|
|
18
|
+
expandSchemas: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** A spec source resolved to a concrete route, label, and renderer. */
|
|
21
|
+
export interface ReferenceSource {
|
|
22
|
+
kind: ReferenceKind;
|
|
23
|
+
renderer: ReferenceRenderer;
|
|
24
|
+
/** Unique token derived from the route; the `<Operation source>` / data key. */
|
|
25
|
+
slug: string;
|
|
26
|
+
/** Normalized route the reference mounts at, e.g. `/reference`. */
|
|
27
|
+
route: string;
|
|
28
|
+
/**
|
|
29
|
+
* Site-wide `basePath` the rendered pages are mounted under (`""` when
|
|
30
|
+
* none). Kept separate from `route` — the content pipeline applies it to
|
|
31
|
+
* staged entries itself — so consumers prefix only the URLs they emit.
|
|
32
|
+
*/
|
|
33
|
+
basePath: string;
|
|
34
|
+
label: string;
|
|
35
|
+
/** Local path or `http(s)` URL, verbatim from config. */
|
|
36
|
+
spec: string;
|
|
37
|
+
/** Per-block Scalar theme name override, if any (Scalar renderer only). */
|
|
38
|
+
theme?: string;
|
|
39
|
+
/** Display options carried through to the Blume renderer. */
|
|
40
|
+
display: ReferenceDisplay;
|
|
41
|
+
/**
|
|
42
|
+
* Warnings recorded while deduping — another source's route collided with
|
|
43
|
+
* this one and was dropped. Surfaced as diagnostics when the source loads.
|
|
44
|
+
*/
|
|
45
|
+
collisions?: string[];
|
|
46
|
+
}
|
|
47
|
+
export declare const slugify: (text: string) => string;
|
|
48
|
+
/** Normalize a configured route to a single leading slash, no trailing slash. */
|
|
49
|
+
export declare const normalizeRoute: (route: string) => string;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve every enabled reference. OpenAPI honors its `renderer` (Blume's own UI
|
|
52
|
+
* by default); AsyncAPI is always rendered by Scalar for now.
|
|
53
|
+
*/
|
|
54
|
+
export declare const resolveReferences: (config: ResolvedConfig) => ReferenceSource[];
|
|
55
|
+
/** Nav tabs (header links) for every reference, regardless of renderer. */
|
|
56
|
+
export declare const referenceTabs: (config: ResolvedConfig) => NavTab[];
|
|
57
|
+
/** Blume-rendered OpenAPI references, deduped by route (first wins). */
|
|
58
|
+
export declare const blumeReferences: (config: ResolvedConfig) => ReferenceSource[];
|
|
59
|
+
/** Whether any reference is Scalar-rendered (gates the `@scalar/astro` dep + pages). */
|
|
60
|
+
export declare const hasScalarReferences: (config: ResolvedConfig) => boolean;
|
package/docs/01-quickstart.mdx
CHANGED
|
@@ -6,7 +6,7 @@ sidebar:
|
|
|
6
6
|
order: 1
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
Go from an empty folder to a running docs site in a few commands. Blume needs **Node.js 22 or newer** and a `docs/` folder with at least one `.md` or `.mdx` file — there's nothing else to set up.
|
|
9
|
+
Go from an empty folder to a running docs site in a few commands. Blume needs **Node.js 22.12 or newer** and a `docs/` folder with at least one `.md` or `.mdx` file — there's nothing else to set up.
|
|
10
10
|
|
|
11
11
|
## Install and run
|
|
12
12
|
|
|
@@ -20,7 +20,10 @@ Go from an empty folder to a running docs site in a few commands. Blume needs **
|
|
|
20
20
|
|
|
21
21
|
</Step>
|
|
22
22
|
<Step title="Scaffold a project">
|
|
23
|
-
`blume init`
|
|
23
|
+
`blume init` asks a few questions — where to create the project, what your
|
|
24
|
+
docs site is called, which template, and where your content lives — then
|
|
25
|
+
scaffolds the minimum surface: a content folder and a config file. Pass
|
|
26
|
+
`--yes` to skip the prompts and take the defaults.
|
|
24
27
|
|
|
25
28
|
```bash
|
|
26
29
|
blume init
|
package/docs/02-deployment.mdx
CHANGED
|
@@ -10,11 +10,11 @@ sidebar:
|
|
|
10
10
|
|
|
11
11
|
`blume build` compiles your docs to plain HTML, CSS, and a local search index in `dist/`. There's no server to run — point any static host at the folder.
|
|
12
12
|
|
|
13
|
-
| Setting | Value
|
|
14
|
-
| ---------------- |
|
|
15
|
-
| Build command | `blume build`
|
|
16
|
-
| Output directory | `dist`
|
|
17
|
-
| Node version | 22 or newer
|
|
13
|
+
| Setting | Value |
|
|
14
|
+
| ---------------- | -------------- |
|
|
15
|
+
| Build command | `blume build` |
|
|
16
|
+
| Output directory | `dist` |
|
|
17
|
+
| Node version | 22.12 or newer |
|
|
18
18
|
|
|
19
19
|
These settings work on Vercel, Netlify, Cloudflare Pages, GitHub Pages, Amazon S3 + CloudFront, or any bucket or CDN. Make sure `blume` is a dependency so the host can run the build.
|
|
20
20
|
|
|
@@ -54,7 +54,7 @@ blume preview
|
|
|
54
54
|
|
|
55
55
|
## Subpath deploys
|
|
56
56
|
|
|
57
|
-
Serving docs under a path like `example.com/docs`? Set `deployment.base` — common for GitHub Pages project sites.
|
|
57
|
+
Serving docs under a path like `example.com/docs`? Set `deployment.base` — common for GitHub Pages project sites. The whole site, root included, moves under the base, and internal links and assets are rewritten to include it.
|
|
58
58
|
|
|
59
59
|
```ts blume.config.ts lineNumbers
|
|
60
60
|
deployment: {
|
|
@@ -62,6 +62,21 @@ deployment: {
|
|
|
62
62
|
}
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
+
## Mount the docs under a path
|
|
66
|
+
|
|
67
|
+
`basePath` mounts every generated route under a segment (`/docs/getting-started`) while leaving the sidebar untouched — the top level is your sections, not a wrapper group. Use it when the docs live at `/docs/*` but the site root stays yours (like Docusaurus `routeBasePath` or Fumadocs `baseUrl`).
|
|
68
|
+
|
|
69
|
+
```ts blume.config.ts lineNumbers
|
|
70
|
+
basePath: "/docs",
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Write links as if mounted at root (`/getting-started`); Blume rewrites them, along with redirects, the sitemap, canonical URLs, Open Graph images, `llms.txt`, and the search index. Public assets (images, files under `public/`) stay at the site root.
|
|
74
|
+
|
|
75
|
+
This is a distinct concept from the two paths above:
|
|
76
|
+
|
|
77
|
+
- A per-source [`prefix`](/docs/content/sources#multiple-sources) namespaces **one** source and **does** add a sidebar group.
|
|
78
|
+
- `deployment.base` is the host subdirectory the **whole** app is served from. The two compose — with both set, a page lands at `{deployment.base}/{basePath}/page`.
|
|
79
|
+
|
|
65
80
|
## Server rendering
|
|
66
81
|
|
|
67
82
|
Static output covers most docs. Switch to server output when you need request-time features — most notably the [Ask AI](/docs/configuration/ai) endpoint:
|
|
@@ -73,7 +88,7 @@ deployment: {
|
|
|
73
88
|
}
|
|
74
89
|
```
|
|
75
90
|
|
|
76
|
-
|
|
91
|
+
The `vercel` and `node` adapters ship with Blume — choosing one just works. The `netlify` and `cloudflare` adapters must be installed in your project (e.g. `bun add -d @astrojs/netlify`); the CLI warns you if the package is missing:
|
|
77
92
|
|
|
78
93
|
| Adapter | Package | Use for |
|
|
79
94
|
| ------------ | --------------------- | ------------------------------------ |
|
|
@@ -82,7 +97,7 @@ Choosing an adapter pulls in the matching Astro adapter automatically:
|
|
|
82
97
|
| `node` | `@astrojs/node` | Self-hosted Node servers, containers |
|
|
83
98
|
| `cloudflare` | `@astrojs/cloudflare` | Cloudflare Workers and Pages |
|
|
84
99
|
|
|
85
|
-
On **Vercel**, **Netlify**, and **Cloudflare Pages**, Blume picks the matching adapter automatically for server output — set `output: "server"` and deploy. Set `adapter` explicitly to override the detected value, or when self-hosting with `node`.
|
|
100
|
+
On **Vercel**, **Netlify**, and **Cloudflare Pages**, Blume picks the matching adapter automatically for server output — set `output: "server"` and deploy (on Netlify and Cloudflare, install the adapter package too). Set `adapter` explicitly to override the detected value, or when self-hosting with `node`.
|
|
86
101
|
|
|
87
102
|
A server build includes everything a static build does, plus any Astro endpoints or middleware you add. The `node` adapter produces a standalone server you can run directly.
|
|
88
103
|
|
|
@@ -111,7 +126,7 @@ When a feature needs a runtime secret, Blume warns at `blume dev`/`build` if it'
|
|
|
111
126
|
| Feature | Variable |
|
|
112
127
|
| --- | --- |
|
|
113
128
|
| Ask AI (AI Gateway) | `AI_GATEWAY_API_KEY` (or Vercel OIDC) |
|
|
114
|
-
| Ask AI (
|
|
129
|
+
| Ask AI (other providers) | the provider's default key env var (`OPENROUTER_API_KEY`, `LLMGATEWAY_API_KEY`, `INKEEP_API_KEY`), or your configured `apiKeyEnv` |
|
|
115
130
|
| Mixedbread search | `MIXEDBREAD_API_KEY` |
|
|
116
131
|
|
|
117
132
|
Set them in `.env.local` for local dev and in your host's environment for production. Build-time secrets for search-index sync (Algolia, Orama Cloud, Typesense) are warned about separately during the sync step.
|
package/docs/03-faq.mdx
CHANGED
|
@@ -79,26 +79,26 @@ Once the opening `:::note` fence is joined to the prose, it's no longer a direct
|
|
|
79
79
|
|
|
80
80
|
### Why it happens
|
|
81
81
|
|
|
82
|
-
This is a bug in oxfmt's Markdown formatter (inherited from Prettier's Markdown printer — see [prettier/prettier#19040](https://github.com/prettier/prettier/pull/19040)). When it wraps prose, it treats the `:::` fence lines as ordinary text and joins them with the adjacent line, breaking the directive. It affects every container directive — `:::note`, `:::tip`, `:::warning`, `:::danger`, `:::success`.
|
|
82
|
+
This is a bug in oxfmt's Markdown formatter (inherited from Prettier's Markdown printer — see [prettier/prettier#19040](https://github.com/prettier/prettier/pull/19040)). When it wraps prose, it treats the `:::` fence lines as ordinary text and joins them with the adjacent line, breaking the directive. It affects every container directive type — `:::note`, `:::tip`, `:::info`, `:::warning`, `:::danger`, `:::success`.
|
|
83
83
|
|
|
84
84
|
We reported it upstream in [oxc-project/oxc#24096](https://github.com/oxc-project/oxc/issues/24096); until it's fixed there, the patch below is the workaround.
|
|
85
85
|
|
|
86
86
|
### The fix
|
|
87
87
|
|
|
88
|
-
Patch oxfmt so it preserves the line break that sits directly against a `:::` fence. Blume ships
|
|
88
|
+
Patch oxfmt so it preserves the line break that sits directly against a `:::` fence. Blume ships the same fix in its own repo, and you can apply it in any project.
|
|
89
89
|
|
|
90
|
-
1. Save the patch as `patches/oxfmt@0.
|
|
90
|
+
1. Save the patch as `patches/oxfmt@0.58.0.patch`:
|
|
91
91
|
|
|
92
|
-
```diff patches/oxfmt@0.
|
|
93
|
-
diff --git a/dist/markdown-
|
|
94
|
-
index
|
|
95
|
-
--- a/dist/markdown-
|
|
96
|
-
+++ b/dist/markdown-
|
|
97
|
-
@@ -
|
|
98
|
-
case "sentence": return
|
|
99
|
-
case "word": return
|
|
92
|
+
```diff patches/oxfmt@0.58.0.patch
|
|
93
|
+
diff --git a/dist/markdown-BjyDFyaO.js b/dist/markdown-BjyDFyaO.js
|
|
94
|
+
index 1905aa7563e612808426e26f1ed28bebbef3456f..42bb9f66829068676c5697fc9fc39279bf937f3e 100644
|
|
95
|
+
--- a/dist/markdown-BjyDFyaO.js
|
|
96
|
+
+++ b/dist/markdown-BjyDFyaO.js
|
|
97
|
+
@@ -4830,7 +4830,43 @@ function lu(e, t, r) {
|
|
98
|
+
case "sentence": return Mh(e, r);
|
|
99
|
+
case "word": return t.parser !== "mdx" ? Vh(e, t) : Gh(e);
|
|
100
100
|
case "whitespace": {
|
|
101
|
-
- let { next: i } = e, u = i && /^>|^(?:[*+-]|#{1,6}|\d+[).])
|
|
101
|
+
- let { next: i } = e, u = i && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(i.value) && !ME(e) && !(t.proseWrap === "preserve" && zE(e)) ? "never" : t.proseWrap;
|
|
102
102
|
+ let { next: i, previous: oxfmtFencePrev } = e;
|
|
103
103
|
+ // Preserve line breaks that sit directly against a `:::` container
|
|
104
104
|
+ // directive fence, so `proseWrap: "never"` keeps the opening/closing
|
|
@@ -106,8 +106,37 @@ Patch oxfmt so it preserves the line break that sits directly against a `:::` fe
|
|
|
106
106
|
+ // breaks the directive). Ordinary prose still wraps per proseWrap.
|
|
107
107
|
+ // See prettier/prettier#19040.
|
|
108
108
|
+ let oxfmtIsFence = (w) => w != null && typeof w.value === "string" && w.value.startsWith(":::");
|
|
109
|
-
+
|
|
110
|
-
|
|
109
|
+
+ // A titled directive (`:::warning[Heads up]`) parses its `[title]` as a
|
|
110
|
+
+ // linkReference between two sentence nodes at the paragraph level: the
|
|
111
|
+
+ // fence word ends the sentence before the reference, and the body's
|
|
112
|
+
+ // leading newline opens the sentence after it. So when this whitespace
|
|
113
|
+
+ // starts its sentence, climb to the paragraph and check whether the two
|
|
114
|
+
+ // preceding siblings are a (link) reference and a sentence ending in a
|
|
115
|
+
+ // `:::` fence word.
|
|
116
|
+
+ let oxfmtPrevIsTitledFence = !1;
|
|
117
|
+
+ if (oxfmtFencePrev == null && e.index === 0 && e.grandparent != null && Array.isArray(e.grandparent.children)) {
|
|
118
|
+
+ let oxfmtSibs = e.grandparent.children, oxfmtSentIdx = oxfmtSibs.indexOf(e.parent);
|
|
119
|
+
+ if (oxfmtSentIdx >= 2) {
|
|
120
|
+
+ let oxfmtLink = oxfmtSibs[oxfmtSentIdx - 1], oxfmtBefore = oxfmtSibs[oxfmtSentIdx - 2];
|
|
121
|
+
+ let oxfmtLastWord = oxfmtBefore && oxfmtBefore.type === "sentence" && Array.isArray(oxfmtBefore.children) ? oxfmtBefore.children[oxfmtBefore.children.length - 1] : null;
|
|
122
|
+
+ oxfmtPrevIsTitledFence = oxfmtLink != null && (oxfmtLink.type === "linkReference" || oxfmtLink.type === "link") && oxfmtIsFence(oxfmtLastWord);
|
|
123
|
+
+ }
|
|
124
|
+
+ }
|
|
125
|
+
+ // The plain-markdown parser keeps a titled fence's `[title]` as literal
|
|
126
|
+
+ // words, so the whole directive is one sentence. For a newline
|
|
127
|
+
+ // whitespace, walk back to the start of its visual line within the
|
|
128
|
+
+ // sentence; a line led by a `:::` word is a fence whose break must stay.
|
|
129
|
+
+ if (!oxfmtPrevIsTitledFence && e.node.value.includes("\n") && e.parent != null && Array.isArray(e.parent.children)) {
|
|
130
|
+
+ let oxfmtLineFirst = null;
|
|
131
|
+
+ for (let oxfmtJ = e.index - 1; oxfmtJ >= 0; oxfmtJ--) {
|
|
132
|
+
+ let oxfmtSib = e.parent.children[oxfmtJ];
|
|
133
|
+
+ if (oxfmtSib.type === "whitespace" && typeof oxfmtSib.value === "string" && oxfmtSib.value.includes("\n")) break;
|
|
134
|
+
+ oxfmtLineFirst = oxfmtSib;
|
|
135
|
+
+ }
|
|
136
|
+
+ oxfmtPrevIsTitledFence = oxfmtIsFence(oxfmtLineFirst);
|
|
137
|
+
+ }
|
|
138
|
+
+ let u = oxfmtIsFence(oxfmtFencePrev) || oxfmtPrevIsTitledFence || oxfmtIsFence(i) ? "preserve" : i && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(i.value) && !ME(e) && !(t.proseWrap === "preserve" && zE(e)) ? "never" : t.proseWrap;
|
|
139
|
+
return ou(e, n.value, u, !1, t);
|
|
111
140
|
}
|
|
112
141
|
case "emphasis": {
|
|
113
142
|
```
|
|
@@ -117,7 +146,7 @@ Patch oxfmt so it preserves the line break that sits directly against a `:::` fe
|
|
|
117
146
|
```json package.json
|
|
118
147
|
{
|
|
119
148
|
"patchedDependencies": {
|
|
120
|
-
"oxfmt@0.
|
|
149
|
+
"oxfmt@0.58.0": "patches/oxfmt@0.58.0.patch"
|
|
121
150
|
}
|
|
122
151
|
}
|
|
123
152
|
```
|
|
@@ -128,5 +157,6 @@ Patch oxfmt so it preserves the line break that sits directly against a `:::` fe
|
|
|
128
157
|
bun install
|
|
129
158
|
```
|
|
130
159
|
|
|
131
|
-
:::warning[Version-pinned]
|
|
160
|
+
:::warning[Version-pinned]
|
|
161
|
+
The patch targets a specific oxfmt build — its diff references a file whose name is hashed per release (`dist/markdown-*.js`). When you bump oxfmt, regenerate the patch (e.g. `bun patch oxfmt`) or check whether the upstream fix has landed and the patch is no longer needed.
|
|
132
162
|
:::
|
|
@@ -74,7 +74,7 @@ The module exposes:
|
|
|
74
74
|
type: "BlumeDataConfig",
|
|
75
75
|
required: true,
|
|
76
76
|
description:
|
|
77
|
-
"Resolved site settings: title, description, logo, favicon, appleIcon, banner, theme, site, repoUrl, search, i18n, mcp, og, analytics, feedback, structuredData, codeWrap, and imageZoom.",
|
|
77
|
+
"Resolved site settings: title, description, logo, favicon, appleIcon, banner, theme, site, repoUrl, search, i18n, mcp, ask, og, analytics, feedback, structuredData, toc, codeThemes, codeWrap, and imageZoom.",
|
|
78
78
|
},
|
|
79
79
|
navigation: {
|
|
80
80
|
type: "Navigation",
|
package/docs/advanced/skills.mdx
CHANGED
|
@@ -18,7 +18,7 @@ npx skills add haydenbleasel/blume
|
|
|
18
18
|
`blume-update-docs` keeps your docs in sync with the product they document. On each run — typically from a schedule you configure in your agent runner — it audits recently merged PRs, changelogs, config schemas, and CLI help against the docs content, updates only pages that are factually stale (feature-flagged work is ignored), verifies with `blume build`, and opens or updates a `blume/*` pull request. If nothing drifted, it reports a clean no-op instead of opening a noisy PR.
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npx skills
|
|
21
|
+
npx skills add haydenbleasel/blume --skill blume-update-docs
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
Blume doesn't host the automation — wire the skill into a scheduled task in Claude Code, a Codex or Cursor automation, or plain cron, with permission to read repo history and open PRs. A typical weekly prompt:
|
|
@@ -17,23 +17,62 @@ ai: {
|
|
|
17
17
|
|
|
18
18
|
While enabled, `blume build` writes two files to the root of your site:
|
|
19
19
|
|
|
20
|
-
- **`/llms.txt`** — a compact index: your site title and description, then a linked list of every page with its summary.
|
|
20
|
+
- **`/llms.txt`** — a compact index: your site title and description, then a linked list of every page with its summary, organized into sections that mirror your sidebar — folders and groups become headings, so an agent sees the docs' structure, not one flat blob.
|
|
21
21
|
- **`/llms-full.txt`** — the entire corpus: each page's full Markdown body, with its source URL, in one file.
|
|
22
22
|
|
|
23
23
|
Draft pages are excluded. Set [`deployment.site`](/docs/deployment) so the links and source URLs resolve to absolute addresses.
|
|
24
24
|
|
|
25
|
+
`llmsTxt` also takes an object form with knobs for what the files include. If your [API reference](/docs/advanced/api-reference) documents a placeholder or example spec, set `openapi: false` to keep its generated pages out of both files:
|
|
26
|
+
|
|
27
|
+
```ts blume.config.ts lineNumbers
|
|
28
|
+
ai: {
|
|
29
|
+
llmsTxt: {
|
|
30
|
+
enabled: true, // default
|
|
31
|
+
openapi: false, // exclude generated API reference pages
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To take full control of either file, add your own `llms.txt` or `llms-full.txt` to your `public/` folder. Like a custom favicon, it's picked up automatically and ships in place of the generated file — override one and Blume still generates the other.
|
|
37
|
+
|
|
25
38
|
## Raw Markdown
|
|
26
39
|
|
|
27
40
|
Append `.md` or `.mdx` to any page's URL to fetch its raw Markdown source — perfect for LLMs, coding agents, and "copy as Markdown" workflows. It's available for every page, in dev and production, with no configuration.
|
|
28
41
|
|
|
29
|
-
| URL | Returns
|
|
30
|
-
| ----------------- |
|
|
31
|
-
| `/quickstart` | The rendered page
|
|
32
|
-
| `/quickstart.md` |
|
|
33
|
-
| `/quickstart.mdx` | The raw
|
|
42
|
+
| URL | Returns |
|
|
43
|
+
| ----------------- | ----------------------------------------- |
|
|
44
|
+
| `/quickstart` | The rendered page |
|
|
45
|
+
| `/quickstart.md` | Plain Markdown, with components converted |
|
|
46
|
+
| `/quickstart.mdx` | The raw MDX source, exactly as written |
|
|
34
47
|
|
|
35
48
|
Nested routes work the same way (`/content/syntax.md`), and the home page is served at `/index.md`.
|
|
36
49
|
|
|
50
|
+
The `.md` variant _downlevels_ components to plain Markdown for consumers that can't interpret JSX: `<TypeTable>` becomes a Markdown table, `<Callout>` a labeled blockquote, `<Steps>` an ordered list, `<Tabs>` bold-labeled sections, and `<YouTube>` a link. Anything that can't be converted faithfully — a custom component, or a prop computed from an import — is left as-is, and component markup inside fenced code blocks is never touched. The same conversion applies to `llms-full.txt` and the MCP server's `get_page` tool, so every agent-facing surface reads clean Markdown. When you want the untransformed source, use the `.mdx` variant.
|
|
51
|
+
|
|
52
|
+
### Custom component serializers
|
|
53
|
+
|
|
54
|
+
Give your own components a Markdown form with `ai.markdownComponents` — a map of JSX name to serializer. Each serializer receives the component's `props` (statically evaluated from the MDX attributes) and its `children` (already downleveled to Markdown), and returns the replacement — or `null` to leave the JSX as-is:
|
|
55
|
+
|
|
56
|
+
```ts blume.config.ts lineNumbers
|
|
57
|
+
import { defineConfig } from "blume";
|
|
58
|
+
import type { ComponentMarkdown } from "blume";
|
|
59
|
+
|
|
60
|
+
const chart: ComponentMarkdown = ({ props }) =>
|
|
61
|
+
``;
|
|
62
|
+
|
|
63
|
+
export default defineConfig({
|
|
64
|
+
ai: {
|
|
65
|
+
markdownComponents: {
|
|
66
|
+
Chart: chart,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
For container components, `childComponents("Name")` extracts direct children by tag — the same way the built-in `<Steps>` serializer collects its `<Step>` items. A same-name entry replaces a built-in serializer, so you can restyle how `<Callout>` downlevels — or return `null` to opt one out entirely.
|
|
73
|
+
|
|
74
|
+
Serializers live in `blume.config.ts`, not `components.tsx`: the config file is executed at build time, while the components file is only statically analyzed (it may import `.astro` files, which can't run outside the site build). Your components themselves stay registered in `components.tsx` exactly as before — `markdownComponents` only adds their agent-facing Markdown form.
|
|
75
|
+
|
|
37
76
|
## Copy as Markdown
|
|
38
77
|
|
|
39
78
|
Every page carries a **Copy as Markdown** action — in the [page actions](/docs/content/navigation#page-actions) beneath the table of contents — that copies the page's raw Markdown to the clipboard. It's the same source served at the [`.md` URL](#raw-markdown) above, ready to paste into an LLM, an issue, or your notes. It's available on every page, in dev and production, with no configuration.
|
|
@@ -46,7 +85,7 @@ The **Open in chat** action opens the current page in an AI assistant — v0, Ch
|
|
|
46
85
|
|
|
47
86
|
Like Copy as Markdown, it needs no setup. The assistant fetches the page over its public URL, so it works as soon as the page is deployed.
|
|
48
87
|
|
|
49
|
-
To embed a ready-to-copy prompt inline in your content — rather than a whole-page action — use the [Prompt component](/docs/content/components#prompt), which renders a
|
|
88
|
+
To embed a ready-to-copy prompt inline in your content — rather than a whole-page action — use the [Prompt component](/docs/content/components#prompt), which renders a labeled row with a **Copy prompt** button and an optional open-in-Cursor link.
|
|
50
89
|
|
|
51
90
|
## Ask AI
|
|
52
91
|
|
|
@@ -172,7 +211,7 @@ mcp: {
|
|
|
172
211
|
| `name` | title | Server name shown to clients (defaults to title). |
|
|
173
212
|
| `instructions` | — | Optional system hint passed to connecting agents. |
|
|
174
213
|
|
|
175
|
-
The server exposes
|
|
214
|
+
The server exposes read-only tools — `search_docs`, `get_page`, `list_pages`, and `get_navigation` — and publishes discovery documents at `/.well-known/mcp.json` and `/.well-known/mcp/server-card.json`. Each page's **Connect to MCP** menu offers copy-and-go install for Claude Code, Cursor, VS Code, and Codex (shown once [`deployment.site`](/docs/deployment) is set).
|
|
176
215
|
|
|
177
216
|
`search_docs` runs its own full-text index, so it works regardless of your [search](/docs/configuration/search) provider — and even when search is set to `none`. The MCP server is a separate feature from on-page search.
|
|
178
217
|
|
|
@@ -196,7 +235,7 @@ claude mcp add --transport http my-docs https://docs.example.com/mcp
|
|
|
196
235
|
|
|
197
236
|
## Agent readability
|
|
198
237
|
|
|
199
|
-
Blume writes an **`/agent-readability.json`** manifest at your site root that indexes the agent-facing surface described on this page — so an agent can discover it in a single fetch instead of guessing at conventions or scraping HTML.
|
|
238
|
+
Blume writes an **`/agent-readability.json`** manifest at your site root that indexes the agent-facing surface described on this page — so an agent can discover it in a single fetch instead of guessing at conventions or scraping HTML. Like `llms.txt`, it's on by default:
|
|
200
239
|
|
|
201
240
|
```ts blume.config.ts lineNumbers
|
|
202
241
|
seo: {
|
|
@@ -241,4 +280,4 @@ npx skills add haydenbleasel/blume
|
|
|
241
280
|
|
|
242
281
|
The skill teaches the agent what Blume is and how to scaffold, write, and configure a site, and points it at the full docs bundled in the installed package (`node_modules/blume/docs`).
|
|
243
282
|
|
|
244
|
-
It's one of the [agent skills Blume ships](/docs/advanced/skills), alongside
|
|
283
|
+
It's one of the [agent skills Blume ships](/docs/advanced/skills), alongside a skill for keeping docs in sync with your product from a scheduled agent run.
|
|
@@ -154,3 +154,14 @@ blume eject --yes
|
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
Eject is a one-way step: the hidden `.blume/` runtime becomes a normal Astro app you own and can modify directly. The `blume` package stays importable, so you keep its components, theme, and Markdown processors.
|
|
157
|
+
|
|
158
|
+
### What eject leaves behind
|
|
159
|
+
|
|
160
|
+
After ejecting, your `build` script runs plain `astro build` — the site itself builds the same, but the artifacts `blume build` layered on top are no longer produced. The eject command warns about the ones your config actually uses. To keep them:
|
|
161
|
+
|
|
162
|
+
- **Pagefind search index** — with `search.provider: "pagefind"`, the search UI loads the index from the built site, so search breaks in production until you index it yourself. Install `pagefind` as a devDependency and index after each build: `"build": "astro build && pagefind --site dist"`.
|
|
163
|
+
- **Hosted search sync** — a hosted provider's index is no longer pushed on build; re-upload your search records after each build with the provider's API or CLI.
|
|
164
|
+
- **sitemap.xml** — recreate it with the standard [@astrojs/sitemap](https://docs.astro.build/en/guides/integrations-guide/sitemap/) integration.
|
|
165
|
+
- **robots.txt** — ship your own as `public/robots.txt`.
|
|
166
|
+
- **llms.txt / llms-full.txt and agent-readability.json** — write them by hand (or generate them in a build step of your own) and serve them from `public/`.
|
|
167
|
+
- **Platform redirect files** — `_redirects` and `vercel.json` are no longer emitted for static builds. Your redirects still work as Astro-generated meta-refresh pages, or you can move them into your host's own config.
|
|
@@ -53,6 +53,12 @@ export default defineConfig({
|
|
|
53
53
|
icons: true, // language icon in the code-block header
|
|
54
54
|
wrap: false, // wrap long lines instead of scrolling
|
|
55
55
|
},
|
|
56
|
+
codeBlocks: {
|
|
57
|
+
theme: {
|
|
58
|
+
light: "github-light", // any bundled Shiki theme
|
|
59
|
+
dark: "github-dark",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
56
62
|
},
|
|
57
63
|
|
|
58
64
|
// AI — see the AI guide
|
|
@@ -183,6 +189,24 @@ content: {
|
|
|
183
189
|
|
|
184
190
|
Static assets live in `public/` — a file at `public/logo.png` is served at `/logo.png`, so a reference like `` resolves against `public/images/create.png`.
|
|
185
191
|
|
|
192
|
+
## GitHub
|
|
193
|
+
|
|
194
|
+
Point Blume at your repository with `github`. It powers the header [repository link](/docs/content/navigation#repository-link) and the **Edit on GitHub** and **Give feedback** [page actions](/docs/content/navigation#page-actions):
|
|
195
|
+
|
|
196
|
+
```ts blume.config.ts lineNumbers
|
|
197
|
+
github: {
|
|
198
|
+
owner: "acme",
|
|
199
|
+
repo: "docs",
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
| Option | Default | Description |
|
|
204
|
+
| --- | --- | --- |
|
|
205
|
+
| `owner` | — | GitHub account or organization that owns the repository. |
|
|
206
|
+
| `repo` | — | Repository name. |
|
|
207
|
+
| `branch` | `"main"` | Branch that edit links point at. |
|
|
208
|
+
| `dir` | — | Path from the repo root to the project root (for monorepos). |
|
|
209
|
+
|
|
186
210
|
## Last modified
|
|
187
211
|
|
|
188
212
|
Show a "Last updated on …" line at the bottom of each page. Off by default; set `lastModified` to `true` to derive each page's date from its git history:
|
|
@@ -242,7 +266,13 @@ The on-this-page outline is on by default and lists `H2`–`H3` headings. Turn i
|
|
|
242
266
|
```ts blume.config.ts
|
|
243
267
|
export default defineConfig({
|
|
244
268
|
toc: false, // hide it everywhere
|
|
245
|
-
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Or narrow the heading range instead:
|
|
273
|
+
|
|
274
|
+
```ts blume.config.ts
|
|
275
|
+
export default defineConfig({
|
|
246
276
|
toc: { minHeadingLevel: 2, maxHeadingLevel: 4 },
|
|
247
277
|
});
|
|
248
278
|
```
|
|
@@ -255,8 +285,8 @@ Each of these has its own guide. The config field is the entry point:
|
|
|
255
285
|
| --- | --- | --- |
|
|
256
286
|
| `theme` | Accent color, corner radius, fonts, light/dark mode | [Theming](/docs/configuration/theming) |
|
|
257
287
|
| `navigation` | Explicit sidebar and header tabs | [Navigation](/docs/content/navigation) |
|
|
258
|
-
| `search` | Provider (Orama
|
|
259
|
-
| `markdown` |
|
|
288
|
+
| `search` | Provider (Orama, Pagefind, Algolia, and more) and indexing | [Search](/docs/configuration/search) |
|
|
289
|
+
| `markdown` | Markdown rendering options — code blocks, heading anchors, image zoom | [Syntax](/docs/content/syntax) |
|
|
260
290
|
| `ai` | `llms.txt`, Ask AI, and the MCP server | [AI](/docs/configuration/ai) |
|
|
261
291
|
| `mcp` | Hosted MCP server for coding agents | [AI](/docs/configuration/ai#mcp-server) |
|
|
262
292
|
| `analytics` | Vercel, PostHog, and custom scripts | [Analytics](/docs/configuration/analytics) |
|
|
@@ -5,7 +5,7 @@ sidebar:
|
|
|
5
5
|
label: SEO
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Blume handles the discoverability layer for you: page metadata, social share images, feeds, and structured data. The
|
|
8
|
+
Blume handles the discoverability layer for you: page metadata, social share images, feeds, and structured data. The configurable features live under the `seo` key in `blume.config.ts`; metadata is driven by your content.
|
|
9
9
|
|
|
10
10
|
```ts blume.config.ts lineNumbers
|
|
11
11
|
seo: {
|
|
@@ -225,6 +225,6 @@ seo: {
|
|
|
225
225
|
}}
|
|
226
226
|
/>
|
|
227
227
|
|
|
228
|
-
Content signals express a preference, not access control: they tell well-behaved crawlers how you'd like your content used, and it's on the crawler to
|
|
228
|
+
Content signals express a preference, not access control: they tell well-behaved crawlers how you'd like your content used, and it's on the crawler to honor them.
|
|
229
229
|
|
|
230
230
|
Ship your own `public/robots.txt` to take over.
|
|
@@ -428,7 +428,7 @@ A single row with a label and a copy button. The `description` (Markdown) is the
|
|
|
428
428
|
|
|
429
429
|
## Visibility
|
|
430
430
|
|
|
431
|
-
Show or hide content by audience. `for="web"` renders only on the site; `for="agents"` targets the
|
|
431
|
+
Show or hide content by audience. `for="web"` renders only on the site; `for="agents"` targets the agent-facing Markdown that AI agents read (`llms-full.txt` and each page's `.md` mirror).
|
|
432
432
|
|
|
433
433
|
<Visibility for="web">
|
|
434
434
|
This note appears on the website but is omitted from the agent-facing
|
|
@@ -546,7 +546,33 @@ A card linking to a GitHub repository with its live star and fork counts. Counts
|
|
|
546
546
|
|
|
547
547
|
`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.
|
|
548
548
|
|
|
549
|
-
The
|
|
549
|
+
The preview renders in an isolated frame that the docs styles never reach — no prose margins, typography, or theme chrome bleed into your component. The frame gets Tailwind (preflight + utilities scanned from your example files and anything they import), Blume's design tokens so classes like `bg-background` follow the site palette by default, and it follows the site's light/dark toggle live.
|
|
550
|
+
|
|
551
|
+
To style previews with your own design system — say, shadcn variables — point `examples.css` at a stylesheet. It's injected into every preview frame after Blume's defaults, so your tokens win. Don't `@import "tailwindcss"` in it; the frame already provides Tailwind. Both `.dark` and `[data-theme="dark"]` work for dark-mode overrides:
|
|
552
|
+
|
|
553
|
+
```ts
|
|
554
|
+
// blume.config.ts
|
|
555
|
+
export default defineConfig({
|
|
556
|
+
examples: { css: "examples/theme.css" },
|
|
557
|
+
});
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
```css
|
|
561
|
+
/* examples/theme.css */
|
|
562
|
+
:root {
|
|
563
|
+
--primary: oklch(0.6 0.2 260);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.dark {
|
|
567
|
+
--primary: oklch(0.75 0.15 260);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
@theme inline {
|
|
571
|
+
--color-primary: var(--primary);
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
The directory is configurable too — set `source` (or use the string shorthand, `examples: "..."`) when your examples live elsewhere (e.g. a registry layout). `path` is always relative to it:
|
|
550
576
|
|
|
551
577
|
```ts
|
|
552
578
|
// blume.config.ts
|
|
@@ -593,6 +619,7 @@ An Astro example renders live with no client JavaScript:
|
|
|
593
619
|
|
|
594
620
|
<CodeBlock
|
|
595
621
|
lang="ts"
|
|
622
|
+
icons={false}
|
|
596
623
|
code={`export const greet = (name: string): string =>
|
|
597
624
|
\`Hello, \${name}!\`;`}
|
|
598
625
|
/>
|
|
@@ -602,7 +629,7 @@ An Astro example renders live with no client JavaScript:
|
|
|
602
629
|
import CodeBlock from "blume/components/content/CodeBlock.astro";
|
|
603
630
|
---
|
|
604
631
|
|
|
605
|
-
<CodeBlock lang="ts" code={source} />
|
|
632
|
+
<CodeBlock lang="ts" code={source} icons={false} />
|
|
606
633
|
```
|
|
607
634
|
|
|
608
635
|
To highlight to an HTML string yourself (e.g. inside your own component), import the underlying helper from `blume/markdown`:
|
package/docs/content/i18n.mdx
CHANGED
|
@@ -108,7 +108,7 @@ When i18n is on, a language switcher appears in the header automatically, genera
|
|
|
108
108
|
|
|
109
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.**
|
|
110
110
|
|
|
111
|
-
Packs ship for
|
|
111
|
+
Packs ship for over 30 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.
|
|
112
112
|
|
|
113
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:
|
|
114
114
|
|
package/docs/content/islands.mdx
CHANGED
|
@@ -77,6 +77,14 @@ export default function Chart() {
|
|
|
77
77
|
|
|
78
78
|
**React works out of the box** — Blume turns it on automatically the moment your project contains a `.tsx`/`.jsx` island.
|
|
79
79
|
|
|
80
|
+
The [React Compiler](https://react.dev/learn/react-compiler) is on by default whenever React is enabled, so your islands are auto-memoized — no hand-written `useMemo`/`useCallback` needed. It ships with Blume; there's nothing to install. Opt out in `blume.config.ts`:
|
|
81
|
+
|
|
82
|
+
```ts blume.config.ts
|
|
83
|
+
export default defineConfig({
|
|
84
|
+
react: { compiler: false },
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
80
88
|
**Vue and Svelte** are supported too; install the matching Astro integration and Blume wires up the renderer when it sees a `.vue` or `.svelte` island:
|
|
81
89
|
|
|
82
90
|
```bash
|
|
@@ -147,7 +147,7 @@ navigation: {
|
|
|
147
147
|
}
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
Each link takes a `label`, an `href`, and an optional `icon` (a [built-in icon](/docs/
|
|
150
|
+
Each link takes a `label`, an `href`, and an optional `icon` (a [built-in icon](/docs/content/components#icon) name, image path/URL, or inline SVG — the same as anywhere else). An `href` may point anywhere: an external URL opens in a new tab, while an internal route (`/contact`) is validated against your pages at build time, warning you if nothing matches.
|
|
151
151
|
|
|
152
152
|
## Explicit sidebar
|
|
153
153
|
|
|
@@ -196,10 +196,10 @@ A right-rail outline is generated automatically from each page's `##` and `###`
|
|
|
196
196
|
|
|
197
197
|
Below the table of contents, every page shows a set of quick actions:
|
|
198
198
|
|
|
199
|
-
- **Edit
|
|
199
|
+
- **Edit on GitHub** — links straight to the source file. Appears once you set [`github`](/docs/configuration) in your config.
|
|
200
200
|
- **Scroll to top** — smoothly returns to the top of long pages.
|
|
201
201
|
- **Give feedback** — opens a prefilled GitHub issue with an optional reaction and note (also requires `github`).
|
|
202
202
|
|
|
203
|
-
|
|
203
|
+
Others hand the page to AI tools — **Copy as Markdown** and **Open in chat** — covered in [AI](/docs/configuration/ai#copy-as-markdown).
|
|
204
204
|
|
|
205
205
|
With [`export`](/docs/configuration/export) on, an **Export** action also lets readers download the page as a PDF or EPUB.
|