blume 0.5.0 → 0.5.2
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/dist/cli/index.js +160 -182
- package/dist/cli/index.js.map +17 -16
- package/dist/types/core/schema.d.ts +0 -26
- package/dist/types/core/types.d.ts +0 -6
- package/dist/types/migrate/mintlify/config.d.ts +14 -0
- package/docs/01-quickstart.mdx +6 -2
- package/docs/02-deployment.mdx +3 -1
- package/docs/advanced/api-reference.mdx +6 -2
- package/docs/advanced/bridge.mdx +3 -1
- package/docs/advanced/custom-pages.mdx +3 -1
- package/docs/advanced/migrate.mdx +6 -2
- package/docs/configuration/ai.mdx +3 -1
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/export.mdx +6 -2
- package/docs/configuration/seo.mdx +3 -1
- package/docs/content/i18n.mdx +6 -2
- package/docs/content/islands.mdx +6 -2
- package/docs/content/meta.mdx +3 -1
- package/docs/content/syntax.mdx +40 -14
- package/package.json +1 -1
- package/src/astro/generate.ts +11 -2
- package/src/astro/templates.ts +34 -8
- package/src/cli/commands/init.ts +2 -27
- package/src/core/graph.ts +0 -3
- package/src/core/nav-diagnostics.ts +2 -12
- package/src/core/navigation.ts +0 -10
- package/src/core/package-json.ts +32 -0
- package/src/core/schema.ts +0 -8
- package/src/core/sources/mintlify.ts +44 -1
- package/src/core/types.ts +0 -7
- package/src/migrate/mintlify/config.ts +40 -99
- package/src/migrate/mintlify/content.ts +16 -0
- package/src/migrate/mintlify/index.ts +42 -1
- package/src/migrate/mintlify/transform.ts +2 -0
- package/src/migrate/shared.ts +24 -1
|
@@ -2041,16 +2041,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2041
2041
|
}>, "many">>;
|
|
2042
2042
|
/** Explicit sidebar override; when omitted the sidebar is generated. */
|
|
2043
2043
|
sidebar: z.ZodOptional<z.ZodArray<z.ZodType<SidebarItemConfig, z.ZodTypeDef, SidebarItemConfig>, "many">>;
|
|
2044
|
-
sidebarVariants: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
2045
|
-
items: z.ZodDefault<z.ZodArray<z.ZodType<SidebarItemConfig, z.ZodTypeDef, SidebarItemConfig>, "many">>;
|
|
2046
|
-
path: z.ZodString;
|
|
2047
|
-
}, "strict", z.ZodTypeAny, {
|
|
2048
|
-
path: string;
|
|
2049
|
-
items: SidebarItemConfig[];
|
|
2050
|
-
}, {
|
|
2051
|
-
path: string;
|
|
2052
|
-
items?: SidebarItemConfig[] | undefined;
|
|
2053
|
-
}>, "many">>;
|
|
2054
2044
|
tabs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
2055
2045
|
icon: z.ZodOptional<z.ZodString>;
|
|
2056
2046
|
items: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -2127,10 +2117,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2127
2117
|
}[];
|
|
2128
2118
|
kind: "version" | "dropdown" | "language" | "product";
|
|
2129
2119
|
}[];
|
|
2130
|
-
sidebarVariants: {
|
|
2131
|
-
path: string;
|
|
2132
|
-
items: SidebarItemConfig[];
|
|
2133
|
-
}[];
|
|
2134
2120
|
sidebar?: SidebarItemConfig[] | undefined;
|
|
2135
2121
|
tabs?: {
|
|
2136
2122
|
path: string;
|
|
@@ -2175,10 +2161,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2175
2161
|
tag?: string | undefined;
|
|
2176
2162
|
}[] | undefined;
|
|
2177
2163
|
}[] | undefined;
|
|
2178
|
-
sidebarVariants?: {
|
|
2179
|
-
path: string;
|
|
2180
|
-
items?: SidebarItemConfig[] | undefined;
|
|
2181
|
-
}[] | undefined;
|
|
2182
2164
|
tabs?: {
|
|
2183
2165
|
path: string;
|
|
2184
2166
|
label: string;
|
|
@@ -2811,10 +2793,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2811
2793
|
}[];
|
|
2812
2794
|
kind: "version" | "dropdown" | "language" | "product";
|
|
2813
2795
|
}[];
|
|
2814
|
-
sidebarVariants: {
|
|
2815
|
-
path: string;
|
|
2816
|
-
items: SidebarItemConfig[];
|
|
2817
|
-
}[];
|
|
2818
2796
|
sidebar?: SidebarItemConfig[] | undefined;
|
|
2819
2797
|
tabs?: {
|
|
2820
2798
|
path: string;
|
|
@@ -3195,10 +3173,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
3195
3173
|
tag?: string | undefined;
|
|
3196
3174
|
}[] | undefined;
|
|
3197
3175
|
}[] | undefined;
|
|
3198
|
-
sidebarVariants?: {
|
|
3199
|
-
path: string;
|
|
3200
|
-
items?: SidebarItemConfig[] | undefined;
|
|
3201
|
-
}[] | undefined;
|
|
3202
3176
|
tabs?: {
|
|
3203
3177
|
path: string;
|
|
3204
3178
|
label: string;
|
|
@@ -168,11 +168,6 @@ export interface NavSelector {
|
|
|
168
168
|
kind: "dropdown" | "language" | "product" | "version";
|
|
169
169
|
items: NavSelectorItem[];
|
|
170
170
|
}
|
|
171
|
-
/** Sidebar tree used when the current route belongs to a nav partition. */
|
|
172
|
-
export interface NavSidebarVariant {
|
|
173
|
-
path: string;
|
|
174
|
-
sidebar: NavNode[];
|
|
175
|
-
}
|
|
176
171
|
/** Chrome overrides used when the current route belongs to a nav partition. */
|
|
177
172
|
export interface NavChromeVariant {
|
|
178
173
|
path: string;
|
|
@@ -184,7 +179,6 @@ export interface Navigation {
|
|
|
184
179
|
selectors: NavSelector[];
|
|
185
180
|
chromeVariants: NavChromeVariant[];
|
|
186
181
|
sidebar: NavNode[];
|
|
187
|
-
sidebarVariants: NavSidebarVariant[];
|
|
188
182
|
/** Repo URL for the header link, or null when hidden (`navigation.repo`). */
|
|
189
183
|
repoUrl?: string | null;
|
|
190
184
|
}
|
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
import type { BlumeConfig } from "../../core/schema.ts";
|
|
2
|
+
type JsonObject = Record<string, unknown>;
|
|
3
|
+
export interface MintlifyRedirectPartition {
|
|
4
|
+
/** Static redirects Blume can honor, translated to Blume's `from`/`to` shape. */
|
|
5
|
+
kept: NonNullable<BlumeConfig["redirects"]>;
|
|
6
|
+
/** Source paths of dynamic redirects dropped because Blume can't model them. */
|
|
7
|
+
dropped: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Split a spec's redirects into the static ones Blume emits and the dynamic
|
|
11
|
+
* (wildcard/param) ones it drops. Keeping a dynamic redirect crashes the Astro
|
|
12
|
+
* build, so the migrator surfaces the dropped sources as a warning instead.
|
|
13
|
+
*/
|
|
14
|
+
export declare const partitionMintlifyRedirects: (spec: JsonObject) => MintlifyRedirectPartition;
|
|
2
15
|
export declare const loadMintlifyConfig: (root: string, file: string) => Promise<BlumeConfig>;
|
|
16
|
+
export {};
|
package/docs/01-quickstart.mdx
CHANGED
|
@@ -51,7 +51,9 @@ Go from an empty folder to a running docs site in a few commands. Blume needs **
|
|
|
51
51
|
</Step>
|
|
52
52
|
</Steps>
|
|
53
53
|
|
|
54
|
-
:::tip
|
|
54
|
+
:::tip
|
|
55
|
+
Blume works with any package manager and never requires you to set up Astro or Tailwind yourself.
|
|
56
|
+
:::
|
|
55
57
|
|
|
56
58
|
## Write your first page
|
|
57
59
|
|
|
@@ -65,7 +67,9 @@ description: Welcome to my docs.
|
|
|
65
67
|
|
|
66
68
|
Welcome! Use **Markdown** and built-in components — no imports required:
|
|
67
69
|
|
|
68
|
-
:::note
|
|
70
|
+
:::note
|
|
71
|
+
Blume ships callouts, cards, tabs, steps, and more.
|
|
72
|
+
:::
|
|
69
73
|
```
|
|
70
74
|
|
|
71
75
|
Save it, and the dev server reloads instantly. Navigation, search, and page metadata are inferred from your files as you add them — keep writing, and the site keeps up.
|
package/docs/02-deployment.mdx
CHANGED
|
@@ -86,7 +86,9 @@ On **Vercel**, **Netlify**, and **Cloudflare Pages**, Blume picks the matching a
|
|
|
86
86
|
|
|
87
87
|
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
88
|
|
|
89
|
-
:::note
|
|
89
|
+
:::note
|
|
90
|
+
Server features have their own configuration — for example, Ask AI needs a model API key. See the [AI guide](/docs/configuration/ai) for setup.
|
|
91
|
+
:::
|
|
90
92
|
|
|
91
93
|
## Redirects
|
|
92
94
|
|
|
@@ -14,7 +14,9 @@ openapi: {
|
|
|
14
14
|
|
|
15
15
|
That mounts the reference at `/reference` (an overview page) with each operation at `/reference/<tag>/<operation>`, and adds a header tab. The `spec` is either an `http(s)` URL or a path to a local file in your project. Blume parses it with [Scalar's OpenAPI parser](https://github.com/scalar/scalar) — Swagger 2.0 and OpenAPI 3.0 specs are upgraded to 3.1 automatically.
|
|
16
16
|
|
|
17
|
-
:::note
|
|
17
|
+
:::note
|
|
18
|
+
Operations are indexed for search by their **summary and tag**. The rendered schema tables and code samples aren't full-text indexed; search matches an operation's title and section, then links to its own page.
|
|
19
|
+
:::
|
|
18
20
|
|
|
19
21
|
## A local spec
|
|
20
22
|
|
|
@@ -94,4 +96,6 @@ asyncapi: {
|
|
|
94
96
|
}
|
|
95
97
|
```
|
|
96
98
|
|
|
97
|
-
:::warning
|
|
99
|
+
:::warning
|
|
100
|
+
Scalar's AsyncAPI support is still a work in progress — it renders channels, operations, messages, and a Models section, but there's **no interactive playground** for events yet. It improves upstream over time.
|
|
101
|
+
:::
|
package/docs/advanced/bridge.mdx
CHANGED
|
@@ -26,7 +26,9 @@ Bridge mode is entirely automatic, gated on two conditions:
|
|
|
26
26
|
|
|
27
27
|
With both true, Blume treats the Mintlify config as its source of truth for that run.
|
|
28
28
|
|
|
29
|
-
:::note
|
|
29
|
+
:::note
|
|
30
|
+
Bridge mode applies to `blume build` too, not just `blume dev` — you can produce a static site from an unconverted Mintlify project. Only `blume dev` prints the detection notice.
|
|
31
|
+
:::
|
|
30
32
|
|
|
31
33
|
## What happens under the hood
|
|
32
34
|
|
|
@@ -260,7 +260,9 @@ import data from "blume:data";
|
|
|
260
260
|
</RootLayout>
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
-
:::note
|
|
263
|
+
:::note
|
|
264
|
+
`RootLayout` is part of the generated runtime, so its props can change between releases. When you want a layout that's fully yours, [`blume eject`](/docs/configuration/customization#eject) turns `.blume/` into a standard Astro project you own outright.
|
|
265
|
+
:::
|
|
264
266
|
|
|
265
267
|
## 404 page
|
|
266
268
|
|
|
@@ -18,7 +18,9 @@ The `<tool>` is the framework you're coming from:
|
|
|
18
18
|
| [Nextra](#nextra) | `content/` or `pages/` + `_meta` | `blume migrate nextra` |
|
|
19
19
|
| [Starlight](#starlight) | `src/content/docs` + `astro.config.*` | `blume migrate starlight` |
|
|
20
20
|
|
|
21
|
-
:::warning
|
|
21
|
+
:::warning
|
|
22
|
+
A migration **rewrites files in place** — pages, config, navigation, and assets. Commit (or stash) your work first so you can review the diff and roll back cleanly.
|
|
23
|
+
:::
|
|
22
24
|
|
|
23
25
|
## What a migration does
|
|
24
26
|
|
|
@@ -62,7 +64,9 @@ Reads `docs.json` (or legacy `mint.json`) and rewrites every page **in place**
|
|
|
62
64
|
- Fonts map to [`theme.fonts`](/docs/configuration/theming) when the family is one of Blume's curated Google Fonts (`fonts.family`, or a `heading`/`body` split); a family outside that set is warned about, not guessed. Header links (`navbar.links`/`navbar.primary`) and footer socials (`footer.socials`) have no `blume.config` equivalent yet, so they're reported as warnings rather than dropped silently — re-add them with [`navigation.tabs`](/docs/content/navigation) or a Header/Footer [layout override](/docs/advanced/custom-pages). The contextual page menu and last-updated timestamp are already Blume defaults.
|
|
63
65
|
- Field components — [`<ParamField>`, `<ResponseField>`, `<RequestField>`](/docs/content/components#api-fields) — render natively via Blume's compat components, so hand-written CLI/SDK/endpoint field docs carry over unchanged. Any remaining component with no Blume equivalent (e.g. `<Update>`) is flagged for manual review.
|
|
64
66
|
|
|
65
|
-
:::tip
|
|
67
|
+
:::tip
|
|
68
|
+
Want to preview Blume against a Mintlify codebase **without** rewriting anything? Run `blume dev` with no config and Blume serves `docs.json` as-is in [Bridge mode](/docs/advanced/bridge). Migrate when you're ready to commit.
|
|
69
|
+
:::
|
|
66
70
|
|
|
67
71
|
### Fumadocs
|
|
68
72
|
|
|
@@ -125,7 +125,9 @@ ai: {
|
|
|
125
125
|
|
|
126
126
|
Set `apiKeyEnv` (and, for the named providers, `baseUrl`) on any backend to point at a different env var or proxy.
|
|
127
127
|
|
|
128
|
-
:::note
|
|
128
|
+
:::note
|
|
129
|
+
**Inkeep** answers from the content you've indexed in the Inkeep dashboard — it runs its own retrieval — so Blume leaves it ungrounded. Every other backend is [grounded](#grounding) in this site's pages.
|
|
130
|
+
:::
|
|
129
131
|
|
|
130
132
|
Keys are read with `process.env`, which covers the Node, Vercel, and Netlify adapters. On Cloudflare, expose the key through the platform's [runtime binding](https://docs.astro.build/en/guides/integrations-guide/cloudflare/#environment-variables-and-secrets). Enabling Ask AI also turns on React for the in-page island — see [Customization](/docs/configuration/customization#interactive-islands).
|
|
131
133
|
|
|
@@ -7,7 +7,9 @@ Blume injects analytics for you from a single `analytics` block in `blume.config
|
|
|
7
7
|
|
|
8
8
|
Analytics loads in **production builds only**. The scripts are emitted by `blume build`, never by `blume dev`, so local traffic never reaches your dashboards and you don't need a separate "development" project.
|
|
9
9
|
|
|
10
|
-
:::note
|
|
10
|
+
:::note
|
|
11
|
+
Analytics is opt-in. With no `analytics` block, Blume injects nothing.
|
|
12
|
+
:::
|
|
11
13
|
|
|
12
14
|
## Vercel Web Analytics
|
|
13
15
|
|
|
@@ -30,7 +30,9 @@ Any format you omit (or set to `false`) is left out of the menu. With both off
|
|
|
30
30
|
|
|
31
31
|
Because it prints the live, fully-styled page, the result keeps crisp, selectable text, real fonts, and syntax-highlighted code. It needs no dependencies and works the same in dev, in production, and on static hosts.
|
|
32
32
|
|
|
33
|
-
:::note
|
|
33
|
+
:::note
|
|
34
|
+
PDF export goes through the browser's native print dialog, so the exact "Save as PDF" wording and options depend on the browser. Enable **Background graphics** in the dialog to keep code-block and callout backgrounds.
|
|
35
|
+
:::
|
|
34
36
|
|
|
35
37
|
## EPUB
|
|
36
38
|
|
|
@@ -42,4 +44,6 @@ To keep the file readable on a device with no stylesheet or JavaScript of its ow
|
|
|
42
44
|
|
|
43
45
|
Both formats export the **single page** a reader is viewing — not the whole site — which matches where the action lives, beneath that page's table of contents.
|
|
44
46
|
|
|
45
|
-
:::note
|
|
47
|
+
:::note
|
|
48
|
+
In an EPUB there's no JavaScript to switch tabs, so tabbed content — like [package-install](/docs/content/syntax) blocks and code groups — is expanded to show every panel at once. Client-rendered embeds such as Mermaid diagrams aren't included.
|
|
49
|
+
:::
|
|
@@ -94,7 +94,9 @@ seo:
|
|
|
94
94
|
---
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
:::note
|
|
97
|
+
:::note
|
|
98
|
+
OG rendering uses hex internally, so an `oklch` custom accent falls back to the default. Use a named accent (`blue`, `teal`, …) or a hex value for custom cards.
|
|
99
|
+
:::
|
|
98
100
|
|
|
99
101
|
`seo.image` is frontmatter, so it only covers Markdown and MDX content. To give a custom [`.astro` page](/docs/advanced/custom-pages) its own social image — a marketing home or landing page, and the way to give the home page alone a bespoke share image — pass the `ogImage` prop to `PageLayout`.
|
|
100
102
|
|
package/docs/content/i18n.mdx
CHANGED
|
@@ -22,7 +22,9 @@ i18n: {
|
|
|
22
22
|
|
|
23
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).
|
|
24
24
|
|
|
25
|
-
:::tip
|
|
25
|
+
:::tip
|
|
26
|
+
Migrating from Mintlify? [`blume migrate mintlify`](/docs/advanced/migrate) reads `navigation.languages[]` and writes the `i18n` block for you — the `default: true` language becomes `defaultLocale`, and translated folders already match Blume's layout.
|
|
27
|
+
:::
|
|
26
28
|
|
|
27
29
|
## Organize translated content
|
|
28
30
|
|
|
@@ -98,7 +100,9 @@ i18n: {
|
|
|
98
100
|
|
|
99
101
|
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.
|
|
100
102
|
|
|
101
|
-
:::tip
|
|
103
|
+
:::tip
|
|
104
|
+
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.
|
|
105
|
+
:::
|
|
102
106
|
|
|
103
107
|
## The language switcher
|
|
104
108
|
|
package/docs/content/islands.mdx
CHANGED
|
@@ -24,7 +24,9 @@ Here's a live counter: <Counter />
|
|
|
24
24
|
|
|
25
25
|
The filename is the component name, so it **must be a PascalCase identifier** — letters, digits, and underscores only (`Counter.tsx` → `<Counter />`). Lowercase filenames, names with dashes/dots/spaces (like `Time-Picker.tsx`), and two islands that resolve to the same name are skipped with a build warning.
|
|
26
26
|
|
|
27
|
-
:::note
|
|
27
|
+
:::note
|
|
28
|
+
Islands are for **interactive** UI. For a static component you reuse across pages (a styled callout, a pricing table), use an [MDX override](/docs/configuration/customization) instead — it ships no JavaScript.
|
|
29
|
+
:::
|
|
28
30
|
|
|
29
31
|
## Registering islands in `components.ts`
|
|
30
32
|
|
|
@@ -98,7 +100,9 @@ const on = ref(false);
|
|
|
98
100
|
|
|
99
101
|
Props you pass in MDX (`<Counter start={5} />`) are forwarded to the component, and children (`<Counter>label</Counter>`) arrive as the default slot.
|
|
100
102
|
|
|
101
|
-
:::tip
|
|
103
|
+
:::tip
|
|
104
|
+
Islands hydrate on the client, so anything you pass as a prop must be serializable — strings, numbers, plain objects, not functions.
|
|
105
|
+
:::
|
|
102
106
|
|
|
103
107
|
## Hooks
|
|
104
108
|
|
package/docs/content/meta.mdx
CHANGED
|
@@ -45,7 +45,9 @@ The `pages` array lists children by slug — the folder or file name with its nu
|
|
|
45
45
|
- **`group`** — a collapsible `<details>` disclosure. Pair it with `collapsed` to set the initial state; a group containing the current page always starts open.
|
|
46
46
|
- **`page`** — a single row that, when clicked, slides the sidebar into a sub-panel showing only that group's items, with a back arrow at the top. The panel is route-aware, so landing directly on a page inside the group opens straight to it.
|
|
47
47
|
|
|
48
|
-
:::tip
|
|
48
|
+
:::tip
|
|
49
|
+
`page` mode keeps deep sections tidy — reach for it when a group has many children and you'd rather drill into it than scroll past it.
|
|
50
|
+
:::
|
|
49
51
|
|
|
50
52
|
`display` works the same on a group in an [explicit sidebar](/docs/content/navigation#explicit-sidebar) config.
|
|
51
53
|
|
package/docs/content/syntax.mdx
CHANGED
|
@@ -242,7 +242,9 @@ config.title;
|
|
|
242
242
|
```
|
|
243
243
|
````
|
|
244
244
|
|
|
245
|
-
:::note
|
|
245
|
+
:::note
|
|
246
|
+
Hide the language icons or wrap long lines instead of scrolling with `markdown: { code: { icons: false, wrap: true } }` in `blume.config.ts`.
|
|
247
|
+
:::
|
|
246
248
|
|
|
247
249
|
## Package install
|
|
248
250
|
|
|
@@ -288,60 +290,82 @@ Callouts pull a reader's attention to context, advice, or risk. Write them as `:
|
|
|
288
290
|
|
|
289
291
|
Neutral, supporting context the reader should keep in mind.
|
|
290
292
|
|
|
291
|
-
:::note
|
|
293
|
+
:::note
|
|
294
|
+
Blume regenerates `.blume/` on every run — never edit it by hand.
|
|
295
|
+
:::
|
|
292
296
|
|
|
293
297
|
```md
|
|
294
|
-
:::note
|
|
298
|
+
:::note
|
|
299
|
+
Blume regenerates `.blume/` on every run — never edit it by hand.
|
|
300
|
+
:::
|
|
295
301
|
```
|
|
296
302
|
|
|
297
303
|
### Tip
|
|
298
304
|
|
|
299
305
|
A helpful shortcut or best practice that isn't required but makes life easier.
|
|
300
306
|
|
|
301
|
-
:::tip
|
|
307
|
+
:::tip
|
|
308
|
+
Set `deployment.site` so sitemaps and Open Graph images use absolute URLs.
|
|
309
|
+
:::
|
|
302
310
|
|
|
303
311
|
```md
|
|
304
|
-
:::tip
|
|
312
|
+
:::tip
|
|
313
|
+
Set `deployment.site` so sitemaps and Open Graph images use absolute URLs.
|
|
314
|
+
:::
|
|
305
315
|
```
|
|
306
316
|
|
|
307
317
|
### Success
|
|
308
318
|
|
|
309
319
|
Confirm a positive outcome or that a step completed as expected.
|
|
310
320
|
|
|
311
|
-
:::success
|
|
321
|
+
:::success
|
|
322
|
+
Your docs built successfully and are ready to deploy.
|
|
323
|
+
:::
|
|
312
324
|
|
|
313
325
|
```md
|
|
314
|
-
:::success
|
|
326
|
+
:::success
|
|
327
|
+
Your docs built successfully and are ready to deploy.
|
|
328
|
+
:::
|
|
315
329
|
```
|
|
316
330
|
|
|
317
331
|
### Warning
|
|
318
332
|
|
|
319
333
|
Flag something that needs care to avoid a mistake or surprising behavior.
|
|
320
334
|
|
|
321
|
-
:::warning[Heads up] Switching to `output: "server"` requires an adapter before you can deploy.
|
|
335
|
+
:::warning[Heads up] Switching to `output: "server"` requires an adapter before you can deploy.
|
|
336
|
+
:::
|
|
322
337
|
|
|
323
338
|
```md
|
|
324
|
-
:::warning[Heads up] Switching to `output: "server"` requires an adapter before you can deploy.
|
|
339
|
+
:::warning[Heads up] Switching to `output: "server"` requires an adapter before you can deploy.
|
|
340
|
+
:::
|
|
325
341
|
```
|
|
326
342
|
|
|
327
343
|
### Danger
|
|
328
344
|
|
|
329
345
|
Call out a destructive or breaking action that can't easily be undone.
|
|
330
346
|
|
|
331
|
-
:::danger
|
|
347
|
+
:::danger
|
|
348
|
+
`blume eject` is a one-way step — the generated Astro project becomes yours.
|
|
349
|
+
:::
|
|
332
350
|
|
|
333
351
|
```md
|
|
334
|
-
:::danger
|
|
352
|
+
:::danger
|
|
353
|
+
`blume eject` is a one-way step — the generated Astro project becomes yours.
|
|
354
|
+
:::
|
|
335
355
|
```
|
|
336
356
|
|
|
337
357
|
### Info
|
|
338
358
|
|
|
339
359
|
An informational aside; an alias-friendly default that reads as neutral.
|
|
340
360
|
|
|
341
|
-
:::info
|
|
361
|
+
:::info
|
|
362
|
+
The core theme ships no client framework JS.
|
|
363
|
+
:::
|
|
342
364
|
|
|
343
365
|
```md
|
|
344
|
-
:::info
|
|
366
|
+
:::info
|
|
367
|
+
The core theme ships no client framework JS.
|
|
368
|
+
:::
|
|
345
369
|
```
|
|
346
370
|
|
|
347
371
|
The names `caution`, `error`, `important`, and `warn` are accepted as aliases for `warning`, `danger`, `note`, and `warning` respectively.
|
|
@@ -364,7 +388,9 @@ $$
|
|
|
364
388
|
$$
|
|
365
389
|
```
|
|
366
390
|
|
|
367
|
-
:::note
|
|
391
|
+
:::note
|
|
392
|
+
Math is opt-in because `$` is common in prose and code. Enable it with `markdown: { math: true }` in `blume.config.ts`.
|
|
393
|
+
:::
|
|
368
394
|
|
|
369
395
|
## Smart punctuation
|
|
370
396
|
|
package/package.json
CHANGED
package/src/astro/generate.ts
CHANGED
|
@@ -618,7 +618,6 @@ export const buildRuntimeData = (project: BlumeProject): string => {
|
|
|
618
618
|
chromeVariants: [],
|
|
619
619
|
selectors: [],
|
|
620
620
|
sidebar: [],
|
|
621
|
-
sidebarVariants: [],
|
|
622
621
|
tabs: [],
|
|
623
622
|
}
|
|
624
623
|
),
|
|
@@ -974,6 +973,11 @@ export const generateRuntime = async (
|
|
|
974
973
|
// entryId so i18n duplicates of one entry write a single file.
|
|
975
974
|
const staged = collectStaged(project);
|
|
976
975
|
const hasStaged = staged.size > 0;
|
|
976
|
+
// Only emit a project-scanning `docs` collection when a filesystem source
|
|
977
|
+
// actually feeds it. Bridge mode has just the staged Mintlify source, so the
|
|
978
|
+
// `docs` glob would otherwise scan (and watch) the whole project root for
|
|
979
|
+
// nothing — see contentConfigTemplate.
|
|
980
|
+
const hasFilesystemSource = project.sources.some((source) => !source.staged);
|
|
977
981
|
|
|
978
982
|
const structural = await Promise.all([
|
|
979
983
|
write(
|
|
@@ -1004,7 +1008,12 @@ export const generateRuntime = async (
|
|
|
1004
1008
|
write(join(srcDir, "env.d.ts"), envTemplate()),
|
|
1005
1009
|
write(
|
|
1006
1010
|
join(srcDir, "content.config.ts"),
|
|
1007
|
-
contentConfigTemplate({
|
|
1011
|
+
contentConfigTemplate({
|
|
1012
|
+
config,
|
|
1013
|
+
context,
|
|
1014
|
+
filesystem: hasFilesystemSource,
|
|
1015
|
+
staged: hasStaged,
|
|
1016
|
+
})
|
|
1008
1017
|
),
|
|
1009
1018
|
write(
|
|
1010
1019
|
join(srcDir, "pages", "[...slug].astro"),
|
package/src/astro/templates.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
import { dirname, join } from "pathe";
|
|
3
|
+
import { dirname, isAbsolute, join, relative } from "pathe";
|
|
4
4
|
|
|
5
5
|
import { askBackendRuntimeDep } from "../ai/ask.ts";
|
|
6
6
|
import type { AskBackend } from "../ai/ask.ts";
|
|
@@ -392,18 +392,44 @@ export const contentConfigTemplate = (options: {
|
|
|
392
392
|
staged?: boolean;
|
|
393
393
|
/** Base dir for the staged collection; defaults to `<outDir>/content`. */
|
|
394
394
|
stagedBase?: string;
|
|
395
|
+
/**
|
|
396
|
+
* Whether any filesystem (non-staged) source feeds the `docs` collection.
|
|
397
|
+
* When false (e.g. Mintlify bridge mode, where every page is staged), the
|
|
398
|
+
* collection globs nothing — see below.
|
|
399
|
+
*/
|
|
400
|
+
filesystem?: boolean;
|
|
395
401
|
}): string => {
|
|
396
402
|
const { context, config } = options;
|
|
397
403
|
const stagedBase = options.stagedBase ?? stagedContentDir(context.outDir);
|
|
398
404
|
|
|
399
405
|
// Fold the content excludes into the glob as negative patterns so the `docs`
|
|
400
|
-
// collection
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
406
|
+
// collection doesn't ingest ignored trees (`node_modules`, `snippets`, the
|
|
407
|
+
// staged bodies under `.blume/content`, …) as entries. This matters when
|
|
408
|
+
// `content.root` is the project root (a migrated `.`-rooted project).
|
|
409
|
+
const outDirRel = relative(context.contentRoot, context.outDir);
|
|
410
|
+
const outDirIgnore =
|
|
411
|
+
outDirRel && !outDirRel.startsWith("..") && !isAbsolute(outDirRel)
|
|
412
|
+
? [`!${outDirRel}/**`]
|
|
413
|
+
: [];
|
|
414
|
+
|
|
415
|
+
// With no filesystem source, no route renders through `docs`, so glob nothing.
|
|
416
|
+
// Beyond skipping wasted work, this is the only thing that keeps Astro's
|
|
417
|
+
// content-layer *watcher* out of `.blume/`: bridge mode roots the collection
|
|
418
|
+
// at the project dir (which contains `.blume/.astro/fonts`, rewritten on every
|
|
419
|
+
// request), and the watcher's match test is `picomatch.isMatch(path, pattern)`
|
|
420
|
+
// — with array-OR semantics, any `!ignored/**` negation *matches* unrelated
|
|
421
|
+
// files, so negative patterns can't exclude a subtree there. An empty pattern
|
|
422
|
+
// matches nothing, so the watcher stays silent. The collection is still
|
|
423
|
+
// declared below so `getCollection("docs")` / `getEntry` resolve (to empty).
|
|
424
|
+
const filesystem = options.filesystem ?? true;
|
|
425
|
+
const docsPattern = filesystem
|
|
426
|
+
? [
|
|
427
|
+
...config.content.include,
|
|
428
|
+
...(config.content.exclude ?? []).map((pattern) => `!${pattern}`),
|
|
429
|
+
"!**/node_modules/**",
|
|
430
|
+
...outDirIgnore,
|
|
431
|
+
]
|
|
432
|
+
: [];
|
|
407
433
|
|
|
408
434
|
// Non-filesystem sources render through a parallel `staged` collection backed
|
|
409
435
|
// by materialized MDX, so the filesystem `docs` collection stays untouched.
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -5,35 +5,10 @@ import { defineCommand } from "citty";
|
|
|
5
5
|
import { basename, dirname, isAbsolute, join, relative } from "pathe";
|
|
6
6
|
|
|
7
7
|
import { ensureGitignore } from "../../core/gitignore.ts";
|
|
8
|
-
import {
|
|
8
|
+
import { blumePackageJson, toPackageName } from "../../core/package-json.ts";
|
|
9
9
|
import { eject } from "../../registry/eject.ts";
|
|
10
10
|
import { logger } from "../log.ts";
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Derive a valid npm package name from a directory name, falling back to
|
|
14
|
-
* `docs` when nothing usable remains.
|
|
15
|
-
*/
|
|
16
|
-
const toPackageName = (raw: string): string =>
|
|
17
|
-
raw
|
|
18
|
-
.toLowerCase()
|
|
19
|
-
.replaceAll(/[^a-z0-9._-]+/gu, "-")
|
|
20
|
-
.replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
|
|
21
|
-
|
|
22
|
-
const packageTemplate = (name: string, version: string): string => `{
|
|
23
|
-
"name": ${JSON.stringify(name)},
|
|
24
|
-
"private": true,
|
|
25
|
-
"type": "module",
|
|
26
|
-
"scripts": {
|
|
27
|
-
"dev": "blume dev",
|
|
28
|
-
"build": "blume build",
|
|
29
|
-
"doctor": "blume doctor"
|
|
30
|
-
},
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"blume": "^${version}"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
12
|
const TEMPLATES = ["docs", "api", "sdk", "changelog"] as const;
|
|
38
13
|
type Template = (typeof TEMPLATES)[number];
|
|
39
14
|
|
|
@@ -221,7 +196,7 @@ export const initCommand = defineCommand({
|
|
|
221
196
|
const starter = STARTERS[template];
|
|
222
197
|
const createdPackage = await writeFileSafe(
|
|
223
198
|
join(root, "package.json"),
|
|
224
|
-
|
|
199
|
+
blumePackageJson(toPackageName(basename(root)))
|
|
225
200
|
);
|
|
226
201
|
await writeFileSafe(join(root, "blume.config.ts"), starter.config);
|
|
227
202
|
await Promise.all(
|
package/src/core/graph.ts
CHANGED
|
@@ -96,7 +96,6 @@ export const buildContentGraph = (
|
|
|
96
96
|
selectors: options.navigation.selectors,
|
|
97
97
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
98
98
|
sidebar: options.navigation.sidebar,
|
|
99
|
-
sidebarVariants: options.navigation.sidebarVariants,
|
|
100
99
|
tabs,
|
|
101
100
|
});
|
|
102
101
|
}
|
|
@@ -104,7 +103,6 @@ export const buildContentGraph = (
|
|
|
104
103
|
chromeVariants: [],
|
|
105
104
|
selectors: [],
|
|
106
105
|
sidebar: [],
|
|
107
|
-
sidebarVariants: [],
|
|
108
106
|
tabs: [],
|
|
109
107
|
};
|
|
110
108
|
} else {
|
|
@@ -114,7 +112,6 @@ export const buildContentGraph = (
|
|
|
114
112
|
selectors: options.navigation.selectors,
|
|
115
113
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
116
114
|
sidebar: options.navigation.sidebar,
|
|
117
|
-
sidebarVariants: options.navigation.sidebarVariants,
|
|
118
115
|
tabs: options.navigation.tabs,
|
|
119
116
|
});
|
|
120
117
|
}
|
|
@@ -42,10 +42,7 @@ const collectIcons = (
|
|
|
42
42
|
push(item.icon, `selector "${item.label}"`);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
const sidebars = [
|
|
46
|
-
navigation.sidebar,
|
|
47
|
-
...navigation.sidebarVariants.map((variant) => variant.sidebar),
|
|
48
|
-
];
|
|
45
|
+
const sidebars = [navigation.sidebar];
|
|
49
46
|
for (const sidebar of sidebars) {
|
|
50
47
|
for (const node of flattenNodes(sidebar)) {
|
|
51
48
|
push(node.icon, `"${node.label}"`);
|
|
@@ -140,10 +137,6 @@ const duplicateLabelDiagnostics = (navigation: Navigation): Diagnostic[] => {
|
|
|
140
137
|
};
|
|
141
138
|
const sidebars: { nodes: NavNode[]; where: string }[] = [
|
|
142
139
|
{ nodes: navigation.sidebar, where: "at the top level" },
|
|
143
|
-
...navigation.sidebarVariants.map((variant) => ({
|
|
144
|
-
nodes: variant.sidebar,
|
|
145
|
-
where: `in the "${variant.path}" section`,
|
|
146
|
-
})),
|
|
147
140
|
];
|
|
148
141
|
for (const { nodes, where } of sidebars) {
|
|
149
142
|
checkLevel(nodes, where);
|
|
@@ -162,10 +155,7 @@ const hiddenInSidebarDiagnostics = (
|
|
|
162
155
|
if (hidden.size === 0) {
|
|
163
156
|
return [];
|
|
164
157
|
}
|
|
165
|
-
const sidebars = [
|
|
166
|
-
navigation.sidebar,
|
|
167
|
-
...navigation.sidebarVariants.map((variant) => variant.sidebar),
|
|
168
|
-
];
|
|
158
|
+
const sidebars = [navigation.sidebar];
|
|
169
159
|
const diagnostics: Diagnostic[] = [];
|
|
170
160
|
const seen = new Set<string>();
|
|
171
161
|
for (const sidebar of sidebars) {
|