blume 0.1.0 → 0.1.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 +1213 -473
- package/dist/cli/index.js.map +33 -29
- package/dist/types/core/bridge.d.ts +24 -0
- package/dist/types/core/config.d.ts +35 -0
- package/dist/types/core/data.d.ts +129 -0
- package/dist/types/core/define-components.d.ts +27 -0
- package/dist/types/core/define-meta.d.ts +16 -0
- package/dist/types/core/deployment-env.d.ts +9 -0
- package/dist/types/core/diagnostics.d.ts +17 -0
- package/dist/types/core/i18n-ui.d.ts +500 -0
- package/dist/types/core/load-module.d.ts +7 -0
- package/dist/types/core/package-root.d.ts +17 -0
- package/dist/types/core/project.d.ts +9 -0
- package/dist/types/core/schema.d.ts +3461 -0
- package/dist/types/core/sources/types.d.ts +107 -0
- package/dist/types/core/types.d.ts +245 -0
- package/dist/types/core/ui-packs/ar.d.ts +3 -0
- package/dist/types/core/ui-packs/bg.d.ts +3 -0
- package/dist/types/core/ui-packs/bn.d.ts +3 -0
- package/dist/types/core/ui-packs/ca.d.ts +3 -0
- package/dist/types/core/ui-packs/cs.d.ts +3 -0
- package/dist/types/core/ui-packs/da.d.ts +3 -0
- package/dist/types/core/ui-packs/de.d.ts +3 -0
- package/dist/types/core/ui-packs/el.d.ts +3 -0
- package/dist/types/core/ui-packs/es.d.ts +3 -0
- package/dist/types/core/ui-packs/fa.d.ts +3 -0
- package/dist/types/core/ui-packs/fi.d.ts +3 -0
- package/dist/types/core/ui-packs/fr.d.ts +3 -0
- package/dist/types/core/ui-packs/he.d.ts +3 -0
- package/dist/types/core/ui-packs/hi.d.ts +3 -0
- package/dist/types/core/ui-packs/hr.d.ts +3 -0
- package/dist/types/core/ui-packs/hu.d.ts +3 -0
- package/dist/types/core/ui-packs/id.d.ts +3 -0
- package/dist/types/core/ui-packs/index.d.ts +13 -0
- package/dist/types/core/ui-packs/it.d.ts +3 -0
- package/dist/types/core/ui-packs/ja.d.ts +3 -0
- package/dist/types/core/ui-packs/ko.d.ts +3 -0
- package/dist/types/core/ui-packs/nl.d.ts +3 -0
- package/dist/types/core/ui-packs/no.d.ts +3 -0
- package/dist/types/core/ui-packs/pl.d.ts +3 -0
- package/dist/types/core/ui-packs/pt-br.d.ts +3 -0
- package/dist/types/core/ui-packs/pt.d.ts +3 -0
- package/dist/types/core/ui-packs/ro.d.ts +3 -0
- package/dist/types/core/ui-packs/ru.d.ts +3 -0
- package/dist/types/core/ui-packs/sk.d.ts +3 -0
- package/dist/types/core/ui-packs/sr.d.ts +3 -0
- package/dist/types/core/ui-packs/sv.d.ts +3 -0
- package/dist/types/core/ui-packs/th.d.ts +3 -0
- package/dist/types/core/ui-packs/tr.d.ts +3 -0
- package/dist/types/core/ui-packs/uk.d.ts +3 -0
- package/dist/types/core/ui-packs/vi.d.ts +3 -0
- package/dist/types/core/ui-packs/zh-tw.d.ts +3 -0
- package/dist/types/core/ui-packs/zh.d.ts +3 -0
- package/dist/types/core/version.d.ts +8 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/migrate/mintlify/config.d.ts +2 -0
- package/dist/types/migrate/mintlify/i18n.d.ts +7 -0
- package/dist/types/theme/fonts.d.ts +163 -0
- package/docs/advanced/custom-pages.mdx +91 -10
- package/docs/configuration/index.mdx +19 -0
- package/docs/content/components.mdx +103 -1
- package/package.json +13 -3
- package/src/ai/llms.ts +1 -2
- package/src/astro/examples.ts +106 -0
- package/src/astro/generate.ts +300 -75
- package/src/astro/index.ts +1 -1
- package/src/astro/islands.ts +1 -1
- package/src/astro/pages.ts +59 -0
- package/src/astro/templates.ts +180 -22
- package/src/cli/commands/validate.ts +1 -0
- package/src/components/content/CodeBlock.astro +28 -0
- package/src/components/content/Component.astro +65 -0
- package/src/components/content/Diff.astro +44 -0
- package/src/components/content/Tab.astro +8 -2
- package/src/components/content/diff.ts +95 -0
- package/src/components/layout/Favicon.astro +11 -4
- package/src/components/layout/PageLayout.astro +173 -0
- package/src/components/layout/ReferenceLayout.astro +6 -1
- package/src/components/layout/RootLayout.astro +9 -5
- package/src/components/layout/head-scripts.ts +19 -0
- package/src/core/data.ts +128 -0
- package/src/core/frontmatter.ts +43 -0
- package/src/core/links.ts +26 -10
- package/src/core/schema.ts +8 -0
- package/src/core/sources/filesystem.ts +1 -1
- package/src/core/sources/mdx-remote.ts +1 -2
- package/src/core/sources/mintlify.ts +1 -1
- package/src/core/sources/normalize.ts +19 -3
- package/src/core/sources/notion.ts +1 -1
- package/src/core/sources/sanity.ts +1 -1
- package/src/core/tsconfig-aliases.ts +201 -0
- package/src/index.ts +12 -0
- package/src/markdown/index.ts +69 -0
- package/src/migrate/fumadocs/config.ts +53 -4
- package/src/migrate/fumadocs/content.ts +1 -1
- package/src/migrate/fumadocs/groups.ts +230 -0
- package/src/migrate/fumadocs/index.ts +104 -19
- package/src/migrate/fumadocs/meta.ts +140 -10
- package/src/migrate/mintlify/snippets.ts +2 -1
- package/src/migrate/mintlify/transform.ts +1 -2
- package/src/migrate/nextra/index.ts +1 -1
- package/src/migrate/shared.ts +98 -1
- package/src/migrate/starlight/index.ts +1 -1
- package/src/registry/eject.ts +57 -10
- package/src/search/documents.ts +1 -2
- package/src/theme/entry.ts +29 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated Google Fonts exposed through `theme.fonts`.
|
|
3
|
+
*
|
|
4
|
+
* Each slug maps to the official Google family name (Astro's font provider needs
|
|
5
|
+
* the exact name), a docs-appropriate set of weights, and a fallback category.
|
|
6
|
+
* Fonts are self-hosted and optimized by Astro's built-in Fonts API; this module
|
|
7
|
+
* only resolves config slugs into the data that drives it.
|
|
8
|
+
*/
|
|
9
|
+
export type FontCategory = "sans" | "serif" | "mono";
|
|
10
|
+
/** The three configurable roles in `theme.fonts`. */
|
|
11
|
+
export type FontSlot = "display" | "body" | "mono";
|
|
12
|
+
/** Resolved theme fonts (a validated slug per role, all optional). */
|
|
13
|
+
export type FontsConfig = Partial<Record<FontSlot, string>> | undefined;
|
|
14
|
+
/** A single Astro `fonts:` entry (sans the literal `fontProviders.google()`). */
|
|
15
|
+
export interface FontEntry {
|
|
16
|
+
cssVariable: string;
|
|
17
|
+
fallbacks: string[];
|
|
18
|
+
name: string;
|
|
19
|
+
weights: number[];
|
|
20
|
+
}
|
|
21
|
+
/** Slug -> Google family + weights + fallback category. Keep keys alphabetical. */
|
|
22
|
+
export declare const GOOGLE_FONTS: {
|
|
23
|
+
"dm-sans": {
|
|
24
|
+
category: "sans";
|
|
25
|
+
family: string;
|
|
26
|
+
weights: number[];
|
|
27
|
+
};
|
|
28
|
+
figtree: {
|
|
29
|
+
category: "sans";
|
|
30
|
+
family: string;
|
|
31
|
+
weights: number[];
|
|
32
|
+
};
|
|
33
|
+
"fira-code": {
|
|
34
|
+
category: "mono";
|
|
35
|
+
family: string;
|
|
36
|
+
weights: number[];
|
|
37
|
+
};
|
|
38
|
+
geist: {
|
|
39
|
+
category: "sans";
|
|
40
|
+
family: string;
|
|
41
|
+
weights: number[];
|
|
42
|
+
};
|
|
43
|
+
"geist-mono": {
|
|
44
|
+
category: "mono";
|
|
45
|
+
family: string;
|
|
46
|
+
weights: number[];
|
|
47
|
+
};
|
|
48
|
+
"ibm-plex-mono": {
|
|
49
|
+
category: "mono";
|
|
50
|
+
family: string;
|
|
51
|
+
weights: number[];
|
|
52
|
+
};
|
|
53
|
+
"ibm-plex-sans": {
|
|
54
|
+
category: "sans";
|
|
55
|
+
family: string;
|
|
56
|
+
weights: number[];
|
|
57
|
+
};
|
|
58
|
+
"ibm-plex-serif": {
|
|
59
|
+
category: "serif";
|
|
60
|
+
family: string;
|
|
61
|
+
weights: number[];
|
|
62
|
+
};
|
|
63
|
+
inter: {
|
|
64
|
+
category: "sans";
|
|
65
|
+
family: string;
|
|
66
|
+
weights: number[];
|
|
67
|
+
};
|
|
68
|
+
"inter-tight": {
|
|
69
|
+
category: "sans";
|
|
70
|
+
family: string;
|
|
71
|
+
weights: number[];
|
|
72
|
+
};
|
|
73
|
+
"jetbrains-mono": {
|
|
74
|
+
category: "mono";
|
|
75
|
+
family: string;
|
|
76
|
+
weights: number[];
|
|
77
|
+
};
|
|
78
|
+
lora: {
|
|
79
|
+
category: "serif";
|
|
80
|
+
family: string;
|
|
81
|
+
weights: number[];
|
|
82
|
+
};
|
|
83
|
+
manrope: {
|
|
84
|
+
category: "sans";
|
|
85
|
+
family: string;
|
|
86
|
+
weights: number[];
|
|
87
|
+
};
|
|
88
|
+
merriweather: {
|
|
89
|
+
category: "serif";
|
|
90
|
+
family: string;
|
|
91
|
+
weights: number[];
|
|
92
|
+
};
|
|
93
|
+
"open-sans": {
|
|
94
|
+
category: "sans";
|
|
95
|
+
family: string;
|
|
96
|
+
weights: number[];
|
|
97
|
+
};
|
|
98
|
+
"playfair-display": {
|
|
99
|
+
category: "serif";
|
|
100
|
+
family: string;
|
|
101
|
+
weights: number[];
|
|
102
|
+
};
|
|
103
|
+
"plus-jakarta-sans": {
|
|
104
|
+
category: "sans";
|
|
105
|
+
family: string;
|
|
106
|
+
weights: number[];
|
|
107
|
+
};
|
|
108
|
+
roboto: {
|
|
109
|
+
category: "sans";
|
|
110
|
+
family: string;
|
|
111
|
+
weights: number[];
|
|
112
|
+
};
|
|
113
|
+
"roboto-mono": {
|
|
114
|
+
category: "mono";
|
|
115
|
+
family: string;
|
|
116
|
+
weights: number[];
|
|
117
|
+
};
|
|
118
|
+
"source-code-pro": {
|
|
119
|
+
category: "mono";
|
|
120
|
+
family: string;
|
|
121
|
+
weights: number[];
|
|
122
|
+
};
|
|
123
|
+
"source-sans-3": {
|
|
124
|
+
category: "sans";
|
|
125
|
+
family: string;
|
|
126
|
+
weights: number[];
|
|
127
|
+
};
|
|
128
|
+
"source-serif-4": {
|
|
129
|
+
category: "serif";
|
|
130
|
+
family: string;
|
|
131
|
+
weights: number[];
|
|
132
|
+
};
|
|
133
|
+
"space-grotesk": {
|
|
134
|
+
category: "sans";
|
|
135
|
+
family: string;
|
|
136
|
+
weights: number[];
|
|
137
|
+
};
|
|
138
|
+
"space-mono": {
|
|
139
|
+
category: "mono";
|
|
140
|
+
family: string;
|
|
141
|
+
weights: number[];
|
|
142
|
+
};
|
|
143
|
+
"work-sans": {
|
|
144
|
+
category: "sans";
|
|
145
|
+
family: string;
|
|
146
|
+
weights: number[];
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
export type FontSlug = keyof typeof GOOGLE_FONTS;
|
|
150
|
+
/** All supported slugs, for schema validation and error messages. */
|
|
151
|
+
export declare const FONT_SLUGS: string[];
|
|
152
|
+
/** Type guard: is `value` a supported font slug? */
|
|
153
|
+
export declare const isFontSlug: (value: string) => value is FontSlug;
|
|
154
|
+
/** The unique Astro `fonts:` entries for the configured roles (deduped). */
|
|
155
|
+
export declare const buildFontEntries: (fonts: FontsConfig) => FontEntry[];
|
|
156
|
+
/**
|
|
157
|
+
* The config-token CSS that points each role's `--blume-font-<role>-src` at the
|
|
158
|
+
* Astro-populated family variable. Concatenated into the generated entry's
|
|
159
|
+
* config tokens; empty when no fonts are set so defaults stay the system stacks.
|
|
160
|
+
*/
|
|
161
|
+
export declare const buildFontsCss: (fonts: FontsConfig) => string;
|
|
162
|
+
/** The CSS variables to feed Astro's `<Font>` component in the document head. */
|
|
163
|
+
export declare const configuredCssVars: (fonts: FontsConfig) => string[];
|
|
@@ -69,32 +69,68 @@ import data from "blume:data";
|
|
|
69
69
|
</ul>
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
Inside a Blume project the module is typed automatically. You can also pull the
|
|
73
|
+
shape in explicitly — for typed helpers, props, or your own tsconfig — with
|
|
74
|
+
`import type { BlumeData } from "blume"`:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import type { BlumeData, BlumeRoute } from "blume";
|
|
78
|
+
|
|
79
|
+
const indexable = (data: BlumeData): BlumeRoute[] =>
|
|
80
|
+
data.routes.filter((route) => route.indexable);
|
|
81
|
+
```
|
|
82
|
+
|
|
72
83
|
The module exposes:
|
|
73
84
|
|
|
74
85
|
<TypeTable
|
|
75
86
|
type={{
|
|
76
87
|
config: {
|
|
77
|
-
type: "
|
|
88
|
+
type: "BlumeDataConfig",
|
|
78
89
|
required: true,
|
|
79
90
|
description:
|
|
80
|
-
"Resolved site
|
|
91
|
+
"Resolved site settings: title, description, logo, favicon, appleIcon, banner, theme, site, repoUrl, search, i18n, mcp, og, analytics, feedback, structuredData, codeWrap, and imageZoom.",
|
|
81
92
|
},
|
|
82
93
|
navigation: {
|
|
83
|
-
type: "
|
|
94
|
+
type: "Navigation",
|
|
95
|
+
required: true,
|
|
96
|
+
description:
|
|
97
|
+
"The sidebar, tabs, and selectors inferred from your content (default locale).",
|
|
98
|
+
},
|
|
99
|
+
navigationByLocale: {
|
|
100
|
+
type: "Record<string, Navigation>",
|
|
84
101
|
required: true,
|
|
85
|
-
description:
|
|
102
|
+
description:
|
|
103
|
+
"Per-locale navigation trees, keyed by locale code. Empty unless i18n is configured.",
|
|
86
104
|
},
|
|
87
105
|
routes: {
|
|
88
|
-
type: "
|
|
106
|
+
type: "BlumeRoute[]",
|
|
89
107
|
required: true,
|
|
90
108
|
description:
|
|
91
|
-
"Every content page: { id, path, title, indexable, hidden, draft, editUrl }.",
|
|
109
|
+
"Every content page: { id, path, title, locale, indexable, hidden, draft, fallback, editUrl, lastModified, alternates, collection, entryId }.",
|
|
92
110
|
},
|
|
93
111
|
feeds: {
|
|
94
|
-
type: "
|
|
112
|
+
type: "BlumeFeed[]",
|
|
95
113
|
required: true,
|
|
96
114
|
description: "Generated RSS feeds: { href, title }.",
|
|
97
115
|
},
|
|
116
|
+
fontCssVars: {
|
|
117
|
+
type: "string[]",
|
|
118
|
+
required: true,
|
|
119
|
+
description:
|
|
120
|
+
"CSS variable names for the configured fonts (Astro <Font> integration).",
|
|
121
|
+
},
|
|
122
|
+
ui: {
|
|
123
|
+
type: "UIStrings",
|
|
124
|
+
required: true,
|
|
125
|
+
description:
|
|
126
|
+
"Resolved UI chrome strings for the default locale (search, sidebar, and footer labels).",
|
|
127
|
+
},
|
|
128
|
+
uiByLocale: {
|
|
129
|
+
type: "Record<string, UIStrings>",
|
|
130
|
+
required: true,
|
|
131
|
+
description:
|
|
132
|
+
"Per-locale UI strings, keyed by locale code. Empty unless i18n is configured.",
|
|
133
|
+
},
|
|
98
134
|
}}
|
|
99
135
|
/>
|
|
100
136
|
|
|
@@ -133,9 +169,54 @@ const posts = (await getCollection("docs"))
|
|
|
133
169
|
|
|
134
170
|
## Using the site layout
|
|
135
171
|
|
|
136
|
-
|
|
137
|
-
—
|
|
138
|
-
|
|
172
|
+
`RootLayout` gives a custom page the full docs chrome — header, sidebar, search,
|
|
173
|
+
TOC, and theme — by wrapping it in the same 3-column grid the generated pages
|
|
174
|
+
use. For a landing or marketing page that grid is in the way, so reach for
|
|
175
|
+
**`PageLayout`** instead: it provides the document shell, header, theme, and
|
|
176
|
+
fonts, then a single full-width `<slot />` (no sidebar, no prose, no TOC). An
|
|
177
|
+
optional `footer` slot renders after `<main>`:
|
|
178
|
+
|
|
179
|
+
```astro pages/index.astro lineNumbers
|
|
180
|
+
---
|
|
181
|
+
import PageLayout from "blume/components/layout/PageLayout.astro";
|
|
182
|
+
import data from "blume:data";
|
|
183
|
+
import Footer from "./_home/Footer.astro";
|
|
184
|
+
|
|
185
|
+
const { config } = data;
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
<PageLayout
|
|
189
|
+
site={{ title: config.title, description: config.description }}
|
|
190
|
+
logo={config.logo}
|
|
191
|
+
banner={config.banner}
|
|
192
|
+
analytics={config.analytics}
|
|
193
|
+
navigation={data.navigation}
|
|
194
|
+
favicon={config.favicon}
|
|
195
|
+
fontCssVars={data.fontCssVars}
|
|
196
|
+
themeMode={config.theme.mode}
|
|
197
|
+
searchEnabled={config.search.enabled}
|
|
198
|
+
siteUrl={config.site}
|
|
199
|
+
ogEnabled={config.og.enabled}
|
|
200
|
+
page={{ title: "Acme — the fastest docs", description: config.description }}
|
|
201
|
+
>
|
|
202
|
+
<section class="mx-auto max-w-5xl px-6 py-24">
|
|
203
|
+
<h1>Build docs that fly</h1>
|
|
204
|
+
</section>
|
|
205
|
+
<Footer slot="footer" />
|
|
206
|
+
</PageLayout>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Passing `siteUrl` (and `ogEnabled`) derives the page's `canonical` and a
|
|
210
|
+
generated `og:image` automatically: Blume renders an Open Graph card for every
|
|
211
|
+
static custom page — the home included, the most-shared URL — served at
|
|
212
|
+
`/og/<route>.png` (`/og/index.png` for `/`). The home card uses the site title
|
|
213
|
+
with the description as its eyebrow; a deeper page is titled from its last path
|
|
214
|
+
segment. Set `ogImage` or `canonical` explicitly to override.
|
|
215
|
+
|
|
216
|
+
`page.title` is used verbatim as the document title (no `- siteTitle` suffix),
|
|
217
|
+
since marketing pages usually set their own. To give a custom page the full docs
|
|
218
|
+
chrome instead — sidebar, TOC, and all — wrap it in `RootLayout`, the layout the
|
|
219
|
+
generated pages use. Pull the required props straight from `blume:data`:
|
|
139
220
|
|
|
140
221
|
```astro pages/pricing.astro lineNumbers
|
|
141
222
|
---
|
|
@@ -137,6 +137,25 @@ SVG wins over PNG over ICO when several are present, and a file in `public/` is
|
|
|
137
137
|
preferred over one at the root. If Blume finds no icon, it falls back to its own
|
|
138
138
|
mark.
|
|
139
139
|
|
|
140
|
+
### Apple touch icon
|
|
141
|
+
|
|
142
|
+
The icon iOS uses when someone adds your site to their home screen is detected
|
|
143
|
+
the same way. Drop an `apple-icon` file (`.png`, `.jpg`, or `.jpeg`) — or an
|
|
144
|
+
`apple-touch-icon.png`, the name most favicon generators emit — in your project
|
|
145
|
+
root or `public/` directory and Blume wires up `<link rel="apple-touch-icon">`
|
|
146
|
+
for you. There's no default; if no file is found, no tag is emitted.
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
my-docs/
|
|
150
|
+
├─ blume.config.ts
|
|
151
|
+
├─ apple-icon.png ← picked up automatically
|
|
152
|
+
└─ docs/
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Put the file in `public/` rather than the project root: iOS ignores the inlined
|
|
156
|
+
data URI Blume uses for a root-level icon, so only a `public/` file (served at
|
|
157
|
+
`/apple-icon.png`) reliably reaches the home screen.
|
|
158
|
+
|
|
140
159
|
### Banner
|
|
141
160
|
|
|
142
161
|
Show a site-wide announcement bar above the header. Pass a string, or an object
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Components
|
|
3
|
-
description: The built-in JSX components — cards, columns, steps, tabs, accordions, badges, code groups, frames, trees, tooltips, type tables, and a GitHub card — usable in any MDX page.
|
|
3
|
+
description: The built-in JSX components — cards, columns, steps, tabs, accordions, badges, code groups, frames, trees, tooltips, type tables, live component previews, diffs, and a GitHub card — usable in any MDX page.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Blume ships an accessible, themeable component set available in any `.mdx` page
|
|
@@ -563,3 +563,105 @@ variable to lift the API rate limit.
|
|
|
563
563
|
<!-- Or point it at any repository -->
|
|
564
564
|
<GithubInfo owner="withastro" repo="astro" />
|
|
565
565
|
```
|
|
566
|
+
|
|
567
|
+
## Component
|
|
568
|
+
|
|
569
|
+
`Component` renders an example file from your project's `examples/` directory as
|
|
570
|
+
a live preview alongside its highlighted source, in tabs. Point it at a file with
|
|
571
|
+
`path` — its location under `examples/`, without the extension (so
|
|
572
|
+
`examples/counter.tsx` is `path="counter"`). React, Vue, Svelte, and Astro
|
|
573
|
+
examples are all supported; framework examples hydrate, Astro ones render
|
|
574
|
+
statically. It keeps the preview and the code in sync from a single file.
|
|
575
|
+
|
|
576
|
+
The directory is configurable — set `examples` in `blume.config.ts` when your
|
|
577
|
+
examples live elsewhere (e.g. a registry layout). `path` is always relative to
|
|
578
|
+
it:
|
|
579
|
+
|
|
580
|
+
```ts
|
|
581
|
+
// blume.config.ts
|
|
582
|
+
export default defineConfig({
|
|
583
|
+
examples: "registry/files-sdk",
|
|
584
|
+
});
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
```astro
|
|
588
|
+
<!-- registry/files-sdk/file-list/basic.tsx -->
|
|
589
|
+
<Component path="file-list/basic" />
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
<Component path="counter" />
|
|
593
|
+
|
|
594
|
+
```astro
|
|
595
|
+
<!-- examples/counter.tsx -->
|
|
596
|
+
<Component path="counter" />
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
An Astro example renders live with no client JavaScript:
|
|
600
|
+
|
|
601
|
+
<Component path="card" />
|
|
602
|
+
|
|
603
|
+
## CodeBlock
|
|
604
|
+
|
|
605
|
+
`CodeBlock` highlights a code string with the same Shiki theme and transformers
|
|
606
|
+
as your fenced code — including the light/dark swap — for places a fence can't
|
|
607
|
+
go, like a landing page or a custom component. Pass `code` and a `lang`:
|
|
608
|
+
|
|
609
|
+
<CodeBlock
|
|
610
|
+
lang="ts"
|
|
611
|
+
code={`export const greet = (name: string): string =>
|
|
612
|
+
\`Hello, \${name}!\`;`}
|
|
613
|
+
/>
|
|
614
|
+
|
|
615
|
+
```astro
|
|
616
|
+
---
|
|
617
|
+
import CodeBlock from "blume/components/content/CodeBlock.astro";
|
|
618
|
+
---
|
|
619
|
+
|
|
620
|
+
<CodeBlock lang="ts" code={source} />
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
To highlight to an HTML string yourself (e.g. inside your own component), import
|
|
624
|
+
the underlying helper from `blume/markdown`:
|
|
625
|
+
|
|
626
|
+
```ts
|
|
627
|
+
import { highlightCode } from "blume/markdown";
|
|
628
|
+
|
|
629
|
+
const html = await highlightCode(source, "ts");
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
## Diff
|
|
633
|
+
|
|
634
|
+
`Diff` renders a git-style diff, highlighted with the same Shiki theme as your
|
|
635
|
+
code blocks and produced entirely at build time — no client JavaScript. Give it
|
|
636
|
+
two inline strings (`old` / `new`), two file paths (`before` / `after`), or a
|
|
637
|
+
unified patch (an inline `patch` string or a `src` file).
|
|
638
|
+
|
|
639
|
+
<Diff
|
|
640
|
+
lang="ts"
|
|
641
|
+
old={`export function greet(name) {
|
|
642
|
+
return "Hi, " + name;
|
|
643
|
+
}`}
|
|
644
|
+
new={`export function greet(name: string): string {
|
|
645
|
+
return "Hi, " + name + "!";
|
|
646
|
+
}`}
|
|
647
|
+
/>
|
|
648
|
+
|
|
649
|
+
```astro
|
|
650
|
+
<Diff
|
|
651
|
+
lang="ts"
|
|
652
|
+
old={`export function greet(name) {
|
|
653
|
+
return "Hi, " + name;
|
|
654
|
+
}`}
|
|
655
|
+
new={`export function greet(name: string): string {
|
|
656
|
+
return "Hi, " + name + "!";
|
|
657
|
+
}`}
|
|
658
|
+
/>
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
Diff two files in your project, relative to its root:
|
|
662
|
+
|
|
663
|
+
<Diff before="diffs/button-before.ts" after="diffs/button-after.ts" />
|
|
664
|
+
|
|
665
|
+
Or render a unified patch from a file:
|
|
666
|
+
|
|
667
|
+
<Diff src="diffs/greet.patch" />
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blume",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Documentation that's fast, AI-ready, and zero-config.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -31,10 +31,17 @@
|
|
|
31
31
|
"docs"
|
|
32
32
|
],
|
|
33
33
|
"type": "module",
|
|
34
|
+
"types": "./dist/types/index.d.ts",
|
|
34
35
|
"exports": {
|
|
35
|
-
".":
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/types/index.d.ts",
|
|
38
|
+
"default": "./src/index.ts"
|
|
39
|
+
},
|
|
36
40
|
"./ai/*": "./src/ai/*",
|
|
37
|
-
"./schema":
|
|
41
|
+
"./schema": {
|
|
42
|
+
"types": "./dist/types/core/schema.d.ts",
|
|
43
|
+
"default": "./src/core/schema.ts"
|
|
44
|
+
},
|
|
38
45
|
"./runtime": "./src/runtime/index.ts",
|
|
39
46
|
"./astro": "./src/astro/index.ts",
|
|
40
47
|
"./og": "./src/og/index.ts",
|
|
@@ -62,6 +69,7 @@
|
|
|
62
69
|
"@astrojs/vercel": "^11.0.0",
|
|
63
70
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
64
71
|
"@orama/orama": "^3.1.18",
|
|
72
|
+
"@pierre/diffs": "^1.2.11",
|
|
65
73
|
"@scalar/astro": "^0.4.5",
|
|
66
74
|
"@shikijs/transformers": "^4.2.0",
|
|
67
75
|
"@shikijs/twoslash": "^4.2.0",
|
|
@@ -79,6 +87,7 @@
|
|
|
79
87
|
"github-slugger": "^2.0.0",
|
|
80
88
|
"gray-matter": "^4.0.3",
|
|
81
89
|
"jiti": "^2.4.0",
|
|
90
|
+
"js-yaml": "^4.1.0",
|
|
82
91
|
"katex": "^0.17.0",
|
|
83
92
|
"mermaid": "^11.15.0",
|
|
84
93
|
"pagefind": "^1.3.0",
|
|
@@ -93,6 +102,7 @@
|
|
|
93
102
|
"zod": "^3.24.0"
|
|
94
103
|
},
|
|
95
104
|
"devDependencies": {
|
|
105
|
+
"@types/js-yaml": "^4.0.9",
|
|
96
106
|
"@types/node": "^22.10.0",
|
|
97
107
|
"@types/react": "^19.0.0",
|
|
98
108
|
"@types/react-dom": "^19.0.0",
|
package/src/ai/llms.ts
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
import { join, relative } from "pathe";
|
|
4
|
+
import { glob } from "tinyglobby";
|
|
5
|
+
|
|
6
|
+
import type { IslandClientMode } from "./islands.ts";
|
|
7
|
+
import { readClientMode } from "./islands.ts";
|
|
8
|
+
|
|
9
|
+
/** Framework an example is authored in, inferred from its extension. */
|
|
10
|
+
export type ExampleFramework = "astro" | "react" | "svelte" | "vue";
|
|
11
|
+
|
|
12
|
+
/** A discovered `examples/` file, ready to wrap (live) and show (source). */
|
|
13
|
+
export interface ExampleSpec {
|
|
14
|
+
/** Hydration directive for a framework example; `undefined` for `.astro`. */
|
|
15
|
+
client?: IslandClientMode;
|
|
16
|
+
/** Absolute path to the example source file. */
|
|
17
|
+
file: string;
|
|
18
|
+
/** Framework, or `astro` for a server-rendered (static) example. */
|
|
19
|
+
framework: ExampleFramework;
|
|
20
|
+
/** Shiki language for the source pane — the file extension. */
|
|
21
|
+
lang: string;
|
|
22
|
+
/** MDX-facing key: the path under `examples/`, sans extension, `/`-joined. */
|
|
23
|
+
path: string;
|
|
24
|
+
/** Raw source text shown in the code tab. */
|
|
25
|
+
source: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ExampleDiscovery {
|
|
29
|
+
examples: ExampleSpec[];
|
|
30
|
+
warnings: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Example extensions mapped to the framework that renders them. */
|
|
34
|
+
const FRAMEWORK_BY_EXT: Record<string, ExampleFramework> = {
|
|
35
|
+
astro: "astro",
|
|
36
|
+
jsx: "react",
|
|
37
|
+
svelte: "svelte",
|
|
38
|
+
tsx: "react",
|
|
39
|
+
vue: "vue",
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Captures the extension so we can strip it from the path key and pick the
|
|
43
|
+
// framework. Kept in sync with the glob below.
|
|
44
|
+
const EXAMPLE_FILE = /\.(?<ext>astro|jsx|svelte|tsx|vue)$/u;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Discover preview examples under `<root>/<subdir>` (the `examples` config,
|
|
48
|
+
* default `examples`). Every `.astro`/`.tsx`/`.jsx`/`.vue`/`.svelte` file
|
|
49
|
+
* becomes addressable by `<Component path="...">`, where the path is the file's
|
|
50
|
+
* location under that directory without its extension (e.g. `forms/login.tsx` →
|
|
51
|
+
* `forms/login`). Discovery is path-based (a glob), so no example code is
|
|
52
|
+
* executed. Framework examples carry a hydration mode (default `client:visible`,
|
|
53
|
+
* overridable via `export const client`); `.astro` examples render statically
|
|
54
|
+
* with no client directive.
|
|
55
|
+
*/
|
|
56
|
+
export const discoverExamples = async (
|
|
57
|
+
root: string,
|
|
58
|
+
subdir = "examples"
|
|
59
|
+
): Promise<ExampleDiscovery> => {
|
|
60
|
+
const dir = join(root, subdir);
|
|
61
|
+
const matches = await glob(["**/*.{astro,jsx,svelte,tsx,vue}"], {
|
|
62
|
+
absolute: true,
|
|
63
|
+
cwd: dir,
|
|
64
|
+
onlyFiles: true,
|
|
65
|
+
});
|
|
66
|
+
const files = matches.toSorted();
|
|
67
|
+
const sources = await Promise.all(
|
|
68
|
+
files.map((file) => readFile(file, "utf-8"))
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const examples: ExampleSpec[] = [];
|
|
72
|
+
const warnings: string[] = [];
|
|
73
|
+
const seen = new Map<string, string>();
|
|
74
|
+
|
|
75
|
+
for (const [index, file] of files.entries()) {
|
|
76
|
+
const ext = file.match(EXAMPLE_FILE)?.groups?.ext;
|
|
77
|
+
const framework = ext ? FRAMEWORK_BY_EXT[ext] : undefined;
|
|
78
|
+
if (!(ext && framework)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// Strip the trailing `.<ext>` to form the `<Component path>` key.
|
|
82
|
+
const path = relative(dir, file).slice(0, -(ext.length + 1));
|
|
83
|
+
const existing = seen.get(path);
|
|
84
|
+
if (existing) {
|
|
85
|
+
warnings.push(
|
|
86
|
+
`Two examples both resolve to "${path}" ("${existing}" and "${file}"); ignoring the second. Give them distinct paths.`
|
|
87
|
+
);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
seen.set(path, file);
|
|
91
|
+
const source = sources[index] ?? "";
|
|
92
|
+
examples.push({
|
|
93
|
+
client:
|
|
94
|
+
framework === "astro"
|
|
95
|
+
? undefined
|
|
96
|
+
: readClientMode(source, file, warnings),
|
|
97
|
+
file,
|
|
98
|
+
framework,
|
|
99
|
+
lang: ext,
|
|
100
|
+
path,
|
|
101
|
+
source,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { examples, warnings };
|
|
106
|
+
};
|