@roottale/cms-renderer-next 0.41.2 → 0.42.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/before-after-client.d.ts +15 -0
  3. package/dist/before-after-client.js +8 -0
  4. package/dist/before-after-client.js.map +1 -0
  5. package/dist/chunk-4LQPZDXZ.js +75 -0
  6. package/dist/chunk-4LQPZDXZ.js.map +1 -0
  7. package/dist/chunk-6GQCFFHU.js +540 -0
  8. package/dist/chunk-6GQCFFHU.js.map +1 -0
  9. package/dist/{chunk-YUT4BRJY.js → chunk-F3G6RVIR.js} +68 -15
  10. package/dist/chunk-F3G6RVIR.js.map +1 -0
  11. package/dist/chunk-H46JUIHZ.js +79 -0
  12. package/dist/chunk-H46JUIHZ.js.map +1 -0
  13. package/dist/chunk-K62RR4UQ.js +53 -0
  14. package/dist/chunk-K62RR4UQ.js.map +1 -0
  15. package/dist/chunk-NUUTTSGT.js +916 -0
  16. package/dist/chunk-NUUTTSGT.js.map +1 -0
  17. package/dist/chunk-RSNUZ4BF.js +3378 -0
  18. package/dist/chunk-RSNUZ4BF.js.map +1 -0
  19. package/dist/chunk-U5AKACPN.js +113 -0
  20. package/dist/chunk-U5AKACPN.js.map +1 -0
  21. package/dist/chunk-WWS43XCT.js +206 -0
  22. package/dist/chunk-WWS43XCT.js.map +1 -0
  23. package/dist/cms-public.css +164 -51
  24. package/dist/concerns-client.d.ts +12 -0
  25. package/dist/concerns-client.js +8 -0
  26. package/dist/concerns-client.js.map +1 -0
  27. package/dist/expertise-client.d.ts +10 -0
  28. package/dist/expertise-client.js +8 -0
  29. package/dist/expertise-client.js.map +1 -0
  30. package/dist/hero-carousel-client.d.ts +22 -1
  31. package/dist/hero-carousel-client.js +1 -1
  32. package/dist/routes.d.ts +51 -5
  33. package/dist/routes.js +109 -62
  34. package/dist/routes.js.map +1 -1
  35. package/dist/seo-checks.d.ts +87 -0
  36. package/dist/seo-checks.js +27 -0
  37. package/dist/seo-checks.js.map +1 -0
  38. package/dist/server.d.ts +51 -2
  39. package/dist/server.js +8 -3
  40. package/dist/site-config-DgYGGwu1.d.ts +3910 -0
  41. package/dist/spaces-client.d.ts +10 -0
  42. package/dist/spaces-client.js +8 -0
  43. package/dist/spaces-client.js.map +1 -0
  44. package/dist/templates.css +3200 -344
  45. package/dist/templates.d.ts +19 -1127
  46. package/dist/templates.js +70 -3
  47. package/dist/templates.js.map +1 -1
  48. package/dist/{theme-css-vars-BiyHBsJG.d.ts → theme-css-vars-CD3jcEkp.d.ts} +2 -2
  49. package/dist/ui-react-motion-client.d.ts +73 -0
  50. package/dist/ui-react-motion-client.js +14 -0
  51. package/dist/ui-react-motion-client.js.map +1 -0
  52. package/dist/validate.d.ts +15 -1
  53. package/dist/validate.js +399 -15
  54. package/dist/validate.js.map +1 -1
  55. package/package.json +15 -5
  56. package/dist/chunk-5R6APJZ2.js +0 -1688
  57. package/dist/chunk-5R6APJZ2.js.map +0 -1
  58. package/dist/chunk-QKZ4HRBB.js +0 -300
  59. package/dist/chunk-QKZ4HRBB.js.map +0 -1
  60. package/dist/chunk-YUT4BRJY.js.map +0 -1
