@otl-core/cms-utils 1.0.0 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,1062 @@
1
+ 'use strict';
2
+
3
+ var clsx = require('clsx');
4
+ var tailwindMerge = require('tailwind-merge');
5
+
6
+ // src/abn-resolver.utils.ts
7
+ function selectVariant(bucket, variants) {
8
+ if (variants.length === 0) {
9
+ throw new Error("selectVariant: variants array must not be empty");
10
+ }
11
+ const totalWeight = variants.reduce((sum, v) => sum + v.weight, 0);
12
+ let cumulative = 0;
13
+ for (const variant of variants) {
14
+ cumulative += variant.weight / totalWeight;
15
+ if (bucket < cumulative) {
16
+ return variant.id;
17
+ }
18
+ }
19
+ return variants[variants.length - 1].id;
20
+ }
21
+ function isMultivariateContent(content) {
22
+ return content.multivariate === true && Array.isArray(content.variants);
23
+ }
24
+ function resolvePageVariant(content, bucket) {
25
+ const variantId = selectVariant(bucket, content.variants);
26
+ const selectedVariant = content.variants.find((v) => v.id === variantId);
27
+ if (!selectedVariant) {
28
+ return {
29
+ sections: content.variants[0].sections,
30
+ variantId: content.variants[0].id
31
+ };
32
+ }
33
+ return { sections: selectedVariant.sections, variantId };
34
+ }
35
+ function resolveBlogPostVariant(content, bucket) {
36
+ if (!content.multivariate || !Array.isArray(content.variants)) return;
37
+ const variants = content.variants;
38
+ const variantConfigs = variants.map((v) => ({
39
+ id: String(v.id),
40
+ weight: Number(v.weight)
41
+ }));
42
+ const selectedId = selectVariant(bucket, variantConfigs);
43
+ const selectedVariant = variants.find((v) => v.id === selectedId);
44
+ if (selectedVariant) {
45
+ content.blocks = selectedVariant.blocks;
46
+ } else if (variants.length > 0) {
47
+ content.blocks = variants[0].blocks;
48
+ }
49
+ delete content.multivariate;
50
+ delete content.variants;
51
+ }
52
+ function resolveFormVariantsInSections(sections, bucket) {
53
+ if (!Array.isArray(sections)) return sections;
54
+ return sections.map((section) => {
55
+ if (!isRecord(section)) return section;
56
+ const config = section.config;
57
+ if (!isRecord(config)) return section;
58
+ const children = config.children;
59
+ if (!Array.isArray(children)) return section;
60
+ const resolvedChildren = children.map(
61
+ (block) => resolveBlockVariant(block, bucket)
62
+ );
63
+ return {
64
+ ...section,
65
+ config: {
66
+ ...config,
67
+ children: resolvedChildren
68
+ }
69
+ };
70
+ });
71
+ }
72
+ function resolveBlockVariant(block, bucket) {
73
+ if (!isRecord(block)) return block;
74
+ const blockType = block.type;
75
+ if (blockType === "form") {
76
+ const data = block.data;
77
+ if (!isRecord(data) || data.multivariate !== true) return block;
78
+ const variants = data.variants;
79
+ if (!Array.isArray(variants) || variants.length === 0) return block;
80
+ const variantConfigs = variants.filter(isRecord).map((v) => ({
81
+ id: String(v.id),
82
+ weight: Number(v.weight)
83
+ }));
84
+ const selectedId = selectVariant(bucket, variantConfigs);
85
+ const selectedVariant = variants.find(
86
+ (v) => isRecord(v) && v.id === selectedId
87
+ );
88
+ if (!selectedVariant || !isRecord(selectedVariant)) return block;
89
+ return {
90
+ ...block,
91
+ data: {
92
+ definition: data.definition,
93
+ document: selectedVariant.document
94
+ }
95
+ };
96
+ }
97
+ const config = block.config;
98
+ if (!isRecord(config)) return block;
99
+ const childKey = Array.isArray(config.children) ? "children" : Array.isArray(config.child) ? "child" : null;
100
+ if (!childKey) return block;
101
+ const children = config[childKey];
102
+ const resolvedChildren = children.map(
103
+ (child) => resolveBlockVariant(child, bucket)
104
+ );
105
+ return {
106
+ ...block,
107
+ config: {
108
+ ...config,
109
+ [childKey]: resolvedChildren
110
+ }
111
+ };
112
+ }
113
+ function isRecord(value) {
114
+ return typeof value === "object" && value !== null && !Array.isArray(value);
115
+ }
116
+
117
+ // src/category.utils.ts
118
+ function buildCategoryTree(categories) {
119
+ const categoryMap = /* @__PURE__ */ new Map();
120
+ const roots = [];
121
+ categories.forEach((category) => {
122
+ categoryMap.set(category.id, { ...category, children: [] });
123
+ });
124
+ categories.forEach((category) => {
125
+ const node = categoryMap.get(category.id);
126
+ if (!node) return;
127
+ if (category.parent_id) {
128
+ const parent = categoryMap.get(category.parent_id);
129
+ if (parent) {
130
+ parent.children.push(node);
131
+ } else {
132
+ roots.push(node);
133
+ }
134
+ } else {
135
+ roots.push(node);
136
+ }
137
+ });
138
+ const sortByOrder = (a, b) => a.sort_order - b.sort_order;
139
+ roots.sort(sortByOrder);
140
+ categoryMap.forEach((node) => {
141
+ node.children.sort(sortByOrder);
142
+ });
143
+ return roots;
144
+ }
145
+ function flattenCategoryTree(tree) {
146
+ const result = [];
147
+ const flatten = (nodes) => {
148
+ nodes.forEach((node) => {
149
+ const { children, ...category } = node;
150
+ result.push(category);
151
+ if (children.length > 0) {
152
+ flatten(children);
153
+ }
154
+ });
155
+ };
156
+ flatten(tree);
157
+ return result;
158
+ }
159
+ function getCategoryPath(categoryId, categories, locale) {
160
+ const categoryMap = /* @__PURE__ */ new Map();
161
+ categories.forEach((cat) => categoryMap.set(cat.id, cat));
162
+ const path = [];
163
+ let currentId = categoryId;
164
+ while (currentId) {
165
+ const category = categoryMap.get(currentId);
166
+ if (!category) break;
167
+ path.unshift(category);
168
+ currentId = category.parent_id;
169
+ }
170
+ return path;
171
+ }
172
+ function getCategoryName(category, locale, fallbackLocale = "en") {
173
+ if (typeof category.name === "string") {
174
+ return category.name;
175
+ }
176
+ return category.name[locale] || category.name[fallbackLocale] || Object.values(category.name)[0] || "Untitled";
177
+ }
178
+ function getCategorySlug(category, locale, fallbackLocale = "en") {
179
+ if (typeof category.slug === "string") {
180
+ return category.slug;
181
+ }
182
+ return category.slug[locale] || category.slug[fallbackLocale] || Object.values(category.slug)[0] || "";
183
+ }
184
+ function isAncestor(ancestorId, descendantId, categories) {
185
+ const categoryMap = /* @__PURE__ */ new Map();
186
+ categories.forEach((cat) => categoryMap.set(cat.id, cat));
187
+ let currentId = descendantId;
188
+ while (currentId) {
189
+ const category = categoryMap.get(currentId);
190
+ if (!category) break;
191
+ if (category.parent_id === ancestorId) {
192
+ return true;
193
+ }
194
+ currentId = category.parent_id;
195
+ }
196
+ return false;
197
+ }
198
+ function getDescendants(categoryId, categories) {
199
+ const descendants = [];
200
+ const findChildren = (parentId) => {
201
+ const children = categories.filter((cat) => cat.parent_id === parentId);
202
+ children.forEach((child) => {
203
+ descendants.push(child);
204
+ findChildren(child.id);
205
+ });
206
+ };
207
+ findChildren(categoryId);
208
+ return descendants;
209
+ }
210
+ function findCategoryBySlug(slug, locale, categories) {
211
+ return categories.find((cat) => {
212
+ const categorySlug = typeof cat.slug === "string" ? cat.slug : cat.slug[locale];
213
+ return categorySlug === slug;
214
+ });
215
+ }
216
+ function cn(...inputs) {
217
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
218
+ }
219
+
220
+ // src/responsive.utils.ts
221
+ function normalizeResponsiveValue(value) {
222
+ if (!value) return {};
223
+ if (typeof value === "object" && value !== null && "base" in value) {
224
+ return value;
225
+ }
226
+ return { base: value };
227
+ }
228
+ function isResponsiveConfig(value) {
229
+ return typeof value === "object" && value !== null && "base" in value && !Array.isArray(value);
230
+ }
231
+ function getBreakpointValue(value, breakpoint) {
232
+ if (!isResponsiveConfig(value)) {
233
+ return value;
234
+ }
235
+ return value[breakpoint] ?? value.base;
236
+ }
237
+ function getDefinedBreakpoints(value) {
238
+ if (!isResponsiveConfig(value)) {
239
+ return ["base"];
240
+ }
241
+ const breakpoints = ["base"];
242
+ if (value.sm !== void 0) breakpoints.push("sm");
243
+ if (value.md !== void 0) breakpoints.push("md");
244
+ if (value.lg !== void 0) breakpoints.push("lg");
245
+ if (value.xl !== void 0) breakpoints.push("xl");
246
+ if (value["2xl"] !== void 0) breakpoints.push("2xl");
247
+ return breakpoints;
248
+ }
249
+ function toResponsiveConfig(fields) {
250
+ const config = { base: fields.base };
251
+ if (fields.sm !== void 0) config.sm = fields.sm;
252
+ if (fields.md !== void 0) config.md = fields.md;
253
+ if (fields.lg !== void 0) config.lg = fields.lg;
254
+ if (fields.xl !== void 0) config.xl = fields.xl;
255
+ if (fields["2xl"] !== void 0) config["2xl"] = fields["2xl"];
256
+ return config;
257
+ }
258
+ function fromResponsiveConfig(value) {
259
+ if (!isResponsiveConfig(value)) {
260
+ return { base: value };
261
+ }
262
+ return {
263
+ base: value.base,
264
+ sm: value.sm,
265
+ md: value.md,
266
+ lg: value.lg,
267
+ xl: value.xl,
268
+ "2xl": value["2xl"]
269
+ };
270
+ }
271
+
272
+ // src/css.utils.ts
273
+ function minifyCSS(css) {
274
+ return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/\s*([{}:;,>+~()[\]])\s*/g, "$1").replace(/:\s+/g, ":").replace(/;}/g, "}").replace(/:0px/g, ":0").replace(/:0em/g, ":0").replace(/:0rem/g, ":0").trim();
275
+ }
276
+ function resolveColorToCSS(colorRef, target) {
277
+ if (!colorRef) return void 0;
278
+ if (typeof colorRef !== "object") return void 0;
279
+ const resolvedTarget = target ?? (colorRef.type !== "custom" ? colorRef.target : void 0) ?? "background";
280
+ if (colorRef.type === "custom") {
281
+ if (typeof colorRef.value === "string") {
282
+ return resolvedTarget === "foreground" ? void 0 : colorRef.value;
283
+ }
284
+ return resolvedTarget === "foreground" ? colorRef.value.foreground : colorRef.value.background;
285
+ } else if (colorRef.type === "theme") {
286
+ return resolvedTarget === "foreground" ? `var(--${colorRef.value}-foreground)` : `var(--${colorRef.value})`;
287
+ } else if (colorRef.type === "variable") {
288
+ return resolvedTarget === "foreground" ? `var(--${colorRef.value}-foreground)` : `var(--${colorRef.value})`;
289
+ }
290
+ return void 0;
291
+ }
292
+ function resolveColorsToCSS(colorRefs) {
293
+ const resolved = {};
294
+ for (const key in colorRefs) {
295
+ const colorRef = colorRefs[key];
296
+ if (colorRef) {
297
+ const color = resolveColorToCSS(colorRef);
298
+ if (color) {
299
+ resolved[key] = color;
300
+ }
301
+ }
302
+ }
303
+ return resolved;
304
+ }
305
+ function resolveBorderToCSS(borderConfig) {
306
+ if (!borderConfig) return void 0;
307
+ const result = {};
308
+ const resolveSide = (side, defaultWidth, defaultStyle, defaultColor) => {
309
+ const width = side?.width || defaultWidth;
310
+ const style = side?.style || defaultStyle;
311
+ const color = side?.color || defaultColor;
312
+ if (!width || !style || !color) return void 0;
313
+ const resolvedColor = resolveColorToCSS(color);
314
+ if (!resolvedColor) return void 0;
315
+ return `${width} ${style} ${resolvedColor}`;
316
+ };
317
+ const hasIndividualSides = borderConfig.top || borderConfig.right || borderConfig.bottom || borderConfig.left;
318
+ if (hasIndividualSides) {
319
+ const topBorder = resolveSide(
320
+ borderConfig.top,
321
+ borderConfig.width,
322
+ borderConfig.style,
323
+ borderConfig.color
324
+ );
325
+ if (topBorder) result.borderTop = topBorder;
326
+ const rightBorder = resolveSide(
327
+ borderConfig.right,
328
+ borderConfig.width,
329
+ borderConfig.style,
330
+ borderConfig.color
331
+ );
332
+ if (rightBorder) result.borderRight = rightBorder;
333
+ const bottomBorder = resolveSide(
334
+ borderConfig.bottom,
335
+ borderConfig.width,
336
+ borderConfig.style,
337
+ borderConfig.color
338
+ );
339
+ if (bottomBorder) result.borderBottom = bottomBorder;
340
+ const leftBorder = resolveSide(
341
+ borderConfig.left,
342
+ borderConfig.width,
343
+ borderConfig.style,
344
+ borderConfig.color
345
+ );
346
+ if (leftBorder) result.borderLeft = leftBorder;
347
+ } else if (borderConfig.width && borderConfig.style && borderConfig.color) {
348
+ const color = resolveColorToCSS(borderConfig.color);
349
+ if (color) {
350
+ result.border = `${borderConfig.width} ${borderConfig.style} ${color}`;
351
+ }
352
+ }
353
+ if (borderConfig.radius) {
354
+ result.borderRadius = borderConfig.radius;
355
+ }
356
+ return Object.keys(result).length > 0 ? result : void 0;
357
+ }
358
+ function normalizeResponsiveValue2(value) {
359
+ if (!value) return {};
360
+ if (isResponsiveConfig(value)) {
361
+ return {
362
+ base: value.base,
363
+ sm: value.sm,
364
+ md: value.md,
365
+ lg: value.lg,
366
+ xl: value.xl
367
+ };
368
+ }
369
+ return { base: value };
370
+ }
371
+ var BREAKPOINTS = [
372
+ { key: "Sm", minWidth: "640px" },
373
+ { key: "Md", minWidth: "768px" },
374
+ { key: "Lg", minWidth: "1024px" },
375
+ { key: "Xl", minWidth: "1280px" }
376
+ ];
377
+ function generateResponsiveSpacingCSS(className, config) {
378
+ const css = [];
379
+ const targetClass = `.${className}`;
380
+ const normalizedBorder = normalizeResponsiveValue2(config.border);
381
+ const normalizedMargin = normalizeResponsiveValue2(config.margin);
382
+ const normalizedPadding = normalizeResponsiveValue2(config.padding);
383
+ const normalizedGap = normalizeResponsiveValue2(config.gap);
384
+ const normalizedShadow = normalizeResponsiveValue2(config.shadow);
385
+ const border = {
386
+ base: normalizedBorder.base,
387
+ sm: normalizedBorder.sm,
388
+ md: normalizedBorder.md,
389
+ lg: normalizedBorder.lg,
390
+ xl: normalizedBorder.xl
391
+ };
392
+ const margin = {
393
+ base: normalizedMargin.base,
394
+ sm: normalizedMargin.sm,
395
+ md: normalizedMargin.md,
396
+ lg: normalizedMargin.lg,
397
+ xl: normalizedMargin.xl
398
+ };
399
+ const padding = {
400
+ base: normalizedPadding.base,
401
+ sm: normalizedPadding.sm,
402
+ md: normalizedPadding.md,
403
+ lg: normalizedPadding.lg,
404
+ xl: normalizedPadding.xl
405
+ };
406
+ const gap = {
407
+ base: normalizedGap.base,
408
+ sm: normalizedGap.sm,
409
+ md: normalizedGap.md,
410
+ lg: normalizedGap.lg,
411
+ xl: normalizedGap.xl
412
+ };
413
+ const shadow = {
414
+ base: normalizedShadow.base,
415
+ sm: normalizedShadow.sm,
416
+ md: normalizedShadow.md,
417
+ lg: normalizedShadow.lg,
418
+ xl: normalizedShadow.xl
419
+ };
420
+ const shadowToCSS = (s) => {
421
+ const parts = [s.offsetX, s.offsetY, s.blurRadius, s.spreadRadius, s.color];
422
+ return s.inset ? `inset ${parts.join(" ")}` : parts.join(" ");
423
+ };
424
+ const baseStyles = [];
425
+ if (border.base) {
426
+ const resolvedBorder = resolveBorderToCSS(border.base);
427
+ if (resolvedBorder) {
428
+ Object.entries(resolvedBorder).forEach(([prop, value]) => {
429
+ if (value) {
430
+ const cssProp = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
431
+ baseStyles.push(`${cssProp}:${value}`);
432
+ }
433
+ });
434
+ }
435
+ }
436
+ if (margin.base) {
437
+ baseStyles.push(`margin:${margin.base}`);
438
+ }
439
+ if (padding.base) {
440
+ baseStyles.push(`padding:${padding.base}`);
441
+ }
442
+ if (gap.base) {
443
+ baseStyles.push(`gap:${gap.base}`);
444
+ }
445
+ if (shadow.base) {
446
+ baseStyles.push(`box-shadow:${shadowToCSS(shadow.base)}`);
447
+ }
448
+ if (baseStyles.length > 0) {
449
+ css.push(`${targetClass}{${baseStyles.join(";")}}`);
450
+ }
451
+ BREAKPOINTS.forEach(({ key, minWidth }) => {
452
+ const bpKey = key.toLowerCase();
453
+ const borderBp = border[bpKey];
454
+ const marginBp = margin[bpKey];
455
+ const paddingBp = padding[bpKey];
456
+ const gapBp = gap[bpKey];
457
+ const shadowBp = shadow[bpKey];
458
+ if (borderBp || marginBp || paddingBp || gapBp || shadowBp) {
459
+ const styles = [];
460
+ if (borderBp) {
461
+ const resolvedBorderBp = resolveBorderToCSS(borderBp);
462
+ if (resolvedBorderBp) {
463
+ Object.entries(resolvedBorderBp).forEach(([prop, value]) => {
464
+ if (value) {
465
+ const cssProp = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
466
+ styles.push(`${cssProp}:${value}`);
467
+ }
468
+ });
469
+ }
470
+ }
471
+ if (marginBp) {
472
+ styles.push(`margin:${marginBp}`);
473
+ }
474
+ if (paddingBp) {
475
+ styles.push(`padding:${paddingBp}`);
476
+ }
477
+ if (gapBp) {
478
+ styles.push(`gap:${gapBp}`);
479
+ }
480
+ if (shadowBp) {
481
+ styles.push(`box-shadow:${shadowToCSS(shadowBp)}`);
482
+ }
483
+ if (styles.length > 0) {
484
+ css.push(
485
+ `@media(min-width:${minWidth}){${targetClass}{${styles.join(";")}}}`
486
+ );
487
+ }
488
+ }
489
+ });
490
+ return css.length > 0 ? minifyCSS(css.join("")) : null;
491
+ }
492
+ function hasAnyMargin(config) {
493
+ if (config.margin) {
494
+ if (isResponsiveConfig(config.margin)) {
495
+ return !!(config.margin.base || config.margin.sm || config.margin.md || config.margin.lg || config.margin.xl);
496
+ }
497
+ return true;
498
+ }
499
+ return false;
500
+ }
501
+ function getAnimationTimingFunction(timing = "ease-in-out") {
502
+ switch (timing) {
503
+ case "ease":
504
+ return "ease";
505
+ case "ease-in":
506
+ return "ease-in";
507
+ case "ease-out":
508
+ return "ease-out";
509
+ case "ease-in-out":
510
+ return "ease-in-out";
511
+ case "linear":
512
+ return "linear";
513
+ case "spring":
514
+ return "cubic-bezier(0.68,-0.55,0.265,1.55)";
515
+ default:
516
+ return "ease-in-out";
517
+ }
518
+ }
519
+
520
+ // src/localization.utils.ts
521
+ function getLocalizedString(value, options) {
522
+ if (value === null || value === void 0) return "";
523
+ if (typeof value === "string") return value;
524
+ const preferredLocale = options?.preferredLocale || options?.defaultLocale || "en";
525
+ if (preferredLocale in value && value[preferredLocale]) {
526
+ return value[preferredLocale];
527
+ }
528
+ if (options?.defaultLocale && options.defaultLocale in value && value[options.defaultLocale]) {
529
+ return value[options.defaultLocale];
530
+ }
531
+ if ("en" in value && value.en) {
532
+ return value.en;
533
+ }
534
+ if (options?.supportedLocales) {
535
+ for (const locale of options.supportedLocales) {
536
+ if (locale in value && value[locale]) {
537
+ return value[locale];
538
+ }
539
+ }
540
+ }
541
+ const keys = Object.keys(value);
542
+ if (keys.length > 0 && value[keys[0]]) {
543
+ return value[keys[0]];
544
+ }
545
+ return "";
546
+ }
547
+ function getAvailableLocales(value) {
548
+ if (typeof value === "string") return [];
549
+ return Object.keys(value).filter((key) => value[key]);
550
+ }
551
+ function isLocalizedString(value) {
552
+ return !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length > 0;
553
+ }
554
+ function detectLocale(defaultLocale = "en", supportedLocales = ["en"]) {
555
+ const glob = globalThis;
556
+ if (typeof glob.window === "undefined") {
557
+ return defaultLocale;
558
+ }
559
+ const urlParams = new URLSearchParams(glob.window.location.search);
560
+ const urlLang = urlParams.get("lang");
561
+ if (urlLang && supportedLocales.includes(urlLang)) {
562
+ return urlLang;
563
+ }
564
+ const pathSegments = glob.window.location.pathname.split("/").filter(Boolean);
565
+ if (pathSegments[0] && supportedLocales.includes(pathSegments[0])) {
566
+ return pathSegments[0];
567
+ }
568
+ if (typeof glob.navigator !== "undefined") {
569
+ const browserLang = glob.navigator.language.split("-")[0];
570
+ if (supportedLocales.includes(browserLang)) {
571
+ return browserLang;
572
+ }
573
+ }
574
+ return defaultLocale;
575
+ }
576
+ function formatLocaleForHtml(locale) {
577
+ const localeMap = {
578
+ en: "en-US",
579
+ de: "de-DE",
580
+ fr: "fr-FR",
581
+ es: "es-ES",
582
+ it: "it-IT",
583
+ pt: "pt-PT",
584
+ nl: "nl-NL",
585
+ pl: "pl-PL"
586
+ };
587
+ return localeMap[locale] || locale;
588
+ }
589
+
590
+ // src/schedule-resolver.utils.ts
591
+ function isContentVisible(publishAt, expiresAt, now) {
592
+ const currentTime = now || /* @__PURE__ */ new Date();
593
+ if (publishAt) {
594
+ const publishDate = new Date(publishAt);
595
+ if (currentTime < publishDate) return false;
596
+ }
597
+ if (expiresAt) {
598
+ const expiryDate = new Date(expiresAt);
599
+ if (currentTime >= expiryDate) return false;
600
+ }
601
+ return true;
602
+ }
603
+ function filterScheduledContent(items, now) {
604
+ return items.filter(
605
+ (item) => isContentVisible(item.publish_at, item.expires_at, now)
606
+ );
607
+ }
608
+
609
+ // src/style.utils.ts
610
+ function getResponsiveBase(value) {
611
+ if (!value) return void 0;
612
+ if (isResponsiveConfig(value)) {
613
+ return value.base;
614
+ }
615
+ return value;
616
+ }
617
+ function borderToStyle(border) {
618
+ if (!border) return "";
619
+ const borderValue = getResponsiveBase(border);
620
+ if (!borderValue) return "";
621
+ const width = borderValue.width || "1px";
622
+ const style = borderValue.style || "solid";
623
+ const color = borderValue.color || "currentColor";
624
+ return `${width} ${style} ${color}`;
625
+ }
626
+ function formatShadow(shadow) {
627
+ if (!shadow) return "";
628
+ const { offsetX, offsetY, blurRadius, spreadRadius, color } = shadow;
629
+ return `${offsetX} ${offsetY} ${blurRadius} ${spreadRadius} ${color}`;
630
+ }
631
+ function paddingToClass(padding) {
632
+ if (!padding) return "";
633
+ const paddingMap = {
634
+ none: "p-0",
635
+ sm: "p-4",
636
+ normal: "p-8",
637
+ lg: "p-12",
638
+ xl: "p-16"
639
+ };
640
+ return paddingMap[padding] || paddingMap["normal"];
641
+ }
642
+ function paddingTopToClass(paddingTop) {
643
+ if (!paddingTop) return "";
644
+ const paddingMap = {
645
+ none: "pt-0",
646
+ sm: "pt-4",
647
+ normal: "pt-8",
648
+ lg: "pt-12",
649
+ xl: "pt-16"
650
+ };
651
+ return paddingMap[paddingTop] || paddingMap["normal"];
652
+ }
653
+ function paddingBottomToClass(paddingBottom) {
654
+ if (!paddingBottom) return "";
655
+ const paddingMap = {
656
+ none: "pb-0",
657
+ sm: "pb-4",
658
+ normal: "pb-8",
659
+ lg: "pb-12",
660
+ xl: "pb-16"
661
+ };
662
+ return paddingMap[paddingBottom] || paddingMap["normal"];
663
+ }
664
+ function spacingToClass(spacing) {
665
+ if (!spacing) return "";
666
+ const spacingMap = {
667
+ tight: "space-y-2",
668
+ normal: "space-y-4",
669
+ relaxed: "space-y-6",
670
+ loose: "space-y-8"
671
+ };
672
+ return spacingMap[spacing] || spacingMap["normal"];
673
+ }
674
+ function widthToClass(width) {
675
+ if (!width) return "";
676
+ const widthMap = {
677
+ full: "w-full",
678
+ container: "max-w-7xl mx-auto",
679
+ wide: "max-w-6xl mx-auto",
680
+ prose: "max-w-4xl mx-auto",
681
+ narrow: "max-w-2xl mx-auto"
682
+ };
683
+ return widthMap[width] || widthMap["container"];
684
+ }
685
+ function colorToStyle(color) {
686
+ if (!color) return {};
687
+ return {
688
+ backgroundColor: color
689
+ };
690
+ }
691
+ function gapToClass(gap) {
692
+ if (gap === void 0 || gap === null) return "";
693
+ if (gap === 0) return "gap-0";
694
+ if (gap <= 4) return "gap-1";
695
+ if (gap <= 8) return "gap-2";
696
+ if (gap <= 12) return "gap-3";
697
+ if (gap <= 16) return "gap-4";
698
+ if (gap <= 24) return "gap-6";
699
+ if (gap <= 32) return "gap-8";
700
+ if (gap <= 48) return "gap-12";
701
+ return "gap-16";
702
+ }
703
+
704
+ // src/password-resolver.utils.ts
705
+ function isPasswordProtected(password_protected) {
706
+ return password_protected === true;
707
+ }
708
+ function filterPasswordProtectedContent(items) {
709
+ return items.filter((item) => !isPasswordProtected(item.password_protected));
710
+ }
711
+
712
+ // src/json-ld.utils.ts
713
+ function buildBreadcrumbs(path, pageTitle) {
714
+ const crumbs = [
715
+ { name: "Home", path: "/" }
716
+ ];
717
+ if (path === "/" || path === "") {
718
+ return crumbs;
719
+ }
720
+ const segments = path.replace(/^\//, "").split("/").filter(Boolean);
721
+ for (let i = 0; i < segments.length; i++) {
722
+ const segPath = "/" + segments.slice(0, i + 1).join("/");
723
+ const isLast = i === segments.length - 1;
724
+ const name = isLast ? pageTitle : slugToTitle(segments[i]);
725
+ crumbs.push({ name, path: segPath });
726
+ }
727
+ return crumbs;
728
+ }
729
+ function generateJsonLd(input) {
730
+ const {
731
+ siteUrl,
732
+ path,
733
+ locale,
734
+ siteName,
735
+ siteDescription,
736
+ organization,
737
+ page,
738
+ blogPost
739
+ } = input;
740
+ const canonicalUrl = siteUrl + path;
741
+ const graph = [];
742
+ const websiteNode = {
743
+ "@type": "WebSite",
744
+ "@id": `${siteUrl}/#website`,
745
+ url: siteUrl,
746
+ name: siteName,
747
+ inLanguage: locale
748
+ };
749
+ if (siteDescription) {
750
+ websiteNode.description = siteDescription;
751
+ }
752
+ if (organization) {
753
+ websiteNode.publisher = { "@id": `${siteUrl}/#organization` };
754
+ }
755
+ graph.push(websiteNode);
756
+ if (organization && hasOrganizationData(organization)) {
757
+ const orgNode = {
758
+ "@type": "Organization",
759
+ "@id": `${siteUrl}/#organization`
760
+ };
761
+ if (organization.name) orgNode.name = organization.name;
762
+ if (organization.legal_name) orgNode.legalName = organization.legal_name;
763
+ if (organization.logo) {
764
+ orgNode.logo = {
765
+ "@type": "ImageObject",
766
+ "@id": `${siteUrl}/#logo`,
767
+ url: organization.logo,
768
+ contentUrl: organization.logo
769
+ };
770
+ orgNode.image = { "@id": `${siteUrl}/#logo` };
771
+ }
772
+ if (organization.url) orgNode.url = organization.url;
773
+ if (organization.email) orgNode.email = organization.email;
774
+ if (organization.phone) orgNode.telephone = organization.phone;
775
+ if (organization.description)
776
+ orgNode.description = organization.description;
777
+ if (organization.address) {
778
+ const addr = organization.address;
779
+ const addressNode = {
780
+ "@type": "PostalAddress"
781
+ };
782
+ if (addr.street) addressNode.streetAddress = addr.street;
783
+ if (addr.city) addressNode.addressLocality = addr.city;
784
+ if (addr.region) addressNode.addressRegion = addr.region;
785
+ if (addr.postal_code) addressNode.postalCode = addr.postal_code;
786
+ if (addr.country) addressNode.addressCountry = addr.country;
787
+ orgNode.address = addressNode;
788
+ }
789
+ if (organization.social_profiles && organization.social_profiles.length > 0) {
790
+ orgNode.sameAs = organization.social_profiles.map((sp) => sp.url);
791
+ }
792
+ graph.push(orgNode);
793
+ }
794
+ const breadcrumbs = input.breadcrumbs ?? buildBreadcrumbs(path, page?.title ?? blogPost?.title ?? siteName);
795
+ const breadcrumbNode = {
796
+ "@type": "BreadcrumbList",
797
+ "@id": `${canonicalUrl}#breadcrumb`,
798
+ itemListElement: breadcrumbs.map((crumb, index) => ({
799
+ "@type": "ListItem",
800
+ position: index + 1,
801
+ name: crumb.name,
802
+ item: siteUrl + crumb.path
803
+ }))
804
+ };
805
+ graph.push(breadcrumbNode);
806
+ if (page) {
807
+ const schemaType = page.schemaType || "WebPage";
808
+ const pageNode = {
809
+ "@type": schemaType,
810
+ "@id": `${canonicalUrl}#webpage`,
811
+ url: canonicalUrl,
812
+ name: page.title,
813
+ isPartOf: { "@id": `${siteUrl}/#website` },
814
+ breadcrumb: { "@id": `${canonicalUrl}#breadcrumb` },
815
+ inLanguage: locale
816
+ };
817
+ if (page.description) pageNode.description = page.description;
818
+ if (page.datePublished) pageNode.datePublished = page.datePublished;
819
+ if (page.dateModified) pageNode.dateModified = page.dateModified;
820
+ if (page.ogImage) {
821
+ pageNode.primaryImageOfPage = {
822
+ "@type": "ImageObject",
823
+ url: page.ogImage
824
+ };
825
+ }
826
+ graph.push(pageNode);
827
+ }
828
+ if (blogPost) {
829
+ const articleNode = {
830
+ "@type": "BlogPosting",
831
+ "@id": `${canonicalUrl}#article`,
832
+ headline: blogPost.title,
833
+ url: canonicalUrl,
834
+ isPartOf: { "@id": `${siteUrl}/#website` },
835
+ mainEntityOfPage: { "@id": `${canonicalUrl}#webpage` },
836
+ inLanguage: locale,
837
+ datePublished: blogPost.datePublished
838
+ };
839
+ if (blogPost.dateModified) articleNode.dateModified = blogPost.dateModified;
840
+ if (blogPost.excerpt) articleNode.description = blogPost.excerpt;
841
+ if (blogPost.featuredImage) {
842
+ articleNode.image = {
843
+ "@type": "ImageObject",
844
+ url: blogPost.featuredImage
845
+ };
846
+ }
847
+ if (blogPost.categories && blogPost.categories.length > 0) {
848
+ articleNode.articleSection = blogPost.categories;
849
+ }
850
+ if (organization) {
851
+ articleNode.publisher = { "@id": `${siteUrl}/#organization` };
852
+ }
853
+ if (blogPost.authorName) {
854
+ const personNode = {
855
+ "@type": "Person",
856
+ "@id": `${siteUrl}/#author`,
857
+ name: blogPost.authorName
858
+ };
859
+ if (blogPost.authorUrl) personNode.url = blogPost.authorUrl;
860
+ graph.push(personNode);
861
+ articleNode.author = { "@id": `${siteUrl}/#author` };
862
+ }
863
+ if (!page) {
864
+ graph.push({
865
+ "@type": "WebPage",
866
+ "@id": `${canonicalUrl}#webpage`,
867
+ url: canonicalUrl,
868
+ name: blogPost.title,
869
+ isPartOf: { "@id": `${siteUrl}/#website` },
870
+ breadcrumb: { "@id": `${canonicalUrl}#breadcrumb` },
871
+ inLanguage: locale
872
+ });
873
+ }
874
+ graph.push(articleNode);
875
+ }
876
+ return {
877
+ "@context": "https://schema.org",
878
+ "@graph": graph
879
+ };
880
+ }
881
+ function slugToTitle(slug) {
882
+ return slug.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
883
+ }
884
+ function hasOrganizationData(org) {
885
+ return !!(org.name || org.legal_name || org.logo || org.url || org.email || org.phone || org.description);
886
+ }
887
+
888
+ // src/seo.utils.ts
889
+ function deriveSiteUrl(configs, siteUrlOverride) {
890
+ let url = "";
891
+ if (siteUrlOverride) {
892
+ url = siteUrlOverride;
893
+ } else {
894
+ const deployment = configs.deployment;
895
+ const customDomains = deployment?.custom_domains;
896
+ if (customDomains?.[0]) {
897
+ url = `https://${customDomains[0]}`;
898
+ } else {
899
+ const subdomain = deployment?.subdomain;
900
+ if (subdomain) url = `https://${subdomain}.otl.studio`;
901
+ }
902
+ }
903
+ return url.replace(/\/+$/, "");
904
+ }
905
+ function deriveSiteName(configs, locale) {
906
+ const website = configs.website;
907
+ if (!website?.site_name) return "Website";
908
+ if (typeof website.site_name === "string") return website.site_name;
909
+ const names = website.site_name;
910
+ return names[locale] || names.en || "Website";
911
+ }
912
+ function deriveSiteDescription(configs, locale) {
913
+ const website = configs.website;
914
+ if (!website?.description) return void 0;
915
+ if (typeof website.description === "string") return website.description;
916
+ const descs = website.description;
917
+ return descs[locale] || void 0;
918
+ }
919
+ function detectLocaleFromSegments(segments, fullPath, supportedLocales, defaultLocale) {
920
+ const normalizedLocales = supportedLocales.map((l) => l.toLowerCase());
921
+ const firstSegment = segments[0];
922
+ const localeIndex = normalizedLocales.indexOf(firstSegment?.toLowerCase());
923
+ if (localeIndex !== -1) {
924
+ return [
925
+ supportedLocales[localeIndex],
926
+ "/" + segments.slice(1).join("/") || "/"
927
+ ];
928
+ }
929
+ return [defaultLocale, fullPath];
930
+ }
931
+ function localeToOgFormat(locale) {
932
+ if (locale.includes("_")) return locale;
933
+ const map = {
934
+ en: "en_US",
935
+ de: "de_DE",
936
+ fr: "fr_FR",
937
+ es: "es_ES",
938
+ it: "it_IT",
939
+ pt: "pt_BR",
940
+ nl: "nl_NL",
941
+ ja: "ja_JP",
942
+ zh: "zh_CN",
943
+ ko: "ko_KR",
944
+ ru: "ru_RU",
945
+ ar: "ar_SA",
946
+ pl: "pl_PL",
947
+ sv: "sv_SE",
948
+ da: "da_DK",
949
+ fi: "fi_FI",
950
+ nb: "nb_NO",
951
+ tr: "tr_TR"
952
+ };
953
+ return map[locale.toLowerCase()] || `${locale}_${locale.toUpperCase()}`;
954
+ }
955
+ function buildHreflangAlternates(siteUrl, path, supportedLocales, defaultLocale) {
956
+ if (!siteUrl || supportedLocales.length <= 1) return void 0;
957
+ const languages = {};
958
+ for (const loc of supportedLocales) {
959
+ if (loc === defaultLocale) {
960
+ languages[loc] = `${siteUrl}${path}`;
961
+ } else {
962
+ languages[loc] = `${siteUrl}/${loc}${path}`;
963
+ }
964
+ }
965
+ languages["x-default"] = `${siteUrl}${path}`;
966
+ return languages;
967
+ }
968
+ function extractPaginationFromLayout(layout) {
969
+ if (!layout) return null;
970
+ for (const section of layout) {
971
+ const sConfig = section?.config;
972
+ if (!sConfig) continue;
973
+ const result = findPaginationInBlocks(
974
+ sConfig.children || []
975
+ );
976
+ if (result) return result;
977
+ }
978
+ return null;
979
+ }
980
+ function findPaginationInBlocks(blocks) {
981
+ for (const block of blocks) {
982
+ const b = block;
983
+ const config = b?.config;
984
+ if (!config) continue;
985
+ const data = config.data;
986
+ if (data?.pagination) {
987
+ const p = data.pagination;
988
+ return {
989
+ page: p.page || 1,
990
+ totalPages: p.totalPages || 1,
991
+ hasNext: p.hasNext || false,
992
+ hasPrev: p.hasPrev || false
993
+ };
994
+ }
995
+ if (config.children) {
996
+ const nested = findPaginationInBlocks(config.children);
997
+ if (nested) return nested;
998
+ }
999
+ if (config.child) {
1000
+ const nested = findPaginationInBlocks(config.child);
1001
+ if (nested) return nested;
1002
+ }
1003
+ }
1004
+ return null;
1005
+ }
1006
+
1007
+ exports.borderToStyle = borderToStyle;
1008
+ exports.buildBreadcrumbs = buildBreadcrumbs;
1009
+ exports.buildCategoryTree = buildCategoryTree;
1010
+ exports.buildHreflangAlternates = buildHreflangAlternates;
1011
+ exports.cn = cn;
1012
+ exports.colorToStyle = colorToStyle;
1013
+ exports.deriveSiteDescription = deriveSiteDescription;
1014
+ exports.deriveSiteName = deriveSiteName;
1015
+ exports.deriveSiteUrl = deriveSiteUrl;
1016
+ exports.detectLocale = detectLocale;
1017
+ exports.detectLocaleFromSegments = detectLocaleFromSegments;
1018
+ exports.extractPaginationFromLayout = extractPaginationFromLayout;
1019
+ exports.filterPasswordProtectedContent = filterPasswordProtectedContent;
1020
+ exports.filterScheduledContent = filterScheduledContent;
1021
+ exports.findCategoryBySlug = findCategoryBySlug;
1022
+ exports.flattenCategoryTree = flattenCategoryTree;
1023
+ exports.formatLocaleForHtml = formatLocaleForHtml;
1024
+ exports.formatShadow = formatShadow;
1025
+ exports.fromResponsiveConfig = fromResponsiveConfig;
1026
+ exports.gapToClass = gapToClass;
1027
+ exports.generateJsonLd = generateJsonLd;
1028
+ exports.generateResponsiveSpacingCSS = generateResponsiveSpacingCSS;
1029
+ exports.getAnimationTimingFunction = getAnimationTimingFunction;
1030
+ exports.getAvailableLocales = getAvailableLocales;
1031
+ exports.getBreakpointValue = getBreakpointValue;
1032
+ exports.getCategoryName = getCategoryName;
1033
+ exports.getCategoryPath = getCategoryPath;
1034
+ exports.getCategorySlug = getCategorySlug;
1035
+ exports.getDefinedBreakpoints = getDefinedBreakpoints;
1036
+ exports.getDescendants = getDescendants;
1037
+ exports.getLocalizedString = getLocalizedString;
1038
+ exports.hasAnyMargin = hasAnyMargin;
1039
+ exports.isAncestor = isAncestor;
1040
+ exports.isContentVisible = isContentVisible;
1041
+ exports.isLocalizedString = isLocalizedString;
1042
+ exports.isMultivariateContent = isMultivariateContent;
1043
+ exports.isPasswordProtected = isPasswordProtected;
1044
+ exports.isResponsiveConfig = isResponsiveConfig;
1045
+ exports.localeToOgFormat = localeToOgFormat;
1046
+ exports.minifyCSS = minifyCSS;
1047
+ exports.normalizeResponsiveValue = normalizeResponsiveValue;
1048
+ exports.paddingBottomToClass = paddingBottomToClass;
1049
+ exports.paddingToClass = paddingToClass;
1050
+ exports.paddingTopToClass = paddingTopToClass;
1051
+ exports.resolveBlogPostVariant = resolveBlogPostVariant;
1052
+ exports.resolveBorderToCSS = resolveBorderToCSS;
1053
+ exports.resolveColorToCSS = resolveColorToCSS;
1054
+ exports.resolveColorsToCSS = resolveColorsToCSS;
1055
+ exports.resolveFormVariantsInSections = resolveFormVariantsInSections;
1056
+ exports.resolvePageVariant = resolvePageVariant;
1057
+ exports.selectVariant = selectVariant;
1058
+ exports.spacingToClass = spacingToClass;
1059
+ exports.toResponsiveConfig = toResponsiveConfig;
1060
+ exports.widthToClass = widthToClass;
1061
+ //# sourceMappingURL=index.cjs.map
1062
+ //# sourceMappingURL=index.cjs.map