@k11k/better-blocks-astro-renderer 0.2.0 → 0.3.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/README.md +42 -15
- package/index.ts +1 -0
- package/package.json +4 -1
- package/src/Block.astro +3 -0
- package/src/Diagram.astro +40 -0
- package/src/types.ts +11 -1
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
<a href="https://github.com/k11k-labs/better-blocks-astro-renderer/blob/main/LICENSE">
|
|
13
13
|
<img alt="license" src="https://img.shields.io/npm/l/@k11k/better-blocks-astro-renderer.svg" />
|
|
14
14
|
</a>
|
|
15
|
+
<a href="https://buymeacoffee.com/k11k">
|
|
16
|
+
<img alt="Buy Me a Coffee" src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-support-FFDD00?logo=buymeacoffee&logoColor=black" />
|
|
17
|
+
</a>
|
|
15
18
|
</p>
|
|
16
19
|
|
|
17
20
|
<p align="center">
|
|
@@ -31,7 +34,8 @@
|
|
|
31
34
|
7. [Custom Renderers](#custom-renderers)
|
|
32
35
|
8. [TypeScript](#typescript)
|
|
33
36
|
9. [Contributing](#contributing)
|
|
34
|
-
10. [
|
|
37
|
+
10. [Support this project](#support-this-project)
|
|
38
|
+
11. [License](#license)
|
|
35
39
|
|
|
36
40
|
---
|
|
37
41
|
|
|
@@ -110,22 +114,31 @@ import 'katex/dist/katex.min.css';
|
|
|
110
114
|
|
|
111
115
|
`katex` ships as a dependency of this package, so the stylesheet resolves without a separate install. If KaTeX fails to parse a formula, the renderer falls back to the raw LaTeX source instead of crashing.
|
|
112
116
|
|
|
117
|
+
### Diagrams (Mermaid)
|
|
118
|
+
|
|
119
|
+
[Mermaid](https://mermaid.js.org/) diagram blocks (`{ type: 'diagram', format: 'mermaid' }`) are **pre-rendered to inline SVG on the server** using [`beautiful-mermaid`](https://www.npmjs.com/package/beautiful-mermaid) — a pure-Node renderer that needs **no headless browser** (no Puppeteer, no Chromium download). Like math, rendering happens during SSR and static builds with **zero client-side JavaScript** and no hydration step.
|
|
120
|
+
|
|
121
|
+
Supported diagram types — **flowchart, sequence, state, class, ER, and xychart** — render to a `<div class="mermaid-diagram">` wrapping the generated SVG. Diagram types `beautiful-mermaid` does not implement yet (gantt, pie, mindmap, gitGraph, …) and any source that fails to parse fall back gracefully to the raw definition in a `<pre class="mermaid-source">`, so content is never lost.
|
|
122
|
+
|
|
123
|
+
`beautiful-mermaid` ships as a dependency of this package, so no extra install or stylesheet is required.
|
|
124
|
+
|
|
113
125
|
## Supported Blocks
|
|
114
126
|
|
|
115
|
-
| Block | Default element
|
|
116
|
-
| ------------------------------- |
|
|
117
|
-
| `paragraph` | `<p>`
|
|
118
|
-
| `heading` (1–6) | `<h1>`–`<h6>`
|
|
119
|
-
| `list` (ordered/unordered/todo) | `<ol>` / `<ul>`
|
|
120
|
-
| `list-item` | `<li>`
|
|
121
|
-
| `link` | `<a>`
|
|
122
|
-
| `quote` | `<blockquote>`
|
|
123
|
-
| `code` | `<pre><code>`
|
|
124
|
-
| `image` | `<figure><img>`
|
|
125
|
-
| `horizontal-line` | `<hr>`
|
|
126
|
-
| `table` | `<table>`
|
|
127
|
-
| `media-embed` | `<iframe>` (16:9)
|
|
128
|
-
| `math` (inline/block) | `<span>` / `<div>`
|
|
127
|
+
| Block | Default element | Source |
|
|
128
|
+
| ------------------------------- | -------------------- | --------------------------- |
|
|
129
|
+
| `paragraph` | `<p>` | Strapi core |
|
|
130
|
+
| `heading` (1–6) | `<h1>`–`<h6>` | Strapi core |
|
|
131
|
+
| `list` (ordered/unordered/todo) | `<ol>` / `<ul>` | Strapi core + Better Blocks |
|
|
132
|
+
| `list-item` | `<li>` | Strapi core |
|
|
133
|
+
| `link` | `<a>` | Strapi core |
|
|
134
|
+
| `quote` | `<blockquote>` | Strapi core |
|
|
135
|
+
| `code` | `<pre><code>` | Strapi core |
|
|
136
|
+
| `image` | `<figure><img>` | Strapi core |
|
|
137
|
+
| `horizontal-line` | `<hr>` | Better Blocks |
|
|
138
|
+
| `table` | `<table>` | Better Blocks |
|
|
139
|
+
| `media-embed` | `<iframe>` (16:9) | Better Blocks |
|
|
140
|
+
| `math` (inline/block) | `<span>` / `<div>` | Better Blocks |
|
|
141
|
+
| `diagram` (mermaid) | `<div>` (inline SVG) | Better Blocks |
|
|
129
142
|
|
|
130
143
|
### Block properties
|
|
131
144
|
|
|
@@ -145,6 +158,8 @@ import 'katex/dist/katex.min.css';
|
|
|
145
158
|
| `originalUrl` | media-embed | Original user-provided URL |
|
|
146
159
|
| `format` | math | `inline` (`<span>`) or `block` (`<div>`) |
|
|
147
160
|
| `value` | math | LaTeX source rendered with KaTeX |
|
|
161
|
+
| `format` | diagram | `mermaid` (the only supported diagram format) |
|
|
162
|
+
| `value` | diagram | Mermaid source, pre-rendered to SVG on the server |
|
|
148
163
|
|
|
149
164
|
## Supported Modifiers
|
|
150
165
|
|
|
@@ -217,6 +232,7 @@ The props each custom block component receives:
|
|
|
217
232
|
| `table` / `table-row` / `table-cell` / `table-header-cell` | children via `<slot />` |
|
|
218
233
|
| `media-embed` | `{ url; originalUrl? }` (no slot) |
|
|
219
234
|
| `math` | `{ formula; inline }` (no slot) — bring your own math engine |
|
|
235
|
+
| `diagram` | `{ code; format }` (no slot) — bring your own diagram engine |
|
|
220
236
|
|
|
221
237
|
### Custom modifier renderers
|
|
222
238
|
|
|
@@ -267,6 +283,7 @@ import type {
|
|
|
267
283
|
TableHeaderCellNode,
|
|
268
284
|
MediaEmbedNode,
|
|
269
285
|
MathNode,
|
|
286
|
+
DiagramNode,
|
|
270
287
|
TextAlign,
|
|
271
288
|
CustomBlocksConfig,
|
|
272
289
|
CustomModifiersConfig,
|
|
@@ -327,6 +344,16 @@ yarn lint # Check formatting
|
|
|
327
344
|
- [@k11k/better-blocks-react-renderer](https://github.com/k11k-labs/better-blocks-react-renderer) — React renderer with the same Better Blocks support
|
|
328
345
|
- [@k11k/strapi-plugin-better-blocks](https://github.com/k11k-labs/strapi-plugin-better-blocks) — Strapi plugin that extends the Blocks editor with colors, tables, to-do lists, media embeds, and more
|
|
329
346
|
|
|
347
|
+
## Support this project
|
|
348
|
+
|
|
349
|
+
This package is built and maintained in my free time, and it's free for everyone. If it has saved you time on a project, you can help keep it caffeinated and actively developed:
|
|
350
|
+
|
|
351
|
+
<a href="https://buymeacoffee.com/k11k">
|
|
352
|
+
<img alt="Buy Me a Coffee" src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-support-FFDD00?logo=buymeacoffee&logoColor=black&style=for-the-badge" />
|
|
353
|
+
</a>
|
|
354
|
+
|
|
355
|
+
Every coffee goes toward fixing bugs, reviewing PRs, writing docs, and shipping the features you ask for. Thank you! ☕
|
|
356
|
+
|
|
330
357
|
## License
|
|
331
358
|
|
|
332
359
|
[MIT License](LICENSE) © [k11k-labs](https://github.com/k11k-labs)
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k11k/better-blocks-astro-renderer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Astro renderer for Strapi v5 Blocks content with full Better Blocks plugin support — colors, tables, to-do lists, media embeds, alignment, and more. Native Astro components, zero client-side JavaScript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.ts",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"*.{js,jsx,ts,tsx,astro,json,md,yml,yaml,css}": "prettier --write"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"beautiful-mermaid": "^1.1.3",
|
|
33
34
|
"katex": "^0.16.11"
|
|
34
35
|
},
|
|
35
36
|
"peerDependencies": {
|
|
@@ -65,6 +66,8 @@
|
|
|
65
66
|
"katex",
|
|
66
67
|
"latex",
|
|
67
68
|
"math",
|
|
69
|
+
"mermaid",
|
|
70
|
+
"diagram",
|
|
68
71
|
"cms",
|
|
69
72
|
"headless-cms"
|
|
70
73
|
],
|
package/src/Block.astro
CHANGED
|
@@ -4,6 +4,7 @@ import Inline from './Inline.astro';
|
|
|
4
4
|
import List from './List.astro';
|
|
5
5
|
import Table from './Table.astro';
|
|
6
6
|
import Math from './Math.astro';
|
|
7
|
+
import Diagram from './Diagram.astro';
|
|
7
8
|
import { getBlockStyle, getPlainText } from './utils';
|
|
8
9
|
|
|
9
10
|
interface Props {
|
|
@@ -154,3 +155,5 @@ const EmbedComp = blocks?.['media-embed'] as any;
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
{block.type === 'math' && <Math node={block} blocks={blocks} />}
|
|
158
|
+
|
|
159
|
+
{block.type === 'diagram' && <Diagram node={block} blocks={blocks} />}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { renderMermaidSVG } from 'beautiful-mermaid';
|
|
3
|
+
import type { CustomBlocksConfig, DiagramNode } from './types';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
node: DiagramNode;
|
|
7
|
+
blocks?: CustomBlocksConfig;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { node, blocks } = Astro.props;
|
|
11
|
+
|
|
12
|
+
const source = node.value ?? '';
|
|
13
|
+
const format = node.format ?? 'mermaid';
|
|
14
|
+
const DiagramComp = blocks?.diagram;
|
|
15
|
+
|
|
16
|
+
// beautiful-mermaid renders Mermaid to an SVG string synchronously on the
|
|
17
|
+
// server — no browser, no client-side hydration. It throws on empty or invalid
|
|
18
|
+
// input and on unsupported diagram types (gantt, pie, mindmap, gitGraph, …); in
|
|
19
|
+
// that case we fall back to the raw source in a <pre> so content is never lost.
|
|
20
|
+
let svg: string | null = null;
|
|
21
|
+
if (!DiagramComp && source) {
|
|
22
|
+
try {
|
|
23
|
+
const out = renderMermaidSVG(source);
|
|
24
|
+
svg = typeof out === 'string' && out.includes('<svg') ? out : null;
|
|
25
|
+
} catch {
|
|
26
|
+
svg = null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const Custom = DiagramComp as any;
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
Custom ? (
|
|
34
|
+
<Custom code={source} format={format} />
|
|
35
|
+
) : svg !== null ? (
|
|
36
|
+
<div class="mermaid-diagram" set:html={svg} />
|
|
37
|
+
) : (
|
|
38
|
+
<pre class="mermaid-source">{source}</pre>
|
|
39
|
+
)
|
|
40
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -128,6 +128,13 @@ export type MediaEmbedNode = {
|
|
|
128
128
|
children: [{ type: 'text'; text: '' }];
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
+
export type DiagramNode = {
|
|
132
|
+
type: 'diagram';
|
|
133
|
+
format: 'mermaid';
|
|
134
|
+
value: string;
|
|
135
|
+
children: [{ type: 'text'; text: '' }];
|
|
136
|
+
};
|
|
137
|
+
|
|
131
138
|
export type BlockNode =
|
|
132
139
|
| ParagraphNode
|
|
133
140
|
| HeadingNode
|
|
@@ -138,7 +145,8 @@ export type BlockNode =
|
|
|
138
145
|
| HorizontalLineNode
|
|
139
146
|
| TableNode
|
|
140
147
|
| MediaEmbedNode
|
|
141
|
-
| MathNode
|
|
148
|
+
| MathNode
|
|
149
|
+
| DiagramNode;
|
|
142
150
|
|
|
143
151
|
export type BlocksContent = BlockNode[];
|
|
144
152
|
|
|
@@ -176,6 +184,7 @@ export type AstroComponentFactory = (...args: any[]) => any;
|
|
|
176
184
|
* - `table` / `table-row` / `table-cell` / `table-header-cell` — children via `<slot />`
|
|
177
185
|
* - `media-embed` — `{ url: string; originalUrl?: string }`
|
|
178
186
|
* - `math` — `{ formula: string; inline: boolean }`
|
|
187
|
+
* - `diagram` — `{ code: string; format: 'mermaid' }`
|
|
179
188
|
*/
|
|
180
189
|
export type CustomBlocksConfig = Partial<{
|
|
181
190
|
paragraph: AstroComponentFactory;
|
|
@@ -193,6 +202,7 @@ export type CustomBlocksConfig = Partial<{
|
|
|
193
202
|
'table-header-cell': AstroComponentFactory;
|
|
194
203
|
'media-embed': AstroComponentFactory;
|
|
195
204
|
math: AstroComponentFactory;
|
|
205
|
+
diagram: AstroComponentFactory;
|
|
196
206
|
}>;
|
|
197
207
|
|
|
198
208
|
/**
|