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