@roottale/cms-renderer-next 0.48.0 → 0.51.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 (36) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/blog-filter-BKCGM0qd.d.ts +29 -0
  3. package/dist/{chunk-6MFHA555.js → chunk-27RT6B3O.js} +1 -1
  4. package/dist/chunk-27RT6B3O.js.map +1 -0
  5. package/dist/chunk-2QU4JU46.js +3927 -0
  6. package/dist/chunk-2QU4JU46.js.map +1 -0
  7. package/dist/chunk-4RQ3SEDL.js +106 -0
  8. package/dist/chunk-4RQ3SEDL.js.map +1 -0
  9. package/dist/{chunk-OMXEU4LS.js → chunk-QYNEOFL7.js} +140 -136
  10. package/dist/chunk-QYNEOFL7.js.map +1 -0
  11. package/dist/concerns-client.d.ts +1 -1
  12. package/dist/expertise-client.d.ts +1 -1
  13. package/dist/expertise-client.js +1 -1
  14. package/dist/hero-carousel-client.js +1 -1
  15. package/dist/routes.d.ts +334 -20
  16. package/dist/routes.js +249 -68
  17. package/dist/routes.js.map +1 -1
  18. package/dist/seo-asset-hosts.d.ts +36 -0
  19. package/dist/seo-asset-hosts.js +391 -0
  20. package/dist/seo-asset-hosts.js.map +1 -0
  21. package/dist/server.d.ts +23 -241
  22. package/dist/server.js +6 -6
  23. package/dist/{site-config-Dicv57oY.d.ts → site-config-DNpvlqA5.d.ts} +201 -201
  24. package/dist/spaces-client.d.ts +1 -1
  25. package/dist/team-expanding-stage-client.d.ts +1 -1
  26. package/dist/team-expanding-stage-client.js +1 -1
  27. package/dist/templates.d.ts +64 -25
  28. package/dist/templates.js +13 -6
  29. package/dist/templates.js.map +1 -1
  30. package/package.json +7 -2
  31. package/dist/chunk-6MFHA555.js.map +0 -1
  32. package/dist/chunk-FZK3EXYZ.js +0 -103
  33. package/dist/chunk-FZK3EXYZ.js.map +0 -1
  34. package/dist/chunk-LIBSVC4M.js +0 -3642
  35. package/dist/chunk-LIBSVC4M.js.map +0 -1
  36. package/dist/chunk-OMXEU4LS.js.map +0 -1
