blume 0.1.4 → 0.2.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/dist/cli/index.js +359 -152
- package/dist/cli/index.js.map +11 -9
- package/dist/types/core/schema.d.ts +110 -6
- package/docs/advanced/changelog.mdx +28 -1
- package/docs/advanced/custom-pages.mdx +0 -1
- package/docs/configuration/index.mdx +12 -11
- package/docs/configuration/search.mdx +13 -1
- package/docs/configuration/theming.mdx +51 -0
- package/docs/content/components.mdx +18 -0
- package/docs/content/navigation.mdx +8 -2
- package/docs/content/sources.mdx +43 -0
- package/docs/content/syntax.mdx +1 -1
- package/docs/index.mdx +1 -1
- package/docs/reference/cli.mdx +7 -1
- package/docs/reference/frontmatter.mdx +9 -1
- package/package.json +1 -1
- package/src/astro/generate.ts +30 -13
- package/src/astro/templates.ts +10 -1
- package/src/cli/env.ts +84 -0
- package/src/cli/index.ts +5 -0
- package/src/cli/prepare.ts +5 -0
- package/src/components/content/CodeBlock.astro +7 -2
- package/src/components/layout/nav-utils.ts +50 -6
- package/src/core/schema.ts +26 -0
- package/src/core/sources/github-releases.ts +200 -0
- package/src/core/sources/resolve.ts +16 -0
- package/src/markdown/index.ts +24 -0
- package/docs/changelog/v0-1-0.mdx +0 -12
- package/docs/changelog/v0-2-0.mdx +0 -16
|
@@ -475,6 +475,40 @@ declare const contentSourceSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
|
|
|
475
475
|
ref?: string | undefined;
|
|
476
476
|
} | undefined;
|
|
477
477
|
pollInterval?: number | undefined;
|
|
478
|
+
}>, z.ZodObject<{
|
|
479
|
+
/** Include draft releases (needs a token with repo write access). */
|
|
480
|
+
drafts: z.ZodOptional<z.ZodBoolean>;
|
|
481
|
+
/** Cap the number of releases materialized, newest-first. Default 100. */
|
|
482
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
483
|
+
/** Repository owner (user or org). */
|
|
484
|
+
owner: z.ZodString;
|
|
485
|
+
/** Opt-in dev polling interval (seconds); omit to freeze for the session. */
|
|
486
|
+
pollInterval: z.ZodOptional<z.ZodNumber>;
|
|
487
|
+
/** Namespaces the source's routes under `/<prefix>/`; e.g. `changelog`. */
|
|
488
|
+
prefix: z.ZodOptional<z.ZodString>;
|
|
489
|
+
/** Include prereleases. */
|
|
490
|
+
prereleases: z.ZodOptional<z.ZodBoolean>;
|
|
491
|
+
/** Repository name. */
|
|
492
|
+
repo: z.ZodString;
|
|
493
|
+
type: z.ZodLiteral<"github-releases">;
|
|
494
|
+
}, "strict", z.ZodTypeAny, {
|
|
495
|
+
type: "github-releases";
|
|
496
|
+
owner: string;
|
|
497
|
+
repo: string;
|
|
498
|
+
prefix?: string | undefined;
|
|
499
|
+
pollInterval?: number | undefined;
|
|
500
|
+
drafts?: boolean | undefined;
|
|
501
|
+
limit?: number | undefined;
|
|
502
|
+
prereleases?: boolean | undefined;
|
|
503
|
+
}, {
|
|
504
|
+
type: "github-releases";
|
|
505
|
+
owner: string;
|
|
506
|
+
repo: string;
|
|
507
|
+
prefix?: string | undefined;
|
|
508
|
+
pollInterval?: number | undefined;
|
|
509
|
+
drafts?: boolean | undefined;
|
|
510
|
+
limit?: number | undefined;
|
|
511
|
+
prereleases?: boolean | undefined;
|
|
478
512
|
}>, z.ZodObject<{
|
|
479
513
|
/** Sanity API version (a date); default `2024-01-01`. */
|
|
480
514
|
apiVersion: z.ZodOptional<z.ZodString>;
|
|
@@ -1119,6 +1153,40 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
1119
1153
|
ref?: string | undefined;
|
|
1120
1154
|
} | undefined;
|
|
1121
1155
|
pollInterval?: number | undefined;
|
|
1156
|
+
}>, z.ZodObject<{
|
|
1157
|
+
/** Include draft releases (needs a token with repo write access). */
|
|
1158
|
+
drafts: z.ZodOptional<z.ZodBoolean>;
|
|
1159
|
+
/** Cap the number of releases materialized, newest-first. Default 100. */
|
|
1160
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
1161
|
+
/** Repository owner (user or org). */
|
|
1162
|
+
owner: z.ZodString;
|
|
1163
|
+
/** Opt-in dev polling interval (seconds); omit to freeze for the session. */
|
|
1164
|
+
pollInterval: z.ZodOptional<z.ZodNumber>;
|
|
1165
|
+
/** Namespaces the source's routes under `/<prefix>/`; e.g. `changelog`. */
|
|
1166
|
+
prefix: z.ZodOptional<z.ZodString>;
|
|
1167
|
+
/** Include prereleases. */
|
|
1168
|
+
prereleases: z.ZodOptional<z.ZodBoolean>;
|
|
1169
|
+
/** Repository name. */
|
|
1170
|
+
repo: z.ZodString;
|
|
1171
|
+
type: z.ZodLiteral<"github-releases">;
|
|
1172
|
+
}, "strict", z.ZodTypeAny, {
|
|
1173
|
+
type: "github-releases";
|
|
1174
|
+
owner: string;
|
|
1175
|
+
repo: string;
|
|
1176
|
+
prefix?: string | undefined;
|
|
1177
|
+
pollInterval?: number | undefined;
|
|
1178
|
+
drafts?: boolean | undefined;
|
|
1179
|
+
limit?: number | undefined;
|
|
1180
|
+
prereleases?: boolean | undefined;
|
|
1181
|
+
}, {
|
|
1182
|
+
type: "github-releases";
|
|
1183
|
+
owner: string;
|
|
1184
|
+
repo: string;
|
|
1185
|
+
prefix?: string | undefined;
|
|
1186
|
+
pollInterval?: number | undefined;
|
|
1187
|
+
drafts?: boolean | undefined;
|
|
1188
|
+
limit?: number | undefined;
|
|
1189
|
+
prereleases?: boolean | undefined;
|
|
1122
1190
|
}>, z.ZodObject<{
|
|
1123
1191
|
/** Sanity API version (a date); default `2024-01-01`. */
|
|
1124
1192
|
apiVersion: z.ZodOptional<z.ZodString>;
|
|
@@ -1327,6 +1395,15 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
1327
1395
|
slug?: string | undefined;
|
|
1328
1396
|
} | undefined;
|
|
1329
1397
|
publishedValue?: string | undefined;
|
|
1398
|
+
} | {
|
|
1399
|
+
type: "github-releases";
|
|
1400
|
+
owner: string;
|
|
1401
|
+
repo: string;
|
|
1402
|
+
prefix?: string | undefined;
|
|
1403
|
+
pollInterval?: number | undefined;
|
|
1404
|
+
drafts?: boolean | undefined;
|
|
1405
|
+
limit?: number | undefined;
|
|
1406
|
+
prereleases?: boolean | undefined;
|
|
1330
1407
|
} | {
|
|
1331
1408
|
type: "mintlify";
|
|
1332
1409
|
exclude: string[];
|
|
@@ -1392,6 +1469,15 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
1392
1469
|
slug?: string | undefined;
|
|
1393
1470
|
} | undefined;
|
|
1394
1471
|
publishedValue?: string | undefined;
|
|
1472
|
+
} | {
|
|
1473
|
+
type: "github-releases";
|
|
1474
|
+
owner: string;
|
|
1475
|
+
repo: string;
|
|
1476
|
+
prefix?: string | undefined;
|
|
1477
|
+
pollInterval?: number | undefined;
|
|
1478
|
+
drafts?: boolean | undefined;
|
|
1479
|
+
limit?: number | undefined;
|
|
1480
|
+
prereleases?: boolean | undefined;
|
|
1395
1481
|
} | {
|
|
1396
1482
|
type: "mintlify";
|
|
1397
1483
|
exclude?: string[] | undefined;
|
|
@@ -2606,12 +2692,12 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2606
2692
|
/** Content types that each get a feed at `/<type>/rss.xml`. */
|
|
2607
2693
|
types: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
2608
2694
|
}, "strict", z.ZodTypeAny, {
|
|
2609
|
-
enabled: boolean;
|
|
2610
2695
|
limit: number;
|
|
2696
|
+
enabled: boolean;
|
|
2611
2697
|
types: string[];
|
|
2612
2698
|
}, {
|
|
2613
|
-
enabled?: boolean | undefined;
|
|
2614
2699
|
limit?: number | undefined;
|
|
2700
|
+
enabled?: boolean | undefined;
|
|
2615
2701
|
types?: string[] | undefined;
|
|
2616
2702
|
}>>;
|
|
2617
2703
|
/** Generate sitemap.xml (requires deployment.site). */
|
|
@@ -2620,8 +2706,8 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2620
2706
|
structuredData: z.ZodDefault<z.ZodBoolean>;
|
|
2621
2707
|
}, "strict", z.ZodTypeAny, {
|
|
2622
2708
|
rss: {
|
|
2623
|
-
enabled: boolean;
|
|
2624
2709
|
limit: number;
|
|
2710
|
+
enabled: boolean;
|
|
2625
2711
|
types: string[];
|
|
2626
2712
|
};
|
|
2627
2713
|
metatags: Record<string, string>;
|
|
@@ -2633,8 +2719,8 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2633
2719
|
structuredData: boolean;
|
|
2634
2720
|
}, {
|
|
2635
2721
|
rss?: {
|
|
2636
|
-
enabled?: boolean | undefined;
|
|
2637
2722
|
limit?: number | undefined;
|
|
2723
|
+
enabled?: boolean | undefined;
|
|
2638
2724
|
types?: string[] | undefined;
|
|
2639
2725
|
} | undefined;
|
|
2640
2726
|
metatags?: Record<string, string> | undefined;
|
|
@@ -2752,8 +2838,8 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2752
2838
|
};
|
|
2753
2839
|
seo: {
|
|
2754
2840
|
rss: {
|
|
2755
|
-
enabled: boolean;
|
|
2756
2841
|
limit: number;
|
|
2842
|
+
enabled: boolean;
|
|
2757
2843
|
types: string[];
|
|
2758
2844
|
};
|
|
2759
2845
|
metatags: Record<string, string>;
|
|
@@ -2817,6 +2903,15 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
2817
2903
|
slug?: string | undefined;
|
|
2818
2904
|
} | undefined;
|
|
2819
2905
|
publishedValue?: string | undefined;
|
|
2906
|
+
} | {
|
|
2907
|
+
type: "github-releases";
|
|
2908
|
+
owner: string;
|
|
2909
|
+
repo: string;
|
|
2910
|
+
prefix?: string | undefined;
|
|
2911
|
+
pollInterval?: number | undefined;
|
|
2912
|
+
drafts?: boolean | undefined;
|
|
2913
|
+
limit?: number | undefined;
|
|
2914
|
+
prereleases?: boolean | undefined;
|
|
2820
2915
|
} | {
|
|
2821
2916
|
type: "mintlify";
|
|
2822
2917
|
exclude: string[];
|
|
@@ -3121,8 +3216,8 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
3121
3216
|
} | undefined;
|
|
3122
3217
|
seo?: {
|
|
3123
3218
|
rss?: {
|
|
3124
|
-
enabled?: boolean | undefined;
|
|
3125
3219
|
limit?: number | undefined;
|
|
3220
|
+
enabled?: boolean | undefined;
|
|
3126
3221
|
types?: string[] | undefined;
|
|
3127
3222
|
} | undefined;
|
|
3128
3223
|
metatags?: Record<string, string> | undefined;
|
|
@@ -3186,6 +3281,15 @@ export declare const blumeConfigSchema: z.ZodObject<{
|
|
|
3186
3281
|
slug?: string | undefined;
|
|
3187
3282
|
} | undefined;
|
|
3188
3283
|
publishedValue?: string | undefined;
|
|
3284
|
+
} | {
|
|
3285
|
+
type: "github-releases";
|
|
3286
|
+
owner: string;
|
|
3287
|
+
repo: string;
|
|
3288
|
+
prefix?: string | undefined;
|
|
3289
|
+
pollInterval?: number | undefined;
|
|
3290
|
+
drafts?: boolean | undefined;
|
|
3291
|
+
limit?: number | undefined;
|
|
3292
|
+
prereleases?: boolean | undefined;
|
|
3189
3293
|
} | {
|
|
3190
3294
|
type: "mintlify";
|
|
3191
3295
|
exclude?: string[] | undefined;
|
|
@@ -5,7 +5,8 @@ description: Author release notes as content, and Blume builds a timeline page a
|
|
|
5
5
|
|
|
6
6
|
Blume ships a changelog out of the box. Write each release as a normal content
|
|
7
7
|
file, mark it `type: changelog`, and Blume collects every entry into a generated
|
|
8
|
-
timeline page and an RSS feed — no layout to build, no list to maintain.
|
|
8
|
+
timeline page and an RSS feed — no layout to build, no list to maintain. Or skip
|
|
9
|
+
the files entirely and [source your changelog from GitHub Releases](#from-github-releases).
|
|
9
10
|
|
|
10
11
|
## Write an entry
|
|
11
12
|
|
|
@@ -72,6 +73,32 @@ replace it with your own design, add a [custom page](/docs/advanced/custom-pages
|
|
|
72
73
|
`pages/changelog.astro` — it takes over and Blume stops generating the default
|
|
73
74
|
timeline.
|
|
74
75
|
|
|
76
|
+
## From GitHub Releases
|
|
77
|
+
|
|
78
|
+
Rather than authoring entries by hand, point the built-in
|
|
79
|
+
[`github-releases` source](/docs/content/sources#github-releases) at a repo and
|
|
80
|
+
every release becomes a `type: changelog` entry — the same timeline and feed,
|
|
81
|
+
fed straight from the releases you already publish:
|
|
82
|
+
|
|
83
|
+
```ts blume.config.ts
|
|
84
|
+
content: {
|
|
85
|
+
sources: [
|
|
86
|
+
{ type: "filesystem", root: "content" },
|
|
87
|
+
{
|
|
88
|
+
type: "github-releases",
|
|
89
|
+
prefix: "changelog",
|
|
90
|
+
owner: "acme",
|
|
91
|
+
repo: "sdk",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The release name becomes the title, its tag becomes `changelog.version`, and its
|
|
98
|
+
published date sorts the timeline. A private repo authenticates with the
|
|
99
|
+
`GITHUB_TOKEN` environment variable. See
|
|
100
|
+
[Content sources](/docs/content/sources#github-releases) for every option.
|
|
101
|
+
|
|
75
102
|
## The RSS feed
|
|
76
103
|
|
|
77
104
|
Blume also builds a changelog feed at **`/changelog/rss.xml`**, sorted
|
|
@@ -20,7 +20,8 @@ export default defineConfig({
|
|
|
20
20
|
|
|
21
21
|
## A complete example
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
A broader example touching the most common options (see each feature's guide for
|
|
24
|
+
the rest):
|
|
24
25
|
|
|
25
26
|
```ts blume.config.ts lineNumbers
|
|
26
27
|
import { defineConfig } from "blume";
|
|
@@ -238,7 +239,7 @@ the full reference.
|
|
|
238
239
|
|
|
239
240
|
```ts blume.config.ts lineNumbers
|
|
240
241
|
seo: {
|
|
241
|
-
og: { enabled:
|
|
242
|
+
og: { enabled: true },
|
|
242
243
|
rss: { enabled: true, types: ["blog", "changelog"] },
|
|
243
244
|
sitemap: true,
|
|
244
245
|
robots: true,
|
|
@@ -246,15 +247,15 @@ seo: {
|
|
|
246
247
|
}
|
|
247
248
|
```
|
|
248
249
|
|
|
249
|
-
| Option | Default | Description
|
|
250
|
-
| ---------------- | ----------------------- |
|
|
251
|
-
| `og.enabled` |
|
|
252
|
-
| `rss.enabled` | `true` | Build feeds for blog and changelog content.
|
|
253
|
-
| `rss.types` | `["blog", "changelog"]` | Content types that each get a feed.
|
|
254
|
-
| `rss.limit` | `50` | Maximum items per feed.
|
|
255
|
-
| `sitemap` | `true` | Generate sitemap.xml (needs deployment.site).
|
|
256
|
-
| `robots` | `true` | Generate robots.txt with a Sitemap link.
|
|
257
|
-
| `structuredData` | `true` | Emit schema.org JSON-LD in each page's head.
|
|
250
|
+
| Option | Default | Description |
|
|
251
|
+
| ---------------- | ----------------------- | ------------------------------------------------------- |
|
|
252
|
+
| `og.enabled` | auto | Per-page Open Graph images — on when a site URL is set. |
|
|
253
|
+
| `rss.enabled` | `true` | Build feeds for blog and changelog content. |
|
|
254
|
+
| `rss.types` | `["blog", "changelog"]` | Content types that each get a feed. |
|
|
255
|
+
| `rss.limit` | `50` | Maximum items per feed. |
|
|
256
|
+
| `sitemap` | `true` | Generate sitemap.xml (needs deployment.site). |
|
|
257
|
+
| `robots` | `true` | Generate robots.txt with a Sitemap link. |
|
|
258
|
+
| `structuredData` | `true` | Emit schema.org JSON-LD in each page's head. |
|
|
258
259
|
|
|
259
260
|
These work best with an absolute [`deployment.site`](/docs/deployment) for full URLs.
|
|
260
261
|
|
|
@@ -17,7 +17,8 @@ so picking one backend never pulls in the others.
|
|
|
17
17
|
## Using search
|
|
18
18
|
|
|
19
19
|
Open search with <Badge variant="accent">⌘K</Badge> (or `Ctrl K`), or press `/`
|
|
20
|
-
when you're not typing in a field. `Esc` closes it
|
|
20
|
+
when you're not typing in a field. `Esc` closes it, and `⌘J` (or `Ctrl J`)
|
|
21
|
+
toggles the result preview pane.
|
|
21
22
|
|
|
22
23
|
Queries match page **titles**, **descriptions**, and **body text**, with title
|
|
23
24
|
matches ranked highest and descriptions above body.
|
|
@@ -29,6 +30,17 @@ to plain text — code blocks, images, and markup are stripped, so results stay
|
|
|
29
30
|
relevant. The index is built from your source files, so it's identical in dev and
|
|
30
31
|
production.
|
|
31
32
|
|
|
33
|
+
## Tags
|
|
34
|
+
|
|
35
|
+
Add `search.tags` to a page's frontmatter to group it under a filter in the
|
|
36
|
+
search dialog — readers can narrow results to a tag with a click. Tags also
|
|
37
|
+
become a facet on the hosted providers.
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
search:
|
|
41
|
+
tags: [api, reference]
|
|
42
|
+
```
|
|
43
|
+
|
|
32
44
|
## Providers
|
|
33
45
|
|
|
34
46
|
The client-side providers are keyless and need no extra config. The hosted ones
|
|
@@ -98,6 +98,55 @@ Each value is a Google Fonts slug from the curated set below:
|
|
|
98
98
|
Need a font that isn't listed, or want to drop back to the system stack? Override
|
|
99
99
|
the `--blume-font-*` tokens directly in [`theme.css`](#theme-css).
|
|
100
100
|
|
|
101
|
+
### Dark-mode colors
|
|
102
|
+
|
|
103
|
+
By default light and dark share one `accent`. Set `accentDark` for a different
|
|
104
|
+
accent in dark mode, and `background` / `backgroundDark` to override the page
|
|
105
|
+
background per mode:
|
|
106
|
+
|
|
107
|
+
```ts blume.config.ts lineNumbers
|
|
108
|
+
theme: {
|
|
109
|
+
accent: "blue",
|
|
110
|
+
accentDark: "teal", // a different accent in dark mode
|
|
111
|
+
background: "#ffffff", // light-mode page background
|
|
112
|
+
backgroundDark: "#0a0a0a", // dark-mode page background
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Each takes a named preset or any CSS color, exactly like `accent`.
|
|
117
|
+
|
|
118
|
+
### Action color
|
|
119
|
+
|
|
120
|
+
`action` is a secondary accent for primary calls to action and the `action`
|
|
121
|
+
Tailwind utilities (`bg-action`, `text-action`). It defaults to your `accent`:
|
|
122
|
+
|
|
123
|
+
```ts blume.config.ts
|
|
124
|
+
theme: {
|
|
125
|
+
action: "#ff0066",
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Background decoration
|
|
130
|
+
|
|
131
|
+
Add a subtle, theme-aware pattern behind your content with `backgroundDecoration`
|
|
132
|
+
— `gradient`, `grid`, or `windows`:
|
|
133
|
+
|
|
134
|
+
```ts blume.config.ts
|
|
135
|
+
theme: {
|
|
136
|
+
backgroundDecoration: "grid",
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
For a full background image, set `backgroundImage` (and `backgroundImageDark` for
|
|
141
|
+
a dark variant) to a URL or a path under `public/`:
|
|
142
|
+
|
|
143
|
+
```ts blume.config.ts lineNumbers
|
|
144
|
+
theme: {
|
|
145
|
+
backgroundImage: "/bg-light.svg",
|
|
146
|
+
backgroundImageDark: "/bg-dark.svg",
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
101
150
|
## theme.css
|
|
102
151
|
|
|
103
152
|
Drop a `theme.css` in your project root to override any design token. It's the
|
|
@@ -128,6 +177,7 @@ dark mode.
|
|
|
128
177
|
| `--blume-border` | Borders and dividers |
|
|
129
178
|
| `--blume-accent` | Accent color |
|
|
130
179
|
| `--blume-accent-foreground` | Text and icons on an accent background |
|
|
180
|
+
| `--blume-action` | Secondary accent (defaults to accent) |
|
|
131
181
|
| `--blume-code-background` | Code block surface |
|
|
132
182
|
| `--blume-radius` | Corner radius |
|
|
133
183
|
| `--blume-font-display` | Heading font |
|
|
@@ -159,6 +209,7 @@ a utility, so your components track the theme automatically:
|
|
|
159
209
|
| `--blume-border` | `border-border` |
|
|
160
210
|
| `--blume-accent` | `bg-accent`, `text-accent` |
|
|
161
211
|
| `--blume-accent-foreground` | `text-accent-foreground` |
|
|
212
|
+
| `--blume-action` | `bg-action`, `text-action` |
|
|
162
213
|
| `--blume-radius` | `rounded-blume` |
|
|
163
214
|
| `--blume-font-display` | `font-display` |
|
|
164
215
|
| `--blume-font-body` | `font-sans` |
|
|
@@ -133,6 +133,24 @@ A negative or breaking state, such as a deprecation.
|
|
|
133
133
|
<Badge variant="danger">Deprecated</Badge>
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
+
## Icon
|
|
137
|
+
|
|
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`).
|
|
141
|
+
|
|
142
|
+
<Icon icon="rocket" size={20} />
|
|
143
|
+
|
|
144
|
+
```astro
|
|
145
|
+
<Icon icon="rocket" size={20} />
|
|
146
|
+
```
|
|
147
|
+
|
|
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.
|
|
153
|
+
|
|
136
154
|
## File tree
|
|
137
155
|
|
|
138
156
|
Illustrate a project or folder layout. Wrap a normal Markdown list and Blume
|
|
@@ -104,8 +104,14 @@ Tabs also **scope the sidebar**: when the current route falls under a tab's
|
|
|
104
104
|
`path`, the sidebar shows only that section's pages — so `/adapters/*` lists the
|
|
105
105
|
adapters and nothing else. The folder at a tab's `path` becomes the section, so
|
|
106
106
|
this needs no extra config beyond the tabs themselves; structure your content
|
|
107
|
-
into a folder per tab and point each tab at it.
|
|
108
|
-
|
|
107
|
+
into a folder per tab and point each tab at it.
|
|
108
|
+
|
|
109
|
+
On a route under no tab (or a tab whose `path` is `/`), the sidebar shows the
|
|
110
|
+
pages that _don't_ belong to a tab — each tab's folder is hidden from it, since
|
|
111
|
+
that section already has its own tab in the header. So a root landing page lists
|
|
112
|
+
your loose top-level pages while the sectioned content stays behind its tab,
|
|
113
|
+
mirroring Fumadocs' root folders. If a route has no pages of its own to show
|
|
114
|
+
this way, the full tree is shown instead, so the sidebar is never left blank.
|
|
109
115
|
|
|
110
116
|
## Explicit sidebar
|
|
111
117
|
|
package/docs/content/sources.mdx
CHANGED
|
@@ -88,6 +88,49 @@ a remote source for changes instead, set `pollInterval` (seconds) on it — the
|
|
|
88
88
|
dev server re-fetches on that interval and reloads only when the content
|
|
89
89
|
actually changes. Leave it unset to avoid hitting the API while you work.
|
|
90
90
|
|
|
91
|
+
## GitHub Releases
|
|
92
|
+
|
|
93
|
+
The built-in `github-releases` source turns a repo's releases into a changelog:
|
|
94
|
+
each release becomes a `type: changelog` entry, so your release notes _are_ your
|
|
95
|
+
changelog — nothing to write twice. Combined with the generated
|
|
96
|
+
[changelog timeline](/docs/advanced/changelog), publishing a GitHub release
|
|
97
|
+
ships a changelog entry.
|
|
98
|
+
|
|
99
|
+
```ts blume.config.ts
|
|
100
|
+
import { defineConfig } from "blume";
|
|
101
|
+
|
|
102
|
+
export default defineConfig({
|
|
103
|
+
content: {
|
|
104
|
+
sources: [
|
|
105
|
+
{ type: "filesystem", root: "content" },
|
|
106
|
+
{
|
|
107
|
+
type: "github-releases",
|
|
108
|
+
prefix: "changelog",
|
|
109
|
+
owner: "acme",
|
|
110
|
+
repo: "sdk",
|
|
111
|
+
// prereleases: false, // include prereleases (default off)
|
|
112
|
+
// drafts: false, // include drafts (needs a write token)
|
|
113
|
+
// limit: 100, // cap releases, newest-first
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Each release maps to the changelog fields automatically: its name (or tag)
|
|
121
|
+
becomes the title, its published date drives the timeline order, the tag becomes
|
|
122
|
+
`changelog.version`, and prereleases are tagged `Prerelease` (others `Release`).
|
|
123
|
+
The notes render as the entry body. Give the source a `prefix` so its release
|
|
124
|
+
pages nest under a route like `/changelog/v1-2-0`.
|
|
125
|
+
|
|
126
|
+
A private repo authenticates with the `GITHUB_TOKEN` environment variable — the
|
|
127
|
+
same token the other GitHub features use, never inlined into your config. Like
|
|
128
|
+
every remote source it's cached under `.blume/cache/<source>/` and served
|
|
129
|
+
offline if the API is unreachable. Because a changelog is supplementary, a fetch
|
|
130
|
+
failure with no cache (say a CI build without a token) degrades to an empty
|
|
131
|
+
changelog with a warning rather than failing the build — set `GITHUB_TOKEN` in
|
|
132
|
+
your CI and deploy environments to populate it.
|
|
133
|
+
|
|
91
134
|
## Sanity
|
|
92
135
|
|
|
93
136
|
The built-in `sanity` source runs a GROQ query and maps each document's fields
|
package/docs/content/syntax.mdx
CHANGED
|
@@ -11,7 +11,7 @@ each.
|
|
|
11
11
|
## Headings
|
|
12
12
|
|
|
13
13
|
Structure a page with headings. Blume renders your frontmatter `title` as the
|
|
14
|
-
page heading, so start your content at `##` — `##`
|
|
14
|
+
page heading, so start your content at `##` — `##` and `###` become entries
|
|
15
15
|
in the table of contents. Every `##`–`######` heading is also wrapped in a link
|
|
16
16
|
to its own anchor, so readers can click a heading to copy, bookmark, or share a
|
|
17
17
|
permalink straight to that section (hover to reveal the `#`). Turn this off with
|
package/docs/index.mdx
CHANGED
|
@@ -83,7 +83,7 @@ loosely-typed YAML.
|
|
|
83
83
|
- **SEO** — metadata, Open Graph images, RSS feeds, and JSON-LD, [built in](/docs/configuration/seo).
|
|
84
84
|
- **Customization** — component overrides, React islands, custom pages, theme
|
|
85
85
|
tokens, and a source-component registry via `blume add`.
|
|
86
|
-
- **Migration** — `blume migrate mintlify | starlight | fumadocs`.
|
|
86
|
+
- **Migration** — `blume migrate mintlify | starlight | nextra | fumadocs`.
|
|
87
87
|
- **Eject** — `blume eject` produces a standalone Astro project that still uses
|
|
88
88
|
the `blume` package.
|
|
89
89
|
|
package/docs/reference/cli.mdx
CHANGED
|
@@ -17,14 +17,20 @@ blume <command> [options]
|
|
|
17
17
|
| `blume preview` | Preview the last build. |
|
|
18
18
|
| `blume add <item>` | Install a source component from the registry. |
|
|
19
19
|
| `blume migrate <tool>` | Migrate from Mintlify, Starlight, Nextra, or Fumadocs. |
|
|
20
|
+
| `blume sync` | Re-fetch remote content sources and regenerate. |
|
|
20
21
|
| `blume eject` | Promote the runtime into a standalone Astro app. |
|
|
21
22
|
| `blume doctor` | Diagnose config and content problems. |
|
|
22
23
|
| `blume validate` | Validate links across your content. |
|
|
23
24
|
|
|
24
25
|
## Common flags
|
|
25
26
|
|
|
27
|
+
- `blume init --content-dir <dir> --yes` — set the content folder (default `docs`) and skip prompts.
|
|
26
28
|
- `blume dev --host --port <n> --open`
|
|
27
|
-
- `blume build --
|
|
29
|
+
- `blume dev --preview` / `blume build --preview` — include drafts and unpublished CMS content.
|
|
30
|
+
- `blume build --strict` — fail the build on diagnostic errors (also works on `blume dev`).
|
|
31
|
+
- `blume preview --host --port <n>` — bind the preview server.
|
|
32
|
+
- `blume sync --force` — re-fetch remote sources, dropping the cached snapshot first.
|
|
33
|
+
- `blume add <item> --force` — overwrite files that already exist.
|
|
28
34
|
- `blume eject --yes` — skip the confirmation prompt.
|
|
29
35
|
- `blume validate --external` — also check external links over the network.
|
|
30
36
|
- `blume validate --strict` — exit non-zero on warnings too.
|
|
@@ -24,6 +24,11 @@ Every page accepts the following frontmatter. All fields are optional.
|
|
|
24
24
|
default: "false",
|
|
25
25
|
description: "Exclude from production builds.",
|
|
26
26
|
},
|
|
27
|
+
lastModified: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description:
|
|
30
|
+
'Pin the page\'s "last updated" date (ISO or YAML date); overrides the git-derived date.',
|
|
31
|
+
},
|
|
27
32
|
}}
|
|
28
33
|
/>
|
|
29
34
|
|
|
@@ -33,7 +38,8 @@ Every page accepts the following frontmatter. All fields are optional.
|
|
|
33
38
|
sidebar:
|
|
34
39
|
label: Install
|
|
35
40
|
order: 2
|
|
36
|
-
icon:
|
|
41
|
+
icon: download
|
|
42
|
+
badge: New
|
|
37
43
|
hidden: false
|
|
38
44
|
```
|
|
39
45
|
|
|
@@ -42,7 +48,9 @@ sidebar:
|
|
|
42
48
|
```yaml lineNumbers
|
|
43
49
|
seo:
|
|
44
50
|
title: Install Blume
|
|
51
|
+
description: Install Blume and scaffold your first project.
|
|
45
52
|
image: /og/install.png
|
|
53
|
+
canonical: https://acme.com/install
|
|
46
54
|
noindex: false
|
|
47
55
|
```
|
|
48
56
|
|
package/package.json
CHANGED
package/src/astro/generate.ts
CHANGED
|
@@ -813,6 +813,28 @@ export interface GenerateResult {
|
|
|
813
813
|
warnings: string[];
|
|
814
814
|
}
|
|
815
815
|
|
|
816
|
+
/**
|
|
817
|
+
* Whether to generate the default `/changelog` index. Written when there are
|
|
818
|
+
* `type: changelog` entries — or when a release-backed changelog source is
|
|
819
|
+
* configured, so its route (and any nav tab pointing at it) still resolves to an
|
|
820
|
+
* empty timeline on a build where the source could not be fetched (e.g. CI
|
|
821
|
+
* without a token). Skipped when a user content page already owns `/changelog`.
|
|
822
|
+
*/
|
|
823
|
+
const shouldGenerateChangelog = (project: BlumeProject): boolean => {
|
|
824
|
+
const hasChangelog = project.graph.pages.some(
|
|
825
|
+
(page) =>
|
|
826
|
+
page.contentType === "changelog" &&
|
|
827
|
+
!(page.meta.draft || page.meta.sidebar.hidden)
|
|
828
|
+
);
|
|
829
|
+
const hasChangelogSource = (project.config.content.sources ?? []).some(
|
|
830
|
+
(source) => source.type === "github-releases"
|
|
831
|
+
);
|
|
832
|
+
const changelogRouteTaken = project.graph.pages.some(
|
|
833
|
+
(page) => page.route === "/changelog"
|
|
834
|
+
);
|
|
835
|
+
return (hasChangelog || hasChangelogSource) && !changelogRouteTaken;
|
|
836
|
+
};
|
|
837
|
+
|
|
816
838
|
/**
|
|
817
839
|
* Write (or update) the generated `.blume/` Astro runtime for a project.
|
|
818
840
|
* Only files whose content changed are rewritten so Vite HMR stays fast.
|
|
@@ -987,21 +1009,16 @@ export const generateRuntime = async (
|
|
|
987
1009
|
);
|
|
988
1010
|
}
|
|
989
1011
|
|
|
990
|
-
// Changelog index (`/changelog`)
|
|
991
|
-
|
|
992
|
-
// when a user content page already occupies the `/changelog` route.
|
|
993
|
-
const hasChangelog = project.graph.pages.some(
|
|
994
|
-
(page) =>
|
|
995
|
-
page.contentType === "changelog" &&
|
|
996
|
-
!(page.meta.draft || page.meta.sidebar.hidden)
|
|
997
|
-
);
|
|
998
|
-
const changelogRouteTaken = project.graph.pages.some(
|
|
999
|
-
(page) => page.route === "/changelog"
|
|
1000
|
-
);
|
|
1001
|
-
if (hasChangelog && !changelogRouteTaken) {
|
|
1012
|
+
// Changelog index (`/changelog`), rendered through the Update timeline layout.
|
|
1013
|
+
if (shouldGenerateChangelog(project)) {
|
|
1002
1014
|
await write(
|
|
1003
1015
|
join(srcDir, "pages", "changelog.astro"),
|
|
1004
|
-
changelogIndexTemplate({
|
|
1016
|
+
changelogIndexTemplate({
|
|
1017
|
+
askEnabled,
|
|
1018
|
+
exportEpub,
|
|
1019
|
+
exportPdf,
|
|
1020
|
+
staged: hasStaged,
|
|
1021
|
+
})
|
|
1005
1022
|
);
|
|
1006
1023
|
}
|
|
1007
1024
|
|
package/src/astro/templates.ts
CHANGED
|
@@ -1056,11 +1056,18 @@ export const changelogIndexTemplate = (options: {
|
|
|
1056
1056
|
askEnabled: boolean;
|
|
1057
1057
|
exportEpub: boolean;
|
|
1058
1058
|
exportPdf: boolean;
|
|
1059
|
+
/** Whether a `staged` collection exists (non-filesystem changelog sources). */
|
|
1060
|
+
staged: boolean;
|
|
1059
1061
|
}): string => {
|
|
1060
1062
|
const askImport = options.askEnabled
|
|
1061
1063
|
? 'import AskAI from "blume/components/islands/AskAI.astro";\n'
|
|
1062
1064
|
: "";
|
|
1063
1065
|
const askSlot = options.askEnabled ? '\n <AskAI slot="ask" />' : "";
|
|
1066
|
+
// Staged sources (e.g. GitHub Releases) render through a parallel collection,
|
|
1067
|
+
// so fold them in alongside filesystem entries when one exists.
|
|
1068
|
+
const stagedSpread = options.staged
|
|
1069
|
+
? '\n ...(await getCollection("staged")),'
|
|
1070
|
+
: "";
|
|
1064
1071
|
|
|
1065
1072
|
return `---
|
|
1066
1073
|
// Generated by Blume. Do not edit.
|
|
@@ -1100,7 +1107,9 @@ const slugify = (text) =>
|
|
|
1100
1107
|
text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") ||
|
|
1101
1108
|
"update";
|
|
1102
1109
|
|
|
1103
|
-
const changelogEntries =
|
|
1110
|
+
const changelogEntries = [
|
|
1111
|
+
...(await getCollection("docs")),${stagedSpread}
|
|
1112
|
+
]
|
|
1104
1113
|
.filter(
|
|
1105
1114
|
(entry) =>
|
|
1106
1115
|
entry.data.type === "changelog" &&
|