chaingrow-blog 0.2.2 → 0.7.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 +617 -139
- package/dist/blog-cards-D1j7ZqHK.d.ts +123 -0
- package/dist/blog-cards-DPfcmUUD.d.cts +123 -0
- package/dist/chunk-4EKET2DQ.js +34 -0
- package/dist/chunk-4EKET2DQ.js.map +1 -0
- package/dist/chunk-BXEQ6QKM.js +636 -0
- package/dist/chunk-BXEQ6QKM.js.map +1 -0
- package/dist/chunk-K3HNYPEP.js +176 -0
- package/dist/chunk-K3HNYPEP.js.map +1 -0
- package/dist/index.cjs +237 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +101 -3
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +682 -11
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +168 -2
- package/dist/next/index.d.ts +168 -2
- package/dist/next/index.js +14 -42
- package/dist/next/index.js.map +1 -1
- package/dist/next/webhook.d.cts +1 -1
- package/dist/next/webhook.d.ts +1 -1
- package/dist/react/index.cjs +721 -37
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +189 -31
- package/dist/react/index.d.ts +189 -31
- package/dist/react/index.js +265 -65
- package/dist/react/index.js.map +1 -1
- package/dist/types-DvkCm1rh.d.cts +114 -0
- package/dist/types-DvkCm1rh.d.ts +114 -0
- package/package.json +1 -1
- package/dist/chunk-OTLGKSYD.js +0 -74
- package/dist/chunk-OTLGKSYD.js.map +0 -1
- package/dist/types-CoPD0ejB.d.cts +0 -53
- package/dist/types-CoPD0ejB.d.ts +0 -53
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SCHEMA_ORG_CONTEXT,
|
|
3
|
+
buildBlogJsonLd,
|
|
4
|
+
createClient,
|
|
5
|
+
interleaveMedia
|
|
6
|
+
} from "./chunk-K3HNYPEP.js";
|
|
7
|
+
|
|
8
|
+
// src/next/metadata.ts
|
|
9
|
+
var trimTrailingSlash = (s) => s.replace(/\/+$/, "");
|
|
10
|
+
var normalizePathPrefix = (s) => {
|
|
11
|
+
let p = s.trim();
|
|
12
|
+
if (!p.startsWith("/")) p = "/" + p;
|
|
13
|
+
while (p.length > 1 && p.endsWith("/")) p = p.slice(0, -1);
|
|
14
|
+
return p;
|
|
15
|
+
};
|
|
16
|
+
var blogUrlFor = (alternates, language, slug) => {
|
|
17
|
+
const base = trimTrailingSlash(alternates.siteUrl);
|
|
18
|
+
const rawPrefix = typeof alternates.pathPrefix === "function" ? alternates.pathPrefix(language) : alternates.pathPrefix ?? "/blog";
|
|
19
|
+
return `${base}${normalizePathPrefix(rawPrefix)}/${slug}`;
|
|
20
|
+
};
|
|
21
|
+
async function generateBlogMetadata(slug, language, opts) {
|
|
22
|
+
const blog = await getBlog(slug, language, opts);
|
|
23
|
+
if (!blog) return {};
|
|
24
|
+
const images = blog.og_image ? [blog.og_image] : void 0;
|
|
25
|
+
const description = blog.description ?? void 0;
|
|
26
|
+
const meta = {
|
|
27
|
+
title: blog.title,
|
|
28
|
+
...description ? { description } : {},
|
|
29
|
+
openGraph: {
|
|
30
|
+
type: "article",
|
|
31
|
+
title: blog.title,
|
|
32
|
+
...description ? { description } : {},
|
|
33
|
+
...images ? { images } : {},
|
|
34
|
+
...blog.published_at ? { publishedTime: blog.published_at } : {}
|
|
35
|
+
},
|
|
36
|
+
twitter: {
|
|
37
|
+
card: blog.og_image ? "summary_large_image" : "summary",
|
|
38
|
+
title: blog.title,
|
|
39
|
+
...description ? { description } : {},
|
|
40
|
+
...images ? { images } : {}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
if (opts?.alternates) {
|
|
44
|
+
const alternates = opts.alternates;
|
|
45
|
+
const canonical = blogUrlFor(alternates, blog.language, blog.slug);
|
|
46
|
+
let languages;
|
|
47
|
+
try {
|
|
48
|
+
const all = await listBlogs({ status: "PUBLISHED" }, opts);
|
|
49
|
+
const variants = all.filter((b) => b.slug === blog.slug && b.language);
|
|
50
|
+
if (variants.length > 1) {
|
|
51
|
+
languages = {};
|
|
52
|
+
for (const variant of variants) {
|
|
53
|
+
languages[variant.language] = blogUrlFor(
|
|
54
|
+
alternates,
|
|
55
|
+
variant.language,
|
|
56
|
+
variant.slug
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const xDefaultUrl = alternates.xDefaultLanguage ? languages[alternates.xDefaultLanguage] : void 0;
|
|
60
|
+
if (xDefaultUrl) languages["x-default"] = xDefaultUrl;
|
|
61
|
+
}
|
|
62
|
+
} catch (err) {
|
|
63
|
+
console.error(
|
|
64
|
+
"chaingrow-blog: hreflang variant lookup failed, emitting canonical only:",
|
|
65
|
+
err
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
meta.alternates = {
|
|
69
|
+
canonical,
|
|
70
|
+
...languages ? { languages } : {}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return meta;
|
|
74
|
+
}
|
|
75
|
+
function generateBlogIndexMetadata(opts) {
|
|
76
|
+
const { title, description, canonical, ogImage } = opts;
|
|
77
|
+
const images = ogImage ? [ogImage] : void 0;
|
|
78
|
+
return {
|
|
79
|
+
title,
|
|
80
|
+
...description ? { description } : {},
|
|
81
|
+
...canonical ? { alternates: { canonical } } : {},
|
|
82
|
+
openGraph: {
|
|
83
|
+
type: "website",
|
|
84
|
+
title,
|
|
85
|
+
...description ? { description } : {},
|
|
86
|
+
...canonical ? { url: canonical } : {},
|
|
87
|
+
...images ? { images } : {}
|
|
88
|
+
},
|
|
89
|
+
twitter: {
|
|
90
|
+
card: ogImage ? "summary_large_image" : "summary",
|
|
91
|
+
title,
|
|
92
|
+
...description ? { description } : {},
|
|
93
|
+
...images ? { images } : {}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/next/BlogPage.tsx
|
|
99
|
+
import { notFound } from "next/navigation";
|
|
100
|
+
|
|
101
|
+
// src/react/defaults.tsx
|
|
102
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
103
|
+
var DefaultHeading = ({
|
|
104
|
+
level,
|
|
105
|
+
children,
|
|
106
|
+
className
|
|
107
|
+
}) => {
|
|
108
|
+
if (level === 1) return /* @__PURE__ */ jsx("h1", { className, children });
|
|
109
|
+
if (level === 3) return /* @__PURE__ */ jsx("h3", { className, children });
|
|
110
|
+
return /* @__PURE__ */ jsx("h2", { className, children });
|
|
111
|
+
};
|
|
112
|
+
var DefaultParagraph = ({
|
|
113
|
+
children,
|
|
114
|
+
className
|
|
115
|
+
}) => /* @__PURE__ */ jsx("p", { className, children });
|
|
116
|
+
var DefaultBulletList = ({
|
|
117
|
+
items,
|
|
118
|
+
className,
|
|
119
|
+
renderBlock
|
|
120
|
+
}) => /* @__PURE__ */ jsx("ul", { className, children: items.map((item, i) => /* @__PURE__ */ jsx("li", { children: item.content.map((b, j) => renderBlock(b, j)) }, i)) });
|
|
121
|
+
var DefaultOrderedList = ({
|
|
122
|
+
items,
|
|
123
|
+
className,
|
|
124
|
+
renderBlock
|
|
125
|
+
}) => /* @__PURE__ */ jsx("ol", { className, children: items.map((item, i) => /* @__PURE__ */ jsx("li", { children: item.content.map((b, j) => renderBlock(b, j)) }, i)) });
|
|
126
|
+
var DefaultBlockquote = ({
|
|
127
|
+
children,
|
|
128
|
+
className
|
|
129
|
+
}) => /* @__PURE__ */ jsx("blockquote", { className, children });
|
|
130
|
+
var DefaultCodeBlock = ({
|
|
131
|
+
language,
|
|
132
|
+
code,
|
|
133
|
+
className
|
|
134
|
+
}) => /* @__PURE__ */ jsx("pre", { className, children: /* @__PURE__ */ jsx("code", { className: language ? `language-${language}` : void 0, children: code }) });
|
|
135
|
+
var DefaultImage = ({
|
|
136
|
+
src,
|
|
137
|
+
alt,
|
|
138
|
+
caption,
|
|
139
|
+
width,
|
|
140
|
+
height,
|
|
141
|
+
className
|
|
142
|
+
}) => {
|
|
143
|
+
const img = (
|
|
144
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
145
|
+
/* @__PURE__ */ jsx("img", { src, alt, width, height })
|
|
146
|
+
);
|
|
147
|
+
if (caption) {
|
|
148
|
+
return /* @__PURE__ */ jsxs("figure", { className, children: [
|
|
149
|
+
img,
|
|
150
|
+
/* @__PURE__ */ jsx("figcaption", { children: caption })
|
|
151
|
+
] });
|
|
152
|
+
}
|
|
153
|
+
return /* @__PURE__ */ jsx("span", { className, children: img });
|
|
154
|
+
};
|
|
155
|
+
var DefaultDivider = ({ className }) => /* @__PURE__ */ jsx("hr", { className });
|
|
156
|
+
var DefaultMedia = ({ media }) => {
|
|
157
|
+
if (media.media_type === "VIDEO") {
|
|
158
|
+
return /* @__PURE__ */ jsx(
|
|
159
|
+
"video",
|
|
160
|
+
{
|
|
161
|
+
src: media.media_url,
|
|
162
|
+
controls: true,
|
|
163
|
+
playsInline: true,
|
|
164
|
+
preload: "metadata"
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return /* @__PURE__ */ jsx("img", { src: media.media_url, alt: media.prompt });
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// src/react/BlogRenderer.tsx
|
|
172
|
+
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
|
|
173
|
+
var MARK_ORDER = [
|
|
174
|
+
"bold",
|
|
175
|
+
"italic",
|
|
176
|
+
"strike",
|
|
177
|
+
"code",
|
|
178
|
+
"link"
|
|
179
|
+
];
|
|
180
|
+
function InlineRenderer({ inline }) {
|
|
181
|
+
return /* @__PURE__ */ jsx2(Fragment, { children: inline.map((run, i) => /* @__PURE__ */ jsx2(InlineRun, { run }, i)) });
|
|
182
|
+
}
|
|
183
|
+
function InlineRun({ run }) {
|
|
184
|
+
const marks = run.marks ? [...run.marks].sort(
|
|
185
|
+
(a, b) => MARK_ORDER.indexOf(b.type) - MARK_ORDER.indexOf(a.type)
|
|
186
|
+
) : [];
|
|
187
|
+
let node = run.text;
|
|
188
|
+
for (const mark of marks) {
|
|
189
|
+
switch (mark.type) {
|
|
190
|
+
case "bold":
|
|
191
|
+
node = /* @__PURE__ */ jsx2("strong", { children: node });
|
|
192
|
+
break;
|
|
193
|
+
case "italic":
|
|
194
|
+
node = /* @__PURE__ */ jsx2("em", { children: node });
|
|
195
|
+
break;
|
|
196
|
+
case "strike":
|
|
197
|
+
node = /* @__PURE__ */ jsx2("s", { children: node });
|
|
198
|
+
break;
|
|
199
|
+
case "code":
|
|
200
|
+
node = /* @__PURE__ */ jsx2("code", { children: node });
|
|
201
|
+
break;
|
|
202
|
+
case "link":
|
|
203
|
+
node = /* @__PURE__ */ jsx2("a", { href: mark.href, rel: "noopener noreferrer", children: node });
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return /* @__PURE__ */ jsx2(Fragment, { children: node });
|
|
208
|
+
}
|
|
209
|
+
function BlockRenderer({
|
|
210
|
+
block,
|
|
211
|
+
components = {},
|
|
212
|
+
classNames = {},
|
|
213
|
+
renderBlock
|
|
214
|
+
}) {
|
|
215
|
+
const recurse = renderBlock ?? ((b, i) => /* @__PURE__ */ jsx2(
|
|
216
|
+
BlockRenderer,
|
|
217
|
+
{
|
|
218
|
+
block: b,
|
|
219
|
+
components,
|
|
220
|
+
classNames,
|
|
221
|
+
renderBlock: recurse
|
|
222
|
+
},
|
|
223
|
+
i
|
|
224
|
+
));
|
|
225
|
+
switch (block.type) {
|
|
226
|
+
case "heading": {
|
|
227
|
+
const Heading = components.heading ?? DefaultHeading;
|
|
228
|
+
return /* @__PURE__ */ jsx2(Heading, { level: block.level, className: classNames.heading, children: /* @__PURE__ */ jsx2(InlineRenderer, { inline: block.content }) });
|
|
229
|
+
}
|
|
230
|
+
case "paragraph": {
|
|
231
|
+
const Paragraph = components.paragraph ?? DefaultParagraph;
|
|
232
|
+
return /* @__PURE__ */ jsx2(Paragraph, { className: classNames.paragraph, children: /* @__PURE__ */ jsx2(InlineRenderer, { inline: block.content }) });
|
|
233
|
+
}
|
|
234
|
+
case "bulletList": {
|
|
235
|
+
const BulletList = components.bulletList ?? DefaultBulletList;
|
|
236
|
+
return /* @__PURE__ */ jsx2(
|
|
237
|
+
BulletList,
|
|
238
|
+
{
|
|
239
|
+
items: block.items,
|
|
240
|
+
className: classNames.bulletList,
|
|
241
|
+
renderBlock: recurse
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
case "orderedList": {
|
|
246
|
+
const OrderedList = components.orderedList ?? DefaultOrderedList;
|
|
247
|
+
return /* @__PURE__ */ jsx2(
|
|
248
|
+
OrderedList,
|
|
249
|
+
{
|
|
250
|
+
items: block.items,
|
|
251
|
+
className: classNames.orderedList,
|
|
252
|
+
renderBlock: recurse
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
case "blockquote": {
|
|
257
|
+
const Blockquote = components.blockquote ?? DefaultBlockquote;
|
|
258
|
+
return /* @__PURE__ */ jsx2(Blockquote, { className: classNames.blockquote, children: /* @__PURE__ */ jsx2(InlineRenderer, { inline: block.content }) });
|
|
259
|
+
}
|
|
260
|
+
case "codeBlock": {
|
|
261
|
+
const CodeBlock = components.codeBlock ?? DefaultCodeBlock;
|
|
262
|
+
return /* @__PURE__ */ jsx2(
|
|
263
|
+
CodeBlock,
|
|
264
|
+
{
|
|
265
|
+
language: block.language,
|
|
266
|
+
code: block.code,
|
|
267
|
+
className: classNames.codeBlock
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
case "image": {
|
|
272
|
+
const ImageComp = components.image ?? DefaultImage;
|
|
273
|
+
return /* @__PURE__ */ jsx2(
|
|
274
|
+
ImageComp,
|
|
275
|
+
{
|
|
276
|
+
src: block.src,
|
|
277
|
+
alt: block.alt,
|
|
278
|
+
caption: block.caption,
|
|
279
|
+
width: block.width,
|
|
280
|
+
height: block.height,
|
|
281
|
+
mediaId: block.mediaId,
|
|
282
|
+
className: classNames.image
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
case "divider": {
|
|
287
|
+
const Divider = components.divider ?? DefaultDivider;
|
|
288
|
+
return /* @__PURE__ */ jsx2(Divider, { className: classNames.divider });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function BlogRenderer({
|
|
293
|
+
blog,
|
|
294
|
+
components = {},
|
|
295
|
+
classNames = {}
|
|
296
|
+
}) {
|
|
297
|
+
const Media = components.media ?? DefaultMedia;
|
|
298
|
+
const Wrapper = components.wrapper;
|
|
299
|
+
const slots = interleaveMedia(blog.blocks, blog.generatedMedia);
|
|
300
|
+
const content = /* @__PURE__ */ jsx2(Fragment, { children: slots.map(
|
|
301
|
+
(slot) => slot.kind === "block" ? /* @__PURE__ */ jsx2(
|
|
302
|
+
BlockRenderer,
|
|
303
|
+
{
|
|
304
|
+
block: slot.block,
|
|
305
|
+
components,
|
|
306
|
+
classNames
|
|
307
|
+
},
|
|
308
|
+
`b:${slot.index}`
|
|
309
|
+
) : /* @__PURE__ */ jsx2(Media, { media: slot.media }, `m:${slot.media.id}`)
|
|
310
|
+
) });
|
|
311
|
+
if (Wrapper) return /* @__PURE__ */ jsx2(Wrapper, { blog, children: content });
|
|
312
|
+
return content;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// src/react/BlogDetail.tsx
|
|
316
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
317
|
+
var defaultFormatDate = (iso) => new Date(iso).toLocaleDateString();
|
|
318
|
+
function DefaultHeader({
|
|
319
|
+
blog,
|
|
320
|
+
formatDate
|
|
321
|
+
}) {
|
|
322
|
+
const hasInlineMedia = (blog.generatedMedia?.length ?? 0) > 0;
|
|
323
|
+
const heroImage = !hasInlineMedia && blog.og_image ? /* @__PURE__ */ jsx3("img", { src: blog.og_image, alt: blog.title }) : null;
|
|
324
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
325
|
+
heroImage,
|
|
326
|
+
/* @__PURE__ */ jsx3("h1", { children: blog.title }),
|
|
327
|
+
blog.published_at && /* @__PURE__ */ jsx3("time", { dateTime: blog.published_at, children: formatDate(blog.published_at) }),
|
|
328
|
+
blog.description && /* @__PURE__ */ jsx3("p", { children: blog.description })
|
|
329
|
+
] });
|
|
330
|
+
}
|
|
331
|
+
function BlogDetail({
|
|
332
|
+
blog,
|
|
333
|
+
components,
|
|
334
|
+
formatDate = defaultFormatDate
|
|
335
|
+
}) {
|
|
336
|
+
const Header = components?.Header ?? DefaultHeader;
|
|
337
|
+
const Footer = components?.Footer;
|
|
338
|
+
return /* @__PURE__ */ jsxs2("article", { children: [
|
|
339
|
+
/* @__PURE__ */ jsx3(Header, { blog, formatDate }),
|
|
340
|
+
/* @__PURE__ */ jsx3(BlogRenderer, { blog, components: components?.blocks }),
|
|
341
|
+
Footer ? /* @__PURE__ */ jsx3(Footer, { blog }) : null
|
|
342
|
+
] });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// src/react/BlogJsonLd.tsx
|
|
346
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
347
|
+
function JsonLdGraph({
|
|
348
|
+
items
|
|
349
|
+
}) {
|
|
350
|
+
if (!items || items.length === 0) return null;
|
|
351
|
+
const payload = JSON.stringify({
|
|
352
|
+
"@context": SCHEMA_ORG_CONTEXT,
|
|
353
|
+
"@graph": items
|
|
354
|
+
});
|
|
355
|
+
return /* @__PURE__ */ jsx4(
|
|
356
|
+
"script",
|
|
357
|
+
{
|
|
358
|
+
type: "application/ld+json",
|
|
359
|
+
dangerouslySetInnerHTML: { __html: payload }
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
function BlogJsonLd({
|
|
364
|
+
blog,
|
|
365
|
+
extraSchemas,
|
|
366
|
+
...opts
|
|
367
|
+
}) {
|
|
368
|
+
const items = [...extraSchemas ?? [], ...buildBlogJsonLd(blog, opts)];
|
|
369
|
+
return /* @__PURE__ */ jsx4(JsonLdGraph, { items });
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/next/BlogPage.tsx
|
|
373
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
374
|
+
async function BlogPage({
|
|
375
|
+
params
|
|
376
|
+
}) {
|
|
377
|
+
const { slug, locale } = await params;
|
|
378
|
+
let blog = null;
|
|
379
|
+
try {
|
|
380
|
+
blog = await getBlog(slug, locale);
|
|
381
|
+
} catch (err) {
|
|
382
|
+
console.error("chaingrow-blog: <BlogPage> getBlog failed:", err);
|
|
383
|
+
}
|
|
384
|
+
if (!blog) notFound();
|
|
385
|
+
return /* @__PURE__ */ jsxs3("div", { className: "cg-blog-article", children: [
|
|
386
|
+
/* @__PURE__ */ jsx5("style", { dangerouslySetInnerHTML: { __html: ARTICLE_CSS } }),
|
|
387
|
+
/* @__PURE__ */ jsx5(BlogJsonLd, { blog }),
|
|
388
|
+
/* @__PURE__ */ jsx5(BlogDetail, { blog })
|
|
389
|
+
] });
|
|
390
|
+
}
|
|
391
|
+
var ARTICLE_CSS = `
|
|
392
|
+
.cg-blog-article {
|
|
393
|
+
max-width: 720px;
|
|
394
|
+
margin: 0 auto;
|
|
395
|
+
padding: 4rem 1.5rem 6rem;
|
|
396
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
397
|
+
font-size: 1.0625rem;
|
|
398
|
+
line-height: 1.7;
|
|
399
|
+
color: inherit;
|
|
400
|
+
-webkit-font-smoothing: antialiased;
|
|
401
|
+
-moz-osx-font-smoothing: grayscale;
|
|
402
|
+
}
|
|
403
|
+
.cg-blog-article h1 {
|
|
404
|
+
font-size: clamp(2rem, 4vw, 2.625rem);
|
|
405
|
+
font-weight: 700;
|
|
406
|
+
line-height: 1.15;
|
|
407
|
+
letter-spacing: -0.022em;
|
|
408
|
+
color: inherit;
|
|
409
|
+
margin: 0 0 1rem;
|
|
410
|
+
}
|
|
411
|
+
.cg-blog-article time {
|
|
412
|
+
display: block;
|
|
413
|
+
font-size: 0.8125rem;
|
|
414
|
+
color: currentColor;
|
|
415
|
+
opacity: 0.55;
|
|
416
|
+
margin: 0 0 2rem;
|
|
417
|
+
font-weight: 400;
|
|
418
|
+
}
|
|
419
|
+
.cg-blog-article h2 {
|
|
420
|
+
font-size: 1.625rem;
|
|
421
|
+
font-weight: 700;
|
|
422
|
+
line-height: 1.25;
|
|
423
|
+
letter-spacing: -0.015em;
|
|
424
|
+
color: inherit;
|
|
425
|
+
margin: 3rem 0 1rem;
|
|
426
|
+
}
|
|
427
|
+
.cg-blog-article h3 {
|
|
428
|
+
font-size: 1.25rem;
|
|
429
|
+
font-weight: 700;
|
|
430
|
+
line-height: 1.3;
|
|
431
|
+
color: inherit;
|
|
432
|
+
margin: 2.25rem 0 0.75rem;
|
|
433
|
+
}
|
|
434
|
+
.cg-blog-article h4 {
|
|
435
|
+
font-size: 1.0625rem;
|
|
436
|
+
font-weight: 700;
|
|
437
|
+
color: inherit;
|
|
438
|
+
margin: 1.75rem 0 0.5rem;
|
|
439
|
+
}
|
|
440
|
+
.cg-blog-article p {
|
|
441
|
+
margin: 0 0 1.25rem;
|
|
442
|
+
color: inherit;
|
|
443
|
+
}
|
|
444
|
+
.cg-blog-article a {
|
|
445
|
+
color: inherit;
|
|
446
|
+
text-decoration: underline;
|
|
447
|
+
text-underline-offset: 3px;
|
|
448
|
+
text-decoration-thickness: 1px;
|
|
449
|
+
transition: opacity 150ms ease;
|
|
450
|
+
}
|
|
451
|
+
.cg-blog-article a:hover { opacity: 0.7; }
|
|
452
|
+
.cg-blog-article strong { color: inherit; font-weight: 700; }
|
|
453
|
+
.cg-blog-article em { font-style: italic; }
|
|
454
|
+
.cg-blog-article ul,
|
|
455
|
+
.cg-blog-article ol {
|
|
456
|
+
margin: 0 0 1.5rem;
|
|
457
|
+
padding-left: 1.5rem;
|
|
458
|
+
color: inherit;
|
|
459
|
+
}
|
|
460
|
+
.cg-blog-article li {
|
|
461
|
+
margin-bottom: 0.5rem;
|
|
462
|
+
line-height: 1.65;
|
|
463
|
+
}
|
|
464
|
+
.cg-blog-article li > p { margin: 0 0 0.5rem; }
|
|
465
|
+
.cg-blog-article li:last-child > p:last-child { margin-bottom: 0; }
|
|
466
|
+
.cg-blog-article blockquote {
|
|
467
|
+
margin: 2rem 0;
|
|
468
|
+
padding: 0.5rem 0 0.5rem 1.5rem;
|
|
469
|
+
border-left: 3px solid currentColor;
|
|
470
|
+
font-style: italic;
|
|
471
|
+
color: inherit;
|
|
472
|
+
font-size: 1.125rem;
|
|
473
|
+
line-height: 1.6;
|
|
474
|
+
}
|
|
475
|
+
.cg-blog-article blockquote p:last-child { margin-bottom: 0; }
|
|
476
|
+
.cg-blog-article img {
|
|
477
|
+
display: block;
|
|
478
|
+
width: 100%;
|
|
479
|
+
height: auto;
|
|
480
|
+
margin: 2.25rem 0;
|
|
481
|
+
border-radius: 6px;
|
|
482
|
+
background: rgba(128, 128, 128, 0.08);
|
|
483
|
+
}
|
|
484
|
+
.cg-blog-article video {
|
|
485
|
+
display: block;
|
|
486
|
+
width: 100%;
|
|
487
|
+
height: auto;
|
|
488
|
+
margin: 2.25rem 0;
|
|
489
|
+
border-radius: 6px;
|
|
490
|
+
background: rgba(128, 128, 128, 0.15);
|
|
491
|
+
}
|
|
492
|
+
.cg-blog-article hr {
|
|
493
|
+
border: 0;
|
|
494
|
+
height: 1px;
|
|
495
|
+
background: currentColor;
|
|
496
|
+
opacity: 0.15;
|
|
497
|
+
margin: 3rem 0;
|
|
498
|
+
}
|
|
499
|
+
.cg-blog-article code {
|
|
500
|
+
background: rgba(128, 128, 128, 0.15);
|
|
501
|
+
color: inherit;
|
|
502
|
+
padding: 0.15em 0.4em;
|
|
503
|
+
border-radius: 3px;
|
|
504
|
+
font-size: 0.9em;
|
|
505
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
|
506
|
+
}
|
|
507
|
+
.cg-blog-article pre {
|
|
508
|
+
background: rgba(128, 128, 128, 0.12);
|
|
509
|
+
color: inherit;
|
|
510
|
+
padding: 1.25rem 1.5rem;
|
|
511
|
+
border-radius: 6px;
|
|
512
|
+
overflow-x: auto;
|
|
513
|
+
font-size: 0.9375rem;
|
|
514
|
+
line-height: 1.6;
|
|
515
|
+
margin: 1.75rem 0;
|
|
516
|
+
}
|
|
517
|
+
.cg-blog-article pre code {
|
|
518
|
+
background: transparent;
|
|
519
|
+
color: inherit;
|
|
520
|
+
padding: 0;
|
|
521
|
+
border-radius: 0;
|
|
522
|
+
font-size: inherit;
|
|
523
|
+
}
|
|
524
|
+
@media (max-width: 640px) {
|
|
525
|
+
.cg-blog-article {
|
|
526
|
+
padding: 2.5rem 1.25rem 4rem;
|
|
527
|
+
font-size: 1rem;
|
|
528
|
+
}
|
|
529
|
+
.cg-blog-article h2 { margin-top: 2.25rem; }
|
|
530
|
+
.cg-blog-article h3 { margin-top: 1.75rem; }
|
|
531
|
+
}
|
|
532
|
+
`;
|
|
533
|
+
function generateBlogPageMetadata(opts) {
|
|
534
|
+
return async ({ params }) => {
|
|
535
|
+
const { slug, locale } = await params;
|
|
536
|
+
try {
|
|
537
|
+
return await generateBlogMetadata(slug, locale, opts);
|
|
538
|
+
} catch (err) {
|
|
539
|
+
console.error(
|
|
540
|
+
"chaingrow-blog: generateBlogPageMetadata failed:",
|
|
541
|
+
err
|
|
542
|
+
);
|
|
543
|
+
return {};
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// src/next/index.ts
|
|
549
|
+
var DEFAULT_API_URL = "https://api.chaingrow.de";
|
|
550
|
+
var DEFAULT_REVALIDATE_SECONDS = 60 * 60 * 24 * 7;
|
|
551
|
+
var resolveEnv = (opts = {}) => {
|
|
552
|
+
const apiUrl = opts.apiUrl ?? process.env.CHAINGROW_API_URL ?? DEFAULT_API_URL;
|
|
553
|
+
const apiKey = opts.apiKey ?? process.env.CHAINGROW_API_KEY;
|
|
554
|
+
if (!apiKey) {
|
|
555
|
+
throw new Error(
|
|
556
|
+
"chaingrow-blog: CHAINGROW_API_KEY is not set (env var or apiKey option required)"
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
return { apiUrl, apiKey };
|
|
560
|
+
};
|
|
561
|
+
var buildFetch = (tag, revalidate) => {
|
|
562
|
+
const effectiveRevalidate = revalidate === void 0 ? DEFAULT_REVALIDATE_SECONDS : revalidate;
|
|
563
|
+
return ((input, init) => fetch(input, {
|
|
564
|
+
...init,
|
|
565
|
+
next: {
|
|
566
|
+
tags: ["chaingrow:blog", tag],
|
|
567
|
+
revalidate: effectiveRevalidate
|
|
568
|
+
}
|
|
569
|
+
}));
|
|
570
|
+
};
|
|
571
|
+
async function getBlog(slug, language, opts = {}) {
|
|
572
|
+
const { apiUrl, apiKey } = resolveEnv(opts);
|
|
573
|
+
const client = createClient({
|
|
574
|
+
apiUrl,
|
|
575
|
+
apiKey,
|
|
576
|
+
fetch: buildFetch(`chaingrow:blog:${slug}`, opts.revalidate)
|
|
577
|
+
});
|
|
578
|
+
return client.getBlog(slug, language);
|
|
579
|
+
}
|
|
580
|
+
async function listBlogs(listOpts = {}, opts = {}) {
|
|
581
|
+
const { apiUrl, apiKey } = resolveEnv(opts);
|
|
582
|
+
const client = createClient({
|
|
583
|
+
apiUrl,
|
|
584
|
+
apiKey,
|
|
585
|
+
fetch: buildFetch("chaingrow:blog:list", opts.revalidate)
|
|
586
|
+
});
|
|
587
|
+
return client.listBlogs(listOpts);
|
|
588
|
+
}
|
|
589
|
+
var trimTrailingSlash2 = (s) => s.replace(/\/+$/, "");
|
|
590
|
+
var normalizePathPrefix2 = (s) => {
|
|
591
|
+
let p = s.trim();
|
|
592
|
+
if (!p.startsWith("/")) p = "/" + p;
|
|
593
|
+
while (p.length > 1 && p.endsWith("/")) p = p.slice(0, -1);
|
|
594
|
+
return p;
|
|
595
|
+
};
|
|
596
|
+
async function getBlogSitemapEntries(opts) {
|
|
597
|
+
const baseUrl = trimTrailingSlash2(opts.siteUrl);
|
|
598
|
+
const pathPrefix = normalizePathPrefix2(opts.pathPrefix ?? "/blog");
|
|
599
|
+
const blogs = await listBlogs(
|
|
600
|
+
{ status: "PUBLISHED", language: opts.language },
|
|
601
|
+
{
|
|
602
|
+
apiKey: opts.apiKey,
|
|
603
|
+
apiUrl: opts.apiUrl,
|
|
604
|
+
revalidate: opts.revalidate
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
return blogs.map((blog) => ({
|
|
608
|
+
url: `${baseUrl}${pathPrefix}/${blog.slug}`,
|
|
609
|
+
lastModified: new Date(blog.published_at)
|
|
610
|
+
}));
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
export {
|
|
614
|
+
generateBlogMetadata,
|
|
615
|
+
generateBlogIndexMetadata,
|
|
616
|
+
DefaultHeading,
|
|
617
|
+
DefaultParagraph,
|
|
618
|
+
DefaultBulletList,
|
|
619
|
+
DefaultOrderedList,
|
|
620
|
+
DefaultBlockquote,
|
|
621
|
+
DefaultCodeBlock,
|
|
622
|
+
DefaultImage,
|
|
623
|
+
DefaultDivider,
|
|
624
|
+
DefaultMedia,
|
|
625
|
+
BlockRenderer,
|
|
626
|
+
BlogRenderer,
|
|
627
|
+
BlogDetail,
|
|
628
|
+
JsonLdGraph,
|
|
629
|
+
BlogJsonLd,
|
|
630
|
+
BlogPage,
|
|
631
|
+
generateBlogPageMetadata,
|
|
632
|
+
getBlog,
|
|
633
|
+
listBlogs,
|
|
634
|
+
getBlogSitemapEntries
|
|
635
|
+
};
|
|
636
|
+
//# sourceMappingURL=chunk-BXEQ6QKM.js.map
|