@@ -1,3642 +0,0 @@
1
- import {
2
- BeforeAfterSlider
3
- } from "./chunk-U5AKACPN.js";
4
- import {
5
- ContactMapClickToLoad
6
- } from "./chunk-LEHHSI6G.js";
7
- import {
8
- ExpertiseTabStage
9
- } from "./chunk-6MFHA555.js";
10
- import {
11
- TeamExpandingStageClient
12
- } from "./chunk-FZK3EXYZ.js";
13
- import {
14
- SpacesStage
15
- } from "./chunk-K62RR4UQ.js";
16
- import {
17
- ConcernsFigureMap
18
- } from "./chunk-H46JUIHZ.js";
19
- import {
20
- AnimateOnScroll,
21
- CountUpStat,
22
- Marquee,
23
- StaggerGroup,
24
- StaggerItem
25
- } from "./chunk-ZL2NA3QT.js";
26
- import {
27
- LeadFormMeta
28
- } from "./chunk-VG6UUF4D.js";
29
- import {
30
- collectCategories,
31
- collectCategoriesWithCounts,
32
- collectCollectionCategories,
33
- defaultCategoryHref,
34
- filterPostsByCategory,
35
- trimSlash
36
- } from "./chunk-U2IM6OCQ.js";
37
- import {
38
- SectionSchema
39
- } from "./chunk-UM37DOIK.js";
40
- import {
41
- HeroCarouselViewport
42
- } from "./chunk-OMXEU4LS.js";
43
-
44
- // src/server.tsx
45
- import {
46
- DEFAULT_BLOG_SETTINGS,
47
- breadcrumbSchema,
48
- fetchBlogSettings,
49
- fetchPost,
50
- fetchPosts,
51
- fetchTheme,
52
- jsonLdJson,
53
- resolvePostDisplay,
54
- selectRelatedPosts
55
- } from "@roottale/cms-client/server";
56
-
57
- // ../cms-i18n/src/index.ts
58
- var DICTS = {
59
- ko: {
60
- blogListEmpty: "\uC544\uC9C1 \uBC1C\uD589\uB41C \uAE00\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
61
- blogCategoriesEmpty: "\uC544\uC9C1 \uCE74\uD14C\uACE0\uB9AC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
62
- allCategoriesLabel: "\uC804\uCCB4",
63
- relatedPostsTitle: "\uAD00\uB828 \uAE00",
64
- postNotFound: "\uAE00\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
65
- pageNotFound: "\uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
66
- tableOfContentsTitle: "\uBAA9\uCC28"
67
- },
68
- en: {
69
- blogListEmpty: "No posts published yet.",
70
- blogCategoriesEmpty: "No categories yet.",
71
- allCategoriesLabel: "All",
72
- relatedPostsTitle: "Related posts",
73
- postNotFound: "Post not found.",
74
- pageNotFound: "Page not found.",
75
- tableOfContentsTitle: "Table of contents"
76
- }
77
- };
78
- function resolveLocale(locale) {
79
- return locale === "en" ? "en" : "ko";
80
- }
81
- function t(locale, key) {
82
- return DICTS[resolveLocale(locale)][key];
83
- }
84
-
85
- // src/server.tsx
86
- import {
87
- bindingSrcValue,
88
- bindingTextValue,
89
- boundFieldValue,
90
- extractFaqEntries,
91
- faqPageJsonLd,
92
- isAllowedEmbedSrc as isAllowedEmbedSrc2,
93
- postsForCollection,
94
- postsNotInAnyCollection,
95
- resolvePostCollection,
96
- resolvePostPath
97
- } from "@roottale/cms-core";
98
-
99
- // src/LeadForm.tsx
100
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
101
- var VERTICAL_LABEL = {
102
- consulting: "\uCEE8\uC124\uD305",
103
- medical: "\uC758\uB8CC",
104
- tax: "\uC138\uBB34",
105
- legal: "\uBC95\uB960"
106
- };
107
- var VERTICAL_OPTIONS = [
108
- { value: "consulting", label: "\uCEE8\uC124\uD305 / \uC77C\uBC18" },
109
- { value: "medical", label: "\uC758\uB8CC (\uBCD1\uC758\uC6D0\xB7\uCE58\uACFC\xB7\uD55C\uC758\uC6D0)" },
110
- { value: "tax", label: "\uC138\uBB34 (\uC138\uBB34\uC0AC\xB7\uD68C\uACC4\uC0AC)" },
111
- { value: "legal", label: "\uBC95\uB960 (\uBC95\uBB34\uBC95\uC778\xB7\uBCC0\uD638\uC0AC)" }
112
- ];
113
- function RootTaleLeadForm(props) {
114
- const {
115
- action,
116
- vertical,
117
- redirectUrl,
118
- heading,
119
- description,
120
- submitLabel = "\uC9C4\uB2E8 \uC2E0\uCCAD",
121
- turnstileSiteKey,
122
- className
123
- } = props;
124
- const formClass = ["rt-cms-lead-form", className].filter(Boolean).join(" ");
125
- const isMedical = vertical === "medical";
126
- return /* @__PURE__ */ jsxs(
127
- "form",
128
- {
129
- method: "post",
130
- action,
131
- "data-roottale-cms": "lead-form",
132
- className: formClass,
133
- children: [
134
- /* @__PURE__ */ jsx(LeadFormMeta, { formId: "contact" }),
135
- heading ? /* @__PURE__ */ jsx("h2", { className: "rt-cms-lead-heading", children: heading }) : null,
136
- description ? /* @__PURE__ */ jsx("p", { className: "rt-cms-lead-description", children: description }) : null,
137
- redirectUrl ? /* @__PURE__ */ jsx("input", { type: "hidden", name: "_redirect_url", value: redirectUrl }) : null,
138
- vertical ? /* @__PURE__ */ jsxs(Fragment, { children: [
139
- /* @__PURE__ */ jsx("input", { type: "hidden", name: "vertical", value: vertical }),
140
- /* @__PURE__ */ jsxs("p", { className: "rt-cms-lead-vertical-label", children: [
141
- "\uBD84\uC57C: ",
142
- /* @__PURE__ */ jsx("strong", { children: VERTICAL_LABEL[vertical] })
143
- ] })
144
- ] }) : /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
145
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
146
- "\uBD84\uC57C ",
147
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
148
- ] }),
149
- /* @__PURE__ */ jsxs(
150
- "select",
151
- {
152
- name: "vertical",
153
- required: true,
154
- className: "rt-cms-field-input rt-cms-field-select",
155
- defaultValue: "",
156
- children: [
157
- /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "\uC120\uD0DD\uD558\uC138\uC694" }),
158
- VERTICAL_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
159
- ]
160
- }
161
- )
162
- ] }),
163
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
164
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
165
- "\uC774\uB984 ",
166
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
167
- ] }),
168
- /* @__PURE__ */ jsx(
169
- "input",
170
- {
171
- type: "text",
172
- name: "contact_name",
173
- required: true,
174
- autoComplete: "name",
175
- className: "rt-cms-field-input"
176
- }
177
- )
178
- ] }),
179
- isMedical ? (
180
- // 환자 문의에는 "사업체명" 개념이 없다 — 화면에는 노출하지 않되,
181
- // intake 가 vertical 불문 hard-required 로 검증하는 계약(위 파일
182
- // 헤더 코멘트 참조)을 만족시키기 위해 자리표시자만 hidden 전송.
183
- /* @__PURE__ */ jsx("input", { type: "hidden", name: "business_name", value: "-" })
184
- ) : /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
185
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
186
- "\uC0AC\uC5C5\uCCB4\uBA85 ",
187
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
188
- ] }),
189
- /* @__PURE__ */ jsx(
190
- "input",
191
- {
192
- type: "text",
193
- name: "business_name",
194
- required: true,
195
- autoComplete: "organization",
196
- className: "rt-cms-field-input"
197
- }
198
- )
199
- ] }),
200
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
201
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
202
- "\uC804\uD654\uBC88\uD638 ",
203
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
204
- ] }),
205
- /* @__PURE__ */ jsx(
206
- "input",
207
- {
208
- type: "tel",
209
- name: "phone",
210
- required: true,
211
- autoComplete: "tel",
212
- inputMode: "tel",
213
- pattern: "0\\d{1,2}-?\\d{3,4}-?\\d{4}",
214
- placeholder: "010-1234-5678",
215
- className: "rt-cms-field-input"
216
- }
217
- )
218
- ] }),
219
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
220
- /* @__PURE__ */ jsxs("span", { className: "rt-cms-field-label", children: [
221
- "\uC774\uBA54\uC77C ",
222
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "*" })
223
- ] }),
224
- /* @__PURE__ */ jsx(
225
- "input",
226
- {
227
- type: "email",
228
- name: "email",
229
- required: true,
230
- autoComplete: "email",
231
- className: "rt-cms-field-input"
232
- }
233
- )
234
- ] }),
235
- isMedical ? /* @__PURE__ */ jsxs(Fragment, { children: [
236
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
237
- /* @__PURE__ */ jsx("span", { className: "rt-cms-field-label", children: "\uC0C1\uB2F4 \uD76C\uB9DD \uBD84\uC57C\xB7\uC99D\uC0C1 (\uC120\uD0DD)" }),
238
- /* @__PURE__ */ jsx(
239
- "input",
240
- {
241
- type: "text",
242
- name: "consultation_field",
243
- placeholder: "\uC608: \uBB34\uB98E \uD1B5\uC99D, \uC815\uAE30\uAC80\uC9C4",
244
- className: "rt-cms-field-input"
245
- }
246
- )
247
- ] }),
248
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
249
- /* @__PURE__ */ jsx("span", { className: "rt-cms-field-label", children: "\uBB38\uC758 \uB0B4\uC6A9 (\uC120\uD0DD)" }),
250
- /* @__PURE__ */ jsx(
251
- "textarea",
252
- {
253
- name: "message",
254
- rows: 4,
255
- placeholder: "\uC99D\uC0C1\uC774 \uC5B8\uC81C\uBD80\uD130 \uC788\uC5C8\uB294\uC9C0, \uAD81\uAE08\uD558\uC2E0 \uC810\uC744 \uC790\uC720\uB86D\uAC8C \uC801\uC5B4\uC8FC\uC138\uC694.",
256
- className: "rt-cms-field-input rt-cms-field-textarea"
257
- }
258
- )
259
- ] })
260
- ] }) : /* @__PURE__ */ jsxs("label", { className: "rt-cms-field", children: [
261
- /* @__PURE__ */ jsx("span", { className: "rt-cms-field-label", children: "\uD604\uC7AC \uC0AC\uC774\uD2B8 URL (\uC120\uD0DD)" }),
262
- /* @__PURE__ */ jsx(
263
- "input",
264
- {
265
- type: "url",
266
- name: "current_site_url",
267
- placeholder: "https://",
268
- className: "rt-cms-field-input"
269
- }
270
- ),
271
- /* @__PURE__ */ jsx("span", { className: "rt-cms-field-hint", children: "\uC5C6\uC73C\uBA74 \uBE44\uC6CC\uB450\uC138\uC694." })
272
- ] }),
273
- /* @__PURE__ */ jsxs("label", { className: "rt-cms-lead-consent", children: [
274
- /* @__PURE__ */ jsx("input", { type: "checkbox", name: "privacy_consent", required: true }),
275
- /* @__PURE__ */ jsxs("span", { children: [
276
- /* @__PURE__ */ jsx("strong", { children: "(\uD544\uC218)" }),
277
- " \uAC1C\uC778\uC815\uBCF4 \uC218\uC9D1\xB7\uC774\uC6A9\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4. (\uC218\uC9D1 \uD56D\uBAA9:",
278
- " ",
279
- isMedical ? "\uC774\uB984\xB7\uC5F0\uB77D\uCC98\xB7\uC774\uBA54\uC77C\xB7\uC0C1\uB2F4 \uB0B4\uC6A9(\uC791\uC131 \uC2DC)\xB7\uC0AC\uC774\uD2B8 \uC774\uC6A9 \uAE30\uB85D(\uBC29\uBB38 \uD398\uC774\uC9C0\xB7\uC0C1\uD638\uC791\uC6A9)" : "\uC774\uB984\xB7\uC5F0\uB77D\uCC98\xB7\uC774\uBA54\uC77C\xB7\uC0AC\uC5C5\uCCB4\uBA85\xB7\uC0AC\uC774\uD2B8 \uC774\uC6A9 \uAE30\uB85D(\uBC29\uBB38 \uD398\uC774\uC9C0\xB7\uC0C1\uD638\uC791\uC6A9)",
280
- ". \uBCF4\uAD00 \uAE30\uAC04: \uBB38\uC758 \uC885\uB8CC \uD6C4 3\uB144)"
281
- ] })
282
- ] }),
283
- vertical === "medical" ? /* @__PURE__ */ jsxs("label", { className: "rt-cms-lead-consent", children: [
284
- /* @__PURE__ */ jsx(
285
- "input",
286
- {
287
- type: "checkbox",
288
- name: "overseas_transfer_consent",
289
- required: true
290
- }
291
- ),
292
- /* @__PURE__ */ jsxs("span", { children: [
293
- /* @__PURE__ */ jsx("strong", { children: "(\uD544\uC218, \uC758\uB8CC)" }),
294
- " \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)"
295
- ] })
296
- ] }) : null,
297
- turnstileSiteKey ? /* @__PURE__ */ jsxs(Fragment, { children: [
298
- /* @__PURE__ */ jsx(
299
- "script",
300
- {
301
- src: "https://challenges.cloudflare.com/turnstile/v0/api.js",
302
- async: true,
303
- defer: true
304
- }
305
- ),
306
- /* @__PURE__ */ jsx(
307
- "div",
308
- {
309
- className: "cf-turnstile",
310
- "data-sitekey": turnstileSiteKey,
311
- "data-action": "turnstile-spin-v1"
312
- }
313
- )
314
- ] }) : null,
315
- /* @__PURE__ */ jsx("div", { className: "rt-cms-lead-actions", children: /* @__PURE__ */ jsx("button", { type: "submit", className: "rt-cms-lead-submit", children: submitLabel }) })
316
- ]
317
- }
318
- );
319
- }
320
-
321
- // src/templates/sections.tsx
322
- import { isAllowedEmbedSrc, isAllowedMapEmbedSrc } from "@roottale/cms-core";
323
-
324
- // src/templates/metric-value.ts
325
- var LEADING_NUMBER_PATTERN = /^(\d[\d,]*)(\.(\d+))?/;
326
- function parseMetricValue(raw) {
327
- const match = LEADING_NUMBER_PATTERN.exec(raw);
328
- if (!match) {
329
- return null;
330
- }
331
- const [matched, integerPart, , fractionPart] = match;
332
- const integerLiteral = (integerPart ?? "").replace(/,/g, "");
333
- const numericLiteral = fractionPart ? `${integerLiteral}.${fractionPart}` : integerLiteral;
334
- const value = Number(numericLiteral);
335
- if (!Number.isFinite(value)) {
336
- return null;
337
- }
338
- return {
339
- value,
340
- decimals: fractionPart?.length ?? 0,
341
- suffix: raw.slice(matched.length)
342
- };
343
- }
344
-
345
- // src/templates/sections.tsx
346
- import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
347
- function sectionThemeStyle(theme) {
348
- if (!theme) return void 0;
349
- const style = {};
350
- for (const [key, value] of Object.entries(theme)) {
351
- if (key.startsWith("--")) style[key] = value;
352
- }
353
- return Object.keys(style).length > 0 ? style : void 0;
354
- }
355
- function CtaLink({
356
- cta,
357
- className,
358
- track
359
- }) {
360
- return /* @__PURE__ */ jsx2(
361
- "a",
362
- {
363
- className: className ?? "rt-tpl-btn rt-tpl-btn--primary",
364
- href: cta.href,
365
- "data-track": track,
366
- children: cta.label
367
- }
368
- );
369
- }
370
- function ctaTrackForHref(href) {
371
- return href.startsWith("tel:") ? "cta_banner" : "cta_hero";
372
- }
373
- function contactHrefTrack(href) {
374
- if (href.startsWith("tel:")) return "phone_click";
375
- if (href.startsWith("mailto:")) return "email_click";
376
- return void 0;
377
- }
378
- function TemplateHeroProof({
379
- proofMetrics
380
- }) {
381
- if (!proofMetrics || proofMetrics.items.length === 0) return null;
382
- return /* @__PURE__ */ jsx2(
383
- "div",
384
- {
385
- className: "rt-tpl-hero-proof",
386
- "data-position": proofMetrics.position,
387
- "aria-label": "\uC2E0\uB8B0 \uC9C0\uD45C",
388
- children: proofMetrics.items.map((metric) => /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-proof-item", children: [
389
- metric.imageSrc ? /* @__PURE__ */ jsx2(
390
- "img",
391
- {
392
- className: "rt-tpl-hero-proof-icon",
393
- src: metric.imageSrc,
394
- alt: metric.imageAlt ?? "",
395
- loading: "lazy"
396
- }
397
- ) : null,
398
- /* @__PURE__ */ jsxs2("span", { className: "rt-tpl-hero-proof-value", children: [
399
- metric.value,
400
- metric.unit ? /* @__PURE__ */ jsx2("span", { children: metric.unit }) : null
401
- ] }),
402
- /* @__PURE__ */ jsx2("span", { className: "rt-tpl-hero-proof-label", children: metric.label }),
403
- metric.source ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-hero-proof-source", children: metric.source }) : null
404
- ] }, `${metric.value}-${metric.label}`))
405
- }
406
- );
407
- }
408
- function TemplateHeroCarousel(section) {
409
- const {
410
- eyebrow,
411
- title,
412
- subtitle,
413
- cta,
414
- slides,
415
- autoplay,
416
- intervalMs,
417
- transition,
418
- proofMetrics,
419
- scrim
420
- } = section.props;
421
- const safeSlides = slides ?? [];
422
- return /* @__PURE__ */ jsxs2(
423
- "section",
424
- {
425
- "data-roottale-tpl": "hero",
426
- "data-variant": "carousel",
427
- id: section.id,
428
- className: "rt-tpl-section rt-tpl-hero rt-tpl-hero--carousel",
429
- style: sectionThemeStyle(section.theme),
430
- children: [
431
- safeSlides.length >= 2 ? /* @__PURE__ */ jsx2(
432
- HeroCarouselViewport,
433
- {
434
- slides: safeSlides,
435
- autoplay: autoplay ?? true,
436
- intervalMs: intervalMs ?? 6e3,
437
- scrim,
438
- transition
439
- }
440
- ) : null,
441
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-hero-carousel-overlay", children: [
442
- eyebrow ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-eyebrow", children: eyebrow }) : null,
443
- /* @__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)) }),
444
- subtitle ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-desc rt-tpl-hero-carousel-subtitle", children: subtitle }) : null,
445
- cta ? /* @__PURE__ */ jsx2(
446
- CtaLink,
447
- {
448
- cta,
449
- track: "cta_hero",
450
- className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-hero-carousel-cta"
451
- }
452
- ) : null,
453
- /* @__PURE__ */ jsx2(TemplateHeroProof, { proofMetrics })
454
- ] })
455
- ]
456
- }
457
- );
458
- }
459
- function TemplateHeroOverlayPanel(section) {
460
- const { eyebrow, title, description, imageSrc, imageAlt, cta, proofMetrics } = section.props;
461
- return /* @__PURE__ */ jsxs2(
462
- "section",
463
- {
464
- "data-roottale-tpl": "hero",
465
- "data-variant": "overlay-panel",
466
- id: section.id,
467
- className: "rt-tpl-section rt-tpl-hero rt-tpl-hero--overlay-panel",
468
- style: sectionThemeStyle(section.theme),
469
- children: [
470
- /* @__PURE__ */ jsx2(
471
- "img",
472
- {
473
- className: "rt-tpl-hero-overlay-img",
474
- src: imageSrc ?? "",
475
- alt: imageAlt ?? "",
476
- loading: "eager"
477
- }
478
- ),
479
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-hero-overlay-scrim", "aria-hidden": "true" }),
480
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-container rt-tpl-hero-overlay-inner", children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-overlay-panel", children: [
481
- eyebrow ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-eyebrow", children: eyebrow }) : null,
482
- /* @__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)) }),
483
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-desc", children: description }) : null,
484
- cta ? /* @__PURE__ */ jsx2(CtaLink, { cta, track: "cta_hero" }) : null,
485
- /* @__PURE__ */ jsx2(TemplateHeroProof, { proofMetrics })
486
- ] }) })
487
- ]
488
- }
489
- );
490
- }
491
- function TemplateHero(section) {
492
- if (section.variant === "carousel") return TemplateHeroCarousel(section);
493
- if (section.variant === "overlay-panel")
494
- return TemplateHeroOverlayPanel(section);
495
- const { eyebrow, title, description, imageSrc, imageAlt, cta, proofMetrics } = section.props;
496
- const variant = section.variant;
497
- const showImage = variant !== "minimal" && imageSrc;
498
- return /* @__PURE__ */ jsx2(
499
- "section",
500
- {
501
- "data-roottale-tpl": "hero",
502
- "data-variant": variant,
503
- id: section.id,
504
- className: "rt-tpl-section rt-tpl-hero",
505
- style: sectionThemeStyle(section.theme),
506
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-hero-inner", children: [
507
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-copy", children: [
508
- eyebrow ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-eyebrow", children: eyebrow }) : null,
509
- /* @__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)) }),
510
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-hero-desc", children: description }) : null,
511
- cta ? /* @__PURE__ */ jsx2(CtaLink, { cta, track: "cta_hero" }) : null,
512
- /* @__PURE__ */ jsx2(TemplateHeroProof, { proofMetrics })
513
- ] }),
514
- showImage ? /* @__PURE__ */ jsx2("div", { className: "rt-tpl-hero-media", children: /* @__PURE__ */ jsx2(
515
- "img",
516
- {
517
- className: "rt-tpl-hero-img",
518
- src: imageSrc,
519
- alt: imageAlt ?? "",
520
- loading: "eager"
521
- }
522
- ) }) : null
523
- ] })
524
- }
525
- );
526
- }
527
- function TemplateRichText(section) {
528
- const { heading, body } = section.props;
529
- return /* @__PURE__ */ jsx2(
530
- "section",
531
- {
532
- "data-roottale-tpl": "rich-text",
533
- id: section.id,
534
- className: "rt-tpl-section rt-tpl-rich-text",
535
- style: sectionThemeStyle(section.theme),
536
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
537
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
538
- body.split("\n\n").map((para, i) => /* @__PURE__ */ jsx2("p", { className: "rt-tpl-rich-text-p", children: para }, i))
539
- ] })
540
- }
541
- );
542
- }
543
- function servicesIndexNum(i) {
544
- return String(i + 1).padStart(2, "0");
545
- }
546
- function ServicesItemMeta({
547
- item
548
- }) {
549
- const hasChips = Boolean(item.chips && item.chips.length > 0);
550
- const hasMeta = Boolean(item.meta && item.meta.length > 0);
551
- if (!hasChips && !hasMeta) return null;
552
- return /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-services-meta-block", children: [
553
- hasChips ? /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-services-chips", "aria-label": `${item.title} \uD0DC\uADF8`, children: (item.chips ?? []).map((chip) => /* @__PURE__ */ jsx2("li", { children: chip }, chip)) }) : null,
554
- hasMeta ? /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-services-meta", "aria-label": `${item.title} \uBA54\uD0C0`, children: (item.meta ?? []).map((meta) => /* @__PURE__ */ jsx2("li", { children: meta }, meta)) }) : null
555
- ] });
556
- }
557
- function ServicesIcon({
558
- item
559
- }) {
560
- if (!item.iconSrc) return null;
561
- return /* @__PURE__ */ jsx2(
562
- "img",
563
- {
564
- className: "rt-tpl-services-icon",
565
- src: item.iconSrc,
566
- alt: item.iconAlt ?? "",
567
- loading: "lazy"
568
- }
569
- );
570
- }
571
- function TemplateServicesActionRail(section) {
572
- const { heading, description, items } = section.props;
573
- return /* @__PURE__ */ jsx2(
574
- "section",
575
- {
576
- "data-roottale-tpl": "services",
577
- "data-variant": "action-rail",
578
- id: section.id,
579
- className: "rt-tpl-section rt-tpl-services",
580
- style: sectionThemeStyle(section.theme),
581
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
582
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
583
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
584
- /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-services-action-rail", children: items.map((item, i) => {
585
- const body = /* @__PURE__ */ jsxs2(Fragment2, { children: [
586
- /* @__PURE__ */ jsx2(ServicesIcon, { item }),
587
- /* @__PURE__ */ jsxs2("span", { className: "rt-tpl-services-action-body", children: [
588
- /* @__PURE__ */ jsx2("span", { className: "rt-tpl-services-title", children: item.title }),
589
- item.subtitle ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-services-subtitle", children: item.subtitle }) : null,
590
- item.description ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-services-desc", children: item.description }) : null,
591
- /* @__PURE__ */ jsx2(ServicesItemMeta, { item }),
592
- item.ctaLabel ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-services-action-label", children: item.ctaLabel }) : null
593
- ] })
594
- ] });
595
- return /* @__PURE__ */ jsx2("li", { "data-kind": item.kind, children: item.href ? /* @__PURE__ */ jsx2(
596
- "a",
597
- {
598
- className: "rt-tpl-services-action-card",
599
- href: item.href,
600
- "data-track": "service_card",
601
- children: body
602
- }
603
- ) : /* @__PURE__ */ jsx2("div", { className: "rt-tpl-services-action-card", children: body }) }, `${item.title}-${i}`);
604
- }) })
605
- ] })
606
- }
607
- );
608
- }
609
- function TemplateServicesPhotoCards(section) {
610
- const { heading, description, items } = section.props;
611
- return /* @__PURE__ */ jsx2(
612
- "section",
613
- {
614
- "data-roottale-tpl": "services",
615
- "data-variant": "photo-cards",
616
- id: section.id,
617
- className: "rt-tpl-section rt-tpl-services",
618
- style: sectionThemeStyle(section.theme),
619
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
620
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
621
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
622
- /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-services-photo-list", children: items.map((item, i) => {
623
- const card = /* @__PURE__ */ jsxs2("article", { className: "rt-tpl-services-photo-card", children: [
624
- /* @__PURE__ */ jsx2(
625
- "img",
626
- {
627
- className: "rt-tpl-services-photo-img",
628
- src: item.imageSrc ?? "",
629
- alt: item.imageAlt ?? "",
630
- loading: "lazy"
631
- }
632
- ),
633
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-services-photo-body", children: [
634
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-services-title", children: item.title }),
635
- item.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-services-desc", children: item.description }) : null,
636
- item.ctaLabel ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-services-action-label", children: item.ctaLabel }) : null
637
- ] })
638
- ] });
639
- return /* @__PURE__ */ jsx2("li", { children: item.href ? /* @__PURE__ */ jsx2(
640
- "a",
641
- {
642
- className: "rt-tpl-services-photo-link",
643
- href: item.href,
644
- "data-track": "service_card",
645
- children: card
646
- }
647
- ) : card }, `${item.title}-${i}`);
648
- }) })
649
- ] })
650
- }
651
- );
652
- }
653
- function TemplateServicesIndexRows(section) {
654
- const { heading, description, items } = section.props;
655
- return /* @__PURE__ */ jsx2(
656
- "section",
657
- {
658
- "data-roottale-tpl": "services",
659
- "data-variant": "index-rows",
660
- id: section.id,
661
- className: "rt-tpl-section rt-tpl-services",
662
- style: sectionThemeStyle(section.theme),
663
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
664
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
665
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
666
- /* @__PURE__ */ jsx2(StaggerGroup, { as: "ol", className: "rt-tpl-services-index-list", children: items.map((item, i) => {
667
- const body = /* @__PURE__ */ jsxs2(Fragment2, { children: [
668
- /* @__PURE__ */ jsx2("span", { className: "rt-tpl-services-index-num", "aria-hidden": "true", children: servicesIndexNum(i) }),
669
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-services-index-body", children: [
670
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-services-index-title", children: item.title }),
671
- item.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-services-index-desc", children: item.description }) : null
672
- ] })
673
- ] });
674
- return /* @__PURE__ */ jsx2(StaggerItem, { as: "li", className: "rt-tpl-services-index-row", children: item.href ? /* @__PURE__ */ jsx2(
675
- "a",
676
- {
677
- className: "rt-tpl-services-index-link",
678
- href: item.href,
679
- "data-track": "service_card",
680
- children: body
681
- }
682
- ) : /* @__PURE__ */ jsx2("div", { className: "rt-tpl-services-index-link", children: body }) }, i);
683
- }) })
684
- ] })
685
- }
686
- );
687
- }
688
- function TemplateServicesSplitFeatured(section) {
689
- const { heading, description, items } = section.props;
690
- const [featured, ...rest] = items;
691
- return /* @__PURE__ */ jsx2(
692
- "section",
693
- {
694
- "data-roottale-tpl": "services",
695
- "data-variant": "split-featured",
696
- id: section.id,
697
- className: "rt-tpl-section rt-tpl-services",
698
- style: sectionThemeStyle(section.theme),
699
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
700
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
701
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
702
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-services-split", children: [
703
- /* @__PURE__ */ jsx2(
704
- AnimateOnScroll,
705
- {
706
- as: "div",
707
- variant: "fade-up",
708
- className: "rt-tpl-services-split-featured",
709
- children: featured ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
710
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-services-split-featured-title", children: featured.title }),
711
- featured.subtitle ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-services-subtitle", children: featured.subtitle }) : null,
712
- featured.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-services-split-featured-desc", children: featured.description }) : null,
713
- /* @__PURE__ */ jsx2(ServicesItemMeta, { item: featured }),
714
- featured.href ? /* @__PURE__ */ jsx2(
715
- "a",
716
- {
717
- className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-services-split-featured-cta",
718
- href: featured.href,
719
- "data-track": "service_card",
720
- children: featured.ctaLabel ?? "\uC790\uC138\uD788 \uBCF4\uAE30"
721
- }
722
- ) : null
723
- ] }) : null
724
- }
725
- ),
726
- /* @__PURE__ */ jsx2(StaggerGroup, { as: "ol", className: "rt-tpl-services-split-list", children: rest.map((item, i) => {
727
- const body = /* @__PURE__ */ jsxs2(Fragment2, { children: [
728
- /* @__PURE__ */ jsx2("h4", { className: "rt-tpl-services-split-item-title", children: item.title }),
729
- item.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-services-split-item-desc", children: item.description }) : null,
730
- /* @__PURE__ */ jsx2(ServicesItemMeta, { item })
731
- ] });
732
- return /* @__PURE__ */ jsx2(
733
- StaggerItem,
734
- {
735
- as: "li",
736
- className: "rt-tpl-services-split-item",
737
- children: item.href ? /* @__PURE__ */ jsx2(
738
- "a",
739
- {
740
- className: "rt-tpl-services-split-item-link",
741
- href: item.href,
742
- "data-track": "service_card",
743
- children: body
744
- }
745
- ) : body
746
- },
747
- i
748
- );
749
- }) })
750
- ] })
751
- ] })
752
- }
753
- );
754
- }
755
- function TemplateServices(section) {
756
- if (section.variant === "index-rows") return TemplateServicesIndexRows(section);
757
- if (section.variant === "split-featured")
758
- return TemplateServicesSplitFeatured(section);
759
- if (section.variant === "action-rail")
760
- return TemplateServicesActionRail(section);
761
- if (section.variant === "photo-cards")
762
- return TemplateServicesPhotoCards(section);
763
- const { heading, description, items } = section.props;
764
- return /* @__PURE__ */ jsx2(
765
- "section",
766
- {
767
- "data-roottale-tpl": "services",
768
- "data-variant": section.variant,
769
- id: section.id,
770
- className: "rt-tpl-section rt-tpl-services",
771
- style: sectionThemeStyle(section.theme),
772
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
773
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
774
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
775
- /* @__PURE__ */ jsx2(StaggerGroup, { as: "ul", className: "rt-tpl-services-list", children: items.map((item, i) => {
776
- const body = /* @__PURE__ */ jsxs2(Fragment2, { children: [
777
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-services-title", children: item.title }),
778
- item.subtitle ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-services-subtitle", children: item.subtitle }) : null,
779
- item.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-services-desc", children: item.description }) : null,
780
- /* @__PURE__ */ jsx2(ServicesItemMeta, { item }),
781
- item.ctaLabel ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-services-action-label", children: item.ctaLabel }) : null
782
- ] });
783
- return /* @__PURE__ */ jsx2(StaggerItem, { as: "li", className: "rt-tpl-services-item", children: item.href ? /* @__PURE__ */ jsxs2(
784
- "a",
785
- {
786
- className: "rt-tpl-services-link",
787
- href: item.href,
788
- "data-track": "service_card",
789
- children: [
790
- /* @__PURE__ */ jsx2(ServicesIcon, { item }),
791
- body
792
- ]
793
- }
794
- ) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
795
- /* @__PURE__ */ jsx2(ServicesIcon, { item }),
796
- body
797
- ] }) }, i);
798
- }) })
799
- ] })
800
- }
801
- );
802
- }
803
- function FooterBrand(section) {
804
- const { businessName, logo, description } = section.props;
805
- return /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-footer-brand", children: [
806
- logo ? /* @__PURE__ */ jsx2(
807
- "img",
808
- {
809
- className: "rt-tpl-footer-logo",
810
- src: logo.src,
811
- alt: logo.alt,
812
- loading: "lazy"
813
- }
814
- ) : null,
815
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-footer-name", children: businessName }),
816
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-footer-description", children: description }) : null
817
- ] });
818
- }
819
- function FooterContact({
820
- contactInfo
821
- }) {
822
- if (!contactInfo?.address && !contactInfo?.phone && !contactInfo?.email) {
823
- return null;
824
- }
825
- return /* @__PURE__ */ jsxs2("address", { className: "rt-tpl-footer-contact", children: [
826
- contactInfo.address ? /* @__PURE__ */ jsx2("span", { children: contactInfo.address }) : null,
827
- contactInfo.phone ? /* @__PURE__ */ jsx2(
828
- "a",
829
- {
830
- href: telHref(contactInfo.phone),
831
- "data-track": "phone_click",
832
- "data-track-placement": "footer",
833
- children: contactInfo.phone
834
- }
835
- ) : null,
836
- contactInfo.email ? /* @__PURE__ */ jsx2(
837
- "a",
838
- {
839
- href: `mailto:${contactInfo.email}`,
840
- "data-track": "email_click",
841
- "data-track-placement": "footer",
842
- children: contactInfo.email
843
- }
844
- ) : null
845
- ] });
846
- }
847
- function FooterLegal(section) {
848
- const { legalInfo, privacyHref, termsHref, copyright, socialLinks, credit } = section.props;
849
- return /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-footer-bottom", children: [
850
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-footer-legal", children: [
851
- legalInfo ? /* @__PURE__ */ jsx2("p", { children: legalInfo }) : null,
852
- copyright ? /* @__PURE__ */ jsx2("p", { children: copyright }) : null
853
- ] }),
854
- /* @__PURE__ */ jsxs2("nav", { className: "rt-tpl-footer-policy", "aria-label": "\uBC95\uC801 \uACE0\uC9C0", children: [
855
- privacyHref ? /* @__PURE__ */ jsx2("a", { href: privacyHref, children: "\uAC1C\uC778\uC815\uBCF4\uCC98\uB9AC\uBC29\uCE68" }) : null,
856
- termsHref ? /* @__PURE__ */ jsx2("a", { href: termsHref, children: "\uC774\uC6A9\uC57D\uAD00" }) : null,
857
- socialLinks?.map((link) => /* @__PURE__ */ jsx2("a", { href: link.href, children: link.kind }, `${link.kind}-${link.href}`))
858
- ] }),
859
- credit === "hidden" ? null : /* @__PURE__ */ jsxs2("p", { className: "rt-tpl-footer-credit", children: [
860
- "Website by",
861
- " ",
862
- /* @__PURE__ */ jsx2("a", { href: "https://roottale.com", target: "_blank", rel: "noopener", children: "RootTale" })
863
- ] })
864
- ] });
865
- }
866
- function TemplateFooterColumns(section) {
867
- const { columns, contactInfo } = section.props;
868
- return /* @__PURE__ */ jsx2(
869
- "footer",
870
- {
871
- role: "contentinfo",
872
- "data-roottale-tpl": "footer",
873
- "data-variant": "columns",
874
- id: section.id,
875
- className: "rt-tpl-footer",
876
- style: sectionThemeStyle(section.theme),
877
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
878
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-footer-columns", children: [
879
- /* @__PURE__ */ jsx2(FooterBrand, { ...section }),
880
- /* @__PURE__ */ jsx2("nav", { className: "rt-tpl-footer-nav", "aria-label": "\uD478\uD130 \uB9C1\uD06C", children: (columns ?? []).map((column) => /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-footer-column", children: [
881
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-footer-column-title", children: column.title }),
882
- /* @__PURE__ */ jsx2("ul", { children: column.links.map((link) => /* @__PURE__ */ jsx2("li", { children: /* @__PURE__ */ jsx2("a", { href: link.href, children: link.label }) }, `${column.title}-${link.label}-${link.href}`)) })
883
- ] }, column.title)) }),
884
- /* @__PURE__ */ jsx2(FooterContact, { contactInfo })
885
- ] }),
886
- /* @__PURE__ */ jsx2(FooterLegal, { ...section })
887
- ] })
888
- }
889
- );
890
- }
891
- function TemplateFooterMinimal(section) {
892
- return /* @__PURE__ */ jsx2(
893
- "footer",
894
- {
895
- role: "contentinfo",
896
- "data-roottale-tpl": "footer",
897
- "data-variant": "minimal",
898
- id: section.id,
899
- className: "rt-tpl-footer rt-tpl-footer--minimal",
900
- style: sectionThemeStyle(section.theme),
901
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
902
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-footer-minimal-row", children: [
903
- /* @__PURE__ */ jsx2(FooterBrand, { ...section }),
904
- /* @__PURE__ */ jsx2(FooterContact, { contactInfo: section.props.contactInfo })
905
- ] }),
906
- /* @__PURE__ */ jsx2(FooterLegal, { ...section })
907
- ] })
908
- }
909
- );
910
- }
911
- function TemplateFooter(section) {
912
- if (section.variant === "minimal") return TemplateFooterMinimal(section);
913
- return TemplateFooterColumns(section);
914
- }
915
- function faqItemsForJsonLd(section) {
916
- if (section.props.groups && section.props.groups.length > 0) {
917
- return section.props.groups.flatMap((group) => group.items);
918
- }
919
- return section.props.items ?? [];
920
- }
921
- function TemplateFaqAccordion(section) {
922
- const { heading, items, contact } = section.props;
923
- const list = items ?? [];
924
- return /* @__PURE__ */ jsxs2(
925
- "div",
926
- {
927
- className: section.variant === "with-contact" ? "rt-tpl-faq-with-contact" : void 0,
928
- children: [
929
- /* @__PURE__ */ jsxs2("div", { children: [
930
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
931
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-faq-list", children: list.map((item, i) => /* @__PURE__ */ jsxs2("details", { className: "rt-tpl-faq-item", children: [
932
- /* @__PURE__ */ jsx2("summary", { className: "rt-tpl-faq-q", children: item.question }),
933
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-faq-a", children: item.answer })
934
- ] }, i)) })
935
- ] }),
936
- section.variant === "with-contact" && contact ? /* @__PURE__ */ jsxs2("aside", { className: "rt-tpl-faq-contact", "aria-label": "\uC0C1\uB2F4 \uBB38\uC758", children: [
937
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-faq-contact-title", children: contact.title }),
938
- contact.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-faq-contact-desc", children: contact.description }) : null,
939
- contact.phone ? /* @__PURE__ */ jsx2(
940
- "a",
941
- {
942
- className: "rt-tpl-faq-contact-phone",
943
- href: telHref(contact.phone),
944
- "data-track": "cta_call",
945
- children: contact.phone
946
- }
947
- ) : null,
948
- contact.cta ? /* @__PURE__ */ jsx2(
949
- CtaLink,
950
- {
951
- cta: contact.cta,
952
- track: ctaTrackForHref(contact.cta.href),
953
- className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-faq-contact-cta"
954
- }
955
- ) : null
956
- ] }) : null
957
- ]
958
- }
959
- );
960
- }
961
- function TemplateFaqTwoColumn(section) {
962
- const { heading, items, groups } = section.props;
963
- const hasGroups = Boolean(groups && groups.length > 0);
964
- return /* @__PURE__ */ jsxs2(Fragment2, { children: [
965
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
966
- hasGroups ? /* @__PURE__ */ jsx2("div", { className: "rt-tpl-faq-groups", children: (groups ?? []).map((group) => /* @__PURE__ */ jsxs2("section", { className: "rt-tpl-faq-group", children: [
967
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-faq-group-title", children: group.title }),
968
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-faq-two-column-list", children: group.items.map((item, i) => /* @__PURE__ */ jsxs2("article", { className: "rt-tpl-faq-open-item", children: [
969
- /* @__PURE__ */ jsx2("h4", { className: "rt-tpl-faq-open-q", children: item.question }),
970
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-faq-open-a", children: item.answer })
971
- ] }, `${group.title}-${i}`)) })
972
- ] }, group.title)) }) : /* @__PURE__ */ jsx2("div", { className: "rt-tpl-faq-two-column-list", children: (items ?? []).map((item, i) => /* @__PURE__ */ jsxs2("article", { className: "rt-tpl-faq-open-item", children: [
973
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-faq-open-q", children: item.question }),
974
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-faq-open-a", children: item.answer })
975
- ] }, i)) })
976
- ] });
977
- }
978
- function TemplateFaqContentAccordion(section) {
979
- const { heading, contentGroups } = section.props;
980
- return /* @__PURE__ */ jsxs2(Fragment2, { children: [
981
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
982
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-faq-content-groups", children: (contentGroups ?? []).map((group) => /* @__PURE__ */ jsxs2("section", { className: "rt-tpl-faq-content-group", children: [
983
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-faq-group-title", children: group.title }),
984
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-faq-list", children: group.items.map((item) => /* @__PURE__ */ jsxs2("details", { className: "rt-tpl-faq-item", children: [
985
- /* @__PURE__ */ jsxs2("summary", { className: "rt-tpl-faq-q", children: [
986
- /* @__PURE__ */ jsx2("span", { children: item.title }),
987
- item.summary ? /* @__PURE__ */ jsx2("small", { children: item.summary }) : null
988
- ] }),
989
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-faq-a rt-tpl-faq-content-body", children: [
990
- /* @__PURE__ */ jsx2("p", { children: item.body }),
991
- item.signs && item.signs.length > 0 ? /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-faq-content-signs", children: item.signs.map((sign) => /* @__PURE__ */ jsx2("li", { children: sign }, sign)) }) : null,
992
- item.href ? /* @__PURE__ */ jsx2("a", { className: "rt-tpl-faq-content-link", href: item.href, children: "\uC790\uC138\uD788 \uBCF4\uAE30" }) : null
993
- ] })
994
- ] }, item.title)) })
995
- ] }, group.title)) })
996
- ] });
997
- }
998
- function TemplateFaq(section) {
999
- const { jsonLd } = section.props;
1000
- const jsonLdItems = faqItemsForJsonLd(section);
1001
- return /* @__PURE__ */ jsxs2(
1002
- "section",
1003
- {
1004
- "data-roottale-tpl": "faq",
1005
- "data-variant": section.variant,
1006
- id: section.id,
1007
- className: "rt-tpl-section rt-tpl-faq",
1008
- style: sectionThemeStyle(section.theme),
1009
- children: [
1010
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-container", children: section.variant === "content-accordion" ? TemplateFaqContentAccordion(section) : section.variant === "two-column" ? TemplateFaqTwoColumn(section) : TemplateFaqAccordion(section) }),
1011
- section.variant !== "content-accordion" && jsonLd && jsonLdItems.length > 0 ? /* @__PURE__ */ jsx2(
1012
- "script",
1013
- {
1014
- type: "application/ld+json",
1015
- dangerouslySetInnerHTML: {
1016
- __html: JSON.stringify({
1017
- "@context": "https://schema.org",
1018
- "@type": "FAQPage",
1019
- mainEntity: jsonLdItems.map((item) => ({
1020
- "@type": "Question",
1021
- name: item.question,
1022
- acceptedAnswer: { "@type": "Answer", text: item.answer }
1023
- }))
1024
- })
1025
- }
1026
- }
1027
- ) : null
1028
- ]
1029
- }
1030
- );
1031
- }
1032
- function TemplateCtaBannerPhotoOverlay(section) {
1033
- const { title, description, cta, image, imageAlt } = section.props;
1034
- return /* @__PURE__ */ jsx2(
1035
- "section",
1036
- {
1037
- "data-roottale-tpl": "cta-banner",
1038
- "data-variant": "photo-overlay",
1039
- id: section.id,
1040
- className: "rt-tpl-section rt-tpl-cta-banner rt-tpl-cta-banner--photo-overlay",
1041
- style: sectionThemeStyle(section.theme),
1042
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-cta-banner-photo", children: [
1043
- /* @__PURE__ */ jsx2(
1044
- "img",
1045
- {
1046
- className: "rt-tpl-cta-banner-photo-img",
1047
- src: image ?? "",
1048
- alt: imageAlt ?? "",
1049
- loading: "lazy"
1050
- }
1051
- ),
1052
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-cta-banner-photo-scrim", "aria-hidden": "true" }),
1053
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-cta-banner-photo-inner", children: [
1054
- /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-cta-banner-photo-title", children: title }),
1055
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-cta-banner-photo-desc", children: description }) : null,
1056
- cta ? /* @__PURE__ */ jsx2(
1057
- CtaLink,
1058
- {
1059
- cta,
1060
- track: "cta_banner",
1061
- className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-cta-banner-photo-cta"
1062
- }
1063
- ) : null
1064
- ] })
1065
- ] })
1066
- }
1067
- );
1068
- }
1069
- function TemplateCtaBanner(section) {
1070
- if (section.variant === "photo-overlay")
1071
- return TemplateCtaBannerPhotoOverlay(section);
1072
- const { title, description, cta } = section.props;
1073
- return /* @__PURE__ */ jsx2(
1074
- "section",
1075
- {
1076
- "data-roottale-tpl": "cta-banner",
1077
- "data-variant": section.variant,
1078
- id: section.id,
1079
- className: "rt-tpl-section rt-tpl-cta-banner",
1080
- style: sectionThemeStyle(section.theme),
1081
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-cta-banner-inner", children: [
1082
- /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-cta-banner-title", children: title }),
1083
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-cta-banner-desc", children: description }) : null,
1084
- cta ? /* @__PURE__ */ jsx2(CtaLink, { cta, track: "cta_banner" }) : null
1085
- ] })
1086
- }
1087
- );
1088
- }
1089
- function TrustMetricValue({ value }) {
1090
- const parsed = parseMetricValue(value);
1091
- if (!parsed) {
1092
- return /* @__PURE__ */ jsx2(Fragment2, { children: value });
1093
- }
1094
- return /* @__PURE__ */ jsx2(
1095
- CountUpStat,
1096
- {
1097
- value: parsed.value,
1098
- decimals: parsed.decimals,
1099
- suffix: parsed.suffix
1100
- }
1101
- );
1102
- }
1103
- function TrustCredentialIcon() {
1104
- return /* @__PURE__ */ jsxs2(
1105
- "svg",
1106
- {
1107
- className: "rt-cred__icon",
1108
- viewBox: "0 0 16 16",
1109
- "aria-hidden": "true",
1110
- focusable: "false",
1111
- children: [
1112
- /* @__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" }),
1113
- /* @__PURE__ */ jsx2("path", { d: "m5.75 8 1.45 1.45 3.2-3.4" })
1114
- ]
1115
- }
1116
- );
1117
- }
1118
- function TemplateTrust(section) {
1119
- const { heading, metrics, credentials, logos, marqueeLogos, chart, disclaimer } = section.props;
1120
- const chartMax = chart?.points.reduce((max, point) => Math.max(max, point.value), 0) ?? 0;
1121
- return /* @__PURE__ */ jsx2(
1122
- "section",
1123
- {
1124
- "data-roottale-tpl": "trust",
1125
- "data-variant": section.variant,
1126
- id: section.id,
1127
- className: "rt-tpl-section rt-tpl-trust",
1128
- style: sectionThemeStyle(section.theme),
1129
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-trust-inner", children: [
1130
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1131
- section.variant === "stat-band" ? (
1132
- // 수치 밴드 진입 시 fade-up(C8) + 지표 숫자 카운트업(ADR-0086 D3로
1133
- // 채택(구 룰 supersede, 2026-07-17)). reduce·SSR 시 <div> 그대로
1134
- // (마크업 불변) + CountUpStat 자체도 mount 전엔 최종값 정적 표시.
1135
- /* @__PURE__ */ jsx2(AnimateOnScroll, { as: "div", variant: "fade-up", className: "rt-tpl-trust-stat-band", children: (metrics ?? []).map((metric) => /* @__PURE__ */ jsxs2(
1136
- "div",
1137
- {
1138
- className: "rt-stat",
1139
- "data-variant": "band-item",
1140
- children: [
1141
- /* @__PURE__ */ jsxs2("span", { className: "rt-stat__value", children: [
1142
- /* @__PURE__ */ jsx2(TrustMetricValue, { value: metric.value }),
1143
- metric.unit ? /* @__PURE__ */ jsx2("span", { className: "rt-stat__unit", children: metric.unit }) : null
1144
- ] }),
1145
- /* @__PURE__ */ jsx2("span", { className: "rt-stat__label", children: metric.label }),
1146
- metric.source ? /* @__PURE__ */ jsx2("span", { className: "rt-stat__source", children: metric.source }) : null
1147
- ]
1148
- },
1149
- `${metric.value}-${metric.label}`
1150
- )) })
1151
- ) : null,
1152
- 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(
1153
- "img",
1154
- {
1155
- className: "rt-tpl-trust-logo",
1156
- src: logo.src,
1157
- alt: logo.alt,
1158
- loading: "lazy"
1159
- }
1160
- ) }) : /* @__PURE__ */ jsx2(
1161
- "img",
1162
- {
1163
- className: "rt-tpl-trust-logo",
1164
- src: logo.src,
1165
- alt: logo.alt,
1166
- loading: "lazy"
1167
- }
1168
- ) }, `${logo.src}-${logo.alt}`)) }) : null,
1169
- 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: [
1170
- /* @__PURE__ */ jsx2(TrustCredentialIcon, {}),
1171
- /* @__PURE__ */ jsx2("span", { className: "rt-cred__label", children: credential.name }),
1172
- credential.issuer ? /* @__PURE__ */ jsx2("span", { className: "rt-cred__issuer", children: credential.issuer }) : null
1173
- ] }) }, `${credential.name}-${credential.issuer ?? ""}`)) }) : null,
1174
- section.variant === "logo-marquee" ? (
1175
- // C8 Marquee 소비(직접 재구현 금지, C10 §1-3). 로고는 흑백/저채도
1176
- // 처리(CSS filter) — hover 시에만 원색 복원.
1177
- /* @__PURE__ */ jsx2(
1178
- Marquee,
1179
- {
1180
- className: "rt-tpl-trust-marquee",
1181
- ariaLabel: heading ?? "\uD30C\uD2B8\uB108/\uC778\uC99D \uB85C\uACE0",
1182
- children: (marqueeLogos ?? []).map(
1183
- (logo, i) => logo.href ? /* @__PURE__ */ jsx2(
1184
- "a",
1185
- {
1186
- className: "rt-tpl-trust-marquee-link",
1187
- href: logo.href,
1188
- children: /* @__PURE__ */ jsx2(
1189
- "img",
1190
- {
1191
- className: "rt-tpl-trust-marquee-logo",
1192
- src: logo.src,
1193
- alt: logo.alt,
1194
- loading: "lazy"
1195
- }
1196
- )
1197
- },
1198
- `${logo.alt}-${i}`
1199
- ) : /* @__PURE__ */ jsx2(
1200
- "img",
1201
- {
1202
- className: "rt-tpl-trust-marquee-logo",
1203
- src: logo.src,
1204
- alt: logo.alt,
1205
- loading: "lazy"
1206
- },
1207
- `${logo.alt}-${i}`
1208
- )
1209
- )
1210
- }
1211
- )
1212
- ) : null,
1213
- section.variant === "credential-list" ? (
1214
- // hairline 자격·이력·수상 리스트 — 연도는 tabular-nums, 위계는
1215
- // 작은 크기로(AI-slop #3 대체: 장식용 큰 숫자 금지).
1216
- /* @__PURE__ */ jsx2("ol", { className: "rt-tpl-trust-credential-list", children: (credentials ?? []).map((credential, i) => /* @__PURE__ */ jsxs2(
1217
- "li",
1218
- {
1219
- className: "rt-tpl-trust-credential-row",
1220
- children: [
1221
- credential.year ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-trust-credential-year", children: credential.year }) : null,
1222
- /* @__PURE__ */ jsx2("span", { className: "rt-tpl-trust-credential-name", children: credential.name }),
1223
- credential.issuer ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-trust-credential-issuer", children: credential.issuer }) : null
1224
- ]
1225
- },
1226
- `${credential.name}-${credential.year ?? i}`
1227
- )) })
1228
- ) : null,
1229
- section.variant === "dashboard" && chart ? /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-trust-dashboard", children: [
1230
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-trust-dashboard-chart", children: [
1231
- /* @__PURE__ */ jsxs2("div", { children: [
1232
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-trust-dashboard-title", children: chart.title }),
1233
- chart.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-trust-dashboard-desc", children: chart.description }) : null
1234
- ] }),
1235
- /* @__PURE__ */ jsx2(
1236
- "ul",
1237
- {
1238
- className: "rt-tpl-trust-dashboard-bars",
1239
- "data-chart-type": chart.type,
1240
- children: chart.points.map((point) => {
1241
- const percent = chartMax > 0 ? `${Math.max(4, Math.round(point.value / chartMax * 100))}%` : "4%";
1242
- return /* @__PURE__ */ jsxs2("li", { children: [
1243
- /* @__PURE__ */ jsx2("span", { children: point.label }),
1244
- /* @__PURE__ */ jsx2("span", { className: "rt-tpl-trust-dashboard-track", children: /* @__PURE__ */ jsx2(
1245
- "span",
1246
- {
1247
- className: "rt-tpl-trust-dashboard-bar",
1248
- style: { inlineSize: percent }
1249
- }
1250
- ) }),
1251
- /* @__PURE__ */ jsx2("strong", { children: point.display ?? String(point.value) })
1252
- ] }, point.label);
1253
- })
1254
- }
1255
- )
1256
- ] }),
1257
- /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-trust-dashboard-metrics", children: (metrics ?? []).map((metric) => /* @__PURE__ */ jsxs2("li", { className: "rt-stat", children: [
1258
- metric.imageSrc ? /* @__PURE__ */ jsx2(
1259
- "img",
1260
- {
1261
- className: "rt-tpl-trust-dashboard-icon",
1262
- src: metric.imageSrc,
1263
- alt: metric.imageAlt ?? "",
1264
- loading: "lazy"
1265
- }
1266
- ) : null,
1267
- /* @__PURE__ */ jsxs2("span", { className: "rt-stat__value", children: [
1268
- /* @__PURE__ */ jsx2(TrustMetricValue, { value: metric.value }),
1269
- metric.unit ? /* @__PURE__ */ jsx2("span", { className: "rt-stat__unit", children: metric.unit }) : null
1270
- ] }),
1271
- /* @__PURE__ */ jsx2("span", { className: "rt-stat__label", children: metric.label }),
1272
- metric.source ? /* @__PURE__ */ jsx2("span", { className: "rt-stat__source", children: metric.source }) : null
1273
- ] }, `${metric.value}-${metric.label}`)) })
1274
- ] }) : null,
1275
- disclaimer ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-trust-disclaimer", children: disclaimer }) : null
1276
- ] })
1277
- }
1278
- );
1279
- }
1280
- function TemplateTestimonialsEditorialQuote(section) {
1281
- const { heading, description, items, disclaimer } = section.props;
1282
- const layout = items.length > 1 ? "stack" : "single";
1283
- return /* @__PURE__ */ jsx2(
1284
- "section",
1285
- {
1286
- "data-roottale-tpl": "testimonials",
1287
- "data-variant": "editorial-quote",
1288
- id: section.id,
1289
- className: "rt-tpl-section rt-tpl-testimonials",
1290
- style: sectionThemeStyle(section.theme),
1291
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1292
- /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }),
1293
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
1294
- /* @__PURE__ */ jsx2(
1295
- StaggerGroup,
1296
- {
1297
- as: "ul",
1298
- className: `rt-tpl-testimonials-editorial-list rt-tpl-testimonials-editorial-list--${layout}`,
1299
- children: items.map((item, i) => /* @__PURE__ */ jsx2(
1300
- StaggerItem,
1301
- {
1302
- as: "li",
1303
- className: "rt-tpl-testimonials-editorial-item",
1304
- children: /* @__PURE__ */ jsxs2("blockquote", { className: "rt-tpl-testimonials-editorial-quote", children: [
1305
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-editorial-text", children: item.quote }),
1306
- /* @__PURE__ */ jsxs2("footer", { className: "rt-tpl-testimonials-editorial-footer", children: [
1307
- /* @__PURE__ */ jsx2("cite", { className: "rt-tpl-testimonials-editorial-author", children: item.author }),
1308
- item.context ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-testimonials-editorial-context", children: item.context }) : null,
1309
- /* @__PURE__ */ jsx2(TestimonialMeta, { item })
1310
- ] }),
1311
- item.reply ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-reply", children: item.reply }) : null
1312
- ] })
1313
- },
1314
- `${item.author}-${i}`
1315
- ))
1316
- }
1317
- ),
1318
- disclaimer ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-disclaimer", children: disclaimer }) : null
1319
- ] })
1320
- }
1321
- );
1322
- }
1323
- function TestimonialMeta({
1324
- item
1325
- }) {
1326
- const values = [
1327
- typeof item.rating === "number" ? `\uD3C9\uC810 ${item.rating.toFixed(1)}` : void 0,
1328
- item.source,
1329
- item.visitedAt,
1330
- item.item
1331
- ].filter((value) => Boolean(value));
1332
- if (values.length === 0) return null;
1333
- return /* @__PURE__ */ jsx2("span", { className: "rt-tpl-testimonials-meta", children: values.map((value) => /* @__PURE__ */ jsx2("span", { children: value }, value)) });
1334
- }
1335
- function TemplateTestimonialsQuoteRail(section) {
1336
- const { heading, description, items, marquee, disclaimer } = section.props;
1337
- return /* @__PURE__ */ jsx2(
1338
- "section",
1339
- {
1340
- "data-roottale-tpl": "testimonials",
1341
- "data-variant": "quote-rail",
1342
- id: section.id,
1343
- className: "rt-tpl-section rt-tpl-testimonials",
1344
- style: sectionThemeStyle(section.theme),
1345
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1346
- /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }),
1347
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
1348
- /* @__PURE__ */ jsx2(
1349
- AnimateOnScroll,
1350
- {
1351
- as: "div",
1352
- variant: "fade-up",
1353
- className: "rt-tpl-testimonials-rail-viewport",
1354
- children: /* @__PURE__ */ jsx2(
1355
- "ul",
1356
- {
1357
- className: marquee ? "rt-tpl-testimonials-rail rt-tpl-testimonials-rail--marquee" : "rt-tpl-testimonials-rail",
1358
- "data-marquee": marquee ? "true" : void 0,
1359
- children: items.map((item, i) => /* @__PURE__ */ jsx2(
1360
- "li",
1361
- {
1362
- className: "rt-tpl-testimonials-rail-item",
1363
- children: /* @__PURE__ */ jsxs2("blockquote", { className: "rt-tpl-testimonials-rail-quote", children: [
1364
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-rail-text", children: item.quote }),
1365
- /* @__PURE__ */ jsxs2("footer", { className: "rt-tpl-testimonials-rail-footer", children: [
1366
- /* @__PURE__ */ jsx2("cite", { className: "rt-tpl-testimonials-rail-author", children: item.author }),
1367
- item.context ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-testimonials-rail-context", children: item.context }) : null,
1368
- /* @__PURE__ */ jsx2(TestimonialMeta, { item })
1369
- ] }),
1370
- item.reply ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-reply", children: item.reply }) : null
1371
- ] })
1372
- },
1373
- `${item.author}-${i}`
1374
- ))
1375
- }
1376
- )
1377
- }
1378
- ),
1379
- disclaimer ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-disclaimer", children: disclaimer }) : null
1380
- ] })
1381
- }
1382
- );
1383
- }
1384
- function StarRating({ rating }) {
1385
- const clamped = Math.min(5, Math.max(0, rating));
1386
- const fill = `${(clamped / 5 * 100).toFixed(0)}%`;
1387
- return /* @__PURE__ */ jsxs2(
1388
- "span",
1389
- {
1390
- className: "rt-tpl-testimonials-stars",
1391
- role: "img",
1392
- "aria-label": `\uD3C9\uC810 5\uC810 \uB9CC\uC810\uC5D0 ${clamped.toFixed(1)}\uC810`,
1393
- style: { "--rt-testimonials-star-fill": fill },
1394
- children: [
1395
- /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", className: "rt-tpl-testimonials-stars-base", children: "\u2605\u2605\u2605\u2605\u2605" }),
1396
- /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", className: "rt-tpl-testimonials-stars-fill", children: "\u2605\u2605\u2605\u2605\u2605" })
1397
- ]
1398
- }
1399
- );
1400
- }
1401
- function TemplateTestimonialsStarCompact(section) {
1402
- const { heading, description, items, disclaimer } = section.props;
1403
- const rated = items.filter(
1404
- (item) => typeof item.rating === "number"
1405
- );
1406
- const average = rated.length > 0 ? rated.reduce((sum, item) => sum + item.rating, 0) / rated.length : void 0;
1407
- return /* @__PURE__ */ jsx2(
1408
- "section",
1409
- {
1410
- "data-roottale-tpl": "testimonials",
1411
- "data-variant": "star-compact",
1412
- id: section.id,
1413
- className: "rt-tpl-section rt-tpl-testimonials",
1414
- style: sectionThemeStyle(section.theme),
1415
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1416
- /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }),
1417
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
1418
- average !== void 0 ? /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-testimonials-star-summary", children: [
1419
- /* @__PURE__ */ jsx2("span", { className: "rt-tpl-testimonials-star-average", children: average.toFixed(1) }),
1420
- /* @__PURE__ */ jsx2(StarRating, { rating: average }),
1421
- /* @__PURE__ */ jsxs2("span", { className: "rt-tpl-testimonials-star-count", children: [
1422
- "\uD6C4\uAE30 ",
1423
- items.length,
1424
- "\uAC74"
1425
- ] })
1426
- ] }) : null,
1427
- /* @__PURE__ */ jsx2(StaggerGroup, { as: "ul", className: "rt-tpl-testimonials-star-list", children: items.map((item, i) => /* @__PURE__ */ jsx2(
1428
- StaggerItem,
1429
- {
1430
- as: "li",
1431
- className: "rt-tpl-testimonials-star-item",
1432
- children: /* @__PURE__ */ jsxs2("blockquote", { className: "rt-tpl-testimonials-star-quote", children: [
1433
- typeof item.rating === "number" ? /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-testimonials-star-head", children: [
1434
- /* @__PURE__ */ jsx2(StarRating, { rating: item.rating }),
1435
- /* @__PURE__ */ jsx2("span", { className: "rt-tpl-testimonials-star-value", children: item.rating.toFixed(1) })
1436
- ] }) : null,
1437
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-star-text", children: item.quote }),
1438
- /* @__PURE__ */ jsxs2("footer", { className: "rt-tpl-testimonials-star-footer", children: [
1439
- /* @__PURE__ */ jsx2("cite", { className: "rt-tpl-testimonials-star-author", children: item.author }),
1440
- item.context ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-testimonials-star-context", children: item.context }) : null,
1441
- /* @__PURE__ */ jsx2(StarCompactMeta, { item })
1442
- ] }),
1443
- item.reply ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-reply", children: item.reply }) : null
1444
- ] })
1445
- },
1446
- `${item.author}-${i}`
1447
- )) }),
1448
- disclaimer ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-testimonials-disclaimer", children: disclaimer }) : null
1449
- ] })
1450
- }
1451
- );
1452
- }
1453
- function StarCompactMeta({
1454
- item
1455
- }) {
1456
- const values = [item.source, item.visitedAt, item.item].filter(
1457
- (value) => Boolean(value)
1458
- );
1459
- if (values.length === 0) return null;
1460
- return /* @__PURE__ */ jsx2("span", { className: "rt-tpl-testimonials-star-meta", children: values.map((value) => /* @__PURE__ */ jsx2("span", { children: value }, value)) });
1461
- }
1462
- function TemplateTestimonials(section) {
1463
- if (section.variant === "quote-rail")
1464
- return TemplateTestimonialsQuoteRail(section);
1465
- if (section.variant === "star-compact")
1466
- return TemplateTestimonialsStarCompact(section);
1467
- return TemplateTestimonialsEditorialQuote(section);
1468
- }
1469
- function memberInitials(name) {
1470
- const parts = name.trim().split(/\s+/).filter(Boolean);
1471
- if (parts.length === 0) return "?";
1472
- const initials = parts.slice(0, 2).map((part) => part.at(0) ?? "").join("");
1473
- return initials || "?";
1474
- }
1475
- function TeamMemberPhoto({
1476
- member,
1477
- featured = false
1478
- }) {
1479
- if (member.photoSrc) {
1480
- return /* @__PURE__ */ jsx2(
1481
- "img",
1482
- {
1483
- className: featured ? "rt-tpl-team-photo rt-tpl-team-photo--featured" : "rt-tpl-team-photo",
1484
- src: member.photoSrc,
1485
- alt: member.photoAlt ?? "",
1486
- loading: "lazy"
1487
- }
1488
- );
1489
- }
1490
- return /* @__PURE__ */ jsx2(
1491
- "div",
1492
- {
1493
- className: featured ? "rt-tpl-team-initials rt-tpl-team-initials--featured" : "rt-tpl-team-initials",
1494
- "aria-hidden": "true",
1495
- children: memberInitials(member.name)
1496
- }
1497
- );
1498
- }
1499
- function TeamMemberBody({
1500
- member
1501
- }) {
1502
- return /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-team-body", children: [
1503
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-team-name", children: member.name }),
1504
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-team-title", children: member.title }),
1505
- member.specialties ? /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-team-specialties", "aria-label": `${member.name} \uC804\uBB38 \uBD84\uC57C`, children: member.specialties.map((specialty) => /* @__PURE__ */ jsx2("li", { children: specialty }, specialty)) }) : null,
1506
- member.credentials ? /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-team-credentials", children: member.credentials.map((credential) => /* @__PURE__ */ jsx2("li", { children: credential }, credential)) }) : null,
1507
- member.bio ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-team-bio", children: member.bio }) : null,
1508
- member.href ? /* @__PURE__ */ jsx2("a", { className: "rt-tpl-team-cta", href: member.href, children: member.ctaLabel ?? "\uD504\uB85C\uD544 \uBCF4\uAE30" }) : null
1509
- ] });
1510
- }
1511
- function TemplateTeamGrid(section) {
1512
- const { heading, description, members } = section.props;
1513
- return /* @__PURE__ */ jsx2(
1514
- "section",
1515
- {
1516
- "data-roottale-tpl": "team",
1517
- "data-variant": "grid",
1518
- id: section.id,
1519
- className: "rt-tpl-section rt-tpl-team",
1520
- style: sectionThemeStyle(section.theme),
1521
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1522
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1523
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
1524
- /* @__PURE__ */ jsx2(StaggerGroup, { as: "ul", className: "rt-tpl-team-grid", children: members.map((member) => /* @__PURE__ */ jsxs2(StaggerItem, { as: "li", className: "rt-tpl-team-card", children: [
1525
- /* @__PURE__ */ jsx2(TeamMemberPhoto, { member }),
1526
- /* @__PURE__ */ jsx2(TeamMemberBody, { member })
1527
- ] }, member.name)) })
1528
- ] })
1529
- }
1530
- );
1531
- }
1532
- function TemplateTeamSpotlight(section) {
1533
- const { heading, description, members } = section.props;
1534
- const [featured, ...rest] = members;
1535
- return /* @__PURE__ */ jsx2(
1536
- "section",
1537
- {
1538
- "data-roottale-tpl": "team",
1539
- "data-variant": "spotlight",
1540
- id: section.id,
1541
- className: "rt-tpl-section rt-tpl-team",
1542
- style: sectionThemeStyle(section.theme),
1543
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1544
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1545
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
1546
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-team-spotlight", children: [
1547
- featured ? /* @__PURE__ */ jsxs2("article", { className: "rt-tpl-team-card rt-tpl-team-card--featured", children: [
1548
- /* @__PURE__ */ jsx2(TeamMemberPhoto, { member: featured, featured: true }),
1549
- /* @__PURE__ */ jsx2(TeamMemberBody, { member: featured })
1550
- ] }) : null,
1551
- /* @__PURE__ */ jsx2(StaggerGroup, { as: "ul", className: "rt-tpl-team-spotlight-list", children: rest.map((member) => /* @__PURE__ */ jsxs2(StaggerItem, { as: "li", className: "rt-tpl-team-card", children: [
1552
- /* @__PURE__ */ jsx2(TeamMemberPhoto, { member }),
1553
- /* @__PURE__ */ jsx2(TeamMemberBody, { member })
1554
- ] }, member.name)) })
1555
- ] })
1556
- ] })
1557
- }
1558
- );
1559
- }
1560
- function TemplateTeamExpandingStage(section) {
1561
- const { heading, description, members } = section.props;
1562
- return /* @__PURE__ */ jsx2(
1563
- "section",
1564
- {
1565
- "data-roottale-tpl": "team",
1566
- "data-variant": "expanding-stage",
1567
- id: section.id,
1568
- className: "rt-tpl-section rt-tpl-team",
1569
- style: sectionThemeStyle(section.theme),
1570
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1571
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1572
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
1573
- /* @__PURE__ */ jsx2(TeamExpandingStageClient, { members })
1574
- ] })
1575
- }
1576
- );
1577
- }
1578
- function TemplateTeamRow(section) {
1579
- const { heading, description, members } = section.props;
1580
- return /* @__PURE__ */ jsx2(
1581
- "section",
1582
- {
1583
- "data-roottale-tpl": "team",
1584
- "data-variant": "row",
1585
- id: section.id,
1586
- className: "rt-tpl-section rt-tpl-team",
1587
- style: sectionThemeStyle(section.theme),
1588
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1589
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1590
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null,
1591
- /* @__PURE__ */ jsx2(StaggerGroup, { as: "ul", className: "rt-tpl-team-row-list", children: members.map((member) => /* @__PURE__ */ jsx2(StaggerItem, { as: "li", className: "rt-tpl-team-row-item", children: /* @__PURE__ */ jsxs2("article", { className: "rt-tpl-team-card rt-tpl-team-card--row", children: [
1592
- /* @__PURE__ */ jsx2(TeamMemberPhoto, { member }),
1593
- /* @__PURE__ */ jsx2(TeamMemberBody, { member })
1594
- ] }) }, member.name)) })
1595
- ] })
1596
- }
1597
- );
1598
- }
1599
- function TemplateTeam(section) {
1600
- if (section.variant === "expanding-stage")
1601
- return TemplateTeamExpandingStage(section);
1602
- if (section.variant === "row") return TemplateTeamRow(section);
1603
- if (section.variant === "spotlight") return TemplateTeamSpotlight(section);
1604
- return TemplateTeamGrid(section);
1605
- }
1606
- function telHref(phone) {
1607
- return `tel:${phone.replace(/[^\d+]/g, "")}`;
1608
- }
1609
- function ContactMap({ url }) {
1610
- if (isAllowedMapEmbedSrc(url) || isAllowedEmbedSrc(url)) {
1611
- return /* @__PURE__ */ jsx2("div", { className: "rt-tpl-contact-map", children: /* @__PURE__ */ jsx2(
1612
- "iframe",
1613
- {
1614
- src: url,
1615
- title: "\uC624\uC2DC\uB294\uAE38 \uC9C0\uB3C4",
1616
- loading: "lazy",
1617
- referrerPolicy: "no-referrer-when-downgrade"
1618
- }
1619
- ) });
1620
- }
1621
- 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" }) });
1622
- }
1623
- function ContactMapBlock({
1624
- map,
1625
- mapEmbedUrl
1626
- }) {
1627
- const embedUrl = map?.embedUrl ?? mapEmbedUrl;
1628
- const externalUrl = map?.externalUrl ?? embedUrl;
1629
- if (!embedUrl && !map?.facadeImageSrc && !externalUrl) return null;
1630
- const liveMap = Boolean(
1631
- embedUrl && (isAllowedMapEmbedSrc(embedUrl) || isAllowedEmbedSrc(embedUrl))
1632
- );
1633
- const clickToLoad = liveMap && embedUrl && (map?.mapLoad ?? "lazy") === "click";
1634
- return /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-contact-map-block", "data-provider": map?.provider, children: [
1635
- map?.facadeImageSrc && !liveMap ? /* @__PURE__ */ jsxs2("figure", { className: "rt-tpl-contact-map-facade", children: [
1636
- /* @__PURE__ */ jsx2(
1637
- "img",
1638
- {
1639
- src: map.facadeImageSrc,
1640
- alt: map.facadeImageAlt ?? "",
1641
- loading: "lazy"
1642
- }
1643
- ),
1644
- externalUrl ? /* @__PURE__ */ jsx2("figcaption", { children: /* @__PURE__ */ jsx2("a", { href: externalUrl, target: "_blank", rel: "noopener noreferrer", children: "\uC9C0\uB3C4 \uD06C\uAC8C \uBCF4\uAE30" }) }) : null
1645
- ] }) : null,
1646
- clickToLoad ? /* @__PURE__ */ jsx2(
1647
- ContactMapClickToLoad,
1648
- {
1649
- embedUrl,
1650
- externalUrl,
1651
- facadeImageSrc: map?.facadeImageSrc,
1652
- facadeImageAlt: map?.facadeImageAlt
1653
- }
1654
- ) : embedUrl ? /* @__PURE__ */ jsx2(ContactMap, { url: embedUrl }) : null
1655
- ] });
1656
- }
1657
- function ContactActions({
1658
- actions
1659
- }) {
1660
- if (!actions || actions.length === 0) return null;
1661
- return /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-contact-actions", children: actions.map((action) => {
1662
- const track = contactHrefTrack(action.href);
1663
- return /* @__PURE__ */ jsx2("li", { "data-kind": action.kind, children: /* @__PURE__ */ jsx2(
1664
- "a",
1665
- {
1666
- href: action.href,
1667
- "data-track": track,
1668
- "data-track-placement": track ? "contact_actions" : void 0,
1669
- children: action.label
1670
- }
1671
- ) }, `${action.label}-${action.href}`);
1672
- }) });
1673
- }
1674
- function TemplateContactChannelCards(section) {
1675
- const { heading, channels, map, mapEmbedUrl, actions } = section.props;
1676
- return /* @__PURE__ */ jsx2(
1677
- "section",
1678
- {
1679
- "data-roottale-tpl": "contact",
1680
- "data-variant": "channel-cards",
1681
- id: section.id,
1682
- className: "rt-tpl-section rt-tpl-contact",
1683
- style: sectionThemeStyle(section.theme),
1684
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1685
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1686
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-contact-channel-layout", children: [
1687
- /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-contact-channel-list", children: (channels ?? []).map((channel) => {
1688
- const content = /* @__PURE__ */ jsxs2(Fragment2, { children: [
1689
- /* @__PURE__ */ jsxs2("span", { className: "rt-tpl-contact-channel-label", children: [
1690
- channel.iconSrc ? /* @__PURE__ */ jsx2(
1691
- "img",
1692
- {
1693
- className: "rt-tpl-contact-channel-icon",
1694
- src: channel.iconSrc,
1695
- alt: channel.iconAlt ?? "",
1696
- loading: "lazy"
1697
- }
1698
- ) : null,
1699
- channel.label
1700
- ] }),
1701
- channel.value ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-contact-channel-value", children: channel.value }) : null,
1702
- channel.description ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-contact-channel-desc", children: channel.description }) : null,
1703
- channel.href && channel.actionLabel ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-contact-channel-action", children: channel.actionLabel }) : null
1704
- ] });
1705
- return /* @__PURE__ */ jsx2(
1706
- "li",
1707
- {
1708
- "data-kind": channel.kind,
1709
- children: channel.href ? /* @__PURE__ */ jsx2(
1710
- "a",
1711
- {
1712
- className: "rt-tpl-contact-channel-card",
1713
- href: channel.href,
1714
- "data-track": channel.href.startsWith("tel:") ? "cta_call" : channel.href.startsWith("mailto:") ? "email_click" : "cta_banner",
1715
- "data-track-placement": channel.href.startsWith("mailto:") ? "contact_channels" : void 0,
1716
- children: content
1717
- }
1718
- ) : /* @__PURE__ */ jsx2("div", { className: "rt-tpl-contact-channel-card", children: content })
1719
- },
1720
- `${channel.label}-${channel.value ?? channel.href ?? ""}`
1721
- );
1722
- }) }),
1723
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-contact-channel-side", children: [
1724
- /* @__PURE__ */ jsx2(ContactMapBlock, { map, mapEmbedUrl }),
1725
- /* @__PURE__ */ jsx2(ContactActions, { actions })
1726
- ] })
1727
- ] })
1728
- ] })
1729
- }
1730
- );
1731
- }
1732
- function ContactHoursSummary({
1733
- hours
1734
- }) {
1735
- if (!hours || hours.length === 0) return null;
1736
- return /* @__PURE__ */ jsxs2("table", { className: "rt-tpl-contact-visit-hours", children: [
1737
- /* @__PURE__ */ jsx2("caption", { className: "rt-tpl-sr-only", children: "\uC9C4\uB8CC\uC2DC\uAC04" }),
1738
- /* @__PURE__ */ jsx2("tbody", { children: hours.map((row) => /* @__PURE__ */ jsxs2("tr", { children: [
1739
- /* @__PURE__ */ jsx2("th", { scope: "row", children: row.day }),
1740
- /* @__PURE__ */ jsxs2("td", { children: [
1741
- /* @__PURE__ */ jsx2("span", { children: row.open }),
1742
- /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "-" }),
1743
- /* @__PURE__ */ jsx2("span", { children: row.close }),
1744
- row.note ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-contact-hours-note", children: row.note }) : null
1745
- ] })
1746
- ] }, `${row.day}-${row.open}-${row.close}`)) })
1747
- ] });
1748
- }
1749
- function TemplateContactVisitBand(section) {
1750
- const { heading, phone, address, hours, map, mapEmbedUrl, actions } = section.props;
1751
- const mapAction = actions?.find((action) => action.kind === "map") ?? actions?.[0];
1752
- const ctaAction = actions?.find((action) => action.kind === "reserve" || action.kind === "call") ?? actions?.[1] ?? mapAction;
1753
- const phoneAction = phone ? { label: phone, href: telHref(phone) } : void 0;
1754
- return /* @__PURE__ */ jsx2(
1755
- "section",
1756
- {
1757
- "data-roottale-tpl": "contact",
1758
- "data-variant": "visit-band",
1759
- id: section.id,
1760
- className: "rt-tpl-section rt-tpl-contact",
1761
- style: sectionThemeStyle(section.theme),
1762
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1763
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1764
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-contact-visit-band", children: [
1765
- /* @__PURE__ */ jsxs2("section", { className: "rt-tpl-contact-visit-panel", "aria-label": "\uC9C4\uB8CC\uC2DC\uAC04", children: [
1766
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-contact-visit-title", children: "\uC9C4\uB8CC\uC2DC\uAC04" }),
1767
- /* @__PURE__ */ jsx2(ContactHoursSummary, { hours })
1768
- ] }),
1769
- /* @__PURE__ */ jsxs2("section", { className: "rt-tpl-contact-visit-panel", "aria-label": "\uC624\uC2DC\uB294 \uAE38", children: [
1770
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-contact-visit-title", children: "\uC624\uC2DC\uB294 \uAE38" }),
1771
- /* @__PURE__ */ jsx2(ContactMapBlock, { map, mapEmbedUrl }),
1772
- address ? /* @__PURE__ */ jsx2("address", { className: "rt-tpl-contact-visit-address", children: address }) : null,
1773
- mapAction ? /* @__PURE__ */ jsx2(
1774
- "a",
1775
- {
1776
- className: "rt-tpl-contact-visit-link",
1777
- href: mapAction.href,
1778
- "data-track": contactHrefTrack(mapAction.href),
1779
- "data-track-placement": contactHrefTrack(mapAction.href) ? "visit" : void 0,
1780
- children: mapAction.label
1781
- }
1782
- ) : null
1783
- ] }),
1784
- /* @__PURE__ */ jsxs2("section", { className: "rt-tpl-contact-visit-panel", "aria-label": "\uC804\uD654", children: [
1785
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-contact-visit-title", children: "\uC804\uD654" }),
1786
- phoneAction ? /* @__PURE__ */ jsx2(
1787
- "a",
1788
- {
1789
- className: "rt-tpl-contact-visit-phone",
1790
- href: phoneAction.href,
1791
- "data-track": "cta_call",
1792
- children: phoneAction.label
1793
- }
1794
- ) : null,
1795
- hours ? /* @__PURE__ */ jsx2(ContactHoursSummary, { hours: hours.slice(0, 2) }) : null,
1796
- ctaAction ? /* @__PURE__ */ jsx2(
1797
- "a",
1798
- {
1799
- className: "rt-tpl-btn rt-tpl-btn--primary",
1800
- href: ctaAction.href,
1801
- "data-track": contactHrefTrack(ctaAction.href),
1802
- "data-track-placement": contactHrefTrack(ctaAction.href) ? "visit" : void 0,
1803
- children: ctaAction.label
1804
- }
1805
- ) : null
1806
- ] })
1807
- ] })
1808
- ] })
1809
- }
1810
- );
1811
- }
1812
- function TemplateContact(section) {
1813
- if (section.variant === "channel-cards")
1814
- return TemplateContactChannelCards(section);
1815
- if (section.variant === "visit-band") return TemplateContactVisitBand(section);
1816
- const { heading, form, phone, address, hours, map, mapEmbedUrl, actions } = section.props;
1817
- return /* @__PURE__ */ jsx2(
1818
- "section",
1819
- {
1820
- "data-roottale-tpl": "contact",
1821
- "data-variant": section.variant,
1822
- id: section.id,
1823
- className: "rt-tpl-section rt-tpl-contact",
1824
- style: sectionThemeStyle(section.theme),
1825
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container rt-tpl-contact-inner", children: [
1826
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-contact-info", children: [
1827
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1828
- phone ? /* @__PURE__ */ jsx2("a", { className: "rt-tpl-contact-phone", href: telHref(phone), "data-track": "cta_call", children: phone }) : null,
1829
- address ? /* @__PURE__ */ jsx2("address", { className: "rt-tpl-contact-address", children: address }) : null,
1830
- hours ? /* @__PURE__ */ jsxs2("table", { className: "rt-tpl-contact-hours", children: [
1831
- /* @__PURE__ */ jsx2("caption", { className: "rt-tpl-sr-only", children: "\uC9C4\uB8CC\uC2DC\uAC04" }),
1832
- /* @__PURE__ */ jsx2("tbody", { children: hours.map((row) => /* @__PURE__ */ jsxs2("tr", { children: [
1833
- /* @__PURE__ */ jsx2("th", { scope: "row", children: row.day }),
1834
- /* @__PURE__ */ jsxs2("td", { children: [
1835
- /* @__PURE__ */ jsx2("span", { children: row.open }),
1836
- /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "-" }),
1837
- /* @__PURE__ */ jsx2("span", { children: row.close }),
1838
- row.note ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-contact-hours-note", children: row.note }) : null
1839
- ] })
1840
- ] }, `${row.day}-${row.open}-${row.close}`)) })
1841
- ] }) : null,
1842
- /* @__PURE__ */ jsx2(ContactMapBlock, { map, mapEmbedUrl }),
1843
- /* @__PURE__ */ jsx2(ContactActions, { actions })
1844
- ] }),
1845
- form.enabled ? /* @__PURE__ */ jsx2("div", { className: "rt-tpl-contact-form", children: /* @__PURE__ */ jsx2(RootTaleLeadForm, { action: "/api/inquiry", vertical: form.vertical }) }) : null
1846
- ] })
1847
- }
1848
- );
1849
- }
1850
- function renderPracticeHeader({
1851
- eyebrow,
1852
- heading,
1853
- description
1854
- }) {
1855
- if (!eyebrow && !heading && !description) return null;
1856
- return /* @__PURE__ */ jsxs2("header", { className: "rt-tpl-practice-header", children: [
1857
- eyebrow ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-practice-eyebrow", children: eyebrow }) : null,
1858
- heading ? /* @__PURE__ */ jsx2("h2", { className: "rt-tpl-heading", children: heading }) : null,
1859
- description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-section-desc", children: description }) : null
1860
- ] });
1861
- }
1862
- function renderHoursBadges(badges) {
1863
- if (!badges) return null;
1864
- const values = [
1865
- badges.lunch,
1866
- badges.evening,
1867
- badges.closed,
1868
- ...badges.extra ?? []
1869
- ].filter((value) => Boolean(value));
1870
- if (values.length === 0) return null;
1871
- return /* @__PURE__ */ jsx2("span", { className: "rt-tpl-practice-badges", children: values.map((value) => /* @__PURE__ */ jsx2("span", { className: "rt-tpl-practice-badge", children: value }, value)) });
1872
- }
1873
- function renderPracticeDisclaimer(disclaimer) {
1874
- return disclaimer ? /* @__PURE__ */ jsx2("aside", { className: "rt-tpl-practice-disclaimer", children: disclaimer }) : null;
1875
- }
1876
- function TemplateHoursCompact(section) {
1877
- const { eyebrow, heading, description, rows, note, disclaimer } = section.props;
1878
- return /* @__PURE__ */ jsx2(
1879
- "section",
1880
- {
1881
- "data-roottale-tpl": "hours",
1882
- "data-variant": "compact",
1883
- id: section.id,
1884
- className: "rt-tpl-section rt-tpl-practice rt-tpl-hours",
1885
- style: sectionThemeStyle(section.theme),
1886
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1887
- renderPracticeHeader({ eyebrow, heading, description }),
1888
- /* @__PURE__ */ jsx2("dl", { className: "rt-tpl-hours-compact-list", children: rows.map((row) => /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hours-compact-row", children: [
1889
- /* @__PURE__ */ jsx2("dt", { className: "rt-tpl-hours-compact-day", children: row.label }),
1890
- /* @__PURE__ */ jsxs2("dd", { className: "rt-tpl-hours-compact-body", children: [
1891
- /* @__PURE__ */ jsx2("span", { className: "rt-tpl-hours-time", children: row.hours }),
1892
- row.lunchHours ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-hours-muted", children: row.lunchHours }) : null,
1893
- renderHoursBadges(row.badges),
1894
- row.note ? /* @__PURE__ */ jsx2("span", { className: "rt-tpl-hours-muted", children: row.note }) : null
1895
- ] })
1896
- ] }, row.day)) }),
1897
- note ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-practice-note", children: note }) : null,
1898
- renderPracticeDisclaimer(disclaimer)
1899
- ] })
1900
- }
1901
- );
1902
- }
1903
- function TemplateHours(section) {
1904
- if (section.variant === "compact") return TemplateHoursCompact(section);
1905
- const { eyebrow, heading, description, rows, note, disclaimer } = section.props;
1906
- return /* @__PURE__ */ jsx2(
1907
- "section",
1908
- {
1909
- "data-roottale-tpl": "hours",
1910
- "data-variant": section.variant,
1911
- id: section.id,
1912
- className: "rt-tpl-section rt-tpl-practice rt-tpl-hours",
1913
- style: sectionThemeStyle(section.theme),
1914
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1915
- renderPracticeHeader({ eyebrow, heading, description }),
1916
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-practice-table-wrap", children: /* @__PURE__ */ jsxs2("table", { className: "rt-tpl-practice-table", children: [
1917
- /* @__PURE__ */ jsx2("caption", { className: "rt-tpl-sr-only", children: "\uC601\uC5C5\uC2DC\uAC04" }),
1918
- /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
1919
- /* @__PURE__ */ jsx2("th", { scope: "col", children: "\uC694\uC77C" }),
1920
- /* @__PURE__ */ jsx2("th", { scope: "col", children: "\uC2DC\uAC04" }),
1921
- /* @__PURE__ */ jsx2("th", { scope: "col", children: "\uC810\uC2EC/\uD734\uAC8C" }),
1922
- /* @__PURE__ */ jsx2("th", { scope: "col", children: "\uC548\uB0B4" })
1923
- ] }) }),
1924
- /* @__PURE__ */ jsxs2("tbody", { children: [
1925
- rows.map((row) => /* @__PURE__ */ jsxs2("tr", { children: [
1926
- /* @__PURE__ */ jsx2("th", { scope: "row", className: "rt-tpl-practice-primary", children: row.label }),
1927
- /* @__PURE__ */ jsx2("td", { children: row.hours }),
1928
- /* @__PURE__ */ jsx2("td", { className: "rt-tpl-practice-muted", children: row.lunchHours ?? "\uBCC4\uB3C4 \uC548\uB0B4" }),
1929
- /* @__PURE__ */ jsxs2("td", { children: [
1930
- renderHoursBadges(row.badges),
1931
- row.note ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-practice-muted", children: row.note }) : null
1932
- ] })
1933
- ] }, row.day)),
1934
- note ? /* @__PURE__ */ jsx2("tr", { className: "rt-tpl-practice-table-note", children: /* @__PURE__ */ jsx2("td", { colSpan: 4, children: note }) }) : null
1935
- ] })
1936
- ] }) }),
1937
- renderPracticeDisclaimer(disclaimer)
1938
- ] })
1939
- }
1940
- );
1941
- }
1942
- function TemplatePricingCards(section) {
1943
- const { eyebrow, heading, description, groups, disclaimer } = section.props;
1944
- return /* @__PURE__ */ jsx2(
1945
- "section",
1946
- {
1947
- "data-roottale-tpl": "pricing",
1948
- "data-variant": "cards",
1949
- id: section.id,
1950
- className: "rt-tpl-section rt-tpl-practice rt-tpl-pricing",
1951
- style: sectionThemeStyle(section.theme),
1952
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1953
- renderPracticeHeader({ eyebrow, heading, description }),
1954
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-pricing-card-groups", children: groups.map((group) => /* @__PURE__ */ jsxs2("section", { className: "rt-tpl-pricing-card-group", children: [
1955
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-pricing-group-title", children: group.label }),
1956
- /* @__PURE__ */ jsx2("ul", { className: "rt-tpl-pricing-card-list", children: group.items.map((item) => /* @__PURE__ */ jsxs2("li", { className: "rt-tpl-pricing-card", children: [
1957
- /* @__PURE__ */ jsxs2("div", { children: [
1958
- /* @__PURE__ */ jsx2("h4", { className: "rt-tpl-pricing-name", children: item.name }),
1959
- item.description ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-pricing-desc", children: item.description }) : null
1960
- ] }),
1961
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-pricing-price", children: item.price }),
1962
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-pricing-condition", children: item.condition ?? "\uC790\uB8CC \uD655\uC778 \uD6C4 \uD655\uC815" })
1963
- ] }, `${group.label}-${item.name}`)) })
1964
- ] }, group.label)) }),
1965
- /* @__PURE__ */ jsx2("aside", { className: "rt-tpl-practice-disclaimer", children: disclaimer })
1966
- ] })
1967
- }
1968
- );
1969
- }
1970
- function TemplatePricing(section) {
1971
- if (section.variant === "cards") return TemplatePricingCards(section);
1972
- const { eyebrow, heading, description, groups, disclaimer } = section.props;
1973
- return /* @__PURE__ */ jsx2(
1974
- "section",
1975
- {
1976
- "data-roottale-tpl": "pricing",
1977
- "data-variant": section.variant,
1978
- id: section.id,
1979
- className: "rt-tpl-section rt-tpl-practice rt-tpl-pricing",
1980
- style: sectionThemeStyle(section.theme),
1981
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
1982
- renderPracticeHeader({ eyebrow, heading, description }),
1983
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-practice-table-wrap", children: /* @__PURE__ */ jsxs2("table", { className: "rt-tpl-practice-table", children: [
1984
- /* @__PURE__ */ jsx2("caption", { className: "rt-tpl-sr-only", children: "\uC694\uAE08 \uC548\uB0B4" }),
1985
- /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
1986
- /* @__PURE__ */ jsx2("th", { scope: "col", children: "\uD56D\uBAA9" }),
1987
- /* @__PURE__ */ jsx2("th", { scope: "col", children: "\uC124\uBA85" }),
1988
- /* @__PURE__ */ jsx2("th", { scope: "col", children: "\uAC00\uACA9" }),
1989
- /* @__PURE__ */ jsx2("th", { scope: "col", children: "\uC870\uAC74" })
1990
- ] }) }),
1991
- /* @__PURE__ */ jsx2("tbody", { children: groups.flatMap((group) => [
1992
- /* @__PURE__ */ jsx2("tr", { className: "rt-tpl-pricing-group-row", children: /* @__PURE__ */ jsx2("td", { colSpan: 4, children: group.label }) }, `${group.label}-group`),
1993
- ...group.items.map((item) => /* @__PURE__ */ jsxs2("tr", { children: [
1994
- /* @__PURE__ */ jsx2("th", { scope: "row", className: "rt-tpl-practice-primary", children: item.name }),
1995
- /* @__PURE__ */ jsx2("td", { className: "rt-tpl-practice-muted", children: item.description ?? "\uC0C1\uB2F4 \uD6C4 \uBC94\uC704 \uD655\uC778" }),
1996
- /* @__PURE__ */ jsx2("td", { className: "rt-tpl-pricing-price", children: item.price }),
1997
- /* @__PURE__ */ jsx2("td", { className: "rt-tpl-practice-muted", children: item.condition ?? "\uC790\uB8CC \uD655\uC778 \uD6C4 \uD655\uC815" })
1998
- ] }, `${group.label}-${item.name}`))
1999
- ]) })
2000
- ] }) }),
2001
- /* @__PURE__ */ jsx2("aside", { className: "rt-tpl-practice-disclaimer", children: disclaimer })
2002
- ] })
2003
- }
2004
- );
2005
- }
2006
- function TemplateProcess(section) {
2007
- const { eyebrow, heading, description, items, connector, disclaimer } = section.props;
2008
- if (section.variant === "timeline-marked") {
2009
- return /* @__PURE__ */ jsx2(
2010
- "section",
2011
- {
2012
- "data-roottale-tpl": "process",
2013
- "data-variant": "timeline-marked",
2014
- id: section.id,
2015
- className: "rt-tpl-section rt-tpl-practice rt-tpl-process",
2016
- style: sectionThemeStyle(section.theme),
2017
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
2018
- renderPracticeHeader({ eyebrow, heading, description }),
2019
- /* @__PURE__ */ jsx2("ol", { className: "rt-tpl-process-marked-list", children: items.map((item, index) => {
2020
- const status = item.status ?? "complete";
2021
- const mark = item.mark ?? (status === "complete" ? "check" : "dot");
2022
- return /* @__PURE__ */ jsx2(
2023
- "li",
2024
- {
2025
- className: "rt-tpl-process-marked-item",
2026
- "data-status": status,
2027
- children: /* @__PURE__ */ jsxs2("article", { className: "rt-tpl-process-marked-card", children: [
2028
- /* @__PURE__ */ jsx2("div", { className: "rt-tpl-process-marked-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2("span", { "data-mark": mark }) }),
2029
- /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-process-marked-body", children: [
2030
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-process-marked-step", children: item.eyebrow ?? `step ${String(index + 1).padStart(2, "0")}` }),
2031
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-process-title", children: item.title }),
2032
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-process-desc", children: item.description }),
2033
- item.duration || item.statusLabel ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-process-duration", children: item.statusLabel ?? item.duration }) : null
2034
- ] })
2035
- ] })
2036
- },
2037
- `${index}-${item.title}`
2038
- );
2039
- }) }),
2040
- renderPracticeDisclaimer(disclaimer)
2041
- ] })
2042
- }
2043
- );
2044
- }
2045
- return /* @__PURE__ */ jsx2(
2046
- "section",
2047
- {
2048
- "data-roottale-tpl": "process",
2049
- "data-variant": section.variant,
2050
- id: section.id,
2051
- className: "rt-tpl-section rt-tpl-practice rt-tpl-process",
2052
- style: sectionThemeStyle(section.theme),
2053
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
2054
- renderPracticeHeader({ eyebrow, heading, description }),
2055
- /* @__PURE__ */ jsx2(
2056
- "ol",
2057
- {
2058
- className: "rt-tpl-process-list",
2059
- "data-connector": connector ?? "line",
2060
- children: items.map((item, index) => /* @__PURE__ */ jsx2("li", { className: "rt-tpl-process-item", children: /* @__PURE__ */ jsxs2("article", { className: "rt-tpl-process-content", children: [
2061
- item.imageSrc ? /* @__PURE__ */ jsx2(
2062
- "img",
2063
- {
2064
- className: "rt-tpl-process-image",
2065
- src: item.imageSrc,
2066
- alt: item.imageAlt ?? "",
2067
- loading: "lazy"
2068
- }
2069
- ) : null,
2070
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-process-step", children: item.eyebrow ?? `step ${String(index + 1).padStart(2, "0")}` }),
2071
- /* @__PURE__ */ jsx2("h3", { className: "rt-tpl-process-title", children: item.title }),
2072
- /* @__PURE__ */ jsx2("p", { className: "rt-tpl-process-desc", children: item.description }),
2073
- item.duration ? /* @__PURE__ */ jsx2("p", { className: "rt-tpl-process-duration", children: item.duration }) : null
2074
- ] }) }, `${index}-${item.title}`))
2075
- }
2076
- ),
2077
- renderPracticeDisclaimer(disclaimer)
2078
- ] })
2079
- }
2080
- );
2081
- }
2082
- function TemplateBeforeAfterSideBySide(section) {
2083
- const { beforeImage, afterImage, beforeLabel, afterLabel } = section.props;
2084
- return /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-before-after-pair", children: [
2085
- /* @__PURE__ */ jsxs2("figure", { className: "rt-tpl-before-after-figure", children: [
2086
- /* @__PURE__ */ jsx2(
2087
- "img",
2088
- {
2089
- className: "rt-tpl-before-after-img",
2090
- src: beforeImage.src,
2091
- alt: beforeImage.alt,
2092
- loading: "lazy"
2093
- }
2094
- ),
2095
- /* @__PURE__ */ jsx2("figcaption", { className: "rt-tpl-before-after-caption", children: beforeLabel })
2096
- ] }),
2097
- /* @__PURE__ */ jsxs2("figure", { className: "rt-tpl-before-after-figure", children: [
2098
- /* @__PURE__ */ jsx2(
2099
- "img",
2100
- {
2101
- className: "rt-tpl-before-after-img",
2102
- src: afterImage.src,
2103
- alt: afterImage.alt,
2104
- loading: "lazy"
2105
- }
2106
- ),
2107
- /* @__PURE__ */ jsx2("figcaption", { className: "rt-tpl-before-after-caption", children: afterLabel })
2108
- ] })
2109
- ] });
2110
- }
2111
- function TemplateBeforeAfter(section) {
2112
- const {
2113
- heading,
2114
- description,
2115
- beforeImage,
2116
- afterImage,
2117
- beforeLabel,
2118
- afterLabel,
2119
- disclaimer
2120
- } = section.props;
2121
- return /* @__PURE__ */ jsx2(
2122
- "section",
2123
- {
2124
- "data-roottale-tpl": "before-after",
2125
- "data-variant": section.variant,
2126
- id: section.id,
2127
- className: "rt-tpl-section rt-tpl-practice rt-tpl-before-after",
2128
- style: sectionThemeStyle(section.theme),
2129
- children: /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-container", children: [
2130
- renderPracticeHeader({ heading, description }),
2131
- section.variant === "side-by-side" ? /* @__PURE__ */ jsx2(TemplateBeforeAfterSideBySide, { ...section }) : /* @__PURE__ */ jsx2(
2132
- BeforeAfterSlider,
2133
- {
2134
- beforeImage,
2135
- afterImage,
2136
- beforeLabel,
2137
- afterLabel
2138
- }
2139
- ),
2140
- renderPracticeDisclaimer(disclaimer)
2141
- ] })
2142
- }
2143
- );
2144
- }
2145
-
2146
- // src/templates/professional-sections.tsx
2147
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2148
- function SectionHeader({
2149
- heading,
2150
- description
2151
- }) {
2152
- if (!heading && !description) return null;
2153
- return /* @__PURE__ */ jsxs3("header", { className: "rt-tpl-client-section-header", children: [
2154
- heading ? /* @__PURE__ */ jsx3("h2", { className: "rt-tpl-heading", children: heading }) : null,
2155
- description ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-section-desc", children: description }) : null
2156
- ] });
2157
- }
2158
- function TagList({
2159
- tags,
2160
- label
2161
- }) {
2162
- if (!tags || tags.length === 0) return null;
2163
- return /* @__PURE__ */ jsx3("ul", { className: "rt-tpl-client-tags", "aria-label": label, children: tags.map((tag) => /* @__PURE__ */ jsx3("li", { children: tag }, tag)) });
2164
- }
2165
- function TemplateExpertiseCards(section) {
2166
- const { heading, description, items } = section.props;
2167
- return /* @__PURE__ */ jsx3(
2168
- "section",
2169
- {
2170
- "data-roottale-tpl": "expertise",
2171
- "data-variant": "cards",
2172
- id: section.id,
2173
- className: "rt-tpl-section rt-tpl-expertise",
2174
- style: sectionThemeStyle(section.theme),
2175
- children: /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-container", children: [
2176
- /* @__PURE__ */ jsx3(SectionHeader, { heading, description }),
2177
- /* @__PURE__ */ jsx3("ul", { className: "rt-tpl-expertise-card-grid", children: items.map((item) => /* @__PURE__ */ jsxs3("li", { className: "rt-tpl-expertise-card", children: [
2178
- item.imageSrc ? /* @__PURE__ */ jsx3(
2179
- "img",
2180
- {
2181
- className: "rt-tpl-expertise-card-img",
2182
- src: item.imageSrc,
2183
- alt: item.imageAlt ?? "",
2184
- loading: "lazy"
2185
- }
2186
- ) : null,
2187
- /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-expertise-card-body", children: [
2188
- item.kicker ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-expertise-kicker", children: item.kicker }) : null,
2189
- /* @__PURE__ */ jsx3("h3", { className: "rt-tpl-expertise-title", children: item.title }),
2190
- /* @__PURE__ */ jsx3("p", { className: "rt-tpl-expertise-body", children: item.body }),
2191
- /* @__PURE__ */ jsx3(TagList, { tags: item.tags, label: `${item.title} \uD0DC\uADF8` }),
2192
- item.href ? /* @__PURE__ */ jsx3("a", { className: "rt-tpl-expertise-cta", href: item.href, children: item.ctaLabel ?? "\uC790\uC138\uD788 \uBCF4\uAE30" }) : null
2193
- ] })
2194
- ] }, item.id)) })
2195
- ] })
2196
- }
2197
- );
2198
- }
2199
- function TemplateExpertise(section) {
2200
- const { heading, description, items } = section.props;
2201
- if (section.variant === "cards") return TemplateExpertiseCards(section);
2202
- return /* @__PURE__ */ jsx3(
2203
- "section",
2204
- {
2205
- "data-roottale-tpl": "expertise",
2206
- "data-variant": "tab-stage",
2207
- id: section.id,
2208
- className: "rt-tpl-section rt-tpl-expertise",
2209
- style: sectionThemeStyle(section.theme),
2210
- children: /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-container", children: [
2211
- /* @__PURE__ */ jsx3(SectionHeader, { heading, description }),
2212
- /* @__PURE__ */ jsx3(ExpertiseTabStage, { items })
2213
- ] })
2214
- }
2215
- );
2216
- }
2217
- function TemplateSpacesMosaic(section) {
2218
- const { heading, description, spaces, disclaimer } = section.props;
2219
- return /* @__PURE__ */ jsx3(
2220
- "section",
2221
- {
2222
- "data-roottale-tpl": "spaces",
2223
- "data-variant": "mosaic",
2224
- id: section.id,
2225
- className: "rt-tpl-section rt-tpl-spaces",
2226
- style: sectionThemeStyle(section.theme),
2227
- children: /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-container", children: [
2228
- /* @__PURE__ */ jsx3(SectionHeader, { heading, description }),
2229
- /* @__PURE__ */ jsx3("ul", { className: "rt-tpl-spaces-mosaic", children: spaces.map((space) => /* @__PURE__ */ jsxs3("li", { className: "rt-tpl-spaces-tile", children: [
2230
- /* @__PURE__ */ jsx3("img", { src: space.imageSrc, alt: space.imageAlt, loading: "lazy" }),
2231
- /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-spaces-tile-caption", children: [
2232
- space.kicker ? /* @__PURE__ */ jsx3("span", { className: "rt-tpl-spaces-kicker", children: space.kicker }) : null,
2233
- /* @__PURE__ */ jsx3("h3", { children: space.title ?? space.label }),
2234
- space.description ? /* @__PURE__ */ jsx3("p", { children: space.description }) : null,
2235
- /* @__PURE__ */ jsx3(TagList, { tags: space.tags, label: `${space.label} \uD0DC\uADF8` })
2236
- ] })
2237
- ] }, space.id)) }),
2238
- disclaimer ? /* @__PURE__ */ jsx3("aside", { className: "rt-tpl-client-disclaimer", children: disclaimer }) : null
2239
- ] })
2240
- }
2241
- );
2242
- }
2243
- function TemplateSpaces(section) {
2244
- const { heading, description, spaces, disclaimer } = section.props;
2245
- if (section.variant === "mosaic") return TemplateSpacesMosaic(section);
2246
- return /* @__PURE__ */ jsx3(
2247
- "section",
2248
- {
2249
- "data-roottale-tpl": "spaces",
2250
- "data-variant": "stage",
2251
- id: section.id,
2252
- className: "rt-tpl-section rt-tpl-spaces",
2253
- style: sectionThemeStyle(section.theme),
2254
- children: /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-container", children: [
2255
- /* @__PURE__ */ jsx3(SectionHeader, { heading, description }),
2256
- /* @__PURE__ */ jsx3(SpacesStage, { spaces }),
2257
- disclaimer ? /* @__PURE__ */ jsx3("aside", { className: "rt-tpl-client-disclaimer", children: disclaimer }) : null
2258
- ] })
2259
- }
2260
- );
2261
- }
2262
- function TemplateConcernsList(section) {
2263
- const { heading, description, regions, disclaimer } = section.props;
2264
- return /* @__PURE__ */ jsx3(
2265
- "section",
2266
- {
2267
- "data-roottale-tpl": "concerns",
2268
- "data-variant": "list",
2269
- id: section.id,
2270
- className: "rt-tpl-section rt-tpl-concerns",
2271
- style: sectionThemeStyle(section.theme),
2272
- children: /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-container", children: [
2273
- /* @__PURE__ */ jsx3(SectionHeader, { heading, description }),
2274
- /* @__PURE__ */ jsx3("ul", { className: "rt-tpl-concerns-list", children: regions.map((region) => /* @__PURE__ */ jsxs3("li", { className: "rt-tpl-concerns-card", children: [
2275
- /* @__PURE__ */ jsx3("p", { className: "rt-tpl-concerns-label", children: region.label }),
2276
- /* @__PURE__ */ jsx3("h3", { className: "rt-tpl-concerns-title", children: region.title }),
2277
- /* @__PURE__ */ jsx3("p", { className: "rt-tpl-concerns-desc", children: region.description }),
2278
- region.items ? /* @__PURE__ */ jsx3("ul", { className: "rt-tpl-concerns-items", children: region.items.map((item) => /* @__PURE__ */ jsx3("li", { children: item }, item)) }) : null,
2279
- region.href ? /* @__PURE__ */ jsx3("a", { className: "rt-tpl-concerns-cta", href: region.href, children: region.ctaLabel ?? "\uC790\uC138\uD788 \uBCF4\uAE30" }) : null
2280
- ] }, region.id)) }),
2281
- /* @__PURE__ */ jsx3("aside", { className: "rt-tpl-client-disclaimer", children: disclaimer })
2282
- ] })
2283
- }
2284
- );
2285
- }
2286
- function TemplateConcerns(section) {
2287
- const {
2288
- heading,
2289
- description,
2290
- figureImage,
2291
- figureAlt,
2292
- regions,
2293
- disclaimer
2294
- } = section.props;
2295
- if (section.variant === "list") return TemplateConcernsList(section);
2296
- return /* @__PURE__ */ jsx3(
2297
- "section",
2298
- {
2299
- "data-roottale-tpl": "concerns",
2300
- "data-variant": "figure-map",
2301
- id: section.id,
2302
- className: "rt-tpl-section rt-tpl-concerns",
2303
- style: sectionThemeStyle(section.theme),
2304
- children: /* @__PURE__ */ jsxs3("div", { className: "rt-tpl-container", children: [
2305
- /* @__PURE__ */ jsx3(SectionHeader, { heading, description }),
2306
- /* @__PURE__ */ jsx3(
2307
- ConcernsFigureMap,
2308
- {
2309
- figureImage: figureImage ?? "",
2310
- figureAlt: figureAlt ?? "",
2311
- regions
2312
- }
2313
- ),
2314
- /* @__PURE__ */ jsx3("aside", { className: "rt-tpl-client-disclaimer", children: disclaimer })
2315
- ] })
2316
- }
2317
- );
2318
- }
2319
-
2320
- // src/render-section-node.tsx
2321
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2322
- function warnSkippedCmsBound(sectionType, isDev) {
2323
- if (isDev()) {
2324
- console.warn(
2325
- `[cms-renderer-next] section \uB178\uB4DC sectionType=${sectionType} \uB294 apiKey \uCEE8\uD14D\uC2A4\uD2B8\uAC00 \uC5C6\uC5B4 \uB80C\uB354 skip`
2326
- );
2327
- }
2328
- }
2329
- function renderSectionNode(node, key, context) {
2330
- const attrs = node.attrs ?? {};
2331
- const input = {
2332
- type: typeof attrs.sectionType === "string" ? attrs.sectionType : "",
2333
- variant: attrs.variant ?? void 0,
2334
- theme: attrs.theme ?? void 0,
2335
- props: attrs.props ?? {}
2336
- };
2337
- const parsed = SectionSchema.safeParse(input);
2338
- if (!parsed.success) {
2339
- if (context.isDev()) {
2340
- console.warn(
2341
- `[cms-renderer-next] section \uB178\uB4DC parse \uC2E4\uD328 (sectionType=${input.type}) \u2014 \uB80C\uB354 skip:`,
2342
- parsed.error.issues
2343
- );
2344
- }
2345
- return null;
2346
- }
2347
- const section = parsed.data;
2348
- switch (section.type) {
2349
- case "hero":
2350
- return /* @__PURE__ */ jsx4(TemplateHero, { ...section }, key);
2351
- case "rich-text":
2352
- return /* @__PURE__ */ jsx4(TemplateRichText, { ...section }, key);
2353
- case "services":
2354
- return /* @__PURE__ */ jsx4(TemplateServices, { ...section }, key);
2355
- case "faq":
2356
- return /* @__PURE__ */ jsx4(TemplateFaq, { ...section }, key);
2357
- case "footer":
2358
- return /* @__PURE__ */ jsx4(TemplateFooter, { ...section }, key);
2359
- case "cta-banner":
2360
- return /* @__PURE__ */ jsx4(TemplateCtaBanner, { ...section }, key);
2361
- case "trust":
2362
- return /* @__PURE__ */ jsx4(TemplateTrust, { ...section }, key);
2363
- case "hours":
2364
- return /* @__PURE__ */ jsx4(TemplateHours, { ...section }, key);
2365
- case "pricing":
2366
- return /* @__PURE__ */ jsx4(TemplatePricing, { ...section }, key);
2367
- case "process":
2368
- return /* @__PURE__ */ jsx4(TemplateProcess, { ...section }, key);
2369
- case "before-after":
2370
- return /* @__PURE__ */ jsx4(TemplateBeforeAfter, { ...section }, key);
2371
- case "testimonials":
2372
- return /* @__PURE__ */ jsx4(TemplateTestimonials, { ...section }, key);
2373
- case "team":
2374
- return /* @__PURE__ */ jsx4(TemplateTeam, { ...section }, key);
2375
- case "expertise":
2376
- return /* @__PURE__ */ jsx4(TemplateExpertise, { ...section }, key);
2377
- case "spaces":
2378
- return /* @__PURE__ */ jsx4(TemplateSpaces, { ...section }, key);
2379
- case "concerns":
2380
- return /* @__PURE__ */ jsx4(TemplateConcerns, { ...section }, key);
2381
- case "contact":
2382
- if (!context.cms) {
2383
- warnSkippedCmsBound(section.type, context.isDev);
2384
- return null;
2385
- }
2386
- return /* @__PURE__ */ jsx4(TemplateContact, { ...section }, key);
2387
- case "blog-list": {
2388
- if (!context.cms) {
2389
- warnSkippedCmsBound(section.type, context.isDev);
2390
- return null;
2391
- }
2392
- const s = section;
2393
- const base = s.props.blogBasePath ?? "/blog";
2394
- return /* @__PURE__ */ jsx4(
2395
- "section",
2396
- {
2397
- "data-roottale-tpl": "blog-list",
2398
- "data-roottale-cms": "list",
2399
- id: s.id,
2400
- className: "rt-tpl-section rt-tpl-blog-list",
2401
- style: sectionThemeStyle(s.theme),
2402
- children: /* @__PURE__ */ jsxs4("div", { className: "rt-tpl-container", children: [
2403
- s.props.heading ? /* @__PURE__ */ jsx4("h2", { className: "rt-tpl-heading", children: s.props.heading }) : null,
2404
- context.renderBlogList({
2405
- apiKey: context.cms.apiKey,
2406
- baseUrl: context.cms.baseUrl,
2407
- limit: s.props.limit,
2408
- emptyMessage: s.props.emptyMessage,
2409
- postHref: (post) => `${base}/${post.slug}`
2410
- })
2411
- ] })
2412
- },
2413
- key
2414
- );
2415
- }
2416
- case "lead-form": {
2417
- if (!context.cms) {
2418
- warnSkippedCmsBound(section.type, context.isDev);
2419
- return null;
2420
- }
2421
- const s = section;
2422
- return /* @__PURE__ */ jsx4(
2423
- "section",
2424
- {
2425
- "data-roottale-tpl": "lead-form",
2426
- "data-roottale-cms": "lead-form",
2427
- id: s.id,
2428
- className: "rt-tpl-section rt-tpl-lead-form",
2429
- style: sectionThemeStyle(s.theme),
2430
- children: /* @__PURE__ */ jsx4("div", { className: "rt-tpl-container", children: /* @__PURE__ */ jsx4(
2431
- RootTaleLeadForm,
2432
- {
2433
- action: s.props.action,
2434
- vertical: s.props.vertical,
2435
- heading: s.props.heading,
2436
- description: s.props.description,
2437
- submitLabel: s.props.submitLabel
2438
- }
2439
- ) })
2440
- },
2441
- key
2442
- );
2443
- }
2444
- default:
2445
- if (context.isDev()) {
2446
- console.warn(
2447
- `[cms-renderer-next] section \uB178\uB4DC sectionType=${section.type} \uB294 renderNode \uC704\uC784 \uB300\uC0C1\uC774 \uC544\uB2D8(cms-bound/\uBBF8\uC9C0) \u2014 skip`
2448
- );
2449
- }
2450
- return null;
2451
- }
2452
- }
2453
-
2454
- // src/PostCard.tsx
2455
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2456
- function firstCategoryName(terms) {
2457
- if (!terms) return null;
2458
- const cat = terms.find((t2) => t2.taxonomy === "category");
2459
- return cat ? cat.name : null;
2460
- }
2461
- function RootTalePostCard(props) {
2462
- const { post, href = defaultHref, display } = props;
2463
- const showDate = display ? display.showDate : true;
2464
- const showAuthor = display ? display.showAuthor : false;
2465
- const showImage = display?.showImage !== false;
2466
- const showCategory = display?.showCategory !== false;
2467
- const authorName = post.authorName;
2468
- const publishedDate = showDate ? formatPublishedDate(post.publishedAt) : "";
2469
- const views = typeof post.viewCount === "number" ? post.viewCount : null;
2470
- const imageUrl = showImage ? post.featuredImageUrl : null;
2471
- const category = showCategory ? firstCategoryName(post.terms) : null;
2472
- return /* @__PURE__ */ jsx5("article", { "data-roottale-cms": "card", className: "rt-cms-card", children: /* @__PURE__ */ jsxs5("a", { className: "rt-cms-card-link", href: href(post), children: [
2473
- imageUrl ? (
2474
- // eslint-disable-next-line @next/next/no-img-element -- SSR string URL, framework-agnostic
2475
- /* @__PURE__ */ jsx5(
2476
- "img",
2477
- {
2478
- className: "rt-cms-card-image",
2479
- src: imageUrl,
2480
- alt: "",
2481
- loading: "lazy",
2482
- decoding: "async"
2483
- }
2484
- )
2485
- ) : null,
2486
- category ? /* @__PURE__ */ jsx5("span", { className: "rt-cms-card-category", children: category }) : null,
2487
- publishedDate || showAuthor && authorName || views !== null ? /* @__PURE__ */ jsxs5("p", { className: "rt-cms-meta", children: [
2488
- publishedDate ? /* @__PURE__ */ jsx5("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "date", children: publishedDate }) : null,
2489
- showAuthor && authorName ? /* @__PURE__ */ jsxs5("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
2490
- "\uC791\uC131\uC790 ",
2491
- authorName
2492
- ] }) : null,
2493
- views !== null ? /* @__PURE__ */ jsxs5("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "views", children: [
2494
- "\uC870\uD68C ",
2495
- views.toLocaleString("ko-KR")
2496
- ] }) : null
2497
- ] }) : null,
2498
- /* @__PURE__ */ jsx5("h2", { className: "rt-cms-title", children: post.title }),
2499
- post.excerpt ? /* @__PURE__ */ jsx5("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null,
2500
- /* @__PURE__ */ jsx5("span", { className: "rt-cms-card-action", "aria-hidden": "true", children: "\uC77D\uAE30" })
2501
- ] }) });
2502
- }
2503
- function defaultHref(post) {
2504
- return `/blog/${post.slug}`;
2505
- }
2506
- function formatPublishedDate(iso) {
2507
- const d = new Date(iso);
2508
- if (Number.isNaN(d.getTime())) return "";
2509
- return new Intl.DateTimeFormat("ko-KR", {
2510
- year: "numeric",
2511
- month: "2-digit",
2512
- day: "2-digit"
2513
- }).format(d);
2514
- }
2515
-
2516
- // src/TableOfContents.tsx
2517
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2518
- function RootTaleTableOfContents(props) {
2519
- const { entries, locale, title = t(locale, "tableOfContentsTitle") } = props;
2520
- if (entries.length === 0) return null;
2521
- return /* @__PURE__ */ jsx6("nav", { "data-roottale-cms": "toc", className: "rt-cms-toc", "aria-label": title, children: /* @__PURE__ */ jsxs6("details", { className: "rt-cms-toc-details", open: true, children: [
2522
- /* @__PURE__ */ jsxs6("summary", { className: "rt-cms-toc-summary", children: [
2523
- title ? /* @__PURE__ */ jsx6("span", { className: "rt-cms-toc-title", children: title }) : null,
2524
- /* @__PURE__ */ jsx6("span", { className: "rt-cms-toc-toggle", "aria-hidden": "true" })
2525
- ] }),
2526
- /* @__PURE__ */ jsx6("ol", { className: "rt-cms-toc-list", children: entries.map((entry) => /* @__PURE__ */ jsx6(
2527
- "li",
2528
- {
2529
- className: `rt-cms-toc-item rt-cms-toc-level-${entry.level}`,
2530
- children: /* @__PURE__ */ jsx6("a", { href: `#${entry.id}`, children: entry.text })
2531
- },
2532
- entry.id
2533
- )) })
2534
- ] }) });
2535
- }
2536
-
2537
- // ../ui-react/dist/theme/index.js
2538
- import { jsx as _jsx } from "react/jsx-runtime";
2539
- function themeToCssVars(theme) {
2540
- return {
2541
- ...theme.colors?.primary ? { "--rt-color-primary": theme.colors.primary } : {},
2542
- ...theme.colors?.primaryForeground ? { "--rt-color-primary-foreground": theme.colors.primaryForeground } : {},
2543
- ...theme.colors?.secondary ? { "--rt-color-secondary": theme.colors.secondary } : {},
2544
- ...theme.colors?.secondaryForeground ? { "--rt-color-secondary-foreground": theme.colors.secondaryForeground } : {},
2545
- ...theme.colors?.accent ? { "--rt-color-accent": theme.colors.accent } : {},
2546
- ...theme.colors?.accentForeground ? { "--rt-color-accent-foreground": theme.colors.accentForeground } : {},
2547
- ...theme.colors?.background ? { "--rt-color-background": theme.colors.background } : {},
2548
- ...theme.colors?.foreground ? { "--rt-color-foreground": theme.colors.foreground } : {},
2549
- ...theme.colors?.muted ? { "--rt-color-muted": theme.colors.muted } : {},
2550
- ...theme.colors?.mutedForeground ? { "--rt-color-muted-foreground": theme.colors.mutedForeground } : {},
2551
- ...theme.colors?.destructive ? { "--rt-color-destructive": theme.colors.destructive } : {},
2552
- ...theme.colors?.destructiveForeground ? { "--rt-color-destructive-foreground": theme.colors.destructiveForeground } : {},
2553
- ...theme.colors?.border ? { "--rt-color-border": theme.colors.border } : {},
2554
- ...theme.colors?.input ? { "--rt-color-input": theme.colors.input } : {},
2555
- ...theme.colors?.ring ? { "--rt-color-ring": theme.colors.ring } : {},
2556
- ...theme.fonts?.body ? { "--rt-font-body": theme.fonts.body } : {},
2557
- ...theme.fonts?.display ? { "--rt-font-display": theme.fonts.display } : {},
2558
- ...theme.radius?.sm ? { "--rt-radius-sm": theme.radius.sm } : {},
2559
- ...theme.radius?.md ? { "--rt-radius-md": theme.radius.md } : {},
2560
- ...theme.radius?.lg ? { "--rt-radius-lg": theme.radius.lg } : {},
2561
- ...theme.radius?.xl ? { "--rt-radius-xl": theme.radius.xl } : {}
2562
- };
2563
- }
2564
-
2565
- // src/theme-css-vars.ts
2566
- function themeToCssVars2(theme) {
2567
- if (!theme) return null;
2568
- const vars = themeToCssVars(theme);
2569
- if (Object.keys(vars).length === 0) return null;
2570
- return vars;
2571
- }
2572
-
2573
- // src/toc.ts
2574
- function tocLevel(rawLevel) {
2575
- if (rawLevel < 1 || rawLevel > 4) return null;
2576
- if (rawLevel < 3) return 2;
2577
- return rawLevel === 3 ? 3 : 4;
2578
- }
2579
- function headingToId(text) {
2580
- return text.trim().toLowerCase().replace(/[^\p{L}\p{N}\s-]/gu, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
2581
- }
2582
- function textOf(node) {
2583
- if (typeof node.text === "string") return node.text;
2584
- if (!Array.isArray(node.content)) return "";
2585
- return node.content.map(textOf).join("");
2586
- }
2587
- function extractToc(doc) {
2588
- const root = doc;
2589
- const content = Array.isArray(root.content) ? root.content : [];
2590
- const entries = [];
2591
- const idCounts = /* @__PURE__ */ new Map();
2592
- for (const node of content) {
2593
- if (node?.type !== "heading") continue;
2594
- const rawLevel = Number(node.attrs?.level ?? 2);
2595
- const level = tocLevel(rawLevel);
2596
- if (level === null) continue;
2597
- const text = textOf(node).trim();
2598
- if (!text) continue;
2599
- const base = headingToId(text) || "heading";
2600
- const count = idCounts.get(base) ?? 0;
2601
- const id = count === 0 ? base : `${base}-${count}`;
2602
- idCounts.set(base, count + 1);
2603
- entries.push({ level, text, id });
2604
- }
2605
- return entries;
2606
- }
2607
- function attachHeadingIds(doc, entries) {
2608
- const root = doc;
2609
- const content = Array.isArray(root.content) ? root.content : [];
2610
- let cursor = 0;
2611
- const nextContent = content.map((node) => {
2612
- if (node?.type !== "heading") return node;
2613
- const rawLevel = Number(node.attrs?.level ?? 2);
2614
- if (rawLevel < 1 || rawLevel > 4) return node;
2615
- if (!textOf(node).trim()) return node;
2616
- const entry = entries[cursor++];
2617
- if (!entry) return node;
2618
- return {
2619
- ...node,
2620
- attrs: { ...node.attrs ?? {}, id: entry.id }
2621
- };
2622
- });
2623
- return { ...root, content: nextContent };
2624
- }
2625
-
2626
- // src/FloatingCta.tsx
2627
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2628
- function RootTaleFloatingCta(props) {
2629
- const { buttons, position = "bottom-right" } = props;
2630
- if (!buttons || buttons.length === 0) return null;
2631
- return /* @__PURE__ */ jsx7(
2632
- "div",
2633
- {
2634
- "data-roottale-cms": "floating-cta",
2635
- className: `rt-cms-floating-cta rt-cms-floating-cta--${position}`,
2636
- children: buttons.map((btn, idx) => {
2637
- const isExternal = btn.type === "kakao" || btn.type === "custom";
2638
- return /* @__PURE__ */ jsxs7(
2639
- "a",
2640
- {
2641
- href: btn.href,
2642
- className: `rt-cms-floating-cta__btn rt-cms-floating-cta__btn--${btn.type}`,
2643
- target: isExternal ? "_blank" : void 0,
2644
- rel: isExternal ? "noopener noreferrer" : void 0,
2645
- children: [
2646
- /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", className: "rt-cms-floating-cta__icon", children: btn.icon ?? defaultIcon(btn.type) }),
2647
- /* @__PURE__ */ jsx7("span", { className: "rt-cms-floating-cta__label", children: btn.label })
2648
- ]
2649
- },
2650
- `${btn.type}-${idx}`
2651
- );
2652
- })
2653
- }
2654
- );
2655
- }
2656
- function defaultIcon(type) {
2657
- switch (type) {
2658
- case "phone":
2659
- return "\u260E";
2660
- case "contact":
2661
- return "\u2709";
2662
- case "kakao":
2663
- return "\u{1F4AC}";
2664
- case "custom":
2665
- return "\u2192";
2666
- }
2667
- }
2668
-
2669
- // src/block-to-react.tsx
2670
- import {
2671
- applyBlockBindings,
2672
- createFieldBindingResolver,
2673
- sanitizeHtml
2674
- } from "@roottale/cms-core";
2675
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2676
- function isString(value) {
2677
- return typeof value === "string";
2678
- }
2679
- function htmlContent(html) {
2680
- return { __html: sanitizeHtml(html) };
2681
- }
2682
- function renderInner(blocks) {
2683
- return blocks.map((b, i) => renderBlock(b, i));
2684
- }
2685
- function renderBlock(block, key = 0) {
2686
- const dataBlockId = block._id;
2687
- switch (block.name) {
2688
- case "core/paragraph": {
2689
- const text = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
2690
- return /* @__PURE__ */ jsx8(
2691
- "p",
2692
- {
2693
- "data-block-id": dataBlockId,
2694
- dangerouslySetInnerHTML: htmlContent(text)
2695
- },
2696
- key
2697
- );
2698
- }
2699
- case "core/heading": {
2700
- const levelRaw = block.attributes.level;
2701
- const level = typeof levelRaw === "number" && levelRaw >= 2 && levelRaw <= 4 ? levelRaw : 2;
2702
- const text = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
2703
- const props = {
2704
- "data-block-id": dataBlockId,
2705
- dangerouslySetInnerHTML: htmlContent(text)
2706
- };
2707
- if (level === 2) return /* @__PURE__ */ jsx8("h2", { ...props }, key);
2708
- if (level === 3) return /* @__PURE__ */ jsx8("h3", { ...props }, key);
2709
- return /* @__PURE__ */ jsx8("h4", { ...props }, key);
2710
- }
2711
- case "core/image": {
2712
- const src = isString(block.attributes.url) ? block.attributes.url : "";
2713
- const alt = isString(block.attributes.alt) ? block.attributes.alt : "";
2714
- const caption = isString(block.attributes.caption) ? block.attributes.caption : null;
2715
- return /* @__PURE__ */ jsxs8("figure", { "data-block-id": dataBlockId, children: [
2716
- /* @__PURE__ */ jsx8("img", { src, alt, loading: "lazy" }),
2717
- caption && /* @__PURE__ */ jsx8("figcaption", { children: caption })
2718
- ] }, key);
2719
- }
2720
- case "core/list": {
2721
- const ordered = block.attributes.ordered === true;
2722
- const items = (block.innerBlocks ?? []).map(
2723
- (item, i) => item.rawHtml ? /* @__PURE__ */ jsx8(
2724
- "li",
2725
- {
2726
- dangerouslySetInnerHTML: htmlContent(item.rawHtml)
2727
- },
2728
- i
2729
- ) : /* @__PURE__ */ jsx8("li", { children: renderInner(item.innerBlocks ?? []) }, i)
2730
- );
2731
- return ordered ? /* @__PURE__ */ jsx8("ol", { "data-block-id": dataBlockId, children: items }, key) : /* @__PURE__ */ jsx8("ul", { "data-block-id": dataBlockId, children: items }, key);
2732
- }
2733
- case "core/quote": {
2734
- const inner = renderInner(block.innerBlocks ?? []);
2735
- const citation = isString(block.attributes.citation) ? block.attributes.citation : null;
2736
- return /* @__PURE__ */ jsxs8("blockquote", { "data-block-id": dataBlockId, children: [
2737
- inner,
2738
- citation && /* @__PURE__ */ jsx8("cite", { children: citation })
2739
- ] }, key);
2740
- }
2741
- case "core/code": {
2742
- const code = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
2743
- const lang = isString(block.attributes.language) ? block.attributes.language : void 0;
2744
- return /* @__PURE__ */ jsx8(
2745
- "pre",
2746
- {
2747
- "data-block-id": dataBlockId,
2748
- "data-language": lang,
2749
- children: /* @__PURE__ */ jsx8("code", { children: code })
2750
- },
2751
- key
2752
- );
2753
- }
2754
- case "core/columns": {
2755
- return /* @__PURE__ */ jsx8(
2756
- "div",
2757
- {
2758
- className: "rt-columns",
2759
- "data-block-id": dataBlockId,
2760
- children: renderInner(block.innerBlocks ?? [])
2761
- },
2762
- key
2763
- );
2764
- }
2765
- case "core/separator":
2766
- return /* @__PURE__ */ jsx8("hr", { "data-block-id": dataBlockId }, key);
2767
- case "core/spacer": {
2768
- const heightRaw = block.attributes.height;
2769
- const height = isString(heightRaw) ? heightRaw : "32px";
2770
- return /* @__PURE__ */ jsx8(
2771
- "div",
2772
- {
2773
- className: "rt-spacer",
2774
- "data-block-id": dataBlockId,
2775
- style: { height }
2776
- },
2777
- key
2778
- );
2779
- }
2780
- case "core/group": {
2781
- return /* @__PURE__ */ jsx8(
2782
- "div",
2783
- {
2784
- className: "rt-group",
2785
- "data-block-id": dataBlockId,
2786
- children: renderInner(block.innerBlocks ?? [])
2787
- },
2788
- key
2789
- );
2790
- }
2791
- default: {
2792
- const rawHtml = block.rawHtml;
2793
- return /* @__PURE__ */ jsx8(
2794
- "div",
2795
- {
2796
- className: "rt-unknown-block",
2797
- "data-block-id": dataBlockId,
2798
- "data-block-name": block.name,
2799
- "data-rawhtml-suppressed": rawHtml ? "true" : void 0,
2800
- children: renderInner(block.innerBlocks ?? [])
2801
- },
2802
- key
2803
- );
2804
- }
2805
- }
2806
- }
2807
- function renderBlocks(blocks) {
2808
- return blocks.map((b, i) => renderBlock(b, i));
2809
- }
2810
- function renderBoundBlocks(blocks, opts = {}) {
2811
- const resolver = opts.resolver ?? createFieldBindingResolver(opts.fields);
2812
- return renderBlocks(applyBlockBindings(blocks, resolver));
2813
- }
2814
-
2815
- // src/server.tsx
2816
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2817
- function authorImageRadiusCss(radius) {
2818
- if (radius === "circle") return "999px";
2819
- if (radius === "rounded") return "0.875rem";
2820
- return "0";
2821
- }
2822
- function RootTaleThemeProvider(props) {
2823
- const style = themeToCssVars2(props.theme ?? null);
2824
- if (!style) return /* @__PURE__ */ jsx9(Fragment3, { children: props.children });
2825
- return /* @__PURE__ */ jsx9("div", { "data-roottale-cms": "theme-root", "data-rt-theme": "", style, children: props.children });
2826
- }
2827
- async function RootTaleBlogList(props) {
2828
- const {
2829
- apiKey,
2830
- baseUrl,
2831
- limit,
2832
- type = "post",
2833
- collection,
2834
- collections,
2835
- excludeCollections = false,
2836
- locale,
2837
- emptyMessage = t(locale, "blogListEmpty"),
2838
- showCategoryFilter = false,
2839
- activeCategory,
2840
- categoryHref = defaultCategoryHref,
2841
- allCategoriesLabel = t(locale, "allCategoriesLabel"),
2842
- author,
2843
- theme: themeProp
2844
- } = props;
2845
- if (collection && excludeCollections) {
2846
- throw new Error(
2847
- "RootTaleBlogList: `collection` \uACFC `excludeCollections` \uB97C \uB3D9\uC2DC\uC5D0 \uC904 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uD3EC\uC9C0\uD2F0\uBE0C/\uB124\uAC70\uD2F0\uBE0C \uC2A4\uCF54\uD504\uB294 \uBC30\uD0C0\uC801\uC785\uB2C8\uB2E4."
2848
- );
2849
- }
2850
- if (excludeCollections && !collections) {
2851
- throw new Error(
2852
- "RootTaleBlogList: `excludeCollections` \uB294 `collections` \uC640 \uD568\uAED8 \uC918\uC57C \uD569\uB2C8\uB2E4."
2853
- );
2854
- }
2855
- const postHref = props.postHref ?? (collections ? makeCollectionPostHref(collections) : defaultPostHref);
2856
- const [page, themeStyle, blogSettings] = await Promise.all([
2857
- fetchPosts({
2858
- apiKey,
2859
- baseUrl,
2860
- limit,
2861
- type,
2862
- ...author ? { author } : {},
2863
- // blog-list-collection-scope.md §2②(잔여 배선) — 포지티브 스코프도 서버가
2864
- // 이미 그 섹션 글만 걸러 fetch 하게 한다(limit 이 스트림 밖 글에 낭비되지
2865
- // 않음). 아래 `postsForCollection` 클라이언트 필터는 방어선으로 유지
2866
- // (판정 시맨틱 = `resolvePostCollection` 동일 정의).
2867
- ...collection && collections ? { collectionKey: collection } : {},
2868
- // blog-list-collection-scope.md §2② — 서버(api-core)가 이미 스트림 글을
2869
- // 걸러 fetch 하게 한다(limit 이 스트림 글에 낭비되지 않음). 아래
2870
- // `postsNotInAnyCollection` 클라이언트 필터는 방어선으로 유지.
2871
- ...excludeCollections && collections ? { excludeCollections: true } : {},
2872
- // ADR-0052 A안 (W4-6 PR C1) — 미지정 시 서버가 사이트 기본 locale 반환
2873
- // (하위호환, 기존 소비자 diff 0).
2874
- ...locale ? { locale } : {}
2875
- }),
2876
- resolveThemeStyle({ themeProp, apiKey, baseUrl }),
2877
- fetchBlogSettings({ apiKey, baseUrl }).catch(() => DEFAULT_BLOG_SETTINGS)
2878
- ]);
2879
- const items = collection && collections ? postsForCollection(page.items, collections, collection) : excludeCollections && collections ? postsNotInAnyCollection(page.items, collections) : page.items;
2880
- if (items.length === 0) {
2881
- return /* @__PURE__ */ jsx9("div", { "data-roottale-cms": "list", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx9("p", { className: "rt-cms-empty", children: emptyMessage }) });
2882
- }
2883
- const categories = showCategoryFilter ? collectCategories(items) : [];
2884
- const visiblePosts = showCategoryFilter ? filterPostsByCategory(items, activeCategory) : items;
2885
- return /* @__PURE__ */ jsxs9("div", { "data-roottale-cms": "list", style: themeStyle ?? void 0, children: [
2886
- showCategoryFilter && categories.length > 0 ? /* @__PURE__ */ jsxs9("nav", { className: "rt-cms-filter", "aria-label": "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130", children: [
2887
- /* @__PURE__ */ jsx9(
2888
- "a",
2889
- {
2890
- className: "rt-cms-filter-chip",
2891
- href: categoryHref(null),
2892
- "data-active": !activeCategory ? "" : void 0,
2893
- "aria-current": !activeCategory ? "true" : void 0,
2894
- children: allCategoriesLabel
2895
- }
2896
- ),
2897
- categories.map((c) => /* @__PURE__ */ jsx9(
2898
- "a",
2899
- {
2900
- className: "rt-cms-filter-chip",
2901
- href: categoryHref(c.slug),
2902
- "data-active": activeCategory === c.slug ? "" : void 0,
2903
- "aria-current": activeCategory === c.slug ? "true" : void 0,
2904
- children: c.name
2905
- },
2906
- c.slug
2907
- ))
2908
- ] }) : null,
2909
- visiblePosts.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "rt-cms-empty", children: emptyMessage }) : /* @__PURE__ */ jsx9("ul", { className: "rt-cms-list", children: visiblePosts.map((post) => /* @__PURE__ */ jsx9("li", { className: "rt-cms-list-item", children: /* @__PURE__ */ jsx9(
2910
- RootTalePostCard,
2911
- {
2912
- post,
2913
- href: postHref,
2914
- display: resolvePostDisplay(post, blogSettings)
2915
- }
2916
- ) }, post.id)) })
2917
- ] });
2918
- }
2919
- async function RootTaleBlogCategories(props) {
2920
- const {
2921
- apiKey,
2922
- baseUrl,
2923
- limit,
2924
- collection,
2925
- collections,
2926
- categoryHref = (slug) => defaultCategoryHref(slug),
2927
- locale,
2928
- emptyMessage = t(locale, "blogCategoriesEmpty"),
2929
- theme: themeProp
2930
- } = props;
2931
- const [page, themeStyle] = await Promise.all([
2932
- fetchPosts({ apiKey, baseUrl, limit, type: "post", ...locale ? { locale } : {} }),
2933
- resolveThemeStyle({ themeProp, apiKey, baseUrl })
2934
- ]);
2935
- const categories = collection && collections ? collectCollectionCategories(page.items, collections, collection) : collectCategoriesWithCounts(page.items);
2936
- return /* @__PURE__ */ jsx9(
2937
- "nav",
2938
- {
2939
- "data-roottale-cms": "categories",
2940
- className: "rt-cms-categories",
2941
- "aria-label": "\uBE14\uB85C\uADF8 \uCE74\uD14C\uACE0\uB9AC",
2942
- style: themeStyle ?? void 0,
2943
- children: categories.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "rt-cms-empty", children: emptyMessage }) : /* @__PURE__ */ jsx9("ul", { className: "rt-cms-category-list", children: categories.map((category) => /* @__PURE__ */ jsx9("li", { className: "rt-cms-category-list-item", children: /* @__PURE__ */ jsxs9(
2944
- "a",
2945
- {
2946
- className: "rt-cms-category-link",
2947
- href: categoryHref(category.slug),
2948
- children: [
2949
- /* @__PURE__ */ jsx9("span", { className: "rt-cms-category-name", children: category.name }),
2950
- /* @__PURE__ */ jsx9("span", { className: "rt-cms-category-count", children: category.count })
2951
- ]
2952
- }
2953
- ) }, category.slug)) })
2954
- }
2955
- );
2956
- }
2957
- async function RootTaleBlogPost(props) {
2958
- const {
2959
- apiKey,
2960
- slugOrId,
2961
- baseUrl,
2962
- notFoundElement,
2963
- showTitle = true,
2964
- showTableOfContents,
2965
- tableOfContentsTitle,
2966
- relatedPostsCount = 0,
2967
- locale,
2968
- relatedPostsTitle = t(locale, "relatedPostsTitle"),
2969
- collections,
2970
- showFieldFacts = false,
2971
- theme: themeProp,
2972
- authorHref = defaultAuthorHref,
2973
- breadcrumb
2974
- } = props;
2975
- const [post, themeStyle, blogSettings] = await Promise.all([
2976
- fetchPost({ apiKey, slugOrId, baseUrl, ...locale ? { locale } : {} }),
2977
- resolveThemeStyle({ themeProp, apiKey, baseUrl }),
2978
- // 사이트 기본 표시 설정 — 실패해도 렌더는 진행 (안전 기본값).
2979
- fetchBlogSettings({ apiKey, baseUrl }).catch(() => DEFAULT_BLOG_SETTINGS)
2980
- ]);
2981
- if (!post) {
2982
- return notFoundElement ?? /* @__PURE__ */ jsx9("div", { "data-roottale-cms": "post-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx9("p", { className: "rt-cms-empty", children: t(locale, "postNotFound") }) });
2983
- }
2984
- const display = resolvePostDisplay(post, blogSettings, {
2985
- showTableOfContents,
2986
- tableOfContentsTitle
2987
- });
2988
- const toc = display.showTableOfContents ? extractToc(post.bodyJson) : [];
2989
- const renderDoc = toc.length > 0 ? attachHeadingIds(post.bodyJson, toc) : post.bodyJson;
2990
- let related = [];
2991
- if (relatedPostsCount > 0) {
2992
- try {
2993
- const candidates = await fetchPosts({
2994
- apiKey,
2995
- baseUrl,
2996
- type: "post",
2997
- limit: 30,
2998
- // ADR-0052 A안 (W4-6 PR C1) — 같은 언어판 후보로만 좁힌다(ko 글이 en
2999
- // 페이지 관련 글에 섞이는 걸 방지).
3000
- ...locale ? { locale } : {}
3001
- });
3002
- related = selectRelatedPosts(post, candidates.items, relatedPostsCount);
3003
- } catch {
3004
- }
3005
- }
3006
- const relatedHref = props.postHref ?? (collections ? makeCollectionPostHref(collections) : defaultPostHref);
3007
- const authorName = post.authorName;
3008
- const authorImageUrl = post.authorImageUrl;
3009
- const postAuthorBio = post.authorBio;
3010
- const authorSlug = post.authorSlug;
3011
- const views = typeof post.viewCount === "number" ? post.viewCount : null;
3012
- const publishedDate = display.showDate ? formatPublishedDate2(post.publishedAt) : "";
3013
- const showTopAuthor = display.showAuthor && Boolean(authorName);
3014
- const displayAuthorName = authorName ?? display.authorProfileName;
3015
- const authorBio = postAuthorBio ?? display.authorProfileBio ?? display.authorCardDescription;
3016
- const authorImageUrlForCard = authorImageUrl ?? display.authorProfileImageUrl;
3017
- const authorImageAlt = `${displayAuthorName ?? ""} \uD504\uB85C\uD544 \uC0AC\uC9C4`.trim();
3018
- const authorImageStyle = {
3019
- borderRadius: authorImageRadiusCss(display.authorProfileImageRadius),
3020
- objectPosition: `${display.authorProfileImagePositionX}% ${display.authorProfileImagePositionY}%`
3021
- };
3022
- const showAuthorCard = display.showAuthorCard && Boolean(displayAuthorName);
3023
- return /* @__PURE__ */ jsxs9(
3024
- "article",
3025
- {
3026
- "data-roottale-cms": "post",
3027
- className: "rt-cms-article",
3028
- style: themeStyle ?? void 0,
3029
- children: [
3030
- renderBreadcrumb(post, collections, relatedHref, breadcrumb),
3031
- /* @__PURE__ */ jsxs9("header", { className: "rt-cms-post-header", children: [
3032
- showTitle ? /* @__PURE__ */ jsx9("h1", { className: "rt-cms-title", children: post.title }) : null,
3033
- post.excerpt ? /* @__PURE__ */ jsx9("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null,
3034
- publishedDate || showTopAuthor || views !== null ? /* @__PURE__ */ jsxs9("p", { className: "rt-cms-meta", children: [
3035
- publishedDate ? /* @__PURE__ */ jsx9(
3036
- "time",
3037
- {
3038
- dateTime: post.publishedAt ?? void 0,
3039
- className: "rt-cms-meta-item",
3040
- "data-rt-cms-meta": "date",
3041
- children: publishedDate
3042
- }
3043
- ) : null,
3044
- showTopAuthor ? /* @__PURE__ */ jsxs9("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
3045
- "\uC791\uC131\uC790",
3046
- " ",
3047
- authorSlug ? /* @__PURE__ */ jsx9("a", { className: "rt-cms-author-link", href: authorHref(authorSlug), children: authorName }) : authorName
3048
- ] }) : null,
3049
- views !== null ? /* @__PURE__ */ jsxs9("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "views", children: [
3050
- "\uC870\uD68C ",
3051
- views.toLocaleString("ko-KR")
3052
- ] }) : null
3053
- ] }) : null
3054
- ] }),
3055
- renderArchiveRelated(post.archiveRelated, collections),
3056
- showFieldFacts ? renderFieldFacts(post) : null,
3057
- (() => {
3058
- const tocEl = toc.length > 0 ? /* @__PURE__ */ jsx9(RootTaleTableOfContents, { entries: toc, title: display.tocTitle }) : null;
3059
- const bodyEl = /* @__PURE__ */ jsx9("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: /* @__PURE__ */ jsx9(
3060
- RenderTiptap,
3061
- {
3062
- doc: renderDoc,
3063
- fields: post.fields,
3064
- apiKey,
3065
- baseUrl
3066
- }
3067
- ) });
3068
- if (display.tocPosition === "sidebar" && tocEl) {
3069
- return /* @__PURE__ */ jsxs9("div", { className: "rt-cms-layout rt-cms-layout--toc-side", children: [
3070
- bodyEl,
3071
- /* @__PURE__ */ jsx9("aside", { className: "rt-cms-toc-side", children: tocEl })
3072
- ] });
3073
- }
3074
- return /* @__PURE__ */ jsxs9(Fragment3, { children: [
3075
- tocEl,
3076
- bodyEl
3077
- ] });
3078
- })(),
3079
- showAuthorCard && displayAuthorName ? /* @__PURE__ */ jsxs9("section", { className: "rt-cms-author-card", "aria-label": "\uC791\uC131\uC790", children: [
3080
- authorImageUrlForCard ? /* @__PURE__ */ jsx9(
3081
- "img",
3082
- {
3083
- className: "rt-cms-author-card__image",
3084
- src: authorImageUrlForCard,
3085
- alt: authorImageAlt,
3086
- loading: "lazy",
3087
- style: authorImageStyle
3088
- }
3089
- ) : /* @__PURE__ */ jsx9("div", { className: "rt-cms-author-card__avatar", "aria-hidden": "true", children: authorInitials(displayAuthorName) }),
3090
- /* @__PURE__ */ jsxs9("div", { className: "rt-cms-author-card__body", children: [
3091
- /* @__PURE__ */ jsx9("p", { className: "rt-cms-author-card__eyebrow", children: display.authorCardEyebrow }),
3092
- /* @__PURE__ */ jsx9("p", { className: "rt-cms-author-card__name", children: authorSlug ? /* @__PURE__ */ jsx9("a", { className: "rt-cms-author-link", href: authorHref(authorSlug), children: displayAuthorName }) : displayAuthorName }),
3093
- authorBio ? /* @__PURE__ */ jsx9("p", { className: "rt-cms-author-card__description", children: authorBio }) : null
3094
- ] })
3095
- ] }) : null,
3096
- renderRelated(related, relatedHref, relatedPostsTitle),
3097
- renderPostCta(blogSettings.postCta),
3098
- renderFaqJsonLd(post.bodyJson)
3099
- ]
3100
- }
3101
- );
3102
- }
3103
- function renderBreadcrumb(post, collections, postHref, options) {
3104
- if (!options) return null;
3105
- const {
3106
- siteUrl,
3107
- homeLabel = "\uD648",
3108
- homeHref = "/",
3109
- listLabel = "\uBE14\uB85C\uADF8",
3110
- showCategory = true,
3111
- categoryHref = defaultCategoryHref
3112
- } = options;
3113
- const listHref = options.listHref ?? (collections ? resolvePostCollection(post, collections)?.basePath || "/blog" : "/blog");
3114
- const categoryTerm = showCategory ? post.terms.find((t2) => t2.taxonomy === "category") : void 0;
3115
- const crumbs = [
3116
- { label: homeLabel, href: homeHref },
3117
- { label: listLabel, href: listHref }
3118
- ];
3119
- if (categoryTerm) {
3120
- crumbs.push({ label: categoryTerm.name, href: categoryHref(categoryTerm.slug) });
3121
- }
3122
- crumbs.push({ label: post.title, href: postHref(post) });
3123
- const jsonLd = siteUrl ? breadcrumbSchema(
3124
- crumbs.map((c) => ({ name: c.label, url: absoluteUrl(siteUrl, c.href) }))
3125
- ) : null;
3126
- return /* @__PURE__ */ jsxs9(Fragment3, { children: [
3127
- /* @__PURE__ */ jsx9("nav", { "aria-label": "\uBE0C\uB808\uB4DC\uD06C\uB7FC", className: "rt-cms-breadcrumb", children: /* @__PURE__ */ jsx9("ol", { children: crumbs.map(
3128
- (c, i) => i === crumbs.length - 1 ? /* @__PURE__ */ jsx9("li", { "aria-current": "page", children: c.label }, i) : /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsx9("a", { href: c.href, children: c.label }) }, i)
3129
- ) }) }),
3130
- jsonLd ? /* @__PURE__ */ jsx9(
3131
- "script",
3132
- {
3133
- type: "application/ld+json",
3134
- dangerouslySetInnerHTML: { __html: jsonLdJson(jsonLd) }
3135
- }
3136
- ) : null
3137
- ] });
3138
- }
3139
- function absoluteUrl(siteUrl, path) {
3140
- const normalized = path.startsWith("/") ? path : `/${path}`;
3141
- return `${trimSlash(siteUrl)}${normalized}`;
3142
- }
3143
- function renderArchiveRelated(groups, collections) {
3144
- const visible = groups.filter((group) => group.items.length > 0);
3145
- if (visible.length === 0) return null;
3146
- return /* @__PURE__ */ jsx9("aside", { className: "rt-archive-related", "aria-label": "\uC5F0\uAD00 \uC815\uBCF4", children: visible.map((group) => /* @__PURE__ */ jsxs9("section", { className: "rt-archive-related__group", children: [
3147
- /* @__PURE__ */ jsx9("h2", { className: "rt-archive-related__title", children: archiveGroupTitle(group) }),
3148
- /* @__PURE__ */ jsx9("ul", { className: "rt-archive-related__list", children: group.items.map((item) => /* @__PURE__ */ jsx9("li", { className: "rt-archive-related__item", children: /* @__PURE__ */ jsxs9(
3149
- "a",
3150
- {
3151
- className: "rt-archive-related__link",
3152
- href: archivePostHref(item.collectionKey, item.slug, collections),
3153
- children: [
3154
- /* @__PURE__ */ jsx9("span", { className: "rt-archive-related__item-title", children: item.title }),
3155
- item.excerpt ? /* @__PURE__ */ jsx9("span", { className: "rt-archive-related__item-excerpt", children: item.excerpt }) : null
3156
- ]
3157
- }
3158
- ) }, item.id)) })
3159
- ] }, group.collectionKey)) });
3160
- }
3161
- var FIELD_FACT_TYPES = /* @__PURE__ */ new Set([
3162
- "text",
3163
- "textarea",
3164
- "email",
3165
- "url",
3166
- "select",
3167
- "radio",
3168
- "button_group",
3169
- "number",
3170
- "range"
3171
- ]);
3172
- function fieldFactValue(raw, meta) {
3173
- if (raw === null || raw === void 0) return null;
3174
- if (typeof raw === "number") return raw.toLocaleString("ko-KR");
3175
- if (typeof raw !== "string" || raw.trim() === "") return null;
3176
- if (meta.choices) {
3177
- const choice = meta.choices.find((c) => c.value === raw);
3178
- return choice ? choice.label : raw;
3179
- }
3180
- return raw;
3181
- }
3182
- function renderFieldFacts(post) {
3183
- const fields = post.fields;
3184
- if (!fields) return null;
3185
- const rows = post.fieldsMeta.filter((meta) => FIELD_FACT_TYPES.has(meta.type)).flatMap((meta) => {
3186
- const value = fieldFactValue(fields[meta.name], meta);
3187
- return value === null ? [] : [{ meta, value }];
3188
- });
3189
- if (rows.length === 0) return null;
3190
- return /* @__PURE__ */ jsx9("aside", { className: "rt-archive-facts", "aria-label": "\uC0C1\uC138 \uC815\uBCF4", children: /* @__PURE__ */ jsx9("dl", { className: "rt-archive-facts__list", children: rows.map(({ meta, value }) => /* @__PURE__ */ jsxs9("div", { className: "rt-archive-facts__row", children: [
3191
- /* @__PURE__ */ jsx9("dt", { className: "rt-archive-facts__label", children: meta.label }),
3192
- /* @__PURE__ */ jsx9(
3193
- "dd",
3194
- {
3195
- className: meta.type === "textarea" ? "rt-archive-facts__value rt-archive-facts__value--multiline" : "rt-archive-facts__value",
3196
- children: value
3197
- }
3198
- )
3199
- ] }, meta.name)) }) });
3200
- }
3201
- function archiveGroupTitle(group) {
3202
- if (group.collectionKey === "conditions") {
3203
- return `\uC774 \uC99D\uC0C1\uACFC \uAD00\uB828\uB41C \uC9C8\uD658 ${group.items.length}`;
3204
- }
3205
- if (group.collectionKey === "treatments") {
3206
- return `\uAD00\uB828 \uCE58\uB8CC\uBC95 ${group.items.length}`;
3207
- }
3208
- if (group.collectionKey === "symptoms") {
3209
- return `\uAD00\uB828 \uC99D\uC0C1 ${group.items.length}`;
3210
- }
3211
- return `${group.label} ${group.items.length}`;
3212
- }
3213
- function archivePostHref(collectionKey, slug, collections) {
3214
- const collection = collections?.find((item) => item.key === collectionKey);
3215
- const basePath = collection?.basePath || defaultArchiveBasePath(collectionKey);
3216
- const trimmedBase = basePath.replace(/\/+$/, "");
3217
- if (collection?.detail === false) return trimmedBase;
3218
- return `${trimmedBase}/${slug}`;
3219
- }
3220
- function defaultArchiveBasePath(collectionKey) {
3221
- if (collectionKey === "symptoms") return "/symptoms";
3222
- if (collectionKey === "conditions") return "/conditions";
3223
- if (collectionKey === "treatments") return "/treatments";
3224
- return "/blog";
3225
- }
3226
- function renderPostCta(cta) {
3227
- if (!cta) return null;
3228
- const href = cta.buttonHref.trim();
3229
- const safe = href.startsWith("/") || href.startsWith("#") || /^(https?:|mailto:|tel:)/i.test(href);
3230
- if (!safe) return null;
3231
- const external = /^https?:/i.test(href);
3232
- return /* @__PURE__ */ jsxs9("aside", { "data-roottale-cms": "post-cta", className: "rt-cms-post-cta", children: [
3233
- cta.title ? /* @__PURE__ */ jsx9("p", { className: "rt-cms-post-cta__title", children: cta.title }) : null,
3234
- cta.description ? /* @__PURE__ */ jsx9("p", { className: "rt-cms-post-cta__desc", children: cta.description }) : null,
3235
- /* @__PURE__ */ jsx9(
3236
- "a",
3237
- {
3238
- className: "rt-cms-post-cta__btn",
3239
- href,
3240
- target: external ? "_blank" : void 0,
3241
- rel: external ? "noopener noreferrer" : void 0,
3242
- children: cta.buttonLabel
3243
- }
3244
- )
3245
- ] });
3246
- }
3247
- function renderRelated(posts, href, title) {
3248
- if (posts.length === 0) return null;
3249
- return /* @__PURE__ */ jsxs9("nav", { "data-roottale-cms": "related", className: "rt-cms-related", "aria-label": title, children: [
3250
- /* @__PURE__ */ jsx9("h2", { className: "rt-cms-related-title", children: title }),
3251
- /* @__PURE__ */ jsx9("ul", { className: "rt-cms-related-list", children: posts.map((p) => /* @__PURE__ */ jsx9("li", { className: "rt-cms-related-item", children: /* @__PURE__ */ jsxs9("a", { className: "rt-cms-related-link", href: href(p), children: [
3252
- p.featuredImageUrl ? /* @__PURE__ */ jsx9(
3253
- "img",
3254
- {
3255
- className: "rt-cms-related-thumb",
3256
- src: p.featuredImageUrl,
3257
- alt: "",
3258
- loading: "lazy"
3259
- }
3260
- ) : null,
3261
- /* @__PURE__ */ jsx9("span", { className: "rt-cms-related-post-title", children: p.title })
3262
- ] }) }, p.id)) })
3263
- ] });
3264
- }
3265
- function renderFaqJsonLd(doc) {
3266
- const ld = faqPageJsonLd(extractFaqEntries(doc));
3267
- if (!ld) return null;
3268
- return /* @__PURE__ */ jsx9(
3269
- "script",
3270
- {
3271
- type: "application/ld+json",
3272
- dangerouslySetInnerHTML: { __html: jsonLdJson(ld) }
3273
- }
3274
- );
3275
- }
3276
- function RootTaleFaqJsonLd({
3277
- doc
3278
- }) {
3279
- return renderFaqJsonLd(doc);
3280
- }
3281
- async function RootTalePage(props) {
3282
- const {
3283
- apiKey,
3284
- slugOrId,
3285
- baseUrl,
3286
- notFoundElement,
3287
- showTitle = true,
3288
- theme: themeProp,
3289
- locale
3290
- } = props;
3291
- const [post, themeStyle] = await Promise.all([
3292
- fetchPost({ apiKey, slugOrId, baseUrl, ...locale ? { locale } : {} }),
3293
- resolveThemeStyle({ themeProp, apiKey, baseUrl })
3294
- ]);
3295
- if (!post) {
3296
- return notFoundElement ?? /* @__PURE__ */ jsx9("div", { "data-roottale-cms": "page-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx9("p", { className: "rt-cms-empty", children: t(locale, "pageNotFound") }) });
3297
- }
3298
- return /* @__PURE__ */ jsxs9(
3299
- "article",
3300
- {
3301
- "data-roottale-cms": "page",
3302
- className: "rt-cms-article",
3303
- style: themeStyle ?? void 0,
3304
- children: [
3305
- showTitle ? /* @__PURE__ */ jsx9("header", { className: "rt-cms-post-header", children: /* @__PURE__ */ jsx9("h1", { className: "rt-cms-title", children: post.title }) }) : null,
3306
- /* @__PURE__ */ jsx9("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: /* @__PURE__ */ jsx9(
3307
- RenderTiptap,
3308
- {
3309
- doc: post.bodyJson,
3310
- fields: post.fields,
3311
- apiKey,
3312
- baseUrl
3313
- }
3314
- ) })
3315
- ]
3316
- }
3317
- );
3318
- }
3319
- function authorInitials(name) {
3320
- const trimmed = name.trim();
3321
- if (!trimmed) return "";
3322
- const parts = trimmed.split(/\s+/).filter(Boolean);
3323
- if (parts.length >= 2) {
3324
- return `${parts[0]?.[0] ?? ""}${parts[1]?.[0] ?? ""}`.toUpperCase();
3325
- }
3326
- return [...trimmed].slice(0, 2).join("").toUpperCase();
3327
- }
3328
- async function resolveThemeStyle(input) {
3329
- const { themeProp, apiKey, baseUrl } = input;
3330
- if (themeProp === null) return null;
3331
- if (themeProp !== void 0) return themeToCssVars2(themeProp);
3332
- try {
3333
- const fetched = await fetchTheme({ apiKey, baseUrl });
3334
- return themeToCssVars2(fetched);
3335
- } catch {
3336
- return null;
3337
- }
3338
- }
3339
- function defaultPostHref(post) {
3340
- return `/blog/${post.slug}`;
3341
- }
3342
- function defaultAuthorHref(slug) {
3343
- return `/blog/author/${slug}`;
3344
- }
3345
- function makeCollectionPostHref(collections) {
3346
- return (post) => {
3347
- const path = resolvePostPath(post, collections);
3348
- if (path) return path;
3349
- const collection = resolvePostCollection(post, collections);
3350
- if (collection && collection.detail === false && collection.basePath) {
3351
- return collection.basePath;
3352
- }
3353
- return defaultPostHref(post);
3354
- };
3355
- }
3356
- function formatPublishedDate2(iso) {
3357
- const d = new Date(iso);
3358
- if (Number.isNaN(d.getTime())) return "";
3359
- return new Intl.DateTimeFormat("ko-KR", {
3360
- year: "numeric",
3361
- month: "2-digit",
3362
- day: "2-digit"
3363
- }).format(d);
3364
- }
3365
- function RenderTiptap({
3366
- doc,
3367
- fields,
3368
- apiKey,
3369
- baseUrl
3370
- }) {
3371
- const rawContent = doc.content;
3372
- const content = Array.isArray(rawContent) ? rawContent : [];
3373
- const hasToc = content.some((n) => n?.type === "tableOfContents");
3374
- const docRecord = doc;
3375
- const entries = hasToc ? extractToc(docRecord) : [];
3376
- const renderDoc = hasToc && entries.length > 0 ? attachHeadingIds(docRecord, entries) : docRecord;
3377
- const nodes = Array.isArray(renderDoc.content) ? renderDoc.content : content;
3378
- const cms = apiKey ? { apiKey, baseUrl } : null;
3379
- const context = {
3380
- fields: fields ?? null,
3381
- section: {
3382
- cms,
3383
- isDev: isDevEnv,
3384
- renderBlogList: (props) => /* @__PURE__ */ jsx9(RootTaleBlogList, { ...props })
3385
- }
3386
- };
3387
- return /* @__PURE__ */ jsx9(Fragment3, { children: nodes.map(
3388
- (node, i) => node?.type === "tableOfContents" ? /* @__PURE__ */ jsx9(
3389
- RootTaleTableOfContents,
3390
- {
3391
- entries,
3392
- title: typeof node.attrs?.title === "string" ? node.attrs.title : "\uBAA9\uCC28"
3393
- },
3394
- i
3395
- ) : renderNode(node, i, context)
3396
- ) });
3397
- }
3398
- function boundContentText(node, fields) {
3399
- return bindingTextValue(
3400
- boundFieldValue(node.attrs?.bindings, "content", fields)
3401
- );
3402
- }
3403
- function isSafeHref(value) {
3404
- if (typeof value !== "string") return false;
3405
- const v = value.trim();
3406
- if (v.length === 0) return false;
3407
- if (v.startsWith("/") || v.startsWith("#") || v.startsWith("?")) return true;
3408
- return /^(https?:|mailto:|tel:)/i.test(v);
3409
- }
3410
- function alignStyle(node) {
3411
- const align = node.attrs?.textAlign;
3412
- if (typeof align !== "string" || align === "" || align === "left") return void 0;
3413
- if (align === "center" || align === "right" || align === "justify") {
3414
- return { textAlign: align };
3415
- }
3416
- return void 0;
3417
- }
3418
- function tableCellSpans(node) {
3419
- const colspan = Number(node.attrs?.colspan);
3420
- const rowspan = Number(node.attrs?.rowspan);
3421
- return {
3422
- colSpan: Number.isFinite(colspan) && colspan > 1 ? colspan : void 0,
3423
- rowSpan: Number.isFinite(rowspan) && rowspan > 1 ? rowspan : void 0
3424
- };
3425
- }
3426
- function isDevEnv() {
3427
- const env = globalThis.process?.env ?? {};
3428
- return env.NODE_ENV !== "production";
3429
- }
3430
- function renderNode(node, key, context = {
3431
- fields: null,
3432
- section: {
3433
- cms: null,
3434
- isDev: isDevEnv,
3435
- renderBlogList: (props) => /* @__PURE__ */ jsx9(RootTaleBlogList, { ...props })
3436
- }
3437
- }) {
3438
- if (!node || typeof node !== "object") return null;
3439
- const children = Array.isArray(node.content) ? node.content.map((child, i) => renderNode(child, i, context)) : void 0;
3440
- switch (node.type) {
3441
- case "paragraph": {
3442
- const bound = boundContentText(node, context.fields);
3443
- return /* @__PURE__ */ jsx9("p", { style: alignStyle(node), children: bound ?? children }, key);
3444
- }
3445
- case "heading": {
3446
- const rawLevel = Number(node.attrs?.level ?? 2);
3447
- const level = Math.min(Math.max(Number.isFinite(rawLevel) ? rawLevel : 2, 2), 4);
3448
- const idAttr = node.attrs?.id;
3449
- const id = typeof idAttr === "string" && idAttr.length > 0 ? idAttr : void 0;
3450
- const style = alignStyle(node);
3451
- const inner = boundContentText(node, context.fields) ?? children;
3452
- if (level === 2) return /* @__PURE__ */ jsx9("h2", { id, style, children: inner }, key);
3453
- if (level === 3) return /* @__PURE__ */ jsx9("h3", { id, style, children: inner }, key);
3454
- return /* @__PURE__ */ jsx9("h4", { id, style, children: inner }, key);
3455
- }
3456
- case "bulletList":
3457
- return /* @__PURE__ */ jsx9("ul", { children }, key);
3458
- case "orderedList":
3459
- return /* @__PURE__ */ jsx9("ol", { children }, key);
3460
- case "listItem":
3461
- return /* @__PURE__ */ jsx9("li", { children }, key);
3462
- case "blockquote":
3463
- return /* @__PURE__ */ jsx9("blockquote", { children }, key);
3464
- case "codeBlock":
3465
- return /* @__PURE__ */ jsx9("pre", { children: /* @__PURE__ */ jsx9("code", { children }) }, key);
3466
- case "horizontalRule":
3467
- return /* @__PURE__ */ jsx9("hr", {}, key);
3468
- case "hardBreak":
3469
- return /* @__PURE__ */ jsx9("br", {}, key);
3470
- case "image": {
3471
- const boundSrc = bindingSrcValue(
3472
- boundFieldValue(node.attrs?.bindings, "src", context.fields)
3473
- );
3474
- const src = boundSrc ?? node.attrs?.src;
3475
- if (typeof src !== "string" || src.length === 0) return null;
3476
- const alt = typeof node.attrs?.alt === "string" ? node.attrs.alt : "";
3477
- const title = typeof node.attrs?.title === "string" ? node.attrs.title : void 0;
3478
- const width = typeof node.attrs?.width === "number" && node.attrs.width > 0 ? node.attrs.width : void 0;
3479
- const height = typeof node.attrs?.height === "number" && node.attrs.height > 0 ? node.attrs.height : void 0;
3480
- return /* @__PURE__ */ jsx9(
3481
- "img",
3482
- {
3483
- src,
3484
- alt,
3485
- title,
3486
- width,
3487
- height,
3488
- loading: "lazy"
3489
- },
3490
- key
3491
- );
3492
- }
3493
- case "columns":
3494
- return /* @__PURE__ */ jsx9("div", { className: "rt-columns", children }, key);
3495
- case "column":
3496
- return /* @__PURE__ */ jsx9("div", { className: "rt-column", children }, key);
3497
- case "table":
3498
- return /* @__PURE__ */ jsx9("div", { className: "rt-table-wrap", children: /* @__PURE__ */ jsx9("table", { className: "rt-table", children: /* @__PURE__ */ jsx9("tbody", { children }) }) }, key);
3499
- case "tableRow":
3500
- return /* @__PURE__ */ jsx9("tr", { children }, key);
3501
- case "tableHeader": {
3502
- const { colSpan, rowSpan } = tableCellSpans(node);
3503
- return /* @__PURE__ */ jsx9("th", { colSpan, rowSpan, children }, key);
3504
- }
3505
- case "tableCell": {
3506
- const { colSpan, rowSpan } = tableCellSpans(node);
3507
- return /* @__PURE__ */ jsx9("td", { colSpan, rowSpan, children }, key);
3508
- }
3509
- case "embed":
3510
- return renderEmbed(node, key);
3511
- case "faq":
3512
- return /* @__PURE__ */ jsx9("div", { "data-roottale-cms": "faq", className: "rt-cms-faq", children }, key);
3513
- case "faqItem":
3514
- return /* @__PURE__ */ jsx9("details", { className: "rt-cms-faq-item", children }, key);
3515
- case "faqQuestion":
3516
- return /* @__PURE__ */ jsx9("summary", { className: "rt-cms-faq-q", children }, key);
3517
- case "faqAnswer":
3518
- return /* @__PURE__ */ jsx9("div", { className: "rt-cms-faq-a", children }, key);
3519
- case "tableOfContents":
3520
- return null;
3521
- case "section":
3522
- return renderSectionNode(node, key, context.section);
3523
- case "text":
3524
- return renderText(node, key);
3525
- default:
3526
- return children ? /* @__PURE__ */ jsx9("span", { children }, key) : null;
3527
- }
3528
- }
3529
- function renderEmbed(node, key) {
3530
- const src = node.attrs?.src;
3531
- if (isAllowedEmbedSrc2(src)) {
3532
- const provider = typeof node.attrs?.provider === "string" ? node.attrs.provider : void 0;
3533
- return /* @__PURE__ */ jsx9(
3534
- "div",
3535
- {
3536
- className: "rt-embed",
3537
- "data-provider": provider,
3538
- style: { aspectRatio: "16 / 9" },
3539
- children: /* @__PURE__ */ jsx9(
3540
- "iframe",
3541
- {
3542
- src,
3543
- title: "\uC784\uBCA0\uB4DC\uB41C \uC601\uC0C1",
3544
- loading: "lazy",
3545
- allowFullScreen: true,
3546
- referrerPolicy: "strict-origin-when-cross-origin",
3547
- allow: "accelerometer; clipboard-write; encrypted-media; picture-in-picture; web-share",
3548
- style: { width: "100%", height: "100%", border: 0 }
3549
- }
3550
- )
3551
- },
3552
- key
3553
- );
3554
- }
3555
- const orig = node.attrs?.originalUrl;
3556
- if (isSafeHref(orig)) {
3557
- return /* @__PURE__ */ jsx9("p", { className: "rt-embed-fallback", children: /* @__PURE__ */ jsx9("a", { href: orig, rel: "noopener noreferrer", target: "_blank", children: orig }) }, key);
3558
- }
3559
- return null;
3560
- }
3561
- function renderText(node, key) {
3562
- const text = node.text ?? "";
3563
- const marks = node.marks ?? [];
3564
- if (marks.length === 0) return text;
3565
- let element = text;
3566
- for (const mark of marks) {
3567
- element = applyMark(mark, element);
3568
- }
3569
- return /* @__PURE__ */ jsx9("span", { children: element }, key);
3570
- }
3571
- function applyMark(mark, child) {
3572
- switch (mark.type) {
3573
- case "bold":
3574
- return /* @__PURE__ */ jsx9("strong", { children: child });
3575
- case "italic":
3576
- return /* @__PURE__ */ jsx9("em", { children: child });
3577
- case "underline":
3578
- return /* @__PURE__ */ jsx9("u", { children: child });
3579
- case "strike":
3580
- return /* @__PURE__ */ jsx9("s", { children: child });
3581
- case "code":
3582
- return /* @__PURE__ */ jsx9("code", { children: child });
3583
- case "highlight": {
3584
- const color = mark.attrs?.color;
3585
- const style = typeof color === "string" && color.length > 0 ? { background: color } : void 0;
3586
- return /* @__PURE__ */ jsx9("mark", { style, children: child });
3587
- }
3588
- case "textStyle": {
3589
- const color = mark.attrs?.color;
3590
- const style = typeof color === "string" && color.length > 0 ? { color } : void 0;
3591
- if (!style) return /* @__PURE__ */ jsx9(Fragment3, { children: child });
3592
- return /* @__PURE__ */ jsx9("span", { style, children: child });
3593
- }
3594
- case "link": {
3595
- const raw = mark.attrs?.href;
3596
- const href = isSafeHref(raw) ? raw : "#";
3597
- return /* @__PURE__ */ jsx9("a", { href, rel: "noopener noreferrer", target: "_blank", children: child });
3598
- }
3599
- default:
3600
- return /* @__PURE__ */ jsx9("span", { children: child });
3601
- }
3602
- }
3603
-
3604
- export {
3605
- RootTaleLeadForm,
3606
- sectionThemeStyle,
3607
- TemplateHero,
3608
- TemplateRichText,
3609
- TemplateServices,
3610
- TemplateFooter,
3611
- TemplateFaq,
3612
- TemplateCtaBanner,
3613
- TemplateTrust,
3614
- TemplateTestimonials,
3615
- TemplateTeam,
3616
- TemplateContact,
3617
- TemplateHours,
3618
- TemplatePricing,
3619
- TemplateProcess,
3620
- TemplateBeforeAfter,
3621
- TemplateExpertise,
3622
- TemplateSpaces,
3623
- TemplateConcerns,
3624
- RootTalePostCard,
3625
- RootTaleTableOfContents,
3626
- themeToCssVars2 as themeToCssVars,
3627
- headingToId,
3628
- extractToc,
3629
- attachHeadingIds,
3630
- RootTaleFloatingCta,
3631
- renderBlock,
3632
- renderBlocks,
3633
- renderBoundBlocks,
3634
- RootTaleThemeProvider,
3635
- RootTaleBlogList,
3636
- RootTaleBlogCategories,
3637
- RootTaleBlogPost,
3638
- RootTaleFaqJsonLd,
3639
- RootTalePage,
3640
- RenderTiptap
3641
- };
3642
- //# sourceMappingURL=chunk-LIBSVC4M.js.map