@k11k/better-blocks-astro-renderer 0.3.0 → 0.4.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 CHANGED
@@ -122,6 +122,31 @@ Supported diagram types — **flowchart, sequence, state, class, ER, and xychart
122
122
 
123
123
  `beautiful-mermaid` ships as a dependency of this package, so no extra install or stylesheet is required.
124
124
 
125
+ ### Callouts (Admonitions)
126
+
127
+ Block-level `callout` nodes render GitHub-style alerts in five variants &mdash; `note`, `tip`, `important`, `warning`, and `caution`. Each renders as an `<aside role="note">` with a colored left border, a title row (icon + label), and the nested block children (paragraphs, lists, links, etc.). If a `title` is set on the node it is used; otherwise the localized variant label is shown.
128
+
129
+ Colors come from a small **scoped `<style>`** that ships with the component (still zero client-side JavaScript), and the default palette **adapts to dark mode automatically** via `@media (prefers-color-scheme: dark)`. The accent for each variant is driven by a `--bb-callout-accent` custom property on the `.bb-callout-{variant}` element, so you can retheme colors from your own CSS without replacing the markup:
130
+
131
+ ```css
132
+ /* Recolor a single variant, or override per color scheme */
133
+ .bb-callout-note {
134
+ --bb-callout-accent: #2563eb;
135
+ }
136
+ ```
137
+
138
+ To replace the markup entirely, override the `callout` block. It receives `variant` and `title`; the nested children arrive via `<slot />`:
139
+
140
+ ```astro
141
+ ---
142
+ import { BlocksRenderer } from '@k11k/better-blocks-astro-renderer';
143
+ import MyCallout from '../components/MyCallout.astro';
144
+ const { blocks } = Astro.props;
145
+ ---
146
+
147
+ <BlocksRenderer content={blocks} blocks={{ callout: MyCallout }} />
148
+ ```
149
+
125
150
  ## Supported Blocks
126
151
 
127
152
  | Block | Default element | Source |
@@ -139,6 +164,7 @@ Supported diagram types — **flowchart, sequence, state, class, ER, and xychart
139
164
  | `media-embed` | `<iframe>` (16:9) | Better Blocks |
140
165
  | `math` (inline/block) | `<span>` / `<div>` | Better Blocks |
141
166
  | `diagram` (mermaid) | `<div>` (inline SVG) | Better Blocks |
167
+ | `callout` (admonition) | `<aside>` | Better Blocks |
142
168
 
143
169
  ### Block properties
144
170
 