@@ -1,1688 +0,0 @@
1
- import {
2
- collectCategories,
3
- collectCategoriesWithCounts,
4
- collectCollectionCategories,
5
- defaultCategoryHref,
6
- filterPostsByCategory
7
- } from "./chunk-FUA5H6JE.js";
8
- import {
9
- SectionSchema
10
- } from "./chunk-QKZ4HRBB.js";
11
- import {
12
- HeroCarouselViewport
13
- } from "./chunk-YUT4BRJY.js";
14
-
15
- // src/server.tsx
16
- import {
17
- DEFAULT_BLOG_SETTINGS,
18
- fetchBlogSettings,
19
- fetchPost,
20
- fetchPosts,
21
- fetchTheme,
22
- resolvePostDisplay,
23
- selectRelatedPosts
24
- } from "@roottale/cms-client/server";
25
- import {
26
- bindingSrcValue,
27
- bindingTextValue,
28
- boundFieldValue,
29
- extractFaqEntries,
30
- faqPageJsonLd,
31
- isAllowedEmbedSrc as isAllowedEmbedSrc2,
32
- postsForCollection,
33
- resolvePostPath
34
- } from "@roottale/cms-core";
35
-
36
- // src/LeadForm.tsx
37
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
38
- var VERTICAL_LABEL = {
39
- consulting: "\uCEE8\uC124\uD305",
40
- medical: "\uC758\uB8CC",
41
- tax: "\uC138\uBB34",
42
- legal: "\uBC95\uB960"
43
- };
44
- var VERTICAL_OPTIONS = [
45
- { value: "consulting", label: "\uCEE8\uC124\uD305 / \uC77C\uBC18" },
46
- { value: "medical", label: "\uC758\uB8CC (\uBCD1\uC758\uC6D0\xB7\uCE58\uACFC\xB7\uD55C\uC758\uC6D0)" },
47
- { value: "tax", label: "\uC138\uBB34 (\uC138\uBB34\uC0AC\xB7\uD68C\uACC4\uC0AC)" },
48
- { value: "legal", label: "\uBC95\uB960 (\uBC95\uBB34\uBC95\uC778\xB7\uBCC0\uD638\uC0AC)" }
49
- ];
50
- function RootTaleLeadForm(props) {
51
- const {
52
- action,
53
- vertical,
54
- redirectUrl,
55
- heading,
56
- description,
57
- submitLabel = "\uC9C4\uB2E8 \uC2E0\uCCAD",
58
- turnstileSiteKey,
59
- className
60
- } = props;
61
- const formClass = ["rt-cms-lead-form", className].filter(Boolean).join(" ");
62
- return /* @__PURE__ */ jsxs(
63
- "form",
64
- {
65
- method: "post",
66
- action,
67
- "data-roottale-cms": "lead-form",
68
- className: formClass,
69
- children: [
70
- heading ? /* @__PURE__ */ jsx("h2", { className: "rt-cms-lead-heading", children: heading }) : null,
71
- description ? /* @__PURE__ */ jsx("p", { className: "rt-cms-lead-description", children: description }) : null,
72
- redirectUrl ? /* @__PURE__ */ jsx("input", { type: "hidden", name: "_redirect_url", value: redirectUrl }) : null,
73
- vertical ? /* @__PURE__ */ jsxs(Fragment, { children: [
74
- /* @__PURE__ */ jsx("input", { type: "hidden", name: "vertical", value: vertical }),
75
- /* @__PURE__ */ jsxs("p", { className: "rt-cms-lead-vertical-label", children: [
76
- "\uBD84\uC57C: ",
77
- /* @__PURE__ */ jsx("strong", { children: VERTICAL_LABEL[vertical] })
78
- ] })
79
- ] }) : /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
80
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
81
- "\uBD84\uC57C ",
82
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
83
- ] }),
84
- /* @__PURE__ */ jsxs(
85
- "select",
86
- {
87
- name: "vertical",
88
- required: true,
89
- className: "rt-cms-field-input rt-cms-field-select",
90
- defaultValue: "",
91
- children: [
92
- /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "\uC120\uD0DD\uD558\uC138\uC694" }),
93
- VERTICAL_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
94
- ]
95
- }
96
- )
97
- ] }),
98
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
99
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
100
- "\uC774\uB984 ",
101
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
102
- ] }),
103
- /* @__PURE__ */ jsx(
104
- "input",
105
- {
106
- type: "text",
107
- name: "contact_name",
108
- required: true,
109
- autoComplete: "name",
110
- className: "rt-cms-field-input"
111
- }
112
- )
113
- ] }),
114
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
115
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
116
- "\uC0AC\uC5C5\uCCB4\uBA85 ",
117
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
118
- ] }),
119
- /* @__PURE__ */ jsx(
120
- "input",
121
- {
122
- type: "text",
123
- name: "business_name",
124
- required: true,
125
- autoComplete: "organization",
126
- className: "rt-cms-field-input"
127
- }
128
- )
129
- ] }),
130
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
131
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
132
- "\uC774\uBA54\uC77C ",
133
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
134
- ] }),
135
- /* @__PURE__ */ jsx(
136
- "input",
137
- {
138
- type: "email",
139
- name: "email",
140
- required: true,
141
- autoComplete: "email",
142
- className: "rt-cms-field-input"
143
- }
144
- )
145
- ] }),
146
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
147
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
148
- "\uC804\uD654\uBC88\uD638 ",
149
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
150
- ] }),
151
- /* @__PURE__ */ jsx(
152
- "input",
153
- {
154
- type: "tel",
155
- name: "phone",
156
- required: true,
157
- autoComplete: "tel",
158
- inputMode: "tel",
159
- pattern: "0\\d{1,2}-?\\d{3,4}-?\\d{4}",
160
- placeholder: "010-1234-5678",
161
- className: "rt-cms-field-input"
162
- }
163
- )
164
- ] }),
165
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
166
- /* @__PURE__ */ jsx("span", { className: "rt-cms-field-label", children: "\uD604\uC7AC \uC0AC\uC774\uD2B8 URL (\uC120\uD0DD)" }),
167
- /* @__PURE__ */ jsx(
168
- "input",
169
- {
170
- type: "url",
171
- name: "current_site_url",
172
- placeholder: "https://",
173
- className: "rt-cms-field-input"
174
- }
175
- ),
176
- /* @__PURE__ */ jsx("span", { className: "rt-cms-field-hint", children: "\uC5C6\uC73C\uBA74 \uBE44\uC6CC\uB450\uC138\uC694." })
177
- ] }),
178
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-lead-consent", children: [
179
- /* @__PURE__ */ jsx("input", { type: "checkbox", name: "privacy_consent", required: true }),
180
- /* @__PURE__ */ jsxs("span", { children: [
181
- /* @__PURE__ */ jsx("strong", { children: "(\uD544\uC218)" }),
182
- " \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)"
183
- ] })
184
- ] }),
185
- vertical === "medical" ? /* @__PURE__ */ jsxs("label", { className: "rt-cms-lead-consent", children: [
186
- /* @__PURE__ */ jsx(
187
- "input",
188
- {
189
- type: "checkbox",
190
- name: "overseas_transfer_consent",
191
- required: true
192
- }
193
- ),
194
- /* @__PURE__ */ jsxs("span", { children: [
195
- /* @__PURE__ */ jsx("strong", { children: "(\uD544\uC218, \uC758\uB8CC)" }),
196
- " \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)"
197
- ] })
198
- ] }) : null,
199
- turnstileSiteKey ? /* @__PURE__ */ jsxs(Fragment, { children: [
200
- /* @__PURE__ */ jsx(
201
- "script",
202
- {
203
- src: "https://challenges.cloudflare.com/turnstile/v0/api.js",
204
- async: true,
205
- defer: true
206
- }
207
- ),
208
- /* @__PURE__ */ jsx(
209
- "div",
210
- {
211
- className: "cf-turnstile",
212
- "data-sitekey": turnstileSiteKey,
213
- "data-action": "turnstile-spin-v1"
214
- }
215
- )
216
- ] }) : null,
217
- /* @__PURE__ */ jsx("div", { className: "rt-cms-lead-actions", children: /* @__PURE__ */ jsx("button", { type: "submit", className: "rt-cms-lead-submit", children: submitLabel }) })
218
- ]
219
- }
220
- );
221
- }
222
-
223
- // src/templates/sections.tsx
224
- import { isAllowedEmbedSrc } from "@roottale/cms-core";
225
- import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
226
- function sectionThemeStyle(theme) {
227
- if (!theme) return void 0;
228
- const style = {};
229
- for (const [key, value] of Object.entries(theme)) {
230
- if (key.startsWith("--")) style[key] = value;
231
- }
232
- return Object.keys(style).length > 0 ? style : void 0;
233
- }
234
- function CtaLink({
235
- cta,
236
- className,
237
- track
238
- }) {
239
- return /* @__PURE__ */ jsx2(
240
- "a",
241
- {
242
- className: className ?? "rt-tpl-btn rt-tpl-btn--primary",
243
- href: cta.href,
244
- "data-track": track,
245
- children: cta.label
246
- }
247
- );
248
- }
249
- function TemplateHeroCarousel(section) {
250
- const { eyebrow, title, subtitle, cta, slides, autoplay, intervalMs } = section.props;
251
- const safeSlides = slides ?? [];
252
- return /* @__PURE__ */ jsxs2(
253
- "section",
254
- {
255
- "data-roottale-tpl": "hero",
256
- "data-variant": "carousel",
257
- id: section.id,
258
- className: "rt-tpl-section rt-tpl-hero rt-tpl-hero--carousel",
259
- style: sectionThemeStyle(section.theme),
260
- children: [
261
- safeSlides.length >= 2 ? /* @__PURE__ */ jsx2(
262
- HeroCarouselViewport,
263
- {
264
- slides: safeSlides,
265
- autoplay: autoplay ?? true,
266
- intervalMs: intervalMs ?? 6e3
267
- }
268
- ) : null,
269
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-hero-carousel-overlay", children: [
270
- eyebrow ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-eyebrow", children: eyebrow }) : null,
271
- /* @__PURE__ */ jsx2("h1", { className: "rt-tpl-hero-title rt-tpl-hero-carousel-title", children: title.split("\n").map((line, i) => /* @__PURE__ */ jsx2("span", { className: "rt-tpl-hero-title-line", children: line }, i)) }),
272
- subtitle ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-desc rt-tpl-hero-carousel-subtitle", children: subtitle }) : null,
273
- cta ? /* @__PURE__ */ jsx2(
274
- CtaLink,
275
- {
276
- cta,
277
- track: "cta_hero",
278
- className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-hero-carousel-cta"
279
- }
280
- ) : null
281
- ] })
282
- ]
283
- }
284
- );
285
- }
286
- function TemplateHero(section) {
287
- if (section.variant === "carousel") return TemplateHeroCarousel(section);
288
- const { eyebrow, title, description, imageSrc, imageAlt, cta } = section.props;
289
- const variant = section.variant;
290
- const showImage = variant !== "minimal" && imageSrc;
291
- return /* @__PURE__ */ jsx2(
292
- "section",
293
- {
294
- "data-roottale-tpl": "hero",
295
- "data-variant": variant,
296
- id: section.id,
297
- className: "rt-tpl-section rt-tpl-hero",
298
- style: sectionThemeStyle(section.theme),
299
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-hero-inner", children: [
300
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-copy", children: [
301
- eyebrow ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-eyebrow", children: eyebrow }) : null,
302
- /* @__PURE__ */ jsx2("h1", { className: "rt-tpl-hero-title", children: title.split("\n").map((line, i) => /* @__PURE__ */ jsx2("span", { className: "rt-tpl-hero-title-line", children: line }, i)) }),
303
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-desc", children: description }) : null,
304
- cta ? /* @__PURE__ */ jsx2(CtaLink, { cta, track: "cta_hero" }) : null
305
- ] }),
306
- showImage ? /* @__PURE__ */ jsx2("div", { className: "rt-tpl-hero-media", children: /* @__PURE__ */ jsx2(
307
- "img",
308
- {
309
- className: "rt-tpl-hero-img",
310
- src: imageSrc,
311
- alt: imageAlt ?? "",
312
- loading: "eager"
313
- }
314
- ) }) : null
315
- ] })
316
- }
317
- );
318
- }
319
- function TemplateRichText(section) {
320
- const { heading, body } = section.props;
321
- return /* @__PURE__ */ jsx2(
322
- "section",
323
- {
324
- "data-roottale-tpl": "rich-text",
325
- id: section.id,
326
- className: "rt-tpl-section rt-tpl-rich-text",
327
- style: sectionThemeStyle(section.theme),
328
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
329
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
330
- body.split("\n\n").map((para, i) => /* @__PURE__ */ jsx2("p", { className: "rt-tpl-rich-text-p", children: para }, i))
331
- ] })
332
- }
333
- );
334
- }
335
- function TemplateServices(section) {
336
- const { heading, description, items } = section.props;
337
- return /* @__PURE__ */ jsx2(
338
- "section",
339
- {
340
- "data-roottale-tpl": "services",
341
- "data-variant": section.variant,
342
- id: section.id,
343
- className: "rt-tpl-section rt-tpl-services",
344
- style: sectionThemeStyle(section.theme),
345
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
346
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
347
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
348
- /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-services-list", children: items.map((item, i) => {
349
- const body = /* @__PURE__ */ jsxs2(Fragment2, { children: [
350
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-services-title", children: item.title }),
351
- item.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-services-desc", children: item.description }) : null
352
- ] });
353
- return /* @__PURE__ */ jsx2("li", { className: "rt-tpl-services-item", children: item.href ? /* @__PURE__ */ jsx2(
354
- "a",
355
- {
356
- className: "rt-tpl-services-link",
357
- href: item.href,
358
- "data-track": "service_card",
359
- children: body
360
- }
361
- ) : body }, i);
362
- }) })
363
- ] })
364
- }
365
- );
366
- }
367
- function TemplateFaq(section) {
368
- const { heading, items, jsonLd } = section.props;
369
- return /* @__PURE__ */ jsxs2(
370
- "section",
371
- {
372
- "data-roottale-tpl": "faq",
373
- id: section.id,
374
- className: "rt-tpl-section rt-tpl-faq",
375
- style: sectionThemeStyle(section.theme),
376
- children: [
377
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
378
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
379
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-faq-list", children: items.map((item, i) => /* @__PURE__ */ jsxs2("details", { className: "rt-tpl-faq-item", children: [
380
- /* @__PURE__ */ jsx2("summary", { className: "rt-tpl-faq-q", children: item.question }),
381
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-faq-a", children: item.answer })
382
- ] }, i)) })
383
- ] }),
384
- jsonLd ? /* @__PURE__ */ jsx2(
385
- "script",
386
- {
387
- type: "application/ld+json",
388
- dangerouslySetInnerHTML: {
389
- __html: JSON.stringify({
390
- "@context": "https://schema.org",
391
- "@type": "FAQPage",
392
- mainEntity: items.map((item) => ({
393
- "@type": "Question",
394
- name: item.question,
395
- acceptedAnswer: { "@type": "Answer", text: item.answer }
396
- }))
397
- })
398
- }
399
- }
400
- ) : null
401
- ]
402
- }
403
- );
404
- }
405
- function TemplateCtaBanner(section) {
406
- const { title, description, cta } = section.props;
407
- return /* @__PURE__ */ jsx2(
408
- "section",
409
- {
410
- "data-roottale-tpl": "cta-banner",
411
- id: section.id,
412
- className: "rt-tpl-section rt-tpl-cta-banner",
413
- style: sectionThemeStyle(section.theme),
414
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-cta-banner-inner", children: [
415
- /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-cta-banner-title", children: title }),
416
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-cta-banner-desc", children: description }) : null,
417
- cta ? /* @__PURE__ */ jsx2(CtaLink, { cta, track: "cta_banner" }) : null
418
- ] })
419
- }
420
- );
421
- }
422
- function TrustCredentialIcon() {
423
- return /* @__PURE__ */ jsxs2(
424
- "svg",
425
- {
426
- className: "rt-cred__icon",
427
- viewBox: "0 0 16 16",
428
- "aria-hidden": "true",
429
- focusable: "false",
430
- children: [
431
- /* @__PURE__ */ jsx2("path", { d: "M8 1.75 13 3.5v3.75c0 3-2 5.45-5 7-3-1.55-5-4-5-7V3.5z" }),
432
- /* @__PURE__ */ jsx2("path", { d: "m5.75 8 1.45 1.45 3.2-3.4" })
433
- ]
434
- }
435
- );
436
- }
437
- function TemplateTrust(section) {
438
- const { heading, metrics, credentials, logos, disclaimer } = section.props;
439
- return /* @__PURE__ */ jsx2(
440
- "section",
441
- {
442
- "data-roottale-tpl": "trust",
443
- "data-variant": section.variant,
444
- id: section.id,
445
- className: "rt-tpl-section rt-tpl-trust",
446
- style: sectionThemeStyle(section.theme),
447
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-trust-inner", children: [
448
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
449
- section.variant === "stat-band" ? /* @__PURE__ */ jsx2("div", { className: "rt-tpl-trust-stat-band", children: (metrics ?? []).map((metric) => /* @__PURE__ */ jsxs2(
450
- "div",
451
- {
452
- className: "rt-stat",
453
- "data-variant": "band-item",
454
- children: [
455
- /* @__PURE__ */ jsxs2("span", { className: "rt-stat__value", children: [
456
- metric.value,
457
- metric.unit ? /* @__PURE__ */ jsx2("span", { className: "rt-stat__unit", children: metric.unit }) : null
458
- ] }),
459
- /* @__PURE__ */ jsx2("span", { className: "rt-stat__label", children: metric.label }),
460
- metric.source ? /* @__PURE__ */ jsx2("span", { className: "rt-stat__source", children: metric.source }) : null
461
- ]
462
- },
463
- `${metric.value}-${metric.label}`
464
- )) }) : null,
465
- section.variant === "logo-cloud" ? /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-trust-logo-list", children: (logos ?? []).map((logo) => /* @__PURE__ */ jsx2("li", { className: "rt-tpl-trust-logo-item", children: logo.href ? /* @__PURE__ */ jsx2("a", { className: "rt-tpl-trust-logo-link", href: logo.href, children: /* @__PURE__ */ jsx2(
466
- "img",
467
- {
468
- className: "rt-tpl-trust-logo",
469
- src: logo.src,
470
- alt: logo.alt,
471
- loading: "lazy"
472
- }
473
- ) }) : /* @__PURE__ */ jsx2(
474
- "img",
475
- {
476
- className: "rt-tpl-trust-logo",
477
- src: logo.src,
478
- alt: logo.alt,
479
- loading: "lazy"
480
- }
481
- ) }, `${logo.src}-${logo.alt}`)) }) : null,
482
- section.variant === "feature-grid" ? /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-trust-cred-list", children: (credentials ?? []).map((credential) => /* @__PURE__ */ jsx2("li", { children: /* @__PURE__ */ jsxs2("span", { className: "rt-cred", "data-kind": credential.kind, children: [
483
- /* @__PURE__ */ jsx2(TrustCredentialIcon, {}),
484
- /* @__PURE__ */ jsx2("span", { className: "rt-cred__label", children: credential.name }),
485
- credential.issuer ? /* @__PURE__ */ jsx2("span", { className: "rt-cred__issuer", children: credential.issuer }) : null
486
- ] }) }, `${credential.name}-${credential.issuer ?? ""}`)) }) : null,
487
- disclaimer ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-trust-disclaimer", children: disclaimer }) : null
488
- ] })
489
- }
490
- );
491
- }
492
- function telHref(phone) {
493
- return `tel:${phone.replace(/[^\d+]/g, "")}`;
494
- }
495
- function ContactMap({ url }) {
496
- if (isAllowedEmbedSrc(url)) {
497
- return /* @__PURE__ */ jsx2("div", { className: "rt-tpl-contact-map", children: /* @__PURE__ */ jsx2(
498
- "iframe",
499
- {
500
- src: url,
501
- title: "\uC624\uC2DC\uB294\uAE38 \uC9C0\uB3C4",
502
- loading: "lazy",
503
- referrerPolicy: "no-referrer-when-downgrade"
504
- }
505
- ) });
506
- }
507
- return /* @__PURE__ */ jsx2("p", { className: "rt-tpl-contact-map-fallback", children: /* @__PURE__ */ jsx2("a", { href: url, rel: "noopener noreferrer", target: "_blank", children: "\uAE38\uCC3E\uAE30" }) });
508
- }
509
- function TemplateContact(section) {
510
- const { heading, form, phone, address, hours, mapEmbedUrl } = section.props;
511
- return /* @__PURE__ */ jsx2(
512
- "section",
513
- {
514
- "data-roottale-tpl": "contact",
515
- "data-variant": section.variant,
516
- id: section.id,
517
- className: "rt-tpl-section rt-tpl-contact",
518
- style: sectionThemeStyle(section.theme),
519
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-contact-inner", children: [
520
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-contact-info", children: [
521
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
522
- phone ? /* @__PURE__ */ jsx2("a", { className: "rt-tpl-contact-phone", href: telHref(phone), "data-track": "cta_call", children: phone }) : null,
523
- address ? /* @__PURE__ */ jsx2("address", { className: "rt-tpl-contact-address", children: address }) : null,
524
- hours ? /* @__PURE__ */ jsxs2("table", { className: "rt-tpl-contact-hours", children: [
525
- /* @__PURE__ */ jsx2("caption", { className: "rt-tpl-sr-only", children: "\uC9C4\uB8CC\uC2DC\uAC04" }),
526
- /* @__PURE__ */ jsx2("tbody", { children: hours.map((row) => /* @__PURE__ */ jsxs2("tr", { children: [
527
- /* @__PURE__ */ jsx2("th", { scope: "row", children: row.day }),
528
- /* @__PURE__ */ jsxs2("td", { children: [
529
- /* @__PURE__ */ jsx2("span", { children: row.open }),
530
- /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "-" }),
531
- /* @__PURE__ */ jsx2("span", { children: row.close }),
532
- row.note ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-contact-hours-note", children: row.note }) : null
533
- ] })
534
- ] }, `${row.day}-${row.open}-${row.close}`)) })
535
- ] }) : null,
536
- mapEmbedUrl ? /* @__PURE__ */ jsx2(ContactMap, { url: mapEmbedUrl }) : null
537
- ] }),
538
- form.enabled ? /* @__PURE__ */ jsx2("div", { className: "rt-tpl-contact-form", children: /* @__PURE__ */ jsx2(RootTaleLeadForm, { action: "/api/inquiry", vertical: form.vertical }) }) : null
539
- ] })
540
- }
541
- );
542
- }
543
-
544
- // src/render-section-node.tsx
545
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
546
- function warnSkippedCmsBound(sectionType, isDev) {
547
- if (isDev()) {
548
- console.warn(
549
- `[cms-renderer-next] section \uB178\uB4DC sectionType=${sectionType} \uB294 apiKey \uCEE8\uD14D\uC2A4\uD2B8\uAC00 \uC5C6\uC5B4 \uB80C\uB354 skip`
550
- );
551
- }
552
- }
553
- function renderSectionNode(node, key, context) {
554
- const attrs = node.attrs ?? {};
555
- const input = {
556
- type: typeof attrs.sectionType === "string" ? attrs.sectionType : "",
557
- variant: attrs.variant ?? void 0,
558
- theme: attrs.theme ?? void 0,
559
- props: attrs.props ?? {}
560
- };
561
- const parsed = SectionSchema.safeParse(input);
562
- if (!parsed.success) {
563
- if (context.isDev()) {
564
- console.warn(
565
- `[cms-renderer-next] section \uB178\uB4DC parse \uC2E4\uD328 (sectionType=${input.type}) \u2014 \uB80C\uB354 skip:`,
566
- parsed.error.issues
567
- );
568
- }
569
- return null;
570
- }
571
- const section = parsed.data;
572
- switch (section.type) {
573
- case "hero":
574
- return /* @__PURE__ */ jsx3(TemplateHero, { ...section }, key);
575
- case "rich-text":
576
- return /* @__PURE__ */ jsx3(TemplateRichText, { ...section }, key);
577
- case "services":
578
- return /* @__PURE__ */ jsx3(TemplateServices, { ...section }, key);
579
- case "faq":
580
- return /* @__PURE__ */ jsx3(TemplateFaq, { ...section }, key);
581
- case "cta-banner":
582
- return /* @__PURE__ */ jsx3(TemplateCtaBanner, { ...section }, key);
583
- case "trust":
584
- return /* @__PURE__ */ jsx3(TemplateTrust, { ...section }, key);
585
- case "contact":
586
- if (!context.cms) {
587
- warnSkippedCmsBound(section.type, context.isDev);
588
- return null;
589
- }
590
- return /* @__PURE__ */ jsx3(TemplateContact, { ...section }, key);
591
- case "blog-list": {
592
- if (!context.cms) {
593
- warnSkippedCmsBound(section.type, context.isDev);
594
- return null;
595
- }
596
- const s = section;
597
- const base = s.props.blogBasePath ?? "/blog";
598
- return /* @__PURE__ */ jsx3(
599
- "section",
600
- {
601
- "data-roottale-tpl": "blog-list",
602
- "data-roottale-cms": "list",
603
- id: s.id,
604
- className: "rt-tpl-section rt-tpl-blog-list",
605
- style: sectionThemeStyle(s.theme),
606
- children: /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-container", children: [
607
- s.props.heading ? /* @__PURE__ */ jsx3("h2", { className: "rt-tpl-heading", children: s.props.heading }) : null,
608
- context.renderBlogList({
609
- apiKey: context.cms.apiKey,
610
- baseUrl: context.cms.baseUrl,
611
- limit: s.props.limit,
612
- emptyMessage: s.props.emptyMessage,
613
- postHref: (post) => `${base}/${post.slug}`
614
- })
615
- ] })
616
- },
617
- key
618
- );
619
- }
620
- case "lead-form": {
621
- if (!context.cms) {
622
- warnSkippedCmsBound(section.type, context.isDev);
623
- return null;
624
- }
625
- const s = section;
626
- return /* @__PURE__ */ jsx3(
627
- "section",
628
- {
629
- "data-roottale-tpl": "lead-form",
630
- "data-roottale-cms": "lead-form",
631
- id: s.id,
632
- className: "rt-tpl-section rt-tpl-lead-form",
633
- style: sectionThemeStyle(s.theme),
634
- children: /* @__PURE__ */ jsx3("div", { className: "rt-tpl-container", children: /* @__PURE__ */ jsx3(
635
- RootTaleLeadForm,
636
- {
637
- action: s.props.action,
638
- vertical: s.props.vertical,
639
- heading: s.props.heading,
640
- description: s.props.description,
641
- submitLabel: s.props.submitLabel
642
- }
643
- ) })
644
- },
645
- key
646
- );
647
- }
648
- default:
649
- if (context.isDev()) {
650
- console.warn(
651
- `[cms-renderer-next] section \uB178\uB4DC sectionType=${section.type} \uB294 renderNode \uC704\uC784 \uB300\uC0C1\uC774 \uC544\uB2D8(cms-bound/\uBBF8\uC9C0) \u2014 skip`
652
- );
653
- }
654
- return null;
655
- }
656
- }
657
-
658
- // src/PostCard.tsx
659
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
660
- function firstCategoryName(terms) {
661
- if (!terms) return null;
662
- const cat = terms.find((t) => t.taxonomy === "category");
663
- return cat ? cat.name : null;
664
- }
665
- function RootTalePostCard(props) {
666
- const { post, href = defaultHref, display } = props;
667
- const showDate = display ? display.showDate : true;
668
- const showAuthor = display ? display.showAuthor : false;
669
- const showImage = display?.showImage !== false;
670
- const showCategory = display?.showCategory !== false;
671
- const authorName = post.authorName;
672
- const publishedDate = showDate ? formatPublishedDate(post.publishedAt) : "";
673
- const views = typeof post.viewCount === "number" ? post.viewCount : null;
674
- const imageUrl = showImage ? post.featuredImageUrl : null;
675
- const category = showCategory ? firstCategoryName(post.terms) : null;
676
- return /* @__PURE__ */ jsx4("article", { "data-roottale-cms": "card", className: "rt-cms-card", children: /* @__PURE__ */ jsxs4("a", { className: "rt-cms-card-link", href: href(post), children: [
677
- imageUrl ? (
678
- // eslint-disable-next-line @next/next/no-img-element -- SSR string URL, framework-agnostic
679
- /* @__PURE__ */ jsx4(
680
- "img",
681
- {
682
- className: "rt-cms-card-image",
683
- src: imageUrl,
684
- alt: "",
685
- loading: "lazy",
686
- decoding: "async"
687
- }
688
- )
689
- ) : null,
690
- category ? /* @__PURE__ */ jsx4("span", { className: "rt-cms-card-category", children: category }) : null,
691
- publishedDate || showAuthor && authorName || views !== null ? /* @__PURE__ */ jsxs4("p", { className: "rt-cms-meta", children: [
692
- publishedDate ? /* @__PURE__ */ jsx4("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "date", children: publishedDate }) : null,
693
- showAuthor && authorName ? /* @__PURE__ */ jsxs4("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
694
- "\uC791\uC131\uC790 ",
695
- authorName
696
- ] }) : null,
697
- views !== null ? /* @__PURE__ */ jsxs4("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "views", children: [
698
- "\uC870\uD68C ",
699
- views.toLocaleString("ko-KR")
700
- ] }) : null
701
- ] }) : null,
702
- /* @__PURE__ */ jsx4("h2", { className: "rt-cms-title", children: post.title }),
703
- post.excerpt ? /* @__PURE__ */ jsx4("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null,
704
- /* @__PURE__ */ jsx4("span", { className: "rt-cms-card-action", "aria-hidden": "true", children: "\uC77D\uAE30" })
705
- ] }) });
706
- }
707
- function defaultHref(post) {
708
- return `/blog/${post.slug}`;
709
- }
710
- function formatPublishedDate(iso) {
711
- const d = new Date(iso);
712
- if (Number.isNaN(d.getTime())) return "";
713
- return new Intl.DateTimeFormat("ko-KR", {
714
- year: "numeric",
715
- month: "2-digit",
716
- day: "2-digit"
717
- }).format(d);
718
- }
719
-
720
- // src/TableOfContents.tsx
721
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
722
- function RootTaleTableOfContents(props) {
723
- const { entries, title = "\uBAA9\uCC28" } = props;
724
- if (entries.length === 0) return null;
725
- return /* @__PURE__ */ jsx5("nav", { "data-roottale-cms": "toc", className: "rt-cms-toc", "aria-label": title, children: /* @__PURE__ */ jsxs5("details", { className: "rt-cms-toc-details", open: true, children: [
726
- /* @__PURE__ */ jsxs5("summary", { className: "rt-cms-toc-summary", children: [
727
- title ? /* @__PURE__ */ jsx5("span", { className: "rt-cms-toc-title", children: title }) : null,
728
- /* @__PURE__ */ jsx5("span", { className: "rt-cms-toc-toggle", "aria-hidden": "true" })
729
- ] }),
730
- /* @__PURE__ */ jsx5("ol", { className: "rt-cms-toc-list", children: entries.map((entry) => /* @__PURE__ */ jsx5(
731
- "li",
732
- {
733
- className: `rt-cms-toc-item rt-cms-toc-level-${entry.level}`,
734
- children: /* @__PURE__ */ jsx5("a", { href: `#${entry.id}`, children: entry.text })
735
- },
736
- entry.id
737
- )) })
738
- ] }) });
739
- }
740
-
741
- // src/theme-css-vars.ts
742
- function themeToCssVars(theme) {
743
- if (!theme) return null;
744
- const vars = {};
745
- const c = theme.colors ?? {};
746
- if (c.primary) vars["--rt-color-primary"] = c.primary;
747
- if (c.primaryForeground) vars["--rt-color-primary-foreground"] = c.primaryForeground;
748
- if (c.foreground) vars["--rt-color-foreground"] = c.foreground;
749
- if (c.background) vars["--rt-color-background"] = c.background;
750
- if (c.secondary) vars["--rt-color-secondary"] = c.secondary;
751
- if (c.secondaryForeground) vars["--rt-color-secondary-foreground"] = c.secondaryForeground;
752
- if (c.accent) vars["--rt-color-accent"] = c.accent;
753
- if (c.accentForeground) vars["--rt-color-accent-foreground"] = c.accentForeground;
754
- if (c.muted) vars["--rt-color-muted"] = c.muted;
755
- if (c.mutedForeground) vars["--rt-color-muted-foreground"] = c.mutedForeground;
756
- if (c.destructive) vars["--rt-color-destructive"] = c.destructive;
757
- if (c.destructiveForeground) vars["--rt-color-destructive-foreground"] = c.destructiveForeground;
758
- if (c.border) vars["--rt-color-border"] = c.border;
759
- if (c.input) vars["--rt-color-input"] = c.input;
760
- if (c.ring) vars["--rt-color-ring"] = c.ring;
761
- const f = theme.fonts ?? {};
762
- if (f.body) vars["--rt-font-body"] = f.body;
763
- if (f.display) vars["--rt-font-display"] = f.display;
764
- const r = theme.radius ?? {};
765
- if (r.sm) vars["--rt-radius-sm"] = r.sm;
766
- if (r.md) vars["--rt-radius-md"] = r.md;
767
- if (r.lg) vars["--rt-radius-lg"] = r.lg;
768
- if (r.xl) vars["--rt-radius-xl"] = r.xl;
769
- if (Object.keys(vars).length === 0) return null;
770
- return vars;
771
- }
772
-
773
- // src/toc.ts
774
- function tocLevel(rawLevel) {
775
- if (rawLevel < 1 || rawLevel > 4) return null;
776
- if (rawLevel < 3) return 2;
777
- return rawLevel === 3 ? 3 : 4;
778
- }
779
- function headingToId(text) {
780
- return text.trim().toLowerCase().replace(/[^\p{L}\p{N}\s-]/gu, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
781
- }
782
- function textOf(node) {
783
- if (typeof node.text === "string") return node.text;
784
- if (!Array.isArray(node.content)) return "";
785
- return node.content.map(textOf).join("");
786
- }
787
- function extractToc(doc) {
788
- const root = doc;
789
- const content = Array.isArray(root.content) ? root.content : [];
790
- const entries = [];
791
- const idCounts = /* @__PURE__ */ new Map();
792
- for (const node of content) {
793
- if (node?.type !== "heading") continue;
794
- const rawLevel = Number(node.attrs?.level ?? 2);
795
- const level = tocLevel(rawLevel);
796
- if (level === null) continue;
797
- const text = textOf(node).trim();
798
- if (!text) continue;
799
- const base = headingToId(text) || "heading";
800
- const count = idCounts.get(base) ?? 0;
801
- const id = count === 0 ? base : `${base}-${count}`;
802
- idCounts.set(base, count + 1);
803
- entries.push({ level, text, id });
804
- }
805
- return entries;
806
- }
807
- function attachHeadingIds(doc, entries) {
808
- const root = doc;
809
- const content = Array.isArray(root.content) ? root.content : [];
810
- let cursor = 0;
811
- const nextContent = content.map((node) => {
812
- if (node?.type !== "heading") return node;
813
- const rawLevel = Number(node.attrs?.level ?? 2);
814
- if (rawLevel < 1 || rawLevel > 4) return node;
815
- if (!textOf(node).trim()) return node;
816
- const entry = entries[cursor++];
817
- if (!entry) return node;
818
- return {
819
- ...node,
820
- attrs: { ...node.attrs ?? {}, id: entry.id }
821
- };
822
- });
823
- return { ...root, content: nextContent };
824
- }
825
-
826
- // src/FloatingCta.tsx
827
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
828
- function RootTaleFloatingCta(props) {
829
- const { buttons, position = "bottom-right" } = props;
830
- if (!buttons || buttons.length === 0) return null;
831
- return /* @__PURE__ */ jsx6(
832
- "div",
833
- {
834
- "data-roottale-cms": "floating-cta",
835
- className: `rt-cms-floating-cta rt-cms-floating-cta--${position}`,
836
- children: buttons.map((btn, idx) => {
837
- const isExternal = btn.type === "kakao" || btn.type === "custom";
838
- return /* @__PURE__ */ jsxs6(
839
- "a",
840
- {
841
- href: btn.href,
842
- className: `rt-cms-floating-cta__btn rt-cms-floating-cta__btn--${btn.type}`,
843
- target: isExternal ? "_blank" : void 0,
844
- rel: isExternal ? "noopener noreferrer" : void 0,
845
- children: [
846
- /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", className: "rt-cms-floating-cta__icon", children: btn.icon ?? defaultIcon(btn.type) }),
847
- /* @__PURE__ */ jsx6("span", { className: "rt-cms-floating-cta__label", children: btn.label })
848
- ]
849
- },
850
- `${btn.type}-${idx}`
851
- );
852
- })
853
- }
854
- );
855
- }
856
- function defaultIcon(type) {
857
- switch (type) {
858
- case "phone":
859
- return "\u260E";
860
- case "contact":
861
- return "\u2709";
862
- case "kakao":
863
- return "\u{1F4AC}";
864
- case "custom":
865
- return "\u2192";
866
- }
867
- }
868
-
869
- // src/block-to-react.tsx
870
- import {
871
- applyBlockBindings,
872
- createFieldBindingResolver,
873
- sanitizeHtml
874
- } from "@roottale/cms-core";
875
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
876
- function isString(value) {
877
- return typeof value === "string";
878
- }
879
- function htmlContent(html) {
880
- return { __html: sanitizeHtml(html) };
881
- }
882
- function renderInner(blocks) {
883
- return blocks.map((b, i) => renderBlock(b, i));
884
- }
885
- function renderBlock(block, key = 0) {
886
- const dataBlockId = block._id;
887
- switch (block.name) {
888
- case "core/paragraph": {
889
- const text = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
890
- return /* @__PURE__ */ jsx7(
891
- "p",
892
- {
893
- "data-block-id": dataBlockId,
894
- dangerouslySetInnerHTML: htmlContent(text)
895
- },
896
- key
897
- );
898
- }
899
- case "core/heading": {
900
- const levelRaw = block.attributes.level;
901
- const level = typeof levelRaw === "number" && levelRaw >= 2 && levelRaw <= 4 ? levelRaw : 2;
902
- const text = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
903
- const props = {
904
- "data-block-id": dataBlockId,
905
- dangerouslySetInnerHTML: htmlContent(text)
906
- };
907
- if (level === 2) return /* @__PURE__ */ jsx7("h2", { ...props }, key);
908
- if (level === 3) return /* @__PURE__ */ jsx7("h3", { ...props }, key);
909
- return /* @__PURE__ */ jsx7("h4", { ...props }, key);
910
- }
911
- case "core/image": {
912
- const src = isString(block.attributes.url) ? block.attributes.url : "";
913
- const alt = isString(block.attributes.alt) ? block.attributes.alt : "";
914
- const caption = isString(block.attributes.caption) ? block.attributes.caption : null;
915
- return /* @__PURE__ */ jsxs7("figure", { "data-block-id": dataBlockId, children: [
916
- /* @__PURE__ */ jsx7("img", { src, alt, loading: "lazy" }),
917
- caption && /* @__PURE__ */ jsx7("figcaption", { children: caption })
918
- ] }, key);
919
- }
920
- case "core/list": {
921
- const ordered = block.attributes.ordered === true;
922
- const items = (block.innerBlocks ?? []).map(
923
- (item, i) => item.rawHtml ? /* @__PURE__ */ jsx7(
924
- "li",
925
- {
926
- dangerouslySetInnerHTML: htmlContent(item.rawHtml)
927
- },
928
- i
929
- ) : /* @__PURE__ */ jsx7("li", { children: renderInner(item.innerBlocks ?? []) }, i)
930
- );
931
- return ordered ? /* @__PURE__ */ jsx7("ol", { "data-block-id": dataBlockId, children: items }, key) : /* @__PURE__ */ jsx7("ul", { "data-block-id": dataBlockId, children: items }, key);
932
- }
933
- case "core/quote": {
934
- const inner = renderInner(block.innerBlocks ?? []);
935
- const citation = isString(block.attributes.citation) ? block.attributes.citation : null;
936
- return /* @__PURE__ */ jsxs7("blockquote", { "data-block-id": dataBlockId, children: [
937
- inner,
938
- citation && /* @__PURE__ */ jsx7("cite", { children: citation })
939
- ] }, key);
940
- }
941
- case "core/code": {
942
- const code = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
943
- const lang = isString(block.attributes.language) ? block.attributes.language : void 0;
944
- return /* @__PURE__ */ jsx7(
945
- "pre",
946
- {
947
- "data-block-id": dataBlockId,
948
- "data-language": lang,
949
- children: /* @__PURE__ */ jsx7("code", { children: code })
950
- },
951
- key
952
- );
953
- }
954
- case "core/columns": {
955
- return /* @__PURE__ */ jsx7(
956
- "div",
957
- {
958
- className: "rt-columns",
959
- "data-block-id": dataBlockId,
960
- children: renderInner(block.innerBlocks ?? [])
961
- },
962
- key
963
- );
964
- }
965
- case "core/separator":
966
- return /* @__PURE__ */ jsx7("hr", { "data-block-id": dataBlockId }, key);
967
- case "core/spacer": {
968
- const heightRaw = block.attributes.height;
969
- const height = isString(heightRaw) ? heightRaw : "32px";
970
- return /* @__PURE__ */ jsx7(
971
- "div",
972
- {
973
- className: "rt-spacer",
974
- "data-block-id": dataBlockId,
975
- style: { height }
976
- },
977
- key
978
- );
979
- }
980
- case "core/group": {
981
- return /* @__PURE__ */ jsx7(
982
- "div",
983
- {
984
- className: "rt-group",
985
- "data-block-id": dataBlockId,
986
- children: renderInner(block.innerBlocks ?? [])
987
- },
988
- key
989
- );
990
- }
991
- default: {
992
- const rawHtml = block.rawHtml;
993
- return /* @__PURE__ */ jsx7(
994
- "div",
995
- {
996
- className: "rt-unknown-block",
997
- "data-block-id": dataBlockId,
998
- "data-block-name": block.name,
999
- "data-rawhtml-suppressed": rawHtml ? "true" : void 0,
1000
- children: renderInner(block.innerBlocks ?? [])
1001
- },
1002
- key
1003
- );
1004
- }
1005
- }
1006
- }
1007
- function renderBlocks(blocks) {
1008
- return blocks.map((b, i) => renderBlock(b, i));
1009
- }
1010
- function renderBoundBlocks(blocks, opts = {}) {
1011
- const resolver = opts.resolver ?? createFieldBindingResolver(opts.fields);
1012
- return renderBlocks(applyBlockBindings(blocks, resolver));
1013
- }
1014
-
1015
- // src/server.tsx
1016
- import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1017
- function authorImageRadiusCss(radius) {
1018
- if (radius === "circle") return "999px";
1019
- if (radius === "rounded") return "0.875rem";
1020
- return "0";
1021
- }
1022
- function RootTaleThemeProvider(props) {
1023
- const style = themeToCssVars(props.theme ?? null);
1024
- if (!style) return /* @__PURE__ */ jsx8(Fragment3, { children: props.children });
1025
- return /* @__PURE__ */ jsx8("div", { "data-roottale-cms": "theme-root", "data-rt-theme": "", style, children: props.children });
1026
- }
1027
- async function RootTaleBlogList(props) {
1028
- const {
1029
- apiKey,
1030
- baseUrl,
1031
- limit,
1032
- type = "post",
1033
- collection,
1034
- collections,
1035
- emptyMessage = "\uC544\uC9C1 \uBC1C\uD589\uB41C \uAE00\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
1036
- showCategoryFilter = false,
1037
- activeCategory,
1038
- categoryHref = defaultCategoryHref,
1039
- allCategoriesLabel = "\uC804\uCCB4",
1040
- author,
1041
- theme: themeProp
1042
- } = props;
1043
- const postHref = props.postHref ?? (collections ? makeCollectionPostHref(collections) : defaultPostHref);
1044
- const [page, themeStyle, blogSettings] = await Promise.all([
1045
- fetchPosts({ apiKey, baseUrl, limit, type, ...author ? { author } : {} }),
1046
- resolveThemeStyle({ themeProp, apiKey, baseUrl }),
1047
- fetchBlogSettings({ apiKey, baseUrl }).catch(() => DEFAULT_BLOG_SETTINGS)
1048
- ]);
1049
- const items = collection && collections ? postsForCollection(page.items, collections, collection) : page.items;
1050
- if (items.length === 0) {
1051
- return /* @__PURE__ */ jsx8("div", { "data-roottale-cms": "list", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx8("p", { className: "rt-cms-empty", children: emptyMessage }) });
1052
- }
1053
- const categories = showCategoryFilter ? collectCategories(items) : [];
1054
- const visiblePosts = showCategoryFilter ? filterPostsByCategory(items, activeCategory) : items;
1055
- return /* @__PURE__ */ jsxs8("div", { "data-roottale-cms": "list", style: themeStyle ?? void 0, children: [
1056
- showCategoryFilter && categories.length > 0 ? /* @__PURE__ */ jsxs8("nav", { className: "rt-cms-filter", "aria-label": "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130", children: [
1057
- /* @__PURE__ */ jsx8(
1058
- "a",
1059
- {
1060
- className: "rt-cms-filter-chip",
1061
- href: categoryHref(null),
1062
- "data-active": !activeCategory ? "" : void 0,
1063
- "aria-current": !activeCategory ? "true" : void 0,
1064
- children: allCategoriesLabel
1065
- }
1066
- ),
1067
- categories.map((c) => /* @__PURE__ */ jsx8(
1068
- "a",
1069
- {
1070
- className: "rt-cms-filter-chip",
1071
- href: categoryHref(c.slug),
1072
- "data-active": activeCategory === c.slug ? "" : void 0,
1073
- "aria-current": activeCategory === c.slug ? "true" : void 0,
1074
- children: c.name
1075
- },
1076
- c.slug
1077
- ))
1078
- ] }) : null,
1079
- visiblePosts.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "rt-cms-empty", children: emptyMessage }) : /* @__PURE__ */ jsx8("ul", { className: "rt-cms-list", children: visiblePosts.map((post) => /* @__PURE__ */ jsx8("li", { className: "rt-cms-list-item", children: /* @__PURE__ */ jsx8(
1080
- RootTalePostCard,
1081
- {
1082
- post,
1083
- href: postHref,
1084
- display: resolvePostDisplay(post, blogSettings)
1085
- }
1086
- ) }, post.id)) })
1087
- ] });
1088
- }
1089
- async function RootTaleBlogCategories(props) {
1090
- const {
1091
- apiKey,
1092
- baseUrl,
1093
- limit,
1094
- collection,
1095
- collections,
1096
- categoryHref = (slug) => defaultCategoryHref(slug),
1097
- emptyMessage = "\uC544\uC9C1 \uCE74\uD14C\uACE0\uB9AC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
1098
- theme: themeProp
1099
- } = props;
1100
- const [page, themeStyle] = await Promise.all([
1101
- fetchPosts({ apiKey, baseUrl, limit, type: "post" }),
1102
- resolveThemeStyle({ themeProp, apiKey, baseUrl })
1103
- ]);
1104
- const categories = collection && collections ? collectCollectionCategories(page.items, collections, collection) : collectCategoriesWithCounts(page.items);
1105
- return /* @__PURE__ */ jsx8(
1106
- "nav",
1107
- {
1108
- "data-roottale-cms": "categories",
1109
- className: "rt-cms-categories",
1110
- "aria-label": "\uBE14\uB85C\uADF8 \uCE74\uD14C\uACE0\uB9AC",
1111
- style: themeStyle ?? void 0,
1112
- children: categories.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "rt-cms-empty", children: emptyMessage }) : /* @__PURE__ */ jsx8("ul", { className: "rt-cms-category-list", children: categories.map((category) => /* @__PURE__ */ jsx8("li", { className: "rt-cms-category-list-item", children: /* @__PURE__ */ jsxs8(
1113
- "a",
1114
- {
1115
- className: "rt-cms-category-link",
1116
- href: categoryHref(category.slug),
1117
- children: [
1118
- /* @__PURE__ */ jsx8("span", { className: "rt-cms-category-name", children: category.name }),
1119
- /* @__PURE__ */ jsx8("span", { className: "rt-cms-category-count", children: category.count })
1120
- ]
1121
- }
1122
- ) }, category.slug)) })
1123
- }
1124
- );
1125
- }
1126
- async function RootTaleBlogPost(props) {
1127
- const {
1128
- apiKey,
1129
- slugOrId,
1130
- baseUrl,
1131
- notFoundElement,
1132
- showTableOfContents,
1133
- tableOfContentsTitle,
1134
- relatedPostsCount = 0,
1135
- relatedPostsTitle = "\uAD00\uB828 \uAE00",
1136
- collections,
1137
- theme: themeProp
1138
- } = props;
1139
- const [post, themeStyle, blogSettings] = await Promise.all([
1140
- fetchPost({ apiKey, slugOrId, baseUrl }),
1141
- resolveThemeStyle({ themeProp, apiKey, baseUrl }),
1142
- // 사이트 기본 표시 설정 — 실패해도 렌더는 진행 (안전 기본값).
1143
- fetchBlogSettings({ apiKey, baseUrl }).catch(() => DEFAULT_BLOG_SETTINGS)
1144
- ]);
1145
- if (!post) {
1146
- return notFoundElement ?? /* @__PURE__ */ jsx8("div", { "data-roottale-cms": "post-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx8("p", { className: "rt-cms-empty", children: "\uAE00\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." }) });
1147
- }
1148
- const display = resolvePostDisplay(post, blogSettings, {
1149
- showTableOfContents,
1150
- tableOfContentsTitle
1151
- });
1152
- const toc = display.showTableOfContents ? extractToc(post.bodyJson) : [];
1153
- const renderDoc = toc.length > 0 ? attachHeadingIds(post.bodyJson, toc) : post.bodyJson;
1154
- let related = [];
1155
- if (relatedPostsCount > 0) {
1156
- try {
1157
- const candidates = await fetchPosts({
1158
- apiKey,
1159
- baseUrl,
1160
- type: "post",
1161
- limit: 30
1162
- });
1163
- related = selectRelatedPosts(post, candidates.items, relatedPostsCount);
1164
- } catch {
1165
- }
1166
- }
1167
- const relatedHref = props.postHref ?? (collections ? makeCollectionPostHref(collections) : defaultPostHref);
1168
- const authorName = post.authorName;
1169
- const authorImageUrl = post.authorImageUrl;
1170
- const postAuthorBio = post.authorBio;
1171
- const views = typeof post.viewCount === "number" ? post.viewCount : null;
1172
- const publishedDate = display.showDate ? formatPublishedDate2(post.publishedAt) : "";
1173
- const showTopAuthor = display.showAuthor && Boolean(authorName);
1174
- const displayAuthorName = authorName ?? display.authorProfileName;
1175
- const authorBio = postAuthorBio ?? display.authorProfileBio ?? display.authorCardDescription;
1176
- const authorImageUrlForCard = authorImageUrl ?? display.authorProfileImageUrl;
1177
- const authorImageAlt = `${displayAuthorName ?? ""} \uD504\uB85C\uD544 \uC0AC\uC9C4`.trim();
1178
- const authorImageStyle = {
1179
- borderRadius: authorImageRadiusCss(display.authorProfileImageRadius),
1180
- objectPosition: `${display.authorProfileImagePositionX}% ${display.authorProfileImagePositionY}%`
1181
- };
1182
- const showAuthorCard = display.showAuthorCard && Boolean(displayAuthorName);
1183
- return /* @__PURE__ */ jsxs8(
1184
- "article",
1185
- {
1186
- "data-roottale-cms": "post",
1187
- className: "rt-cms-article",
1188
- style: themeStyle ?? void 0,
1189
- children: [
1190
- /* @__PURE__ */ jsxs8("header", { className: "rt-cms-post-header", children: [
1191
- publishedDate || showTopAuthor || views !== null ? /* @__PURE__ */ jsxs8("p", { className: "rt-cms-meta", children: [
1192
- publishedDate ? /* @__PURE__ */ jsx8("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "date", children: publishedDate }) : null,
1193
- showTopAuthor ? /* @__PURE__ */ jsxs8("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
1194
- "\uC791\uC131\uC790 ",
1195
- authorName
1196
- ] }) : null,
1197
- views !== null ? /* @__PURE__ */ jsxs8("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "views", children: [
1198
- "\uC870\uD68C ",
1199
- views.toLocaleString("ko-KR")
1200
- ] }) : null
1201
- ] }) : null,
1202
- /* @__PURE__ */ jsx8("h1", { className: "rt-cms-title", children: post.title }),
1203
- post.excerpt ? /* @__PURE__ */ jsx8("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null
1204
- ] }),
1205
- renderArchiveRelated(post.archiveRelated, collections),
1206
- (() => {
1207
- const tocEl = toc.length > 0 ? /* @__PURE__ */ jsx8(RootTaleTableOfContents, { entries: toc, title: display.tocTitle }) : null;
1208
- const bodyEl = /* @__PURE__ */ jsx8("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: /* @__PURE__ */ jsx8(
1209
- RenderTiptap,
1210
- {
1211
- doc: renderDoc,
1212
- fields: post.fields,
1213
- apiKey,
1214
- baseUrl
1215
- }
1216
- ) });
1217
- if (display.tocPosition === "sidebar" && tocEl) {
1218
- return /* @__PURE__ */ jsxs8("div", { className: "rt-cms-layout rt-cms-layout--toc-side", children: [
1219
- bodyEl,
1220
- /* @__PURE__ */ jsx8("aside", { className: "rt-cms-toc-side", children: tocEl })
1221
- ] });
1222
- }
1223
- return /* @__PURE__ */ jsxs8(Fragment3, { children: [
1224
- tocEl,
1225
- bodyEl
1226
- ] });
1227
- })(),
1228
- showAuthorCard && displayAuthorName ? /* @__PURE__ */ jsxs8("section", { className: "rt-cms-author-card", "aria-label": "\uC791\uC131\uC790", children: [
1229
- authorImageUrlForCard ? /* @__PURE__ */ jsx8(
1230
- "img",
1231
- {
1232
- className: "rt-cms-author-card__image",
1233
- src: authorImageUrlForCard,
1234
- alt: authorImageAlt,
1235
- loading: "lazy",
1236
- style: authorImageStyle
1237
- }
1238
- ) : /* @__PURE__ */ jsx8("div", { className: "rt-cms-author-card__avatar", "aria-hidden": "true", children: authorInitials(displayAuthorName) }),
1239
- /* @__PURE__ */ jsxs8("div", { className: "rt-cms-author-card__body", children: [
1240
- /* @__PURE__ */ jsx8("p", { className: "rt-cms-author-card__eyebrow", children: display.authorCardEyebrow }),
1241
- /* @__PURE__ */ jsx8("p", { className: "rt-cms-author-card__name", children: displayAuthorName }),
1242
- authorBio ? /* @__PURE__ */ jsx8("p", { className: "rt-cms-author-card__description", children: authorBio }) : null
1243
- ] })
1244
- ] }) : null,
1245
- renderRelated(related, relatedHref, relatedPostsTitle),
1246
- renderPostCta(blogSettings.postCta),
1247
- renderFaqJsonLd(post.bodyJson)
1248
- ]
1249
- }
1250
- );
1251
- }
1252
- function renderArchiveRelated(groups, collections) {
1253
- const visible = groups.filter((group) => group.items.length > 0);
1254
- if (visible.length === 0) return null;
1255
- return /* @__PURE__ */ jsx8("aside", { className: "rt-archive-related", "aria-label": "\uC5F0\uAD00 \uC815\uBCF4", children: visible.map((group) => /* @__PURE__ */ jsxs8("section", { className: "rt-archive-related__group", children: [
1256
- /* @__PURE__ */ jsx8("h2", { className: "rt-archive-related__title", children: archiveGroupTitle(group) }),
1257
- /* @__PURE__ */ jsx8("ul", { className: "rt-archive-related__list", children: group.items.map((item) => /* @__PURE__ */ jsx8("li", { className: "rt-archive-related__item", children: /* @__PURE__ */ jsxs8(
1258
- "a",
1259
- {
1260
- className: "rt-archive-related__link",
1261
- href: archivePostHref(item.collectionKey, item.slug, collections),
1262
- children: [
1263
- /* @__PURE__ */ jsx8("span", { className: "rt-archive-related__item-title", children: item.title }),
1264
- item.excerpt ? /* @__PURE__ */ jsx8("span", { className: "rt-archive-related__item-excerpt", children: item.excerpt }) : null
1265
- ]
1266
- }
1267
- ) }, item.id)) })
1268
- ] }, group.collectionKey)) });
1269
- }
1270
- function archiveGroupTitle(group) {
1271
- if (group.collectionKey === "conditions") {
1272
- return `\uC774 \uC99D\uC0C1\uACFC \uAD00\uB828\uB41C \uC9C8\uD658 ${group.items.length}`;
1273
- }
1274
- if (group.collectionKey === "treatments") {
1275
- return `\uAD00\uB828 \uCE58\uB8CC\uBC95 ${group.items.length}`;
1276
- }
1277
- if (group.collectionKey === "symptoms") {
1278
- return `\uAD00\uB828 \uC99D\uC0C1 ${group.items.length}`;
1279
- }
1280
- return `${group.label} ${group.items.length}`;
1281
- }
1282
- function archivePostHref(collectionKey, slug, collections) {
1283
- const collection = collections?.find((item) => item.key === collectionKey);
1284
- const basePath = collection?.basePath ?? defaultArchiveBasePath(collectionKey);
1285
- return `${basePath.replace(/\/+$/, "")}/${slug}`;
1286
- }
1287
- function defaultArchiveBasePath(collectionKey) {
1288
- if (collectionKey === "symptoms") return "/symptoms";
1289
- if (collectionKey === "conditions") return "/conditions";
1290
- if (collectionKey === "treatments") return "/treatments";
1291
- return "/blog";
1292
- }
1293
- function renderPostCta(cta) {
1294
- if (!cta) return null;
1295
- const href = cta.buttonHref.trim();
1296
- const safe = href.startsWith("/") || href.startsWith("#") || /^(https?:|mailto:|tel:)/i.test(href);
1297
- if (!safe) return null;
1298
- const external = /^https?:/i.test(href);
1299
- return /* @__PURE__ */ jsxs8("aside", { "data-roottale-cms": "post-cta", className: "rt-cms-post-cta", children: [
1300
- cta.title ? /* @__PURE__ */ jsx8("p", { className: "rt-cms-post-cta__title", children: cta.title }) : null,
1301
- cta.description ? /* @__PURE__ */ jsx8("p", { className: "rt-cms-post-cta__desc", children: cta.description }) : null,
1302
- /* @__PURE__ */ jsx8(
1303
- "a",
1304
- {
1305
- className: "rt-cms-post-cta__btn",
1306
- href,
1307
- target: external ? "_blank" : void 0,
1308
- rel: external ? "noopener noreferrer" : void 0,
1309
- children: cta.buttonLabel
1310
- }
1311
- )
1312
- ] });
1313
- }
1314
- function renderRelated(posts, href, title) {
1315
- if (posts.length === 0) return null;
1316
- return /* @__PURE__ */ jsxs8("nav", { "data-roottale-cms": "related", className: "rt-cms-related", "aria-label": title, children: [
1317
- /* @__PURE__ */ jsx8("h2", { className: "rt-cms-related-title", children: title }),
1318
- /* @__PURE__ */ jsx8("ul", { className: "rt-cms-related-list", children: posts.map((p) => /* @__PURE__ */ jsx8("li", { className: "rt-cms-related-item", children: /* @__PURE__ */ jsxs8("a", { className: "rt-cms-related-link", href: href(p), children: [
1319
- p.featuredImageUrl ? /* @__PURE__ */ jsx8(
1320
- "img",
1321
- {
1322
- className: "rt-cms-related-thumb",
1323
- src: p.featuredImageUrl,
1324
- alt: "",
1325
- loading: "lazy"
1326
- }
1327
- ) : null,
1328
- /* @__PURE__ */ jsx8("span", { className: "rt-cms-related-post-title", children: p.title })
1329
- ] }) }, p.id)) })
1330
- ] });
1331
- }
1332
- function renderFaqJsonLd(doc) {
1333
- const ld = faqPageJsonLd(extractFaqEntries(doc));
1334
- if (!ld) return null;
1335
- const json = JSON.stringify(ld).replace(/</g, "\\u003c");
1336
- return /* @__PURE__ */ jsx8(
1337
- "script",
1338
- {
1339
- type: "application/ld+json",
1340
- dangerouslySetInnerHTML: { __html: json }
1341
- }
1342
- );
1343
- }
1344
- function RootTaleFaqJsonLd({
1345
- doc
1346
- }) {
1347
- return renderFaqJsonLd(doc);
1348
- }
1349
- async function RootTalePage(props) {
1350
- const {
1351
- apiKey,
1352
- slugOrId,
1353
- baseUrl,
1354
- notFoundElement,
1355
- showTitle = true,
1356
- theme: themeProp
1357
- } = props;
1358
- const [post, themeStyle] = await Promise.all([
1359
- fetchPost({ apiKey, slugOrId, baseUrl }),
1360
- resolveThemeStyle({ themeProp, apiKey, baseUrl })
1361
- ]);
1362
- if (!post) {
1363
- return notFoundElement ?? /* @__PURE__ */ jsx8("div", { "data-roottale-cms": "page-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx8("p", { className: "rt-cms-empty", children: "\uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." }) });
1364
- }
1365
- return /* @__PURE__ */ jsxs8(
1366
- "article",
1367
- {
1368
- "data-roottale-cms": "page",
1369
- className: "rt-cms-article",
1370
- style: themeStyle ?? void 0,
1371
- children: [
1372
- showTitle ? /* @__PURE__ */ jsx8("header", { className: "rt-cms-post-header", children: /* @__PURE__ */ jsx8("h1", { className: "rt-cms-title", children: post.title }) }) : null,
1373
- /* @__PURE__ */ jsx8("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: /* @__PURE__ */ jsx8(
1374
- RenderTiptap,
1375
- {
1376
- doc: post.bodyJson,
1377
- fields: post.fields,
1378
- apiKey,
1379
- baseUrl
1380
- }
1381
- ) })
1382
- ]
1383
- }
1384
- );
1385
- }
1386
- function authorInitials(name) {
1387
- const trimmed = name.trim();
1388
- if (!trimmed) return "";
1389
- const parts = trimmed.split(/\s+/).filter(Boolean);
1390
- if (parts.length >= 2) {
1391
- return `${parts[0]?.[0] ?? ""}${parts[1]?.[0] ?? ""}`.toUpperCase();
1392
- }
1393
- return [...trimmed].slice(0, 2).join("").toUpperCase();
1394
- }
1395
- async function resolveThemeStyle(input) {
1396
- const { themeProp, apiKey, baseUrl } = input;
1397
- if (themeProp === null) return null;
1398
- if (themeProp !== void 0) return themeToCssVars(themeProp);
1399
- try {
1400
- const fetched = await fetchTheme({ apiKey, baseUrl });
1401
- return themeToCssVars(fetched);
1402
- } catch {
1403
- return null;
1404
- }
1405
- }
1406
- function defaultPostHref(post) {
1407
- return `/blog/${post.slug}`;
1408
- }
1409
- function makeCollectionPostHref(collections) {
1410
- return (post) => resolvePostPath(post, collections) ?? defaultPostHref(post);
1411
- }
1412
- function formatPublishedDate2(iso) {
1413
- const d = new Date(iso);
1414
- if (Number.isNaN(d.getTime())) return "";
1415
- return new Intl.DateTimeFormat("ko-KR", {
1416
- year: "numeric",
1417
- month: "2-digit",
1418
- day: "2-digit"
1419
- }).format(d);
1420
- }
1421
- function RenderTiptap({
1422
- doc,
1423
- fields,
1424
- apiKey,
1425
- baseUrl
1426
- }) {
1427
- const rawContent = doc.content;
1428
- const content = Array.isArray(rawContent) ? rawContent : [];
1429
- const hasToc = content.some((n) => n?.type === "tableOfContents");
1430
- const docRecord = doc;
1431
- const entries = hasToc ? extractToc(docRecord) : [];
1432
- const renderDoc = hasToc && entries.length > 0 ? attachHeadingIds(docRecord, entries) : docRecord;
1433
- const nodes = Array.isArray(renderDoc.content) ? renderDoc.content : content;
1434
- const cms = apiKey ? { apiKey, baseUrl } : null;
1435
- const context = {
1436
- fields: fields ?? null,
1437
- section: {
1438
- cms,
1439
- isDev: isDevEnv,
1440
- renderBlogList: (props) => /* @__PURE__ */ jsx8(RootTaleBlogList, { ...props })
1441
- }
1442
- };
1443
- return /* @__PURE__ */ jsx8(Fragment3, { children: nodes.map(
1444
- (node, i) => node?.type === "tableOfContents" ? /* @__PURE__ */ jsx8(
1445
- RootTaleTableOfContents,
1446
- {
1447
- entries,
1448
- title: typeof node.attrs?.title === "string" ? node.attrs.title : "\uBAA9\uCC28"
1449
- },
1450
- i
1451
- ) : renderNode(node, i, context)
1452
- ) });
1453
- }
1454
- function boundContentText(node, fields) {
1455
- return bindingTextValue(
1456
- boundFieldValue(node.attrs?.bindings, "content", fields)
1457
- );
1458
- }
1459
- function isSafeHref(value) {
1460
- if (typeof value !== "string") return false;
1461
- const v = value.trim();
1462
- if (v.length === 0) return false;
1463
- if (v.startsWith("/") || v.startsWith("#") || v.startsWith("?")) return true;
1464
- return /^(https?:|mailto:|tel:)/i.test(v);
1465
- }
1466
- function alignStyle(node) {
1467
- const align = node.attrs?.textAlign;
1468
- if (typeof align !== "string" || align === "" || align === "left") return void 0;
1469
- if (align === "center" || align === "right" || align === "justify") {
1470
- return { textAlign: align };
1471
- }
1472
- return void 0;
1473
- }
1474
- function tableCellSpans(node) {
1475
- const colspan = Number(node.attrs?.colspan);
1476
- const rowspan = Number(node.attrs?.rowspan);
1477
- return {
1478
- colSpan: Number.isFinite(colspan) && colspan > 1 ? colspan : void 0,
1479
- rowSpan: Number.isFinite(rowspan) && rowspan > 1 ? rowspan : void 0
1480
- };
1481
- }
1482
- function isDevEnv() {
1483
- const env = globalThis.process?.env ?? {};
1484
- return env.NODE_ENV !== "production";
1485
- }
1486
- function renderNode(node, key, context = {
1487
- fields: null,
1488
- section: {
1489
- cms: null,
1490
- isDev: isDevEnv,
1491
- renderBlogList: (props) => /* @__PURE__ */ jsx8(RootTaleBlogList, { ...props })
1492
- }
1493
- }) {
1494
- if (!node || typeof node !== "object") return null;
1495
- const children = Array.isArray(node.content) ? node.content.map((child, i) => renderNode(child, i, context)) : void 0;
1496
- switch (node.type) {
1497
- case "paragraph": {
1498
- const bound = boundContentText(node, context.fields);
1499
- return /* @__PURE__ */ jsx8("p", { style: alignStyle(node), children: bound ?? children }, key);
1500
- }
1501
- case "heading": {
1502
- const rawLevel = Number(node.attrs?.level ?? 2);
1503
- const level = Math.min(Math.max(Number.isFinite(rawLevel) ? rawLevel : 2, 2), 4);
1504
- const idAttr = node.attrs?.id;
1505
- const id = typeof idAttr === "string" && idAttr.length > 0 ? idAttr : void 0;
1506
- const style = alignStyle(node);
1507
- const inner = boundContentText(node, context.fields) ?? children;
1508
- if (level === 2) return /* @__PURE__ */ jsx8("h2", { id, style, children: inner }, key);
1509
- if (level === 3) return /* @__PURE__ */ jsx8("h3", { id, style, children: inner }, key);
1510
- return /* @__PURE__ */ jsx8("h4", { id, style, children: inner }, key);
1511
- }
1512
- case "bulletList":
1513
- return /* @__PURE__ */ jsx8("ul", { children }, key);
1514
- case "orderedList":
1515
- return /* @__PURE__ */ jsx8("ol", { children }, key);
1516
- case "listItem":
1517
- return /* @__PURE__ */ jsx8("li", { children }, key);
1518
- case "blockquote":
1519
- return /* @__PURE__ */ jsx8("blockquote", { children }, key);
1520
- case "codeBlock":
1521
- return /* @__PURE__ */ jsx8("pre", { children: /* @__PURE__ */ jsx8("code", { children }) }, key);
1522
- case "horizontalRule":
1523
- return /* @__PURE__ */ jsx8("hr", {}, key);
1524
- case "hardBreak":
1525
- return /* @__PURE__ */ jsx8("br", {}, key);
1526
- case "image": {
1527
- const boundSrc = bindingSrcValue(
1528
- boundFieldValue(node.attrs?.bindings, "src", context.fields)
1529
- );
1530
- const src = boundSrc ?? node.attrs?.src;
1531
- if (typeof src !== "string" || src.length === 0) return null;
1532
- const alt = typeof node.attrs?.alt === "string" ? node.attrs.alt : "";
1533
- const title = typeof node.attrs?.title === "string" ? node.attrs.title : void 0;
1534
- const width = typeof node.attrs?.width === "number" && node.attrs.width > 0 ? node.attrs.width : void 0;
1535
- const height = typeof node.attrs?.height === "number" && node.attrs.height > 0 ? node.attrs.height : void 0;
1536
- return /* @__PURE__ */ jsx8(
1537
- "img",
1538
- {
1539
- src,
1540
- alt,
1541
- title,
1542
- width,
1543
- height,
1544
- loading: "lazy"
1545
- },
1546
- key
1547
- );
1548
- }
1549
- case "columns":
1550
- return /* @__PURE__ */ jsx8("div", { className: "rt-columns", children }, key);
1551
- case "column":
1552
- return /* @__PURE__ */ jsx8("div", { className: "rt-column", children }, key);
1553
- case "table":
1554
- return /* @__PURE__ */ jsx8("div", { className: "rt-table-wrap", children: /* @__PURE__ */ jsx8("table", { className: "rt-table", children: /* @__PURE__ */ jsx8("tbody", { children }) }) }, key);
1555
- case "tableRow":
1556
- return /* @__PURE__ */ jsx8("tr", { children }, key);
1557
- case "tableHeader": {
1558
- const { colSpan, rowSpan } = tableCellSpans(node);
1559
- return /* @__PURE__ */ jsx8("th", { colSpan, rowSpan, children }, key);
1560
- }
1561
- case "tableCell": {
1562
- const { colSpan, rowSpan } = tableCellSpans(node);
1563
- return /* @__PURE__ */ jsx8("td", { colSpan, rowSpan, children }, key);
1564
- }
1565
- case "embed":
1566
- return renderEmbed(node, key);
1567
- case "faq":
1568
- return /* @__PURE__ */ jsx8("div", { "data-roottale-cms": "faq", className: "rt-cms-faq", children }, key);
1569
- case "faqItem":
1570
- return /* @__PURE__ */ jsx8("details", { className: "rt-cms-faq-item", children }, key);
1571
- case "faqQuestion":
1572
- return /* @__PURE__ */ jsx8("summary", { className: "rt-cms-faq-q", children }, key);
1573
- case "faqAnswer":
1574
- return /* @__PURE__ */ jsx8("div", { className: "rt-cms-faq-a", children }, key);
1575
- case "tableOfContents":
1576
- return null;
1577
- case "section":
1578
- return renderSectionNode(node, key, context.section);
1579
- case "text":
1580
- return renderText(node, key);
1581
- default:
1582
- return children ? /* @__PURE__ */ jsx8("span", { children }, key) : null;
1583
- }
1584
- }
1585
- function renderEmbed(node, key) {
1586
- const src = node.attrs?.src;
1587
- if (isAllowedEmbedSrc2(src)) {
1588
- const provider = typeof node.attrs?.provider === "string" ? node.attrs.provider : void 0;
1589
- return /* @__PURE__ */ jsx8(
1590
- "div",
1591
- {
1592
- className: "rt-embed",
1593
- "data-provider": provider,
1594
- style: { aspectRatio: "16 / 9" },
1595
- children: /* @__PURE__ */ jsx8(
1596
- "iframe",
1597
- {
1598
- src,
1599
- title: "\uC784\uBCA0\uB4DC\uB41C \uC601\uC0C1",
1600
- loading: "lazy",
1601
- allowFullScreen: true,
1602
- referrerPolicy: "strict-origin-when-cross-origin",
1603
- allow: "accelerometer; clipboard-write; encrypted-media; picture-in-picture; web-share",
1604
- style: { width: "100%", height: "100%", border: 0 }
1605
- }
1606
- )
1607
- },
1608
- key
1609
- );
1610
- }
1611
- const orig = node.attrs?.originalUrl;
1612
- if (isSafeHref(orig)) {
1613
- return /* @__PURE__ */ jsx8("p", { className: "rt-embed-fallback", children: /* @__PURE__ */ jsx8("a", { href: orig, rel: "noopener noreferrer", target: "_blank", children: orig }) }, key);
1614
- }
1615
- return null;
1616
- }
1617
- function renderText(node, key) {
1618
- const text = node.text ?? "";
1619
- const marks = node.marks ?? [];
1620
- if (marks.length === 0) return text;
1621
- let element = text;
1622
- for (const mark of marks) {
1623
- element = applyMark(mark, element);
1624
- }
1625
- return /* @__PURE__ */ jsx8("span", { children: element }, key);
1626
- }
1627
- function applyMark(mark, child) {
1628
- switch (mark.type) {
1629
- case "bold":
1630
- return /* @__PURE__ */ jsx8("strong", { children: child });
1631
- case "italic":
1632
- return /* @__PURE__ */ jsx8("em", { children: child });
1633
- case "underline":
1634
- return /* @__PURE__ */ jsx8("u", { children: child });
1635
- case "strike":
1636
- return /* @__PURE__ */ jsx8("s", { children: child });
1637
- case "code":
1638
- return /* @__PURE__ */ jsx8("code", { children: child });
1639
- case "highlight": {
1640
- const color = mark.attrs?.color;
1641
- const style = typeof color === "string" && color.length > 0 ? { background: color } : void 0;
1642
- return /* @__PURE__ */ jsx8("mark", { style, children: child });
1643
- }
1644
- case "textStyle": {
1645
- const color = mark.attrs?.color;
1646
- const style = typeof color === "string" && color.length > 0 ? { color } : void 0;
1647
- if (!style) return /* @__PURE__ */ jsx8(Fragment3, { children: child });
1648
- return /* @__PURE__ */ jsx8("span", { style, children: child });
1649
- }
1650
- case "link": {
1651
- const raw = mark.attrs?.href;
1652
- const href = isSafeHref(raw) ? raw : "#";
1653
- return /* @__PURE__ */ jsx8("a", { href, rel: "noopener noreferrer", target: "_blank", children: child });
1654
- }
1655
- default:
1656
- return /* @__PURE__ */ jsx8("span", { children: child });
1657
- }
1658
- }
1659
-
1660
- export {
1661
- RootTaleLeadForm,
1662
- sectionThemeStyle,
1663
- TemplateHero,
1664
- TemplateRichText,
1665
- TemplateServices,
1666
- TemplateFaq,
1667
- TemplateCtaBanner,
1668
- TemplateTrust,
1669
- TemplateContact,
1670
- RootTalePostCard,
1671
- RootTaleTableOfContents,
1672
- themeToCssVars,
1673
- headingToId,
1674
- extractToc,
1675
- attachHeadingIds,
1676
- RootTaleFloatingCta,
1677
- renderBlock,
1678
- renderBlocks,
1679
- renderBoundBlocks,
1680
- RootTaleThemeProvider,
1681
- RootTaleBlogList,
1682
- RootTaleBlogCategories,
1683
- RootTaleBlogPost,
1684
- RootTaleFaqJsonLd,
1685
- RootTalePage,
1686
- RenderTiptap
1687
- };
1688
- //# sourceMappingURL=chunk-5R6APJZ2.js.map