@roottale/cms-renderer-next 0.40.0 → 0.41.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.
@@ -1,1057 +0,0 @@
1
- import {
2
- collectCategories,
3
- collectCategoriesWithCounts,
4
- collectCollectionCategories,
5
- defaultCategoryHref,
6
- filterPostsByCategory
7
- } from "./chunk-FUA5H6JE.js";
8
-
9
- // src/server.tsx
10
- import {
11
- DEFAULT_BLOG_SETTINGS,
12
- fetchBlogSettings,
13
- fetchPost,
14
- fetchPosts,
15
- fetchTheme,
16
- resolvePostDisplay
17
- } from "@roottale/cms-client/server";
18
- import {
19
- bindingSrcValue,
20
- bindingTextValue,
21
- boundFieldValue,
22
- isAllowedEmbedSrc,
23
- postsForCollection,
24
- resolvePostPath
25
- } from "@roottale/cms-core";
26
-
27
- // src/PostCard.tsx
28
- import { jsx, jsxs } from "react/jsx-runtime";
29
- function firstCategoryName(terms) {
30
- if (!terms) return null;
31
- const cat = terms.find((t) => t.taxonomy === "category");
32
- return cat ? cat.name : null;
33
- }
34
- function RootTalePostCard(props) {
35
- const { post, href = defaultHref, display } = props;
36
- const showDate = display ? display.showDate : true;
37
- const showAuthor = display ? display.showAuthor : false;
38
- const showImage = display?.showImage !== false;
39
- const showCategory = display?.showCategory !== false;
40
- const authorName = post.authorName;
41
- const publishedDate = showDate ? formatPublishedDate(post.publishedAt) : "";
42
- const views = typeof post.viewCount === "number" ? post.viewCount : null;
43
- const imageUrl = showImage ? post.featuredImageUrl : null;
44
- const category = showCategory ? firstCategoryName(post.terms) : null;
45
- return /* @__PURE__ */ jsx("article", { "data-roottale-cms": "card", className: "rt-cms-card", children: /* @__PURE__ */ jsxs("a", { className: "rt-cms-card-link", href: href(post), children: [
46
- imageUrl ? (
47
- // eslint-disable-next-line @next/next/no-img-element -- SSR string URL, framework-agnostic
48
- /* @__PURE__ */ jsx(
49
- "img",
50
- {
51
- className: "rt-cms-card-image",
52
- src: imageUrl,
53
- alt: "",
54
- loading: "lazy",
55
- decoding: "async"
56
- }
57
- )
58
- ) : null,
59
- category ? /* @__PURE__ */ jsx("span", { className: "rt-cms-card-category", children: category }) : null,
60
- publishedDate || showAuthor && authorName || views !== null ? /* @__PURE__ */ jsxs("p", { className: "rt-cms-meta", children: [
61
- publishedDate ? /* @__PURE__ */ jsx("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "date", children: publishedDate }) : null,
62
- showAuthor && authorName ? /* @__PURE__ */ jsxs("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
63
- "\uC791\uC131\uC790 ",
64
- authorName
65
- ] }) : null,
66
- views !== null ? /* @__PURE__ */ jsxs("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "views", children: [
67
- "\uC870\uD68C ",
68
- views.toLocaleString("ko-KR")
69
- ] }) : null
70
- ] }) : null,
71
- /* @__PURE__ */ jsx("h2", { className: "rt-cms-title", children: post.title }),
72
- post.excerpt ? /* @__PURE__ */ jsx("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null,
73
- /* @__PURE__ */ jsx("span", { className: "rt-cms-card-action", "aria-hidden": "true", children: "\uC77D\uAE30" })
74
- ] }) });
75
- }
76
- function defaultHref(post) {
77
- return `/blog/${post.slug}`;
78
- }
79
- function formatPublishedDate(iso) {
80
- const d = new Date(iso);
81
- if (Number.isNaN(d.getTime())) return "";
82
- return new Intl.DateTimeFormat("ko-KR", {
83
- year: "numeric",
84
- month: "2-digit",
85
- day: "2-digit"
86
- }).format(d);
87
- }
88
-
89
- // src/TableOfContents.tsx
90
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
91
- function RootTaleTableOfContents(props) {
92
- const { entries, title = "\uBAA9\uCC28" } = props;
93
- if (entries.length === 0) return null;
94
- return /* @__PURE__ */ jsx2("nav", { "data-roottale-cms": "toc", className: "rt-cms-toc", "aria-label": title, children: /* @__PURE__ */ jsxs2("details", { className: "rt-cms-toc-details", open: true, children: [
95
- /* @__PURE__ */ jsxs2("summary", { className: "rt-cms-toc-summary", children: [
96
- title ? /* @__PURE__ */ jsx2("span", { className: "rt-cms-toc-title", children: title }) : null,
97
- /* @__PURE__ */ jsx2("span", { className: "rt-cms-toc-toggle", "aria-hidden": "true" })
98
- ] }),
99
- /* @__PURE__ */ jsx2("ol", { className: "rt-cms-toc-list", children: entries.map((entry) => /* @__PURE__ */ jsx2(
100
- "li",
101
- {
102
- className: `rt-cms-toc-item rt-cms-toc-level-${entry.level}`,
103
- children: /* @__PURE__ */ jsx2("a", { href: `#${entry.id}`, children: entry.text })
104
- },
105
- entry.id
106
- )) })
107
- ] }) });
108
- }
109
-
110
- // src/toc.ts
111
- function tocLevel(rawLevel) {
112
- if (rawLevel < 1 || rawLevel > 4) return null;
113
- if (rawLevel < 3) return 2;
114
- return rawLevel === 3 ? 3 : 4;
115
- }
116
- function headingToId(text) {
117
- return text.trim().toLowerCase().replace(/[^\p{L}\p{N}\s-]/gu, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
118
- }
119
- function textOf(node) {
120
- if (typeof node.text === "string") return node.text;
121
- if (!Array.isArray(node.content)) return "";
122
- return node.content.map(textOf).join("");
123
- }
124
- function extractToc(doc) {
125
- const root = doc;
126
- const content = Array.isArray(root.content) ? root.content : [];
127
- const entries = [];
128
- const idCounts = /* @__PURE__ */ new Map();
129
- for (const node of content) {
130
- if (node?.type !== "heading") continue;
131
- const rawLevel = Number(node.attrs?.level ?? 2);
132
- const level = tocLevel(rawLevel);
133
- if (level === null) continue;
134
- const text = textOf(node).trim();
135
- if (!text) continue;
136
- const base = headingToId(text) || "heading";
137
- const count = idCounts.get(base) ?? 0;
138
- const id = count === 0 ? base : `${base}-${count}`;
139
- idCounts.set(base, count + 1);
140
- entries.push({ level, text, id });
141
- }
142
- return entries;
143
- }
144
- function attachHeadingIds(doc, entries) {
145
- const root = doc;
146
- const content = Array.isArray(root.content) ? root.content : [];
147
- let cursor = 0;
148
- const nextContent = content.map((node) => {
149
- if (node?.type !== "heading") return node;
150
- const rawLevel = Number(node.attrs?.level ?? 2);
151
- if (rawLevel < 1 || rawLevel > 4) return node;
152
- if (!textOf(node).trim()) return node;
153
- const entry = entries[cursor++];
154
- if (!entry) return node;
155
- return {
156
- ...node,
157
- attrs: { ...node.attrs ?? {}, id: entry.id }
158
- };
159
- });
160
- return { ...root, content: nextContent };
161
- }
162
-
163
- // src/FloatingCta.tsx
164
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
165
- function RootTaleFloatingCta(props) {
166
- const { buttons, position = "bottom-right" } = props;
167
- if (!buttons || buttons.length === 0) return null;
168
- return /* @__PURE__ */ jsx3(
169
- "div",
170
- {
171
- "data-roottale-cms": "floating-cta",
172
- className: `rt-cms-floating-cta rt-cms-floating-cta--${position}`,
173
- children: buttons.map((btn, idx) => {
174
- const isExternal = btn.type === "kakao" || btn.type === "custom";
175
- return /* @__PURE__ */ jsxs3(
176
- "a",
177
- {
178
- href: btn.href,
179
- className: `rt-cms-floating-cta__btn rt-cms-floating-cta__btn--${btn.type}`,
180
- target: isExternal ? "_blank" : void 0,
181
- rel: isExternal ? "noopener noreferrer" : void 0,
182
- children: [
183
- /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", className: "rt-cms-floating-cta__icon", children: btn.icon ?? defaultIcon(btn.type) }),
184
- /* @__PURE__ */ jsx3("span", { className: "rt-cms-floating-cta__label", children: btn.label })
185
- ]
186
- },
187
- `${btn.type}-${idx}`
188
- );
189
- })
190
- }
191
- );
192
- }
193
- function defaultIcon(type) {
194
- switch (type) {
195
- case "phone":
196
- return "\u260E";
197
- case "contact":
198
- return "\u2709";
199
- case "kakao":
200
- return "\u{1F4AC}";
201
- case "custom":
202
- return "\u2192";
203
- }
204
- }
205
-
206
- // src/LeadForm.tsx
207
- import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
208
- var VERTICAL_LABEL = {
209
- consulting: "\uCEE8\uC124\uD305",
210
- medical: "\uC758\uB8CC",
211
- tax: "\uC138\uBB34",
212
- legal: "\uBC95\uB960"
213
- };
214
- var VERTICAL_OPTIONS = [
215
- { value: "consulting", label: "\uCEE8\uC124\uD305 / \uC77C\uBC18" },
216
- { value: "medical", label: "\uC758\uB8CC (\uBCD1\uC758\uC6D0\xB7\uCE58\uACFC\xB7\uD55C\uC758\uC6D0)" },
217
- { value: "tax", label: "\uC138\uBB34 (\uC138\uBB34\uC0AC\xB7\uD68C\uACC4\uC0AC)" },
218
- { value: "legal", label: "\uBC95\uB960 (\uBC95\uBB34\uBC95\uC778\xB7\uBCC0\uD638\uC0AC)" }
219
- ];
220
- function RootTaleLeadForm(props) {
221
- const {
222
- action,
223
- vertical,
224
- redirectUrl,
225
- heading,
226
- description,
227
- submitLabel = "\uC9C4\uB2E8 \uC2E0\uCCAD",
228
- className
229
- } = props;
230
- const formClass = ["rt-cms-lead-form", className].filter(Boolean).join(" ");
231
- return /* @__PURE__ */ jsxs4(
232
- "form",
233
- {
234
- method: "post",
235
- action,
236
- "data-roottale-cms": "lead-form",
237
- className: formClass,
238
- children: [
239
- heading ? /* @__PURE__ */ jsx4("h2", { className: "rt-cms-lead-heading", children: heading }) : null,
240
- description ? /* @__PURE__ */ jsx4("p", { className: "rt-cms-lead-description", children: description }) : null,
241
- redirectUrl ? /* @__PURE__ */ jsx4("input", { type: "hidden", name: "_redirect_url", value: redirectUrl }) : null,
242
- vertical ? /* @__PURE__ */ jsxs4(Fragment, { children: [
243
- /* @__PURE__ */ jsx4("input", { type: "hidden", name: "vertical", value: vertical }),
244
- /* @__PURE__ */ jsxs4("p", { className: "rt-cms-lead-vertical-label", children: [
245
- "\uBD84\uC57C: ",
246
- /* @__PURE__ */ jsx4("strong", { children: VERTICAL_LABEL[vertical] })
247
- ] })
248
- ] }) : /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
249
- /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
250
- "\uBD84\uC57C ",
251
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
252
- ] }),
253
- /* @__PURE__ */ jsxs4(
254
- "select",
255
- {
256
- name: "vertical",
257
- required: true,
258
- className: "rt-cms-field-input rt-cms-field-select",
259
- defaultValue: "",
260
- children: [
261
- /* @__PURE__ */ jsx4("option", { value: "", disabled: true, children: "\uC120\uD0DD\uD558\uC138\uC694" }),
262
- VERTICAL_OPTIONS.map((opt) => /* @__PURE__ */ jsx4("option", { value: opt.value, children: opt.label }, opt.value))
263
- ]
264
- }
265
- )
266
- ] }),
267
- /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
268
- /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
269
- "\uC774\uB984 ",
270
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
271
- ] }),
272
- /* @__PURE__ */ jsx4(
273
- "input",
274
- {
275
- type: "text",
276
- name: "contact_name",
277
- required: true,
278
- autoComplete: "name",
279
- className: "rt-cms-field-input"
280
- }
281
- )
282
- ] }),
283
- /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
284
- /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
285
- "\uC0AC\uC5C5\uCCB4\uBA85 ",
286
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
287
- ] }),
288
- /* @__PURE__ */ jsx4(
289
- "input",
290
- {
291
- type: "text",
292
- name: "business_name",
293
- required: true,
294
- autoComplete: "organization",
295
- className: "rt-cms-field-input"
296
- }
297
- )
298
- ] }),
299
- /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
300
- /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
301
- "\uC774\uBA54\uC77C ",
302
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
303
- ] }),
304
- /* @__PURE__ */ jsx4(
305
- "input",
306
- {
307
- type: "email",
308
- name: "email",
309
- required: true,
310
- autoComplete: "email",
311
- className: "rt-cms-field-input"
312
- }
313
- )
314
- ] }),
315
- /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
316
- /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
317
- "\uC804\uD654\uBC88\uD638 ",
318
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
319
- ] }),
320
- /* @__PURE__ */ jsx4(
321
- "input",
322
- {
323
- type: "tel",
324
- name: "phone",
325
- required: true,
326
- autoComplete: "tel",
327
- inputMode: "tel",
328
- pattern: "0\\d{1,2}-?\\d{3,4}-?\\d{4}",
329
- placeholder: "010-1234-5678",
330
- className: "rt-cms-field-input"
331
- }
332
- )
333
- ] }),
334
- /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
335
- /* @__PURE__ */ jsx4("span", { className: "rt-cms-field-label", children: "\uD604\uC7AC \uC0AC\uC774\uD2B8 URL (\uC120\uD0DD)" }),
336
- /* @__PURE__ */ jsx4(
337
- "input",
338
- {
339
- type: "url",
340
- name: "current_site_url",
341
- placeholder: "https://",
342
- className: "rt-cms-field-input"
343
- }
344
- ),
345
- /* @__PURE__ */ jsx4("span", { className: "rt-cms-field-hint", children: "\uC5C6\uC73C\uBA74 \uBE44\uC6CC\uB450\uC138\uC694." })
346
- ] }),
347
- /* @__PURE__ */ jsxs4("label", { className: "rt-cms-lead-consent", children: [
348
- /* @__PURE__ */ jsx4("input", { type: "checkbox", name: "privacy_consent", required: true }),
349
- /* @__PURE__ */ jsxs4("span", { children: [
350
- /* @__PURE__ */ jsx4("strong", { children: "(\uD544\uC218)" }),
351
- " \uAC1C\uC778\uC815\uBCF4 \uC218\uC9D1\xB7\uC774\uC6A9\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4. (\uC218\uC9D1 \uD56D\uBAA9: \uC774\uB984\xB7\uC5F0\uB77D\uCC98\xB7\uC774\uBA54\uC77C\xB7\uC0AC\uC5C5\uCCB4\uBA85. \uBCF4\uAD00 \uAE30\uAC04: \uBB38\uC758 \uC885\uB8CC \uD6C4 3\uB144)"
352
- ] })
353
- ] }),
354
- vertical === "medical" ? /* @__PURE__ */ jsxs4("label", { className: "rt-cms-lead-consent", children: [
355
- /* @__PURE__ */ jsx4(
356
- "input",
357
- {
358
- type: "checkbox",
359
- name: "overseas_transfer_consent",
360
- required: true
361
- }
362
- ),
363
- /* @__PURE__ */ jsxs4("span", { children: [
364
- /* @__PURE__ */ jsx4("strong", { children: "(\uD544\uC218, \uC758\uB8CC)" }),
365
- " \uC758\uB8CC PII \uC758 \uAD6D\uC678\uC774\uC804(\uBCF4\uAD00\xB7\uCC98\uB9AC)\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4. (\uC758\uB8CC\uBC95 \xA721\xB7\uAC1C\uC778\uC815\uBCF4\uBCF4\uD638\uBC95 \xA728 \u2014 ADR-0018)"
366
- ] })
367
- ] }) : null,
368
- /* @__PURE__ */ jsx4("div", { className: "rt-cms-lead-actions", children: /* @__PURE__ */ jsx4("button", { type: "submit", className: "rt-cms-lead-submit", children: submitLabel }) })
369
- ]
370
- }
371
- );
372
- }
373
-
374
- // src/block-to-react.tsx
375
- import {
376
- applyBlockBindings,
377
- createFieldBindingResolver,
378
- sanitizeHtml
379
- } from "@roottale/cms-core";
380
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
381
- function isString(value) {
382
- return typeof value === "string";
383
- }
384
- function htmlContent(html) {
385
- return { __html: sanitizeHtml(html) };
386
- }
387
- function renderInner(blocks) {
388
- return blocks.map((b, i) => renderBlock(b, i));
389
- }
390
- function renderBlock(block, key = 0) {
391
- const dataBlockId = block._id;
392
- switch (block.name) {
393
- case "core/paragraph": {
394
- const text = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
395
- return /* @__PURE__ */ jsx5(
396
- "p",
397
- {
398
- "data-block-id": dataBlockId,
399
- dangerouslySetInnerHTML: htmlContent(text)
400
- },
401
- key
402
- );
403
- }
404
- case "core/heading": {
405
- const levelRaw = block.attributes.level;
406
- const level = typeof levelRaw === "number" && levelRaw >= 2 && levelRaw <= 4 ? levelRaw : 2;
407
- const text = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
408
- const props = {
409
- "data-block-id": dataBlockId,
410
- dangerouslySetInnerHTML: htmlContent(text)
411
- };
412
- if (level === 2) return /* @__PURE__ */ jsx5("h2", { ...props }, key);
413
- if (level === 3) return /* @__PURE__ */ jsx5("h3", { ...props }, key);
414
- return /* @__PURE__ */ jsx5("h4", { ...props }, key);
415
- }
416
- case "core/image": {
417
- const src = isString(block.attributes.url) ? block.attributes.url : "";
418
- const alt = isString(block.attributes.alt) ? block.attributes.alt : "";
419
- const caption = isString(block.attributes.caption) ? block.attributes.caption : null;
420
- return /* @__PURE__ */ jsxs5("figure", { "data-block-id": dataBlockId, children: [
421
- /* @__PURE__ */ jsx5("img", { src, alt, loading: "lazy" }),
422
- caption && /* @__PURE__ */ jsx5("figcaption", { children: caption })
423
- ] }, key);
424
- }
425
- case "core/list": {
426
- const ordered = block.attributes.ordered === true;
427
- const items = (block.innerBlocks ?? []).map(
428
- (item, i) => item.rawHtml ? /* @__PURE__ */ jsx5(
429
- "li",
430
- {
431
- dangerouslySetInnerHTML: htmlContent(item.rawHtml)
432
- },
433
- i
434
- ) : /* @__PURE__ */ jsx5("li", { children: renderInner(item.innerBlocks ?? []) }, i)
435
- );
436
- return ordered ? /* @__PURE__ */ jsx5("ol", { "data-block-id": dataBlockId, children: items }, key) : /* @__PURE__ */ jsx5("ul", { "data-block-id": dataBlockId, children: items }, key);
437
- }
438
- case "core/quote": {
439
- const inner = renderInner(block.innerBlocks ?? []);
440
- const citation = isString(block.attributes.citation) ? block.attributes.citation : null;
441
- return /* @__PURE__ */ jsxs5("blockquote", { "data-block-id": dataBlockId, children: [
442
- inner,
443
- citation && /* @__PURE__ */ jsx5("cite", { children: citation })
444
- ] }, key);
445
- }
446
- case "core/code": {
447
- const code = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
448
- const lang = isString(block.attributes.language) ? block.attributes.language : void 0;
449
- return /* @__PURE__ */ jsx5(
450
- "pre",
451
- {
452
- "data-block-id": dataBlockId,
453
- "data-language": lang,
454
- children: /* @__PURE__ */ jsx5("code", { children: code })
455
- },
456
- key
457
- );
458
- }
459
- case "core/columns": {
460
- return /* @__PURE__ */ jsx5(
461
- "div",
462
- {
463
- className: "rt-columns",
464
- "data-block-id": dataBlockId,
465
- children: renderInner(block.innerBlocks ?? [])
466
- },
467
- key
468
- );
469
- }
470
- case "core/separator":
471
- return /* @__PURE__ */ jsx5("hr", { "data-block-id": dataBlockId }, key);
472
- case "core/spacer": {
473
- const heightRaw = block.attributes.height;
474
- const height = isString(heightRaw) ? heightRaw : "32px";
475
- return /* @__PURE__ */ jsx5(
476
- "div",
477
- {
478
- className: "rt-spacer",
479
- "data-block-id": dataBlockId,
480
- style: { height }
481
- },
482
- key
483
- );
484
- }
485
- case "core/group": {
486
- return /* @__PURE__ */ jsx5(
487
- "div",
488
- {
489
- className: "rt-group",
490
- "data-block-id": dataBlockId,
491
- children: renderInner(block.innerBlocks ?? [])
492
- },
493
- key
494
- );
495
- }
496
- default: {
497
- const rawHtml = block.rawHtml;
498
- return /* @__PURE__ */ jsx5(
499
- "div",
500
- {
501
- className: "rt-unknown-block",
502
- "data-block-id": dataBlockId,
503
- "data-block-name": block.name,
504
- "data-rawhtml-suppressed": rawHtml ? "true" : void 0,
505
- children: renderInner(block.innerBlocks ?? [])
506
- },
507
- key
508
- );
509
- }
510
- }
511
- }
512
- function renderBlocks(blocks) {
513
- return blocks.map((b, i) => renderBlock(b, i));
514
- }
515
- function renderBoundBlocks(blocks, opts = {}) {
516
- const resolver = opts.resolver ?? createFieldBindingResolver(opts.fields);
517
- return renderBlocks(applyBlockBindings(blocks, resolver));
518
- }
519
-
520
- // src/server.tsx
521
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
522
- function authorImageRadiusCss(radius) {
523
- if (radius === "circle") return "999px";
524
- if (radius === "rounded") return "0.875rem";
525
- return "0";
526
- }
527
- function RootTaleThemeProvider(props) {
528
- const style = themeToCssVars(props.theme ?? null);
529
- if (!style) return /* @__PURE__ */ jsx6(Fragment2, { children: props.children });
530
- return /* @__PURE__ */ jsx6("div", { "data-roottale-cms": "theme-root", style, children: props.children });
531
- }
532
- async function RootTaleBlogList(props) {
533
- const {
534
- apiKey,
535
- baseUrl,
536
- limit,
537
- type = "post",
538
- collection,
539
- collections,
540
- emptyMessage = "\uC544\uC9C1 \uBC1C\uD589\uB41C \uAE00\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
541
- showCategoryFilter = false,
542
- activeCategory,
543
- categoryHref = defaultCategoryHref,
544
- allCategoriesLabel = "\uC804\uCCB4",
545
- author,
546
- theme: themeProp
547
- } = props;
548
- const postHref = props.postHref ?? (collections ? makeCollectionPostHref(collections) : defaultPostHref);
549
- const [page, themeStyle, blogSettings] = await Promise.all([
550
- fetchPosts({ apiKey, baseUrl, limit, type, ...author ? { author } : {} }),
551
- resolveThemeStyle({ themeProp, apiKey, baseUrl }),
552
- fetchBlogSettings({ apiKey, baseUrl }).catch(() => DEFAULT_BLOG_SETTINGS)
553
- ]);
554
- const items = collection && collections ? postsForCollection(page.items, collections, collection) : page.items;
555
- if (items.length === 0) {
556
- return /* @__PURE__ */ jsx6("div", { "data-roottale-cms": "list", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx6("p", { className: "rt-cms-empty", children: emptyMessage }) });
557
- }
558
- const categories = showCategoryFilter ? collectCategories(items) : [];
559
- const visiblePosts = showCategoryFilter ? filterPostsByCategory(items, activeCategory) : items;
560
- return /* @__PURE__ */ jsxs6("div", { "data-roottale-cms": "list", style: themeStyle ?? void 0, children: [
561
- showCategoryFilter && categories.length > 0 ? /* @__PURE__ */ jsxs6("nav", { className: "rt-cms-filter", "aria-label": "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130", children: [
562
- /* @__PURE__ */ jsx6(
563
- "a",
564
- {
565
- className: "rt-cms-filter-chip",
566
- href: categoryHref(null),
567
- "data-active": !activeCategory ? "" : void 0,
568
- "aria-current": !activeCategory ? "true" : void 0,
569
- children: allCategoriesLabel
570
- }
571
- ),
572
- categories.map((c) => /* @__PURE__ */ jsx6(
573
- "a",
574
- {
575
- className: "rt-cms-filter-chip",
576
- href: categoryHref(c.slug),
577
- "data-active": activeCategory === c.slug ? "" : void 0,
578
- "aria-current": activeCategory === c.slug ? "true" : void 0,
579
- children: c.name
580
- },
581
- c.slug
582
- ))
583
- ] }) : null,
584
- visiblePosts.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "rt-cms-empty", children: emptyMessage }) : /* @__PURE__ */ jsx6("ul", { className: "rt-cms-list", children: visiblePosts.map((post) => /* @__PURE__ */ jsx6("li", { className: "rt-cms-list-item", children: /* @__PURE__ */ jsx6(
585
- RootTalePostCard,
586
- {
587
- post,
588
- href: postHref,
589
- display: resolvePostDisplay(post, blogSettings)
590
- }
591
- ) }, post.id)) })
592
- ] });
593
- }
594
- async function RootTaleBlogCategories(props) {
595
- const {
596
- apiKey,
597
- baseUrl,
598
- limit,
599
- collection,
600
- collections,
601
- categoryHref = (slug) => defaultCategoryHref(slug),
602
- emptyMessage = "\uC544\uC9C1 \uCE74\uD14C\uACE0\uB9AC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
603
- theme: themeProp
604
- } = props;
605
- const [page, themeStyle] = await Promise.all([
606
- fetchPosts({ apiKey, baseUrl, limit, type: "post" }),
607
- resolveThemeStyle({ themeProp, apiKey, baseUrl })
608
- ]);
609
- const categories = collection && collections ? collectCollectionCategories(page.items, collections, collection) : collectCategoriesWithCounts(page.items);
610
- return /* @__PURE__ */ jsx6(
611
- "nav",
612
- {
613
- "data-roottale-cms": "categories",
614
- className: "rt-cms-categories",
615
- "aria-label": "\uBE14\uB85C\uADF8 \uCE74\uD14C\uACE0\uB9AC",
616
- style: themeStyle ?? void 0,
617
- children: categories.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "rt-cms-empty", children: emptyMessage }) : /* @__PURE__ */ jsx6("ul", { className: "rt-cms-category-list", children: categories.map((category) => /* @__PURE__ */ jsx6("li", { className: "rt-cms-category-list-item", children: /* @__PURE__ */ jsxs6(
618
- "a",
619
- {
620
- className: "rt-cms-category-link",
621
- href: categoryHref(category.slug),
622
- children: [
623
- /* @__PURE__ */ jsx6("span", { className: "rt-cms-category-name", children: category.name }),
624
- /* @__PURE__ */ jsx6("span", { className: "rt-cms-category-count", children: category.count })
625
- ]
626
- }
627
- ) }, category.slug)) })
628
- }
629
- );
630
- }
631
- async function RootTaleBlogPost(props) {
632
- const {
633
- apiKey,
634
- slugOrId,
635
- baseUrl,
636
- notFoundElement,
637
- showTableOfContents,
638
- tableOfContentsTitle,
639
- theme: themeProp
640
- } = props;
641
- const [post, themeStyle, blogSettings] = await Promise.all([
642
- fetchPost({ apiKey, slugOrId, baseUrl }),
643
- resolveThemeStyle({ themeProp, apiKey, baseUrl }),
644
- // 사이트 기본 표시 설정 — 실패해도 렌더는 진행 (안전 기본값).
645
- fetchBlogSettings({ apiKey, baseUrl }).catch(() => DEFAULT_BLOG_SETTINGS)
646
- ]);
647
- if (!post) {
648
- return notFoundElement ?? /* @__PURE__ */ jsx6("div", { "data-roottale-cms": "post-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx6("p", { className: "rt-cms-empty", children: "\uAE00\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." }) });
649
- }
650
- const display = resolvePostDisplay(post, blogSettings, {
651
- showTableOfContents,
652
- tableOfContentsTitle
653
- });
654
- const toc = display.showTableOfContents ? extractToc(post.bodyJson) : [];
655
- const renderDoc = toc.length > 0 ? attachHeadingIds(post.bodyJson, toc) : post.bodyJson;
656
- const authorName = post.authorName;
657
- const authorImageUrl = post.authorImageUrl;
658
- const postAuthorBio = post.authorBio;
659
- const views = typeof post.viewCount === "number" ? post.viewCount : null;
660
- const publishedDate = display.showDate ? formatPublishedDate2(post.publishedAt) : "";
661
- const showTopAuthor = display.showAuthor && Boolean(authorName);
662
- const displayAuthorName = authorName ?? display.authorProfileName;
663
- const authorBio = postAuthorBio ?? display.authorProfileBio ?? display.authorCardDescription;
664
- const authorImageUrlForCard = authorImageUrl ?? display.authorProfileImageUrl;
665
- const authorImageAlt = `${displayAuthorName ?? ""} \uD504\uB85C\uD544 \uC0AC\uC9C4`.trim();
666
- const authorImageStyle = {
667
- borderRadius: authorImageRadiusCss(display.authorProfileImageRadius),
668
- objectPosition: `${display.authorProfileImagePositionX}% ${display.authorProfileImagePositionY}%`
669
- };
670
- const showAuthorCard = display.showAuthorCard && Boolean(displayAuthorName);
671
- return /* @__PURE__ */ jsxs6(
672
- "article",
673
- {
674
- "data-roottale-cms": "post",
675
- className: "rt-cms-article",
676
- style: themeStyle ?? void 0,
677
- children: [
678
- /* @__PURE__ */ jsxs6("header", { className: "rt-cms-post-header", children: [
679
- publishedDate || showTopAuthor || views !== null ? /* @__PURE__ */ jsxs6("p", { className: "rt-cms-meta", children: [
680
- publishedDate ? /* @__PURE__ */ jsx6("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "date", children: publishedDate }) : null,
681
- showTopAuthor ? /* @__PURE__ */ jsxs6("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
682
- "\uC791\uC131\uC790 ",
683
- authorName
684
- ] }) : null,
685
- views !== null ? /* @__PURE__ */ jsxs6("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "views", children: [
686
- "\uC870\uD68C ",
687
- views.toLocaleString("ko-KR")
688
- ] }) : null
689
- ] }) : null,
690
- /* @__PURE__ */ jsx6("h1", { className: "rt-cms-title", children: post.title }),
691
- post.excerpt ? /* @__PURE__ */ jsx6("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null
692
- ] }),
693
- toc.length > 0 ? /* @__PURE__ */ jsx6(RootTaleTableOfContents, { entries: toc, title: display.tocTitle }) : null,
694
- /* @__PURE__ */ jsx6("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: /* @__PURE__ */ jsx6(RenderTiptap, { doc: renderDoc, fields: post.fields }) }),
695
- showAuthorCard && displayAuthorName ? /* @__PURE__ */ jsxs6("section", { className: "rt-cms-author-card", "aria-label": "\uC791\uC131\uC790", children: [
696
- authorImageUrlForCard ? /* @__PURE__ */ jsx6(
697
- "img",
698
- {
699
- className: "rt-cms-author-card__image",
700
- src: authorImageUrlForCard,
701
- alt: authorImageAlt,
702
- loading: "lazy",
703
- style: authorImageStyle
704
- }
705
- ) : /* @__PURE__ */ jsx6("div", { className: "rt-cms-author-card__avatar", "aria-hidden": "true", children: authorInitials(displayAuthorName) }),
706
- /* @__PURE__ */ jsxs6("div", { className: "rt-cms-author-card__body", children: [
707
- /* @__PURE__ */ jsx6("p", { className: "rt-cms-author-card__eyebrow", children: display.authorCardEyebrow }),
708
- /* @__PURE__ */ jsx6("p", { className: "rt-cms-author-card__name", children: displayAuthorName }),
709
- authorBio ? /* @__PURE__ */ jsx6("p", { className: "rt-cms-author-card__description", children: authorBio }) : null
710
- ] })
711
- ] }) : null,
712
- renderPostCta(blogSettings.postCta)
713
- ]
714
- }
715
- );
716
- }
717
- function renderPostCta(cta) {
718
- if (!cta) return null;
719
- const href = cta.buttonHref.trim();
720
- const safe = href.startsWith("/") || href.startsWith("#") || /^(https?:|mailto:|tel:)/i.test(href);
721
- if (!safe) return null;
722
- const external = /^https?:/i.test(href);
723
- return /* @__PURE__ */ jsxs6("aside", { "data-roottale-cms": "post-cta", className: "rt-cms-post-cta", children: [
724
- cta.title ? /* @__PURE__ */ jsx6("p", { className: "rt-cms-post-cta__title", children: cta.title }) : null,
725
- cta.description ? /* @__PURE__ */ jsx6("p", { className: "rt-cms-post-cta__desc", children: cta.description }) : null,
726
- /* @__PURE__ */ jsx6(
727
- "a",
728
- {
729
- className: "rt-cms-post-cta__btn",
730
- href,
731
- target: external ? "_blank" : void 0,
732
- rel: external ? "noopener noreferrer" : void 0,
733
- children: cta.buttonLabel
734
- }
735
- )
736
- ] });
737
- }
738
- async function RootTalePage(props) {
739
- const {
740
- apiKey,
741
- slugOrId,
742
- baseUrl,
743
- notFoundElement,
744
- showTitle = true,
745
- theme: themeProp
746
- } = props;
747
- const [post, themeStyle] = await Promise.all([
748
- fetchPost({ apiKey, slugOrId, baseUrl }),
749
- resolveThemeStyle({ themeProp, apiKey, baseUrl })
750
- ]);
751
- if (!post) {
752
- return notFoundElement ?? /* @__PURE__ */ jsx6("div", { "data-roottale-cms": "page-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx6("p", { className: "rt-cms-empty", children: "\uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." }) });
753
- }
754
- return /* @__PURE__ */ jsxs6(
755
- "article",
756
- {
757
- "data-roottale-cms": "page",
758
- className: "rt-cms-article",
759
- style: themeStyle ?? void 0,
760
- children: [
761
- showTitle ? /* @__PURE__ */ jsx6("header", { className: "rt-cms-post-header", children: /* @__PURE__ */ jsx6("h1", { className: "rt-cms-title", children: post.title }) }) : null,
762
- /* @__PURE__ */ jsx6("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: /* @__PURE__ */ jsx6(RenderTiptap, { doc: post.bodyJson, fields: post.fields }) })
763
- ]
764
- }
765
- );
766
- }
767
- function authorInitials(name) {
768
- const trimmed = name.trim();
769
- if (!trimmed) return "";
770
- const parts = trimmed.split(/\s+/).filter(Boolean);
771
- if (parts.length >= 2) {
772
- return `${parts[0]?.[0] ?? ""}${parts[1]?.[0] ?? ""}`.toUpperCase();
773
- }
774
- return [...trimmed].slice(0, 2).join("").toUpperCase();
775
- }
776
- async function resolveThemeStyle(input) {
777
- const { themeProp, apiKey, baseUrl } = input;
778
- if (themeProp === null) return null;
779
- if (themeProp !== void 0) return themeToCssVars(themeProp);
780
- try {
781
- const fetched = await fetchTheme({ apiKey, baseUrl });
782
- return themeToCssVars(fetched);
783
- } catch {
784
- return null;
785
- }
786
- }
787
- function themeToCssVars(theme) {
788
- if (!theme) return null;
789
- const vars = {};
790
- const c = theme.colors ?? {};
791
- if (c.primary) vars["--rt-color-primary"] = c.primary;
792
- if (c.primaryForeground) vars["--rt-color-primary-foreground"] = c.primaryForeground;
793
- if (c.foreground) vars["--rt-color-foreground"] = c.foreground;
794
- if (c.background) vars["--rt-color-background"] = c.background;
795
- if (c.secondary) vars["--rt-color-secondary"] = c.secondary;
796
- if (c.secondaryForeground) vars["--rt-color-secondary-foreground"] = c.secondaryForeground;
797
- if (c.accent) vars["--rt-color-accent"] = c.accent;
798
- if (c.accentForeground) vars["--rt-color-accent-foreground"] = c.accentForeground;
799
- if (c.muted) vars["--rt-color-muted"] = c.muted;
800
- if (c.mutedForeground) vars["--rt-color-muted-foreground"] = c.mutedForeground;
801
- if (c.destructive) vars["--rt-color-destructive"] = c.destructive;
802
- if (c.destructiveForeground) vars["--rt-color-destructive-foreground"] = c.destructiveForeground;
803
- if (c.border) vars["--rt-color-border"] = c.border;
804
- if (c.input) vars["--rt-color-input"] = c.input;
805
- if (c.ring) vars["--rt-color-ring"] = c.ring;
806
- const f = theme.fonts ?? {};
807
- if (f.body) vars["--rt-font-body"] = f.body;
808
- if (f.display) vars["--rt-font-display"] = f.display;
809
- const r = theme.radius ?? {};
810
- if (r.sm) vars["--rt-radius-sm"] = r.sm;
811
- if (r.md) vars["--rt-radius-md"] = r.md;
812
- if (r.lg) vars["--rt-radius-lg"] = r.lg;
813
- if (r.xl) vars["--rt-radius-xl"] = r.xl;
814
- if (Object.keys(vars).length === 0) return null;
815
- return vars;
816
- }
817
- function defaultPostHref(post) {
818
- return `/blog/${post.slug}`;
819
- }
820
- function makeCollectionPostHref(collections) {
821
- return (post) => resolvePostPath(post, collections) ?? defaultPostHref(post);
822
- }
823
- function formatPublishedDate2(iso) {
824
- const d = new Date(iso);
825
- if (Number.isNaN(d.getTime())) return "";
826
- return new Intl.DateTimeFormat("ko-KR", {
827
- year: "numeric",
828
- month: "2-digit",
829
- day: "2-digit"
830
- }).format(d);
831
- }
832
- function RenderTiptap({
833
- doc,
834
- fields
835
- }) {
836
- const rawContent = doc.content;
837
- const content = Array.isArray(rawContent) ? rawContent : [];
838
- const hasToc = content.some((n) => n?.type === "tableOfContents");
839
- const docRecord = doc;
840
- const entries = hasToc ? extractToc(docRecord) : [];
841
- const renderDoc = hasToc && entries.length > 0 ? attachHeadingIds(docRecord, entries) : docRecord;
842
- const nodes = Array.isArray(renderDoc.content) ? renderDoc.content : content;
843
- return /* @__PURE__ */ jsx6(Fragment2, { children: nodes.map(
844
- (node, i) => node?.type === "tableOfContents" ? /* @__PURE__ */ jsx6(
845
- RootTaleTableOfContents,
846
- {
847
- entries,
848
- title: typeof node.attrs?.title === "string" ? node.attrs.title : "\uBAA9\uCC28"
849
- },
850
- i
851
- ) : renderNode(node, i, fields ?? null)
852
- ) });
853
- }
854
- function boundContentText(node, fields) {
855
- return bindingTextValue(
856
- boundFieldValue(node.attrs?.bindings, "content", fields)
857
- );
858
- }
859
- function isSafeHref(value) {
860
- if (typeof value !== "string") return false;
861
- const v = value.trim();
862
- if (v.length === 0) return false;
863
- if (v.startsWith("/") || v.startsWith("#") || v.startsWith("?")) return true;
864
- return /^(https?:|mailto:|tel:)/i.test(v);
865
- }
866
- function alignStyle(node) {
867
- const align = node.attrs?.textAlign;
868
- if (typeof align !== "string" || align === "" || align === "left") return void 0;
869
- if (align === "center" || align === "right" || align === "justify") {
870
- return { textAlign: align };
871
- }
872
- return void 0;
873
- }
874
- function tableCellSpans(node) {
875
- const colspan = Number(node.attrs?.colspan);
876
- const rowspan = Number(node.attrs?.rowspan);
877
- return {
878
- colSpan: Number.isFinite(colspan) && colspan > 1 ? colspan : void 0,
879
- rowSpan: Number.isFinite(rowspan) && rowspan > 1 ? rowspan : void 0
880
- };
881
- }
882
- function renderNode(node, key, fields = null) {
883
- if (!node || typeof node !== "object") return null;
884
- const children = Array.isArray(node.content) ? node.content.map((child, i) => renderNode(child, i, fields)) : void 0;
885
- switch (node.type) {
886
- case "paragraph": {
887
- const bound = boundContentText(node, fields);
888
- return /* @__PURE__ */ jsx6("p", { style: alignStyle(node), children: bound ?? children }, key);
889
- }
890
- case "heading": {
891
- const rawLevel = Number(node.attrs?.level ?? 2);
892
- const level = Math.min(Math.max(Number.isFinite(rawLevel) ? rawLevel : 2, 2), 4);
893
- const idAttr = node.attrs?.id;
894
- const id = typeof idAttr === "string" && idAttr.length > 0 ? idAttr : void 0;
895
- const style = alignStyle(node);
896
- const inner = boundContentText(node, fields) ?? children;
897
- if (level === 2) return /* @__PURE__ */ jsx6("h2", { id, style, children: inner }, key);
898
- if (level === 3) return /* @__PURE__ */ jsx6("h3", { id, style, children: inner }, key);
899
- return /* @__PURE__ */ jsx6("h4", { id, style, children: inner }, key);
900
- }
901
- case "bulletList":
902
- return /* @__PURE__ */ jsx6("ul", { children }, key);
903
- case "orderedList":
904
- return /* @__PURE__ */ jsx6("ol", { children }, key);
905
- case "listItem":
906
- return /* @__PURE__ */ jsx6("li", { children }, key);
907
- case "blockquote":
908
- return /* @__PURE__ */ jsx6("blockquote", { children }, key);
909
- case "codeBlock":
910
- return /* @__PURE__ */ jsx6("pre", { children: /* @__PURE__ */ jsx6("code", { children }) }, key);
911
- case "horizontalRule":
912
- return /* @__PURE__ */ jsx6("hr", {}, key);
913
- case "hardBreak":
914
- return /* @__PURE__ */ jsx6("br", {}, key);
915
- case "image": {
916
- const boundSrc = bindingSrcValue(
917
- boundFieldValue(node.attrs?.bindings, "src", fields)
918
- );
919
- const src = boundSrc ?? node.attrs?.src;
920
- if (typeof src !== "string" || src.length === 0) return null;
921
- const alt = typeof node.attrs?.alt === "string" ? node.attrs.alt : "";
922
- const title = typeof node.attrs?.title === "string" ? node.attrs.title : void 0;
923
- const width = typeof node.attrs?.width === "number" && node.attrs.width > 0 ? node.attrs.width : void 0;
924
- const height = typeof node.attrs?.height === "number" && node.attrs.height > 0 ? node.attrs.height : void 0;
925
- return /* @__PURE__ */ jsx6(
926
- "img",
927
- {
928
- src,
929
- alt,
930
- title,
931
- width,
932
- height,
933
- loading: "lazy"
934
- },
935
- key
936
- );
937
- }
938
- case "columns":
939
- return /* @__PURE__ */ jsx6("div", { className: "rt-columns", children }, key);
940
- case "column":
941
- return /* @__PURE__ */ jsx6("div", { className: "rt-column", children }, key);
942
- case "table":
943
- return /* @__PURE__ */ jsx6("div", { className: "rt-table-wrap", children: /* @__PURE__ */ jsx6("table", { className: "rt-table", children: /* @__PURE__ */ jsx6("tbody", { children }) }) }, key);
944
- case "tableRow":
945
- return /* @__PURE__ */ jsx6("tr", { children }, key);
946
- case "tableHeader": {
947
- const { colSpan, rowSpan } = tableCellSpans(node);
948
- return /* @__PURE__ */ jsx6("th", { colSpan, rowSpan, children }, key);
949
- }
950
- case "tableCell": {
951
- const { colSpan, rowSpan } = tableCellSpans(node);
952
- return /* @__PURE__ */ jsx6("td", { colSpan, rowSpan, children }, key);
953
- }
954
- case "embed":
955
- return renderEmbed(node, key);
956
- case "tableOfContents":
957
- return null;
958
- case "text":
959
- return renderText(node, key);
960
- default:
961
- return children ? /* @__PURE__ */ jsx6("span", { children }, key) : null;
962
- }
963
- }
964
- function renderEmbed(node, key) {
965
- const src = node.attrs?.src;
966
- if (isAllowedEmbedSrc(src)) {
967
- const provider = typeof node.attrs?.provider === "string" ? node.attrs.provider : void 0;
968
- return /* @__PURE__ */ jsx6(
969
- "div",
970
- {
971
- className: "rt-embed",
972
- "data-provider": provider,
973
- style: { aspectRatio: "16 / 9" },
974
- children: /* @__PURE__ */ jsx6(
975
- "iframe",
976
- {
977
- src,
978
- title: "\uC784\uBCA0\uB4DC\uB41C \uC601\uC0C1",
979
- loading: "lazy",
980
- allowFullScreen: true,
981
- referrerPolicy: "strict-origin-when-cross-origin",
982
- allow: "accelerometer; clipboard-write; encrypted-media; picture-in-picture; web-share",
983
- style: { width: "100%", height: "100%", border: 0 }
984
- }
985
- )
986
- },
987
- key
988
- );
989
- }
990
- const orig = node.attrs?.originalUrl;
991
- if (isSafeHref(orig)) {
992
- return /* @__PURE__ */ jsx6("p", { className: "rt-embed-fallback", children: /* @__PURE__ */ jsx6("a", { href: orig, rel: "noopener noreferrer", target: "_blank", children: orig }) }, key);
993
- }
994
- return null;
995
- }
996
- function renderText(node, key) {
997
- const text = node.text ?? "";
998
- const marks = node.marks ?? [];
999
- if (marks.length === 0) return text;
1000
- let element = text;
1001
- for (const mark of marks) {
1002
- element = applyMark(mark, element);
1003
- }
1004
- return /* @__PURE__ */ jsx6("span", { children: element }, key);
1005
- }
1006
- function applyMark(mark, child) {
1007
- switch (mark.type) {
1008
- case "bold":
1009
- return /* @__PURE__ */ jsx6("strong", { children: child });
1010
- case "italic":
1011
- return /* @__PURE__ */ jsx6("em", { children: child });
1012
- case "underline":
1013
- return /* @__PURE__ */ jsx6("u", { children: child });
1014
- case "strike":
1015
- return /* @__PURE__ */ jsx6("s", { children: child });
1016
- case "code":
1017
- return /* @__PURE__ */ jsx6("code", { children: child });
1018
- case "highlight": {
1019
- const color = mark.attrs?.color;
1020
- const style = typeof color === "string" && color.length > 0 ? { background: color } : void 0;
1021
- return /* @__PURE__ */ jsx6("mark", { style, children: child });
1022
- }
1023
- case "textStyle": {
1024
- const color = mark.attrs?.color;
1025
- const style = typeof color === "string" && color.length > 0 ? { color } : void 0;
1026
- if (!style) return /* @__PURE__ */ jsx6(Fragment2, { children: child });
1027
- return /* @__PURE__ */ jsx6("span", { style, children: child });
1028
- }
1029
- case "link": {
1030
- const raw = mark.attrs?.href;
1031
- const href = isSafeHref(raw) ? raw : "#";
1032
- return /* @__PURE__ */ jsx6("a", { href, rel: "noopener noreferrer", target: "_blank", children: child });
1033
- }
1034
- default:
1035
- return /* @__PURE__ */ jsx6("span", { children: child });
1036
- }
1037
- }
1038
-
1039
- export {
1040
- RootTalePostCard,
1041
- RootTaleTableOfContents,
1042
- headingToId,
1043
- extractToc,
1044
- attachHeadingIds,
1045
- RootTaleFloatingCta,
1046
- RootTaleLeadForm,
1047
- renderBlock,
1048
- renderBlocks,
1049
- renderBoundBlocks,
1050
- RootTaleThemeProvider,
1051
- RootTaleBlogList,
1052
- RootTaleBlogCategories,
1053
- RootTaleBlogPost,
1054
- RootTalePage,
1055
- RenderTiptap
1056
- };
1057
- //# sourceMappingURL=chunk-3JUIHMPP.js.map