blume 0.0.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/bin/blume.mjs +18 -0
  2. package/dist/cli/index.js +12696 -0
  3. package/dist/cli/index.js.map +145 -0
  4. package/dist/types/core/bridge.d.ts +24 -0
  5. package/dist/types/core/config.d.ts +35 -0
  6. package/dist/types/core/data.d.ts +129 -0
  7. package/dist/types/core/define-components.d.ts +27 -0
  8. package/dist/types/core/define-meta.d.ts +16 -0
  9. package/dist/types/core/deployment-env.d.ts +9 -0
  10. package/dist/types/core/diagnostics.d.ts +17 -0
  11. package/dist/types/core/i18n-ui.d.ts +500 -0
  12. package/dist/types/core/load-module.d.ts +7 -0
  13. package/dist/types/core/package-root.d.ts +17 -0
  14. package/dist/types/core/project.d.ts +9 -0
  15. package/dist/types/core/schema.d.ts +3451 -0
  16. package/dist/types/core/sources/types.d.ts +107 -0
  17. package/dist/types/core/types.d.ts +245 -0
  18. package/dist/types/core/ui-packs/ar.d.ts +3 -0
  19. package/dist/types/core/ui-packs/bg.d.ts +3 -0
  20. package/dist/types/core/ui-packs/bn.d.ts +3 -0
  21. package/dist/types/core/ui-packs/ca.d.ts +3 -0
  22. package/dist/types/core/ui-packs/cs.d.ts +3 -0
  23. package/dist/types/core/ui-packs/da.d.ts +3 -0
  24. package/dist/types/core/ui-packs/de.d.ts +3 -0
  25. package/dist/types/core/ui-packs/el.d.ts +3 -0
  26. package/dist/types/core/ui-packs/es.d.ts +3 -0
  27. package/dist/types/core/ui-packs/fa.d.ts +3 -0
  28. package/dist/types/core/ui-packs/fi.d.ts +3 -0
  29. package/dist/types/core/ui-packs/fr.d.ts +3 -0
  30. package/dist/types/core/ui-packs/he.d.ts +3 -0
  31. package/dist/types/core/ui-packs/hi.d.ts +3 -0
  32. package/dist/types/core/ui-packs/hr.d.ts +3 -0
  33. package/dist/types/core/ui-packs/hu.d.ts +3 -0
  34. package/dist/types/core/ui-packs/id.d.ts +3 -0
  35. package/dist/types/core/ui-packs/index.d.ts +13 -0
  36. package/dist/types/core/ui-packs/it.d.ts +3 -0
  37. package/dist/types/core/ui-packs/ja.d.ts +3 -0
  38. package/dist/types/core/ui-packs/ko.d.ts +3 -0
  39. package/dist/types/core/ui-packs/nl.d.ts +3 -0
  40. package/dist/types/core/ui-packs/no.d.ts +3 -0
  41. package/dist/types/core/ui-packs/pl.d.ts +3 -0
  42. package/dist/types/core/ui-packs/pt-br.d.ts +3 -0
  43. package/dist/types/core/ui-packs/pt.d.ts +3 -0
  44. package/dist/types/core/ui-packs/ro.d.ts +3 -0
  45. package/dist/types/core/ui-packs/ru.d.ts +3 -0
  46. package/dist/types/core/ui-packs/sk.d.ts +3 -0
  47. package/dist/types/core/ui-packs/sr.d.ts +3 -0
  48. package/dist/types/core/ui-packs/sv.d.ts +3 -0
  49. package/dist/types/core/ui-packs/th.d.ts +3 -0
  50. package/dist/types/core/ui-packs/tr.d.ts +3 -0
  51. package/dist/types/core/ui-packs/uk.d.ts +3 -0
  52. package/dist/types/core/ui-packs/vi.d.ts +3 -0
  53. package/dist/types/core/ui-packs/zh-tw.d.ts +3 -0
  54. package/dist/types/core/ui-packs/zh.d.ts +3 -0
  55. package/dist/types/core/version.d.ts +8 -0
  56. package/dist/types/index.d.ts +10 -0
  57. package/dist/types/migrate/mintlify/config.d.ts +2 -0
  58. package/dist/types/migrate/mintlify/i18n.d.ts +7 -0
  59. package/dist/types/theme/fonts.d.ts +163 -0
  60. package/docs/01-quickstart.mdx +99 -0
  61. package/docs/02-deployment.mdx +129 -0
  62. package/docs/advanced/api-reference.mdx +114 -0
  63. package/docs/advanced/blog.mdx +121 -0
  64. package/docs/advanced/changelog.mdx +113 -0
  65. package/docs/advanced/custom-pages.mdx +268 -0
  66. package/docs/advanced/meta.ts +7 -0
  67. package/docs/changelog/v0-1-0.mdx +12 -0
  68. package/docs/changelog/v0-2-0.mdx +16 -0
  69. package/docs/configuration/ai.mdx +228 -0
  70. package/docs/configuration/analytics.mdx +98 -0
  71. package/docs/configuration/customization.mdx +91 -0
  72. package/docs/configuration/export.mdx +70 -0
  73. package/docs/configuration/index.mdx +290 -0
  74. package/docs/configuration/meta.ts +15 -0
  75. package/docs/configuration/search.mdx +172 -0
  76. package/docs/configuration/seo.mdx +196 -0
  77. package/docs/configuration/theming.mdx +178 -0
  78. package/docs/content/components.mdx +651 -0
  79. package/docs/content/i18n.mdx +205 -0
  80. package/docs/content/index.mdx +161 -0
  81. package/docs/content/islands.mdx +94 -0
  82. package/docs/content/meta.mdx +119 -0
  83. package/docs/content/meta.ts +15 -0
  84. package/docs/content/navigation.mdx +168 -0
  85. package/docs/content/sources.mdx +216 -0
  86. package/docs/content/syntax.mdx +445 -0
  87. package/docs/index.mdx +112 -0
  88. package/docs/reference/cli.mdx +43 -0
  89. package/docs/reference/frontmatter.mdx +74 -0
  90. package/docs/reference/meta.ts +7 -0
  91. package/package.json +150 -6
  92. package/src/ai/ask.ts +93 -0
  93. package/src/ai/llms.ts +64 -0
  94. package/src/ai/markdown.ts +31 -0
  95. package/src/ai/mcp/data.ts +74 -0
  96. package/src/ai/mcp/discovery.ts +49 -0
  97. package/src/ai/mcp/server.ts +225 -0
  98. package/src/ai/mcp/tools.ts +47 -0
  99. package/src/assets/icon.png +0 -0
  100. package/src/astro/examples.ts +104 -0
  101. package/src/astro/generate.ts +1006 -0
  102. package/src/astro/index.ts +4 -0
  103. package/src/astro/integration.ts +74 -0
  104. package/src/astro/islands.ts +131 -0
  105. package/src/astro/markdown-negotiation.ts +68 -0
  106. package/src/astro/pages.ts +87 -0
  107. package/src/astro/templates.ts +1326 -0
  108. package/src/cli/commands/add.ts +81 -0
  109. package/src/cli/commands/build.ts +103 -0
  110. package/src/cli/commands/dev.ts +108 -0
  111. package/src/cli/commands/doctor.ts +74 -0
  112. package/src/cli/commands/eject.ts +57 -0
  113. package/src/cli/commands/init.ts +98 -0
  114. package/src/cli/commands/migrate.ts +39 -0
  115. package/src/cli/commands/preview.ts +39 -0
  116. package/src/cli/commands/sync.ts +52 -0
  117. package/src/cli/commands/validate.ts +61 -0
  118. package/src/cli/index.ts +35 -0
  119. package/src/cli/log.ts +37 -0
  120. package/src/cli/prepare.ts +80 -0
  121. package/src/components/Icon.astro +99 -0
  122. package/src/components/content/Accordion.astro +8 -0
  123. package/src/components/content/AccordionItem.astro +121 -0
  124. package/src/components/content/AutoTypeTable.astro +51 -0
  125. package/src/components/content/Badge.astro +124 -0
  126. package/src/components/content/Callout.astro +73 -0
  127. package/src/components/content/Card.astro +104 -0
  128. package/src/components/content/CardGroup.astro +14 -0
  129. package/src/components/content/CodeBlock.astro +28 -0
  130. package/src/components/content/CodeGroup.astro +13 -0
  131. package/src/components/content/Color.astro +15 -0
  132. package/src/components/content/ColorItem.astro +87 -0
  133. package/src/components/content/ColorRow.astro +10 -0
  134. package/src/components/content/Column.astro +6 -0
  135. package/src/components/content/Columns.astro +9 -0
  136. package/src/components/content/Component.astro +65 -0
  137. package/src/components/content/Diff.astro +44 -0
  138. package/src/components/content/Expandable.astro +11 -0
  139. package/src/components/content/FileTree.astro +8 -0
  140. package/src/components/content/Frame.astro +70 -0
  141. package/src/components/content/GithubInfo.astro +110 -0
  142. package/src/components/content/Math.astro +24 -0
  143. package/src/components/content/Panel.astro +20 -0
  144. package/src/components/content/Prompt.astro +129 -0
  145. package/src/components/content/Step.astro +34 -0
  146. package/src/components/content/Steps.astro +20 -0
  147. package/src/components/content/Tab.astro +46 -0
  148. package/src/components/content/Tabs.astro +273 -0
  149. package/src/components/content/Tile.astro +42 -0
  150. package/src/components/content/Tooltip.astro +68 -0
  151. package/src/components/content/Tree.astro +300 -0
  152. package/src/components/content/TreeFile.astro +15 -0
  153. package/src/components/content/TreeFolder.astro +62 -0
  154. package/src/components/content/TypeTable.astro +106 -0
  155. package/src/components/content/Update.astro +66 -0
  156. package/src/components/content/Visibility.astro +12 -0
  157. package/src/components/content/Warning.astro +9 -0
  158. package/src/components/content/auto-type-table.ts +141 -0
  159. package/src/components/content/diff.ts +95 -0
  160. package/src/components/content/github-info.ts +79 -0
  161. package/src/components/content/mermaid-element.ts +68 -0
  162. package/src/components/github-mark.ts +9 -0
  163. package/src/components/index.ts +14 -0
  164. package/src/components/islands/AskAI.astro +12 -0
  165. package/src/components/islands/ask-ai.tsx +156 -0
  166. package/src/components/layout/Analytics.astro +63 -0
  167. package/src/components/layout/Banner.astro +50 -0
  168. package/src/components/layout/Breadcrumbs.astro +31 -0
  169. package/src/components/layout/Favicon.astro +22 -0
  170. package/src/components/layout/Fonts.astro +14 -0
  171. package/src/components/layout/Header.astro +188 -0
  172. package/src/components/layout/LanguageSwitcher.astro +56 -0
  173. package/src/components/layout/NavTree.astro +462 -0
  174. package/src/components/layout/PageActions.astro +438 -0
  175. package/src/components/layout/PageFeedback.astro +58 -0
  176. package/src/components/layout/PageLayout.astro +173 -0
  177. package/src/components/layout/Pagination.astro +56 -0
  178. package/src/components/layout/ReferenceLayout.astro +107 -0
  179. package/src/components/layout/RootLayout.astro +537 -0
  180. package/src/components/layout/Search.astro +608 -0
  181. package/src/components/layout/TableOfContents.astro +68 -0
  182. package/src/components/layout/analytics-client.ts +38 -0
  183. package/src/components/layout/head-scripts.ts +19 -0
  184. package/src/components/layout/nav-utils.ts +87 -0
  185. package/src/components/layout/overrides.ts +32 -0
  186. package/src/components/layout/search/algolia.ts +43 -0
  187. package/src/components/layout/search/endpoint.ts +22 -0
  188. package/src/components/layout/search/flexsearch.ts +52 -0
  189. package/src/components/layout/search/orama-cloud.ts +41 -0
  190. package/src/components/layout/search/orama.ts +26 -0
  191. package/src/components/layout/search/pagefind.ts +43 -0
  192. package/src/components/layout/search/types.ts +163 -0
  193. package/src/components/layout/search/typesense.ts +60 -0
  194. package/src/components/layout/toc-element.ts +108 -0
  195. package/src/core/bridge.ts +92 -0
  196. package/src/core/config.ts +112 -0
  197. package/src/core/content.ts +50 -0
  198. package/src/core/data.ts +128 -0
  199. package/src/core/define-components.ts +34 -0
  200. package/src/core/define-meta.ts +20 -0
  201. package/src/core/deployment-env.ts +73 -0
  202. package/src/core/diagnostics.ts +104 -0
  203. package/src/core/frontmatter.ts +43 -0
  204. package/src/core/graph.ts +128 -0
  205. package/src/core/i18n-ui.ts +171 -0
  206. package/src/core/i18n.ts +169 -0
  207. package/src/core/last-modified.ts +88 -0
  208. package/src/core/links.ts +352 -0
  209. package/src/core/load-module.ts +15 -0
  210. package/src/core/manifest.ts +126 -0
  211. package/src/core/meta.ts +97 -0
  212. package/src/core/navigation.ts +392 -0
  213. package/src/core/package-root.ts +37 -0
  214. package/src/core/project-graph.ts +153 -0
  215. package/src/core/project.ts +56 -0
  216. package/src/core/schema.ts +1057 -0
  217. package/src/core/server-features.ts +23 -0
  218. package/src/core/sources/assets.ts +77 -0
  219. package/src/core/sources/cache.ts +122 -0
  220. package/src/core/sources/filesystem.ts +99 -0
  221. package/src/core/sources/mdx-remote.ts +215 -0
  222. package/src/core/sources/mintlify.ts +161 -0
  223. package/src/core/sources/normalize.ts +243 -0
  224. package/src/core/sources/notion.ts +440 -0
  225. package/src/core/sources/portable-text.ts +143 -0
  226. package/src/core/sources/read.ts +36 -0
  227. package/src/core/sources/resolve.ts +158 -0
  228. package/src/core/sources/sanity.ts +218 -0
  229. package/src/core/sources/types.ts +105 -0
  230. package/src/core/tsconfig-aliases.ts +201 -0
  231. package/src/core/types.ts +261 -0
  232. package/src/core/ui-packs/ar.ts +47 -0
  233. package/src/core/ui-packs/bg.ts +47 -0
  234. package/src/core/ui-packs/bn.ts +47 -0
  235. package/src/core/ui-packs/ca.ts +47 -0
  236. package/src/core/ui-packs/cs.ts +47 -0
  237. package/src/core/ui-packs/da.ts +47 -0
  238. package/src/core/ui-packs/de.ts +47 -0
  239. package/src/core/ui-packs/el.ts +47 -0
  240. package/src/core/ui-packs/es.ts +47 -0
  241. package/src/core/ui-packs/fa.ts +47 -0
  242. package/src/core/ui-packs/fi.ts +47 -0
  243. package/src/core/ui-packs/fr.ts +47 -0
  244. package/src/core/ui-packs/he.ts +47 -0
  245. package/src/core/ui-packs/hi.ts +47 -0
  246. package/src/core/ui-packs/hr.ts +47 -0
  247. package/src/core/ui-packs/hu.ts +47 -0
  248. package/src/core/ui-packs/id.ts +47 -0
  249. package/src/core/ui-packs/index.ts +87 -0
  250. package/src/core/ui-packs/it.ts +47 -0
  251. package/src/core/ui-packs/ja.ts +47 -0
  252. package/src/core/ui-packs/ko.ts +47 -0
  253. package/src/core/ui-packs/nl.ts +47 -0
  254. package/src/core/ui-packs/no.ts +47 -0
  255. package/src/core/ui-packs/pl.ts +47 -0
  256. package/src/core/ui-packs/pt-br.ts +47 -0
  257. package/src/core/ui-packs/pt.ts +47 -0
  258. package/src/core/ui-packs/ro.ts +47 -0
  259. package/src/core/ui-packs/ru.ts +47 -0
  260. package/src/core/ui-packs/sk.ts +47 -0
  261. package/src/core/ui-packs/sr.ts +47 -0
  262. package/src/core/ui-packs/sv.ts +47 -0
  263. package/src/core/ui-packs/th.ts +47 -0
  264. package/src/core/ui-packs/tr.ts +47 -0
  265. package/src/core/ui-packs/uk.ts +47 -0
  266. package/src/core/ui-packs/vi.ts +47 -0
  267. package/src/core/ui-packs/zh-tw.ts +47 -0
  268. package/src/core/ui-packs/zh.ts +47 -0
  269. package/src/core/version.ts +23 -0
  270. package/src/deploy/robots.ts +20 -0
  271. package/src/deploy/rss.ts +128 -0
  272. package/src/deploy/sitemap.ts +28 -0
  273. package/src/index.ts +39 -0
  274. package/src/markdown/code-title.ts +71 -0
  275. package/src/markdown/directives.ts +83 -0
  276. package/src/markdown/heading-anchors.ts +137 -0
  277. package/src/markdown/index.ts +228 -0
  278. package/src/markdown/inline-code.ts +108 -0
  279. package/src/markdown/language-icon.ts +172 -0
  280. package/src/markdown/math.ts +32 -0
  281. package/src/markdown/mdast.ts +48 -0
  282. package/src/markdown/mermaid.ts +37 -0
  283. package/src/markdown/package-commands.ts +159 -0
  284. package/src/markdown/package-install.ts +40 -0
  285. package/src/migrate/fumadocs/config.ts +155 -0
  286. package/src/migrate/fumadocs/content.ts +365 -0
  287. package/src/migrate/fumadocs/frontmatter.ts +18 -0
  288. package/src/migrate/fumadocs/groups.ts +230 -0
  289. package/src/migrate/fumadocs/index.ts +337 -0
  290. package/src/migrate/fumadocs/meta.ts +244 -0
  291. package/src/migrate/migrate.ts +53 -0
  292. package/src/migrate/mintlify/config.ts +1040 -0
  293. package/src/migrate/mintlify/content.ts +98 -0
  294. package/src/migrate/mintlify/frontmatter.ts +126 -0
  295. package/src/migrate/mintlify/i18n.ts +51 -0
  296. package/src/migrate/mintlify/icons.ts +128 -0
  297. package/src/migrate/mintlify/index.ts +266 -0
  298. package/src/migrate/mintlify/snippets.ts +306 -0
  299. package/src/migrate/mintlify/transform.ts +80 -0
  300. package/src/migrate/nextra/content.ts +46 -0
  301. package/src/migrate/nextra/frontmatter.ts +40 -0
  302. package/src/migrate/nextra/index.ts +374 -0
  303. package/src/migrate/nextra/meta.ts +266 -0
  304. package/src/migrate/shared.ts +720 -0
  305. package/src/migrate/starlight/config.ts +459 -0
  306. package/src/migrate/starlight/content.ts +78 -0
  307. package/src/migrate/starlight/frontmatter.ts +111 -0
  308. package/src/migrate/starlight/i18n.ts +54 -0
  309. package/src/migrate/starlight/index.ts +131 -0
  310. package/src/og/card.ts +92 -0
  311. package/src/og/index.ts +2 -0
  312. package/src/openapi/scalar.ts +246 -0
  313. package/src/registry/eject.ts +310 -0
  314. package/src/registry/registry.ts +100 -0
  315. package/src/registry/rewrite-imports.ts +39 -0
  316. package/src/runtime/index.ts +14 -0
  317. package/src/search/build.ts +23 -0
  318. package/src/search/documents.ts +164 -0
  319. package/src/search/orama-index.ts +66 -0
  320. package/src/search/providers.ts +91 -0
  321. package/src/search/sync/algolia.ts +30 -0
  322. package/src/search/sync/index.ts +50 -0
  323. package/src/search/sync/orama-cloud.ts +40 -0
  324. package/src/search/sync/typesense.ts +65 -0
  325. package/src/seo/jsonld.ts +113 -0
  326. package/src/theme/entry.ts +637 -0
  327. package/src/theme/fonts.ts +198 -0
  328. package/src/theme/icons.ts +184 -0
  329. package/src/theme/palette.ts +143 -0
  330. package/src/theme/twoslash.ts +81 -0