package/index.ts CHANGED
@@ -22,6 +22,8 @@ export type {
22
22
  MediaEmbedNode,
23
23
  MathNode,
24
24
  DiagramNode,
25
+ CalloutNode,
26
+ CalloutVariant,
25
27
  TextAlign,
26
28
  StyleValue,
27
29
  CustomBlocksConfig,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k11k/better-blocks-astro-renderer",
3
- "version": "0.3.0",
3
+ "version": "0.4.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",
package/src/Block.astro CHANGED
@@ -5,6 +5,7 @@ import List from './List.astro';
5
5
  import Table from './Table.astro';
6
6
  import Math from './Math.astro';
7
7
  import Diagram from './Diagram.astro';
8
+ import Callout from './Callout.astro';
8
9
  import { getBlockStyle, getPlainText } from './utils';
9
10
 
10
11
  interface Props {
@@ -157,3 +158,5 @@ const EmbedComp = blocks?.['media-embed'] as any;
157
158
  {block.type === 'math' && <Math node={block} blocks={blocks} />}
158
159
 
159
160
  {block.type === 'diagram' && <Diagram node={block} blocks={blocks} />}
161
+
162
+ {block.type === 'callout' && <Callout node={block} blocks={blocks} modifiers={modifiers} />}
@@ -0,0 +1,135 @@
1
+ ---
2
+ import type {
3
+ CalloutNode,
4
+ CalloutVariant,
5
+ CustomBlocksConfig,
6
+ CustomModifiersConfig,
7
+ } from './types';
8
+ import Block from './Block.astro';
9
+
10
+ interface Props {
11
+ node: CalloutNode;
12
+ blocks?: CustomBlocksConfig;
13
+ modifiers?: CustomModifiersConfig;
14
+ }
15
+
16
+ const { node, blocks, modifiers } = Astro.props;
17
+
18
+ // GitHub-style alert metadata: default label and octicon path. Accent colors
19
+ // live in the scoped <style> below so they can adapt to dark mode.
20
+ const VARIANTS: Record<CalloutVariant, { label: string; icon: string }> = {
21
+ note: {
22
+ label: 'Note',
23
+ icon: 'M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z',
24
+ },
25
+ tip: {
26
+ label: 'Tip',
27
+ icon: 'M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z',
28
+ },
29
+ important: {
30
+ label: 'Important',
31
+ icon: 'M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z',
32
+ },
33
+ warning: {
34
+ label: 'Warning',
35
+ icon: 'M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z',
36
+ },
37
+ caution: {
38
+ label: 'Caution',
39
+ icon: 'M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .39.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.39.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z',
40
+ },
41
+ };
42
+
43
+ const variant: CalloutVariant = VARIANTS[node.variant] ? node.variant : 'note';
44
+ const meta = VARIANTS[variant];
45
+ const title = node.title?.trim() ? node.title : meta.label;
46
+ const CalloutComp = blocks?.callout as any;
47
+ ---
48
+
49
+ {
50
+ CalloutComp ? (
51
+ <CalloutComp variant={variant} title={node.title}>
52
+ {node.children.map((child) => (
53
+ <Block block={child} blocks={blocks} modifiers={modifiers} />
54
+ ))}
55
+ </CalloutComp>
56
+ ) : (
57
+ <aside class={`bb-callout bb-callout-${variant}`} role="note">
58
+ <p class="bb-callout-title">
59
+ <svg class="bb-callout-icon" viewBox="0 0 16 16" aria-hidden="true">
60
+ <path d={meta.icon} />
61
+ </svg>
62
+ {title}
63
+ </p>
64
+ <div class="bb-callout-body">
65
+ {node.children.map((child) => (
66
+ <Block block={child} blocks={blocks} modifiers={modifiers} />
67
+ ))}
68
+ </div>
69
+ </aside>
70
+ )
71
+ }
72
+
73
+ <style>
74
+ .bb-callout {
75
+ border-left: 0.25rem solid var(--bb-callout-accent, #0969da);
76
+ padding: 0.5rem 1rem;
77
+ margin: 1rem 0;
78
+ }
79
+ .bb-callout-title {
80
+ display: flex;
81
+ align-items: center;
82
+ gap: 0.5rem;
83
+ margin: 0 0 0.25rem;
84
+ font-weight: 600;
85
+ color: var(--bb-callout-accent, #0969da);
86
+ }
87
+ .bb-callout-icon {
88
+ width: 16px;
89
+ height: 16px;
90
+ flex: none;
91
+ fill: currentColor;
92
+ }
93
+ .bb-callout-body > :first-child {
94
+ margin-top: 0;
95
+ }
96
+ .bb-callout-body > :last-child {
97
+ margin-bottom: 0;
98
+ }
99
+
100
+ /* Light-mode accents (GitHub palette) */
101
+ .bb-callout-note {
102
+ --bb-callout-accent: #0969da;
103
+ }
104
+ .bb-callout-tip {
105
+ --bb-callout-accent: #1a7f37;
106
+ }
107
+ .bb-callout-important {
108
+ --bb-callout-accent: #8250df;
109
+ }
110
+ .bb-callout-warning {
111
+ --bb-callout-accent: #9a6700;
112
+ }
113
+ .bb-callout-caution {
114
+ --bb-callout-accent: #cf222e;
115
+ }
116
+
117
+ /* Dark-mode accents adapt automatically */
118
+ @media (prefers-color-scheme: dark) {
119
+ .bb-callout-note {
120
+ --bb-callout-accent: #4493f8;
121
+ }
122
+ .bb-callout-tip {
123
+ --bb-callout-accent: #3fb950;
124
+ }
125
+ .bb-callout-important {
126
+ --bb-callout-accent: #ab7df8;
127
+ }
128
+ .bb-callout-warning {
129
+ --bb-callout-accent: #d29922;
130
+ }
131
+ .bb-callout-caution {
132
+ --bb-callout-accent: #f85149;
133
+ }
134
+ }
135
+ </style>
package/src/types.ts CHANGED
@@ -135,6 +135,15 @@ export type DiagramNode = {
135
135
  children: [{ type: 'text'; text: '' }];
136
136
  };
137
137
 
138
+ export type CalloutVariant = 'note' | 'tip' | 'important' | 'warning' | 'caution';
139
+
140
+ export type CalloutNode = {
141
+ type: 'callout';
142
+ variant: CalloutVariant;
143
+ title?: string;
144
+ children: BlockNode[];
145
+ };
146
+
138
147
  export type BlockNode =
139
148
  | ParagraphNode
140
149
  | HeadingNode
@@ -146,7 +155,8 @@ export type BlockNode =
146
155
  | TableNode
147
156
  | MediaEmbedNode
148
157
  | MathNode
149
- | DiagramNode;
158
+ | DiagramNode
159
+ | CalloutNode;
150
160
 
151
161
  export type BlocksContent = BlockNode[];
152
162
 
@@ -185,6 +195,7 @@ export type AstroComponentFactory = (...args: any[]) => any;
185
195
  * - `media-embed` — `{ url: string; originalUrl?: string }`
186
196
  * - `math` — `{ formula: string; inline: boolean }`
187
197
  * - `diagram` — `{ code: string; format: 'mermaid' }`
198
+ * - `callout` — `{ variant: CalloutVariant; title?: string }` (children via `<slot />`)
188
199
  */
189
200
  export type CustomBlocksConfig = Partial<{
190
201
  paragraph: AstroComponentFactory;
@@ -203,6 +214,7 @@ export type CustomBlocksConfig = Partial<{
203
214
  'media-embed': AstroComponentFactory;
204
215
  math: AstroComponentFactory;
205
216
  diagram: AstroComponentFactory;
217
+ callout: AstroComponentFactory;
206
218
  }>;
207
219
 
208
220
  /**