@@ -0,0 +1,104 @@
1
+ ---
2
+ import Icon from "../Icon.astro";
3
+
4
+ interface Props {
5
+ title?: string;
6
+ href?: string;
7
+ icon?: string;
8
+ iconType?: string;
9
+ img?: string;
10
+ horizontal?: boolean | string;
11
+ cta?: string;
12
+ arrow?: boolean | string;
13
+ type?: "info" | "warning" | "note" | "tip" | "check" | "danger";
14
+ color?: string;
15
+ }
16
+
17
+ const { arrow, color, cta, horizontal, href, icon, iconType, img, title, type } =
18
+ Astro.props;
19
+ const Tag = href ? "a" : "div";
20
+ const external = href?.startsWith("http");
21
+ const isHorizontal = horizontal === true || horizontal === "true";
22
+ const showArrow =
23
+ href && arrow === undefined ? external : arrow === true || arrow === "true";
24
+ const iconByType = {
25
+ check: "circle-check",
26
+ danger: "circle-x",
27
+ info: "info",
28
+ note: "info",
29
+ tip: "lightbulb",
30
+ warning: "triangle-alert",
31
+ };
32
+ const iconClass = {
33
+ check: "text-green-600 dark:text-green-400",
34
+ danger: "text-red-600 dark:text-red-400",
35
+ info: "text-blue-600 dark:text-blue-400",
36
+ note: "text-muted-foreground/70",
37
+ tip: "text-accent",
38
+ warning: "text-amber-600 dark:text-amber-400",
39
+ };
40
+ const iconName = icon ?? (type ? iconByType[type] : undefined);
41
+ const variantClass = {
42
+ check: "border-green-500/30 bg-green-500/10",
43
+ danger: "border-red-500/30 bg-red-500/10",
44
+ info: "border-blue-500/30 bg-blue-500/10",
45
+ note: "border-border bg-muted/40",
46
+ tip: "border-accent/30 bg-accent/10",
47
+ warning: "border-amber-500/30 bg-amber-500/10",
48
+ }[type ?? "note"];
49
+ ---
50
+
51
+ <Tag
52
+ class:list={[
53
+ "not-prose block overflow-hidden rounded-blume border text-inherit no-underline! transition-colors hover:no-underline! hover:[&[href]]:border-accent",
54
+ type ? variantClass : "border-border bg-background",
55
+ isHorizontal ? "sm:flex" : "",
56
+ ]}
57
+ data-blume-card
58
+ href={href}
59
+ rel={external ? "noreferrer" : undefined}
60
+ target={external ? "_blank" : undefined}
61
+ >
62
+ {
63
+ img && (
64
+ <img
65
+ alt=""
66
+ class:list={[
67
+ "w-full object-cover",
68
+ isHorizontal ? "sm:w-40 sm:shrink-0" : "max-h-48",
69
+ ]}
70
+ src={img}
71
+ />
72
+ )
73
+ }
74
+ <div class="p-5">
75
+ {
76
+ iconName && (
77
+ <div class:list={["mb-2.5", color ? "" : type ? iconClass[type] : "text-accent"]}>
78
+ <Icon color={color} iconType={iconType} name={iconName} size={20} />
79
+ </div>
80
+ )
81
+ }
82
+ {
83
+ title && (
84
+ <p class="mt-0! mb-1.5! flex items-center gap-1.5 font-medium text-foreground">
85
+ {title}
86
+ {showArrow && (
87
+ <Icon class="text-muted-foreground" name="arrow-right" size={14} />
88
+ )}
89
+ </p>
90
+ )
91
+ }
92
+ <div class="font-normal text-muted-foreground text-sm [&>:first-child]:mt-0! [&>:last-child]:mb-0!">
93
+ <slot />
94
+ </div>
95
+ {
96
+ cta && (
97
+ <p class="mt-4! mb-0! flex items-center gap-1.5 font-medium text-accent text-sm">
98
+ {cta}
99
+ {showArrow && <Icon name="arrow-right" size={14} />}
100
+ </p>
101
+ )
102
+ }
103
+ </div>
104
+ </Tag>
@@ -0,0 +1,14 @@
1
+ ---
2
+ interface Props {
3
+ cols?: number;
4
+ }
5
+
6
+ const { cols = 2 } = Astro.props;
7
+ ---
8
+
9
+ <div
10
+ class="not-prose my-6 grid grid-cols-1 gap-4 sm:grid-cols-[repeat(var(--blume-cols),minmax(0,1fr))]"
11
+ style={`--blume-cols:${cols}`}
12
+ >
13
+ <slot />
14
+ </div>
@@ -0,0 +1,28 @@
1
+ ---
2
+ // Render a code string highlighted with Blume's Markdown code-block theme — the
3
+ // same Shiki themes, transformers, and dual light/dark swap as fenced code.
4
+ // Use it to show themed code outside the Markdown pipeline (a landing page, a
5
+ // custom component) where there's no fence to write.
6
+ //
7
+ // <CodeBlock lang="ts" code={`export const x = 1;`} />
8
+ //
9
+ // The theme's code styles are scoped to `.prose`, so the output is wrapped in a
10
+ // `.prose` container (`max-w-none` so it fills its own column rather than the
11
+ // prose reading measure); that's what makes the light/dark swap work on a bare
12
+ // page without the manual `[data-theme]` CSS it would otherwise need.
13
+ import { highlightCode } from "../../markdown/index.ts";
14
+
15
+ interface Props {
16
+ /** The source to highlight. */
17
+ code: string;
18
+ /** Shiki language id (default `txt`); an unknown one renders plain. */
19
+ lang?: string;
20
+ /** Show the brand language icon in the header (default on, like fences). */
21
+ icons?: boolean;
22
+ }
23
+
24
+ const { code, lang = "txt", icons } = Astro.props;
25
+ const html = await highlightCode(code.replace(/\n+$/u, ""), lang, { icons });
26
+ ---
27
+
28
+ <div class="prose max-w-none"><Fragment set:html={html} /></div>
@@ -0,0 +1,13 @@
1
+ ---
2
+ import Tabs from "./Tabs.astro";
3
+
4
+ interface Props {
5
+ dropdown?: boolean;
6
+ }
7
+
8
+ const { dropdown = false } = Astro.props;
9
+ ---
10
+
11
+ <Tabs dropdown={dropdown} hash={false}>
12
+ <slot />
13
+ </Tabs>
@@ -0,0 +1,15 @@
1
+ ---
2
+ const { variant = "compact" } = Astro.props;
3
+ ---
4
+
5
+ <div
6
+ class:list={[
7
+ "not-prose my-6",
8
+ variant === "table"
9
+ ? "space-y-4"
10
+ : "grid grid-cols-2 gap-x-5 gap-y-4 sm:grid-cols-4",
11
+ ]}
12
+ data-blume-color={variant}
13
+ >
14
+ <slot />
15
+ </div>
@@ -0,0 +1,87 @@
1
+ ---
2
+ interface ColorValue {
3
+ dark?: string;
4
+ light?: string;
5
+ }
6
+
7
+ interface Props {
8
+ name: string;
9
+ value: string | ColorValue;
10
+ }
11
+
12
+ const { name, value } = Astro.props;
13
+
14
+ const lightValue = typeof value === "string" ? value : value.light ?? value.dark;
15
+ const darkValue = typeof value === "string" ? value : value.dark ?? value.light;
16
+ const displayValue =
17
+ lightValue && darkValue && lightValue !== darkValue
18
+ ? `${lightValue} / ${darkValue}`
19
+ : lightValue;
20
+ ---
21
+
22
+ <button
23
+ aria-label={`Copy ${name} color ${displayValue}`}
24
+ class="group flex w-full min-w-0 cursor-pointer flex-col gap-2.5 text-center focus:outline-none"
25
+ data-blume-color-copy={displayValue}
26
+ style={`--blume-color-light:${lightValue};--blume-color-dark:${darkValue};`}
27
+ type="button"
28
+ >
29
+ <span
30
+ class="block aspect-square w-full rounded-2xl border border-border/60 shadow-sm transition group-hover:ring-2 group-hover:ring-accent/30 group-focus-visible:ring-2 group-focus-visible:ring-accent/40"
31
+ data-blume-color-swatch
32
+ style="background:var(--blume-color-light)"
33
+ >
34
+ </span>
35
+ <span class="block min-w-0 leading-tight">
36
+ <span class="block truncate font-semibold text-foreground text-sm">
37
+ {name}
38
+ </span>
39
+ <span
40
+ class="mt-0.5 block truncate font-mono text-muted-foreground text-xs uppercase"
41
+ data-blume-color-status
42
+ >
43
+ {displayValue}
44
+ </span>
45
+ </span>
46
+ </button>
47
+
48
+ <style>
49
+ :global(.dark) [data-blume-color-swatch] {
50
+ background: var(--blume-color-dark, var(--blume-color-light));
51
+ }
52
+ </style>
53
+
54
+ <script>
55
+ const state = window as Window & { __blumeColorCopy?: boolean };
56
+ if (!state.__blumeColorCopy) {
57
+ state.__blumeColorCopy = true;
58
+ document.addEventListener("click", async (event) => {
59
+ const target = event.target;
60
+ if (!(target instanceof Element)) {
61
+ return;
62
+ }
63
+
64
+ const button = target.closest<HTMLButtonElement>("[data-blume-color-copy]");
65
+ if (!button) {
66
+ return;
67
+ }
68
+
69
+ try {
70
+ await navigator.clipboard.writeText(button.dataset.blumeColorCopy ?? "");
71
+ } catch {
72
+ return;
73
+ }
74
+
75
+ const status = button.querySelector<HTMLElement>("[data-blume-color-status]");
76
+ if (!status) {
77
+ return;
78
+ }
79
+
80
+ const original = status.textContent;
81
+ status.textContent = "Copied";
82
+ window.setTimeout(() => {
83
+ status.textContent = original;
84
+ }, 1500);
85
+ });
86
+ }
87
+ </script>
@@ -0,0 +1,10 @@
1
+ ---
2
+ const { title } = Astro.props;
3
+ ---
4
+
5
+ <div class="rounded-blume border border-border bg-background p-4">
6
+ {title && <p class="mt-0! mb-3! font-medium text-foreground text-sm">{title}</p>}
7
+ <div class="grid grid-cols-2 gap-x-5 gap-y-4 sm:grid-cols-4">
8
+ <slot />
9
+ </div>
10
+ </div>
@@ -0,0 +1,6 @@
1
+ ---
2
+ ---
3
+
4
+ <div class="min-w-0">
5
+ <slot />
6
+ </div>
@@ -0,0 +1,9 @@
1
+ ---
2
+ import CardGroup from "./CardGroup.astro";
3
+
4
+ const { cols = 2 } = Astro.props;
5
+ ---
6
+
7
+ <CardGroup cols={cols}>
8
+ <slot />
9
+ </CardGroup>
@@ -0,0 +1,65 @@
1
+ ---
2
+ // Render an example file (under the project's `examples/` dir) as a live,
3
+ // hydrated preview alongside its highlighted source, in tabs. `path` is the
4
+ // file's location under `examples/` without its extension, e.g.
5
+ // `<Component path="forms/login" />` for `examples/forms/login.tsx`.
6
+ //
7
+ // Blume discovers `examples/` at build time and generates `blume:examples`: a
8
+ // map of path → { Component (a static hydration wrapper), code, lang }. React,
9
+ // Vue, Svelte, and Astro examples are all supported. The source is highlighted
10
+ // with the same Shiki setup as ordinary code fences.
11
+ import { highlightCode } from "../../markdown/index.ts";
12
+ import Tab from "./Tab.astro";
13
+ import Tabs from "./Tabs.astro";
14
+ // Generated per project; resolves to an empty map when there are no examples.
15
+ import { examples } from "blume:examples";
16
+
17
+ interface Props {
18
+ path: string;
19
+ }
20
+
21
+ const { path } = Astro.props;
22
+ const entry = examples[path];
23
+ const Preview = entry?.Component;
24
+
25
+ // Highlight the source with the shared helper so it matches Markdown fences.
26
+ // `blume-source` makes the inner `<code>` (not the `<pre>`) the scroll/height-
27
+ // capped box — see the theme entry — so the copy button, pinned to the `<pre>`,
28
+ // stays put. This pane already lives inside `.prose`, so the theme styles it.
29
+ const codeHtml = entry
30
+ ? await highlightCode(entry.code, entry.lang, { className: "blume-source" })
31
+ : undefined;
32
+
33
+ // Both tabs share one height so toggling them never shifts the layout. Size it
34
+ // to the source (≈21px/line + padding), clamped to a comfortable 18rem floor and
35
+ // a 400px ceiling — taller sources scroll inside the pane.
36
+ const LINE_PX = 21;
37
+ const PADDING_PX = 36;
38
+ const lineCount = entry ? entry.code.replace(/\n+$/u, "").split("\n").length : 0;
39
+ const paneHeight = Math.min(400, Math.max(288, lineCount * LINE_PX + PADDING_PX));
40
+ const paneStyle = `height:${paneHeight}px`;
41
+ ---
42
+
43
+ {
44
+ entry ? (
45
+ // `sync={false}`: each preview's Preview/Code tabs are independent — unlike
46
+ // CodeGroup, switching one Component must not switch the others.
47
+ <Tabs hash={false} sync={false}>
48
+ <Tab
49
+ class="flex items-center justify-center overflow-auto"
50
+ style={paneStyle}
51
+ title="Preview"
52
+ >
53
+ <Preview />
54
+ </Tab>
55
+ <Tab class="overflow-hidden" style={paneStyle} title="Code">
56
+ <Fragment set:html={codeHtml} />
57
+ </Tab>
58
+ </Tabs>
59
+ ) : (
60
+ <div class="not-prose my-6 rounded-blume border border-border px-3 py-2 text-muted-foreground text-sm">
61
+ No example found at <code class="font-mono">{path}</code>. Add it under{" "}
62
+ <code class="font-mono">examples/</code> in your project.
63
+ </div>
64
+ )
65
+ }
@@ -0,0 +1,44 @@
1
+ ---
2
+ // Render a git-style diff with `@pierre/diffs`, fully at build time. The library
3
+ // emits a self-contained blob whose styles are scoped to `:host`, so we mount it
4
+ // in a declarative shadow root — no client JS. `--blume-diff-color-scheme`
5
+ // (set in the theme entry from `data-theme`) drives the diff's `light-dark()`.
6
+ //
7
+ // Inputs (one of): `patch`/`src` (unified patch), `before`+`after` (file paths),
8
+ // or `old`+`new` (inline strings, with optional `lang`).
9
+ import { renderDiff } from "./diff.ts";
10
+
11
+ interface Props {
12
+ after?: string;
13
+ before?: string;
14
+ lang?: string;
15
+ new?: string;
16
+ old?: string;
17
+ patch?: string;
18
+ src?: string;
19
+ }
20
+
21
+ let html: string | undefined;
22
+ let error: string | undefined;
23
+
24
+ try {
25
+ html = await renderDiff(Astro.props);
26
+ } catch (cause) {
27
+ error = cause instanceof Error ? cause.message : String(cause);
28
+ }
29
+
30
+ const COLOR_SCHEME =
31
+ "<style>:host{color-scheme:var(--blume-diff-color-scheme, light dark)}</style>";
32
+ ---
33
+
34
+ {
35
+ error ? (
36
+ <div class="not-prose my-6 rounded-blume border border-border px-3 py-2 text-muted-foreground text-sm">
37
+ Could not render diff: {error}
38
+ </div>
39
+ ) : (
40
+ <blume-diff class="not-prose my-6 block overflow-hidden rounded-blume border border-border">
41
+ <template shadowrootmode="open" set:html={html + COLOR_SCHEME} />
42
+ </blume-diff>
43
+ )
44
+ }
@@ -0,0 +1,11 @@
1
+ ---
2
+ import AccordionItem from "./AccordionItem.astro";
3
+
4
+ const { defaultOpen = false, title = "Show more" } = Astro.props;
5
+ ---
6
+
7
+ <div class="not-prose my-4 overflow-hidden rounded-blume border border-border">
8
+ <AccordionItem defaultOpen={defaultOpen} title={title}>
9
+ <slot />
10
+ </AccordionItem>
11
+ </div>
@@ -0,0 +1,8 @@
1
+ ---
2
+ ---
3
+
4
+ <div
5
+ class="not-prose my-6 rounded-blume border border-border p-5 text-sm [&_ul]:m-0! [&_ul]:list-none [&_ul]:ps-4 [&>ul]:ps-0"
6
+ >
7
+ <slot />
8
+ </div>
@@ -0,0 +1,70 @@
1
+ ---
2
+ import { createSatteriMarkdownProcessor } from "@astrojs/markdown-satteri";
3
+
4
+ interface Props {
5
+ caption?: string;
6
+ hint?: string;
7
+ }
8
+
9
+ const { caption, hint } = Astro.props;
10
+
11
+ const escapeRawHtml = (value: string): string =>
12
+ value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
13
+
14
+ const unwrapParagraph = (html: string): string => {
15
+ const trimmed = html.trim();
16
+ const match = trimmed.match(/^<p>(?<content>[\s\S]*)<\/p>$/u);
17
+ return match?.groups?.content ?? trimmed;
18
+ };
19
+
20
+ const markdownProcessor = await createSatteriMarkdownProcessor();
21
+ const captionHtml = caption
22
+ ? unwrapParagraph((await markdownProcessor.render(escapeRawHtml(caption))).code)
23
+ : undefined;
24
+ ---
25
+
26
+ <blume-frame class="not-prose my-6 block">
27
+ <figure class="m-0">
28
+ {
29
+ hint && (
30
+ <p class="mb-2 text-muted-foreground text-sm leading-6">
31
+ {hint}
32
+ </p>
33
+ )
34
+ }
35
+ <div
36
+ class="flex justify-center overflow-hidden rounded-blume border border-border bg-muted/30 p-6 [&>:first-child]:m-0! [&_img]:h-auto [&_img]:max-w-full [&_video]:h-auto [&_video]:max-w-full"
37
+ >
38
+ <slot />
39
+ </div>
40
+ {
41
+ captionHtml && (
42
+ <figcaption
43
+ class="mt-2 text-center text-muted-foreground text-xs leading-5 [&_a]:font-medium [&_a]:text-foreground [&_a]:underline [&_strong]:font-semibold [&_strong]:text-foreground"
44
+ set:html={captionHtml}
45
+ />
46
+ )
47
+ }
48
+ </figure>
49
+ </blume-frame>
50
+
51
+ <script>
52
+ class BlumeFrame extends HTMLElement {
53
+ connectedCallback() {
54
+ for (const video of this.querySelectorAll<HTMLVideoElement>(
55
+ "video[autoplay]"
56
+ )) {
57
+ video.playsInline = true;
58
+ video.loop = true;
59
+ video.muted = true;
60
+ video.setAttribute("playsinline", "");
61
+ video.setAttribute("loop", "");
62
+ video.setAttribute("muted", "");
63
+ }
64
+ }
65
+ }
66
+
67
+ if (!customElements.get("blume-frame")) {
68
+ customElements.define("blume-frame", BlumeFrame);
69
+ }
70
+ </script>
@@ -0,0 +1,110 @@
1
+ ---
2
+ // A card linking to a GitHub repository with its star and fork counts, fetched
3
+ // at build time (no client JS). Pass `owner`/`repo`, or omit them to use the
4
+ // repo from blume.config. A `GITHUB_TOKEN` env var lifts the API rate limit.
5
+ // If the API is unreachable the card still renders, just without counts.
6
+ import data from "blume:data";
7
+ import { GITHUB_MARK } from "../github-mark.ts";
8
+ import { fetchRepositoryInfo } from "./github-info.ts";
9
+
10
+ interface Props {
11
+ owner?: string;
12
+ repo?: string;
13
+ token?: string;
14
+ }
15
+
16
+ // The resolved config exposes the repo as `repoUrl`, not `github`; parse the
17
+ // owner/repo back out so <GithubInfo /> can default to the configured repo.
18
+ const repoMatch = data.config.repoUrl?.match(
19
+ /github\.com\/(?<owner>[^/]+)\/(?<repo>[^/]+)/u
20
+ );
21
+ const owner = Astro.props.owner ?? repoMatch?.groups?.owner;
22
+ const repo = Astro.props.repo ?? repoMatch?.groups?.repo;
23
+ const token = Astro.props.token ?? process.env.GITHUB_TOKEN;
24
+
25
+ const info =
26
+ owner && repo ? await fetchRepositoryInfo({ owner, repo, token }) : null;
27
+
28
+ // Compact notation matches GitHub's own counts (e.g. 1.2k, 34.5k).
29
+ const numbers = new Intl.NumberFormat("en", {
30
+ maximumFractionDigits: 1,
31
+ notation: "compact",
32
+ });
33
+
34
+ const statIcon =
35
+ "size-3.5 shrink-0 text-muted-foreground"; /* shared classes for stat icons */
36
+ ---
37
+
38
+ {
39
+ owner && repo && (
40
+ <a
41
+ class="not-prose my-6 flex flex-col gap-2 rounded-blume border border-border p-4 no-underline! transition-colors hover:border-foreground/30 hover:bg-muted/40"
42
+ href={`https://github.com/${owner}/${repo}`}
43
+ rel="noreferrer"
44
+ target="_blank"
45
+ >
46
+ <span class="flex items-center gap-2 font-medium text-foreground text-sm">
47
+ <svg
48
+ aria-hidden="true"
49
+ class="shrink-0 text-muted-foreground"
50
+ fill="currentColor"
51
+ height="16"
52
+ set:html={GITHUB_MARK}
53
+ viewBox="0 0 16 16"
54
+ width="16"
55
+ xmlns="http://www.w3.org/2000/svg"
56
+ />
57
+ <span class="truncate">
58
+ {owner}/{repo}
59
+ </span>
60
+ </span>
61
+
62
+ {info?.description && (
63
+ <span class="text-muted-foreground text-sm">{info.description}</span>
64
+ )}
65
+
66
+ {info && (
67
+ <span class="flex items-center gap-4 text-muted-foreground text-xs">
68
+ <span class="flex items-center gap-1.5">
69
+ <svg
70
+ aria-hidden="true"
71
+ class={statIcon}
72
+ fill="none"
73
+ height="14"
74
+ stroke="currentColor"
75
+ stroke-linecap="round"
76
+ stroke-linejoin="round"
77
+ stroke-width="2"
78
+ viewBox="0 0 24 24"
79
+ width="14"
80
+ >
81
+ <path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z" />
82
+ </svg>
83
+ <span>{numbers.format(info.stars)}</span>
84
+ </span>
85
+ <span class="flex items-center gap-1.5">
86
+ <svg
87
+ aria-hidden="true"
88
+ class={statIcon}
89
+ fill="none"
90
+ height="14"
91
+ stroke="currentColor"
92
+ stroke-linecap="round"
93
+ stroke-linejoin="round"
94
+ stroke-width="2"
95
+ viewBox="0 0 24 24"
96
+ width="14"
97
+ >
98
+ <circle cx="12" cy="18" r="3" />
99
+ <circle cx="6" cy="6" r="3" />
100
+ <circle cx="18" cy="6" r="3" />
101
+ <path d="M18 9v2c0 .6-.4 1-1 1H7c-.6 0-1-.4-1-1V9" />
102
+ <path d="M12 12v3" />
103
+ </svg>
104
+ <span>{numbers.format(info.forks)}</span>
105
+ </span>
106
+ </span>
107
+ )}
108
+ </a>
109
+ )
110
+ }
@@ -0,0 +1,24 @@
1
+ ---
2
+ import "katex/dist/katex.min.css";
3
+ import katex from "katex";
4
+
5
+ interface Props {
6
+ code: string;
7
+ display?: boolean;
8
+ }
9
+
10
+ const { code, display = false } = Astro.props;
11
+
12
+ const html = katex.renderToString(code, {
13
+ displayMode: display,
14
+ throwOnError: false,
15
+ });
16
+ ---
17
+
18
+ {
19
+ display ? (
20
+ <div class="not-prose my-4 overflow-x-auto" set:html={html} />
21
+ ) : (
22
+ <Fragment set:html={html} />
23
+ )
24
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+ const { title } = Astro.props;
3
+ ---
4
+
5
+ <aside
6
+ class="not-prose my-6 overflow-hidden rounded-blume border border-border/80 bg-background shadow-sm shadow-border/30"
7
+ data-blume-panel
8
+ data-blume-right-rail-item
9
+ >
10
+ {
11
+ title && (
12
+ <p class="m-0! border-border/70 border-b bg-muted/35 px-3.5 py-2 font-medium text-muted-foreground text-xs">
13
+ {title}
14
+ </p>
15
+ )
16
+ }
17
+ <div class="px-3.5 py-3 text-sm leading-6 [&>:first-child]:mt-0! [&>:last-child]:mb-0!">
18
+ <slot />
19
+ </div>
20
+ </aside>