cinqcinqdev-seo 0.1.72 → 1.0.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 (122) hide show
  1. package/README.md +94 -11
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/assets/admin-tw.css +1 -1
  4. package/dist/runtime/components/admin-cms/DynamicRenderer.vue +16 -2
  5. package/dist/runtime/components/sections/swiss-style/BlogHero.d.vue.ts +3 -0
  6. package/dist/runtime/components/sections/swiss-style/BlogHero.vue +146 -0
  7. package/dist/runtime/components/sections/swiss-style/BlogHero.vue.d.ts +3 -0
  8. package/dist/runtime/components/sections/swiss-style/CallToAction.d.vue.ts +3 -0
  9. package/dist/runtime/components/sections/swiss-style/CallToAction.vue +138 -0
  10. package/dist/runtime/components/sections/swiss-style/CallToAction.vue.d.ts +3 -0
  11. package/dist/runtime/components/sections/swiss-style/Comparison.d.vue.ts +3 -0
  12. package/dist/runtime/components/sections/swiss-style/Comparison.vue +280 -0
  13. package/dist/runtime/components/sections/swiss-style/Comparison.vue.d.ts +3 -0
  14. package/dist/runtime/components/sections/swiss-style/ContactForm.d.vue.ts +3 -0
  15. package/dist/runtime/components/sections/swiss-style/ContactForm.vue +173 -0
  16. package/dist/runtime/components/sections/swiss-style/ContactForm.vue.d.ts +3 -0
  17. package/dist/runtime/components/sections/swiss-style/DataTable.d.vue.ts +3 -0
  18. package/dist/runtime/components/sections/swiss-style/DataTable.vue +245 -0
  19. package/dist/runtime/components/sections/swiss-style/DataTable.vue.d.ts +3 -0
  20. package/dist/runtime/components/sections/swiss-style/FAQ.d.vue.ts +3 -0
  21. package/dist/runtime/components/sections/swiss-style/FAQ.vue +107 -0
  22. package/dist/runtime/components/sections/swiss-style/FAQ.vue.d.ts +3 -0
  23. package/dist/runtime/components/sections/swiss-style/Features.d.vue.ts +3 -0
  24. package/dist/runtime/components/sections/swiss-style/Features.vue +103 -0
  25. package/dist/runtime/components/sections/swiss-style/Features.vue.d.ts +3 -0
  26. package/dist/runtime/components/sections/swiss-style/HeroFan.d.vue.ts +3 -0
  27. package/dist/runtime/components/sections/swiss-style/HeroFan.vue +108 -0
  28. package/dist/runtime/components/sections/swiss-style/HeroFan.vue.d.ts +3 -0
  29. package/dist/runtime/components/sections/swiss-style/HeroSection.d.vue.ts +3 -0
  30. package/dist/runtime/components/sections/swiss-style/HeroSection.vue +190 -0
  31. package/dist/runtime/components/sections/swiss-style/HeroSection.vue.d.ts +3 -0
  32. package/dist/runtime/components/sections/swiss-style/HeroSlider.d.vue.ts +3 -0
  33. package/dist/runtime/components/sections/swiss-style/HeroSlider.vue +138 -0
  34. package/dist/runtime/components/sections/swiss-style/HeroSlider.vue.d.ts +3 -0
  35. package/dist/runtime/components/sections/swiss-style/Newsletter.d.vue.ts +3 -0
  36. package/dist/runtime/components/sections/swiss-style/Newsletter.vue +125 -0
  37. package/dist/runtime/components/sections/swiss-style/Newsletter.vue.d.ts +3 -0
  38. package/dist/runtime/components/sections/swiss-style/Pricing.d.vue.ts +3 -0
  39. package/dist/runtime/components/sections/swiss-style/Pricing.vue +148 -0
  40. package/dist/runtime/components/sections/swiss-style/Pricing.vue.d.ts +3 -0
  41. package/dist/runtime/components/sections/swiss-style/Process.d.vue.ts +3 -0
  42. package/dist/runtime/components/sections/swiss-style/Process.vue +124 -0
  43. package/dist/runtime/components/sections/swiss-style/Process.vue.d.ts +3 -0
  44. package/dist/runtime/components/sections/swiss-style/Quote.d.vue.ts +3 -0
  45. package/dist/runtime/components/sections/swiss-style/Quote.vue +130 -0
  46. package/dist/runtime/components/sections/swiss-style/Quote.vue.d.ts +3 -0
  47. package/dist/runtime/components/sections/swiss-style/RelatedPages.d.vue.ts +3 -0
  48. package/dist/runtime/components/sections/swiss-style/RelatedPages.vue +212 -0
  49. package/dist/runtime/components/sections/swiss-style/RelatedPages.vue.d.ts +3 -0
  50. package/dist/runtime/components/sections/swiss-style/RichText.d.vue.ts +3 -0
  51. package/dist/runtime/components/sections/swiss-style/RichText.vue +100 -0
  52. package/dist/runtime/components/sections/swiss-style/RichText.vue.d.ts +3 -0
  53. package/dist/runtime/components/sections/swiss-style/ServiceGrid.d.vue.ts +3 -0
  54. package/dist/runtime/components/sections/swiss-style/ServiceGrid.vue +121 -0
  55. package/dist/runtime/components/sections/swiss-style/ServiceGrid.vue.d.ts +3 -0
  56. package/dist/runtime/components/sections/swiss-style/Testimonials.d.vue.ts +3 -0
  57. package/dist/runtime/components/sections/swiss-style/Testimonials.vue +126 -0
  58. package/dist/runtime/components/sections/swiss-style/Testimonials.vue.d.ts +3 -0
  59. package/dist/runtime/components/sections/swiss-style/TextVisual.d.vue.ts +3 -0
  60. package/dist/runtime/components/sections/swiss-style/TextVisual.vue +146 -0
  61. package/dist/runtime/components/sections/swiss-style/TextVisual.vue.d.ts +3 -0
  62. package/dist/runtime/composables/useAdminSettings.d.ts +1 -0
  63. package/dist/runtime/pages/admin/editor/[id].vue +15 -1
  64. package/dist/runtime/pages/admin/setup.vue +77 -2
  65. package/package.json +1 -1
  66. /package/dist/runtime/components/sections/{BlogHero.d.vue.ts → cinqcinq/BlogHero.d.vue.ts} +0 -0
  67. /package/dist/runtime/components/sections/{BlogHero.vue → cinqcinq/BlogHero.vue} +0 -0
  68. /package/dist/runtime/components/sections/{BlogHero.vue.d.ts → cinqcinq/BlogHero.vue.d.ts} +0 -0
  69. /package/dist/runtime/components/sections/{CallToAction.d.vue.ts → cinqcinq/CallToAction.d.vue.ts} +0 -0
  70. /package/dist/runtime/components/sections/{CallToAction.vue → cinqcinq/CallToAction.vue} +0 -0
  71. /package/dist/runtime/components/sections/{CallToAction.vue.d.ts → cinqcinq/CallToAction.vue.d.ts} +0 -0
  72. /package/dist/runtime/components/sections/{Comparison.d.vue.ts → cinqcinq/Comparison.d.vue.ts} +0 -0
  73. /package/dist/runtime/components/sections/{Comparison.vue → cinqcinq/Comparison.vue} +0 -0
  74. /package/dist/runtime/components/sections/{Comparison.vue.d.ts → cinqcinq/Comparison.vue.d.ts} +0 -0
  75. /package/dist/runtime/components/sections/{ContactForm.d.vue.ts → cinqcinq/ContactForm.d.vue.ts} +0 -0
  76. /package/dist/runtime/components/sections/{ContactForm.vue → cinqcinq/ContactForm.vue} +0 -0
  77. /package/dist/runtime/components/sections/{ContactForm.vue.d.ts → cinqcinq/ContactForm.vue.d.ts} +0 -0
  78. /package/dist/runtime/components/sections/{DataTable.d.vue.ts → cinqcinq/DataTable.d.vue.ts} +0 -0
  79. /package/dist/runtime/components/sections/{DataTable.vue → cinqcinq/DataTable.vue} +0 -0
  80. /package/dist/runtime/components/sections/{DataTable.vue.d.ts → cinqcinq/DataTable.vue.d.ts} +0 -0
  81. /package/dist/runtime/components/sections/{FAQ.d.vue.ts → cinqcinq/FAQ.d.vue.ts} +0 -0
  82. /package/dist/runtime/components/sections/{FAQ.vue → cinqcinq/FAQ.vue} +0 -0
  83. /package/dist/runtime/components/sections/{FAQ.vue.d.ts → cinqcinq/FAQ.vue.d.ts} +0 -0
  84. /package/dist/runtime/components/sections/{Features.d.vue.ts → cinqcinq/Features.d.vue.ts} +0 -0
  85. /package/dist/runtime/components/sections/{Features.vue → cinqcinq/Features.vue} +0 -0
  86. /package/dist/runtime/components/sections/{Features.vue.d.ts → cinqcinq/Features.vue.d.ts} +0 -0
  87. /package/dist/runtime/components/sections/{HeroFan.d.vue.ts → cinqcinq/HeroFan.d.vue.ts} +0 -0
  88. /package/dist/runtime/components/sections/{HeroFan.vue → cinqcinq/HeroFan.vue} +0 -0
  89. /package/dist/runtime/components/sections/{HeroFan.vue.d.ts → cinqcinq/HeroFan.vue.d.ts} +0 -0
  90. /package/dist/runtime/components/sections/{HeroSection.d.vue.ts → cinqcinq/HeroSection.d.vue.ts} +0 -0
  91. /package/dist/runtime/components/sections/{HeroSection.vue → cinqcinq/HeroSection.vue} +0 -0
  92. /package/dist/runtime/components/sections/{HeroSection.vue.d.ts → cinqcinq/HeroSection.vue.d.ts} +0 -0
  93. /package/dist/runtime/components/sections/{HeroSlider.d.vue.ts → cinqcinq/HeroSlider.d.vue.ts} +0 -0
  94. /package/dist/runtime/components/sections/{HeroSlider.vue → cinqcinq/HeroSlider.vue} +0 -0
  95. /package/dist/runtime/components/sections/{HeroSlider.vue.d.ts → cinqcinq/HeroSlider.vue.d.ts} +0 -0
  96. /package/dist/runtime/components/sections/{Newsletter.d.vue.ts → cinqcinq/Newsletter.d.vue.ts} +0 -0
  97. /package/dist/runtime/components/sections/{Newsletter.vue → cinqcinq/Newsletter.vue} +0 -0
  98. /package/dist/runtime/components/sections/{Newsletter.vue.d.ts → cinqcinq/Newsletter.vue.d.ts} +0 -0
  99. /package/dist/runtime/components/sections/{Pricing.d.vue.ts → cinqcinq/Pricing.d.vue.ts} +0 -0
  100. /package/dist/runtime/components/sections/{Pricing.vue → cinqcinq/Pricing.vue} +0 -0
  101. /package/dist/runtime/components/sections/{Pricing.vue.d.ts → cinqcinq/Pricing.vue.d.ts} +0 -0
  102. /package/dist/runtime/components/sections/{Process.d.vue.ts → cinqcinq/Process.d.vue.ts} +0 -0
  103. /package/dist/runtime/components/sections/{Process.vue → cinqcinq/Process.vue} +0 -0
  104. /package/dist/runtime/components/sections/{Process.vue.d.ts → cinqcinq/Process.vue.d.ts} +0 -0
  105. /package/dist/runtime/components/sections/{Quote.d.vue.ts → cinqcinq/Quote.d.vue.ts} +0 -0
  106. /package/dist/runtime/components/sections/{Quote.vue → cinqcinq/Quote.vue} +0 -0
  107. /package/dist/runtime/components/sections/{Quote.vue.d.ts → cinqcinq/Quote.vue.d.ts} +0 -0
  108. /package/dist/runtime/components/sections/{RelatedPages.d.vue.ts → cinqcinq/RelatedPages.d.vue.ts} +0 -0
  109. /package/dist/runtime/components/sections/{RelatedPages.vue → cinqcinq/RelatedPages.vue} +0 -0
  110. /package/dist/runtime/components/sections/{RelatedPages.vue.d.ts → cinqcinq/RelatedPages.vue.d.ts} +0 -0
  111. /package/dist/runtime/components/sections/{RichText.d.vue.ts → cinqcinq/RichText.d.vue.ts} +0 -0
  112. /package/dist/runtime/components/sections/{RichText.vue → cinqcinq/RichText.vue} +0 -0
  113. /package/dist/runtime/components/sections/{RichText.vue.d.ts → cinqcinq/RichText.vue.d.ts} +0 -0
  114. /package/dist/runtime/components/sections/{ServiceGrid.d.vue.ts → cinqcinq/ServiceGrid.d.vue.ts} +0 -0
  115. /package/dist/runtime/components/sections/{ServiceGrid.vue → cinqcinq/ServiceGrid.vue} +0 -0
  116. /package/dist/runtime/components/sections/{ServiceGrid.vue.d.ts → cinqcinq/ServiceGrid.vue.d.ts} +0 -0
  117. /package/dist/runtime/components/sections/{Testimonials.d.vue.ts → cinqcinq/Testimonials.d.vue.ts} +0 -0
  118. /package/dist/runtime/components/sections/{Testimonials.vue → cinqcinq/Testimonials.vue} +0 -0
  119. /package/dist/runtime/components/sections/{Testimonials.vue.d.ts → cinqcinq/Testimonials.vue.d.ts} +0 -0
  120. /package/dist/runtime/components/sections/{TextVisual.d.vue.ts → cinqcinq/TextVisual.d.vue.ts} +0 -0
  121. /package/dist/runtime/components/sections/{TextVisual.vue → cinqcinq/TextVisual.vue} +0 -0
  122. /package/dist/runtime/components/sections/{TextVisual.vue.d.ts → cinqcinq/TextVisual.vue.d.ts} +0 -0
@@ -0,0 +1,245 @@
1
+ <template>
2
+ <section ref="sectionEl" :class="[sectionPad, isVisible ? 'sv-in' : 'sv-out']" :dir="textDirection" :style="[{ backgroundColor: bgColor, color: textColor }, spacingStyle]">
3
+ <div :class="[containerClass]">
4
+
5
+ <!-- Header row: title + search -->
6
+ <div v-if="badge || title || description || searchable" class="flex flex-col md:flex-row md:items-end gap-6 mb-10 pb-6 border-b" :style="{ borderColor: ca(textColor,'12') }">
7
+ <div class="flex-1">
8
+ <span v-if="badge" class="block text-[9px] font-black uppercase tracking-[0.5em] mb-3" :style="{ opacity: 0.35 }">{{ badge }}</span>
9
+ <component :is="titleTag" v-if="title" class="font-black uppercase leading-[0.88]"
10
+ :style="{ fontSize: titleFontSize, letterSpacing: '-0.03em' }">{{ title }}</component>
11
+ <p v-if="description" :class="[bodyClass, 'leading-relaxed mt-3']" :style="{ opacity: 0.55 }">{{ description }}</p>
12
+ </div>
13
+ <!-- Search input -->
14
+ <div v-if="searchable" class="shrink-0 relative">
15
+ <input
16
+ v-model="query"
17
+ type="search"
18
+ placeholder="Search…"
19
+ :class="[bodyClass, 'w-full md:w-56 pl-9 pr-4 py-2.5 border outline-none transition-all bg-transparent']"
20
+ :style="{ borderColor: ca(textColor,'20'), color: textColor }"
21
+ @input="currentPage = 1"
22
+ />
23
+ <span class="absolute left-3 top-1/2 -translate-y-1/2 text-sm pointer-events-none" :style="{ opacity: 0.35 }">⌕</span>
24
+ </div>
25
+ </div>
26
+
27
+ <!-- DEFAULT / STRIPED / MINIMAL table -->
28
+ <div v-if="layout !== 'cards'" class="overflow-x-auto border" :style="{ borderColor: ca(textColor,'12') }">
29
+ <table class="w-full min-w-[400px]" style="border-collapse: collapse;">
30
+ <caption v-if="caption" class="text-left px-6 pb-3 text-xs" :style="{ opacity: 0.4 }">{{ caption }}</caption>
31
+ <thead :class="stickyHeader ? 'sticky top-0 z-10' : ''" :style="{ backgroundColor: bgColor }">
32
+ <tr :style="{ borderBottom: `2px solid ${ca(textColor,'15')}` }">
33
+ <th
34
+ v-for="(col, ci) in parsedCols" :key="ci"
35
+ :class="['px-6 py-4 text-[9px] font-black uppercase tracking-[0.4em] select-none', col.align === 'center' ? 'text-center' : col.align === 'right' ? 'text-right' : 'text-left', sortable ? 'cursor-pointer hover:opacity-100' : '']"
36
+ :style="{ opacity: 0.4, borderLeft: ci > 0 ? `1px solid ${ca(textColor,'08')}` : 'none' }"
37
+ @click="sortable && toggleSort(ci)"
38
+ >
39
+ <span class="inline-flex items-center gap-1.5">
40
+ {{ col.label }}
41
+ <span v-if="sortable" class="text-[10px] transition-all" :style="{ opacity: sortCol === ci ? 1 : 0.25 }">
42
+ {{ sortCol === ci ? (sortDir === 'asc' ? '↑' : '↓') : '↕' }}
43
+ </span>
44
+ </span>
45
+ </th>
46
+ </tr>
47
+ </thead>
48
+ <tbody>
49
+ <tr v-if="!pageRows.length">
50
+ <td :colspan="parsedCols.length" class="px-6 py-12 text-center text-sm" :style="{ opacity: 0.3 }">No results found</td>
51
+ </tr>
52
+ <tr
53
+ v-for="(row, ri) in pageRows" :key="ri"
54
+ :style="{
55
+ borderTop: `1px solid ${ca(textColor,'07')}`,
56
+ backgroundColor: layout === 'striped' && ri % 2 === 1 ? ca(textColor,'03') : 'transparent',
57
+ }"
58
+ >
59
+ <td
60
+ v-for="(cell, ci) in row.cells" :key="ci"
61
+ :class="['px-6 py-4', parsedCols[ci]?.align === 'center' ? 'text-center' : parsedCols[ci]?.align === 'right' ? 'text-right' : 'text-left']"
62
+ :style="{ borderLeft: ci > 0 ? `1px solid ${ca(textColor,'06')}` : 'none' }"
63
+ >
64
+ <span v-if="parsedCols[ci]?.badge" class="inline-block text-[9px] font-black uppercase tracking-wider px-2.5 py-0.5 border"
65
+ :style="{ borderColor: ca(textColor,'18'), color: textColor }">{{ cell }}</span>
66
+ <span v-else :class="[bodyClass]" :style="{ opacity: 0.8 }">{{ cell }}</span>
67
+ </td>
68
+ </tr>
69
+ </tbody>
70
+ </table>
71
+ </div>
72
+
73
+ <!-- CARDS layout -->
74
+ <div v-else class="grid gap-0 border divide-x divide-y" :class="gridCols" :style="{ borderColor: ca(textColor,'12') }">
75
+ <div v-if="!pageRows.length" class="col-span-full py-12 text-center text-sm" :style="{ opacity: 0.3 }">No results found</div>
76
+ <div
77
+ v-for="(row, ri) in pageRows" :key="ri"
78
+ class="p-6"
79
+ >
80
+ <dl class="space-y-3">
81
+ <div v-for="(cell, ci) in row.cells" :key="ci" class="flex items-start justify-between gap-4 border-b pb-2.5 last:border-b-0" :style="{ borderColor: ca(textColor,'07') }">
82
+ <dt class="text-[9px] font-black uppercase tracking-[0.4em] shrink-0" :style="{ opacity: 0.35 }">{{ parsedCols[ci]?.label }}</dt>
83
+ <dd :class="[bodyClass, 'font-medium text-right']" :style="{ opacity: 0.8 }">{{ cell }}</dd>
84
+ </div>
85
+ </dl>
86
+ </div>
87
+ </div>
88
+
89
+ <!-- Pagination -->
90
+ <div v-if="perPage > 0 && totalPages > 1" class="flex items-center justify-between mt-6 border-t pt-4" :style="{ borderColor: ca(textColor,'10') }">
91
+ <span :class="[bodyClass]" :style="{ opacity: 0.4 }">
92
+ {{ (currentPage - 1) * perPage + 1 }}–{{ Math.min(currentPage * perPage, filteredRows.length) }} of {{ filteredRows.length }}
93
+ </span>
94
+ <div class="flex items-center gap-1">
95
+ <button
96
+ v-for="p in totalPages" :key="p"
97
+ class="w-8 h-8 text-xs font-black border transition-all"
98
+ :style="p === currentPage
99
+ ? { backgroundColor: textColor, color: bgColor, borderColor: textColor }
100
+ : { borderColor: ca(textColor,'15'), color: textColor, opacity: 0.5 }"
101
+ @click="currentPage = p"
102
+ >{{ p }}</button>
103
+ </div>
104
+ </div>
105
+
106
+ </div>
107
+ </section>
108
+ </template>
109
+
110
+ <script setup>
111
+ const ca = (c, h) => {
112
+ const m = c?.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
113
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : (c || "") + h;
114
+ };
115
+ import { ref, computed, onMounted } from "vue";
116
+ const props = defineProps({
117
+ layout: { type: String, default: "default" },
118
+ titleTag: { type: String, default: "h2" },
119
+ badge: { type: String, default: "" },
120
+ title: { type: String, default: "" },
121
+ description: { type: String, default: "" },
122
+ caption: { type: String, default: "" },
123
+ searchable: { type: Boolean, default: false },
124
+ sortable: { type: Boolean, default: true },
125
+ stickyHeader: { type: Boolean, default: false },
126
+ perPage: { type: Number, default: 0 },
127
+ cardColumns: { type: String, default: "auto" },
128
+ columns: { type: Array, default: () => [
129
+ { label: "Name", align: "left", badge: false },
130
+ { label: "Role", align: "left", badge: false },
131
+ { label: "Department", align: "left", badge: false },
132
+ { label: "Status", align: "left", badge: true }
133
+ ] },
134
+ items: { type: Array, default: () => [
135
+ { cells: "Alice Martin | Lead Designer | Product | Active" },
136
+ { cells: "Bob Chen | Senior Developer | Engineering | Active" },
137
+ { cells: "Clara Dumont | Product Manager | Product | On leave" },
138
+ { cells: "David Kim | UX Researcher | Design | Active" },
139
+ { cells: "Emma Laurent | DevOps Engineer | Engineering | Active" },
140
+ { cells: "F\xE9lix Moreau | Data Analyst | Analytics | Active" }
141
+ ] },
142
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
143
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
144
+ spacing: { type: String, default: "normal" },
145
+ radius: { type: String, default: "sharp" },
146
+ textDirection: { type: String, default: "ltr" },
147
+ contentWidth: { type: String, default: "normal" },
148
+ textSize: { type: String, default: "md" },
149
+ paddingTop: { type: String, default: "" },
150
+ paddingBottom: { type: String, default: "" },
151
+ marginTop: { type: String, default: "" },
152
+ marginBottom: { type: String, default: "" },
153
+ paddingX: { type: String, default: "" }
154
+ });
155
+ const sectionEl = ref(null);
156
+ const isVisible = ref(false);
157
+ onMounted(() => {
158
+ const obs = new IntersectionObserver(([e]) => {
159
+ if (e.isIntersecting) {
160
+ isVisible.value = true;
161
+ obs.disconnect();
162
+ }
163
+ }, { threshold: 0.05 });
164
+ if (sectionEl.value) obs.observe(sectionEl.value);
165
+ setTimeout(() => {
166
+ if (!isVisible.value) isVisible.value = true;
167
+ }, 300);
168
+ });
169
+ const sectionPad = computed(() => ({ compact: "py-8 px-4 md:px-8", normal: "py-14 px-8 md:px-16", spacious: "py-24 px-8 md:px-16" })[props.spacing] || "py-14 px-8 md:px-16");
170
+ const containerClass = computed(() => ({ narrow: "max-w-3xl mx-auto", normal: "max-w-6xl mx-auto", wide: "max-w-7xl mx-auto", full: "max-w-full" })[props.contentWidth] || "max-w-6xl mx-auto");
171
+ const titleFontSize = computed(() => ({ sm: "clamp(0.9rem,1vw,1.1rem)", md: "clamp(1rem,1.5vw,1.4rem)", lg: "clamp(2.2rem,5vw,4rem)" })[props.textSize] || "clamp(1rem,1.5vw,1.4rem)");
172
+ const bodyClass = computed(() => ({ sm: "text-xs", md: "text-sm", lg: "text-base" })[props.textSize] || "text-sm");
173
+ const parsedCols = computed(() => (props.columns || []).map((col) => ({
174
+ label: col.label || "",
175
+ align: col.align || "left",
176
+ badge: col.badge || false
177
+ })));
178
+ const parsedRows = computed(() => (props.items || []).map((row) => ({
179
+ cells: (row.cells || "").split("|").map((c) => c.trim())
180
+ })));
181
+ const query = ref("");
182
+ const sortCol = ref(-1);
183
+ const sortDir = ref("asc");
184
+ const toggleSort = (i) => {
185
+ if (sortCol.value === i) sortDir.value = sortDir.value === "asc" ? "desc" : "asc";
186
+ else {
187
+ sortCol.value = i;
188
+ sortDir.value = "asc";
189
+ }
190
+ };
191
+ const currentPage = ref(1);
192
+ const filteredRows = computed(() => {
193
+ let rows = parsedRows.value;
194
+ if (props.searchable && query.value.trim()) {
195
+ const q = query.value.toLowerCase();
196
+ rows = rows.filter((r) => r.cells.some((c) => c.toLowerCase().includes(q)));
197
+ }
198
+ if (props.sortable && sortCol.value >= 0) {
199
+ rows = [...rows].sort((a, b) => {
200
+ const av = a.cells[sortCol.value] || "";
201
+ const bv = b.cells[sortCol.value] || "";
202
+ const cmp = av.localeCompare(bv, void 0, { numeric: true, sensitivity: "base" });
203
+ return sortDir.value === "asc" ? cmp : -cmp;
204
+ });
205
+ }
206
+ return rows;
207
+ });
208
+ const totalPages = computed(() => props.perPage > 0 ? Math.ceil(filteredRows.value.length / props.perPage) : 1);
209
+ const pageRows = computed(() => {
210
+ if (props.perPage <= 0) return filteredRows.value;
211
+ const start = (currentPage.value - 1) * props.perPage;
212
+ return filteredRows.value.slice(start, start + props.perPage);
213
+ });
214
+ const gridCols = computed(() => {
215
+ if (props.cardColumns === "1") return "grid-cols-1";
216
+ if (props.cardColumns === "2") return "grid-cols-1 md:grid-cols-2";
217
+ if (props.cardColumns === "4") return "grid-cols-1 sm:grid-cols-2 xl:grid-cols-4";
218
+ const n = parsedCols.value.length;
219
+ if (n <= 3) return "grid-cols-1 md:grid-cols-2";
220
+ return "grid-cols-1 md:grid-cols-2 lg:grid-cols-3";
221
+ });
222
+ const SM = { none: "0", xs: "8px", sm: "24px", md: "48px", lg: "80px", xl: "128px", "-xs": "-8px", "-sm": "-24px", "-md": "-48px", "-lg": "-80px", "-xl": "-128px" };
223
+ const spacingStyle = computed(() => {
224
+ const s = {};
225
+ if (props.paddingTop && SM[props.paddingTop]) s.paddingTop = SM[props.paddingTop];
226
+ if (props.paddingBottom && SM[props.paddingBottom]) s.paddingBottom = SM[props.paddingBottom];
227
+ if (props.marginTop && SM[props.marginTop]) s.marginTop = SM[props.marginTop];
228
+ if (props.marginBottom && SM[props.marginBottom]) s.marginBottom = SM[props.marginBottom];
229
+ if (props.paddingX && SM[props.paddingX]) {
230
+ const v = SM[props.paddingX];
231
+ if (v.startsWith("-")) {
232
+ s.marginLeft = v;
233
+ s.marginRight = v;
234
+ } else {
235
+ s.paddingLeft = v;
236
+ s.paddingRight = v;
237
+ }
238
+ }
239
+ return s;
240
+ });
241
+ </script>
242
+
243
+ <style scoped>
244
+ .sv-out{opacity:0;transform:translateY(16px)}.sv-in{opacity:1;transform:none;transition:opacity .6s ease,transform .6s ease}
245
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: any;
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: any;
@@ -0,0 +1,107 @@
1
+ <template>
2
+ <section ref="sectionEl" :class="[sectionPad, isVisible ? 'sv-in' : 'sv-out']" :dir="textDirection" :style="[{ backgroundColor: bgColor, color: textColor }, spacingStyle]">
3
+ <div :class="[containerClass]">
4
+
5
+ <!-- Header -->
6
+ <div class="border-b pb-6 mb-0 flex items-end gap-8 justify-between" :style="{ borderColor: ca(textColor,'15') }">
7
+ <component :is="titleTag" class="font-black uppercase leading-[0.88]" :style="{ fontSize: titleFontSize, letterSpacing: '-0.03em' }">{{ title }}</component>
8
+ <span class="text-[9px] font-black uppercase tracking-[0.4em] pb-1 shrink-0" :style="{ opacity: 0.3 }">Q&amp;A</span>
9
+ </div>
10
+
11
+ <!-- Items -->
12
+ <div class="divide-y" :style="{ borderColor: ca(textColor,'10') }">
13
+ <div v-for="(item, index) in items" :key="index" :style="{ borderColor: ca(textColor,'10') }">
14
+ <button @click="toggle(index)" class="w-full flex items-start justify-between py-7 text-left cursor-pointer gap-8">
15
+ <div class="flex items-start gap-6">
16
+ <span class="text-[11px] font-black tabular-nums pt-0.5 shrink-0" :style="{ opacity: 0.25 }">{{ String(index + 1).padStart(2, '0') }}</span>
17
+ <span class="font-black uppercase tracking-tight leading-snug">{{ item.question }}</span>
18
+ </div>
19
+ <span class="text-xl font-light shrink-0 mt-0.5 transition-transform duration-200" :style="{ transform: openIndex === index ? 'rotate(45deg)' : 'none', opacity: 0.4 }">+</span>
20
+ </button>
21
+ <div v-if="openIndex === index" class="pl-14 pb-7">
22
+ <p :class="[bodyClass, 'leading-relaxed']" :style="{ opacity: 0.6 }">{{ item.answer }}</p>
23
+ </div>
24
+ </div>
25
+
26
+ <!-- Placeholders -->
27
+ <div v-if="!items.length" v-for="n in 3" :key="n" :style="{ borderColor: ca(textColor,'10') }">
28
+ <div class="flex items-center gap-6 py-7">
29
+ <span class="text-[11px] font-black tabular-nums" :style="{ opacity: 0.15 }">0{{ n }}</span>
30
+ <div class="h-4 flex-1" :style="{ backgroundColor: ca(textColor,'10'), width: n === 1 ? '70%' : n === 2 ? '55%' : '65%' }"></div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+
35
+ </div>
36
+ </section>
37
+ </template>
38
+
39
+ <script setup>
40
+ const ca = (c, h) => {
41
+ const m = c?.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
42
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : (c || "") + h;
43
+ };
44
+ import { ref, computed, onMounted } from "vue";
45
+ const props = defineProps({
46
+ title: { type: String, default: "FAQ" },
47
+ titleTag: { type: String, default: "h2" },
48
+ items: { type: Array, default: () => [] },
49
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
50
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
51
+ spacing: { type: String, default: "normal" },
52
+ radius: { type: String, default: "sharp" },
53
+ textDirection: { type: String, default: "ltr" },
54
+ contentWidth: { type: String, default: "narrow" },
55
+ textSize: { type: String, default: "md" },
56
+ paddingTop: { type: String, default: "" },
57
+ paddingBottom: { type: String, default: "" },
58
+ marginTop: { type: String, default: "" },
59
+ marginBottom: { type: String, default: "" },
60
+ paddingX: { type: String, default: "" }
61
+ });
62
+ const sectionEl = ref(null);
63
+ const isVisible = ref(false);
64
+ onMounted(() => {
65
+ const obs = new IntersectionObserver(([e]) => {
66
+ if (e.isIntersecting) {
67
+ isVisible.value = true;
68
+ obs.disconnect();
69
+ }
70
+ }, { threshold: 0.06 });
71
+ if (sectionEl.value) obs.observe(sectionEl.value);
72
+ setTimeout(() => {
73
+ if (!isVisible.value) isVisible.value = true;
74
+ }, 300);
75
+ });
76
+ const sectionPad = computed(() => ({ compact: "py-8 px-4 md:px-8", normal: "py-14 px-8 md:px-16", spacious: "py-24 px-8 md:px-16" })[props.spacing] || "py-14 px-8 md:px-16");
77
+ const containerClass = computed(() => ({ narrow: "max-w-3xl mx-auto", normal: "max-w-6xl mx-auto", wide: "max-w-7xl mx-auto", full: "max-w-full" })[props.contentWidth] || "max-w-3xl mx-auto");
78
+ const titleFontSize = computed(() => ({ sm: "clamp(1rem,1.5vw,1.3rem)", md: "clamp(1.5rem,2.5vw,2rem)", lg: "clamp(2.5rem,6vw,5rem)" })[props.textSize] || "clamp(1.5rem,2.5vw,2rem)");
79
+ const bodyClass = computed(() => ({ sm: "text-xs", md: "text-sm", lg: "text-base" })[props.textSize] || "text-sm");
80
+ const openIndex = ref(null);
81
+ const toggle = (index) => {
82
+ openIndex.value = openIndex.value === index ? null : index;
83
+ };
84
+ const SM = { none: "0", xs: "8px", sm: "24px", md: "48px", lg: "80px", xl: "128px", "-xs": "-8px", "-sm": "-24px", "-md": "-48px", "-lg": "-80px", "-xl": "-128px" };
85
+ const spacingStyle = computed(() => {
86
+ const s = {};
87
+ if (props.paddingTop && SM[props.paddingTop]) s.paddingTop = SM[props.paddingTop];
88
+ if (props.paddingBottom && SM[props.paddingBottom]) s.paddingBottom = SM[props.paddingBottom];
89
+ if (props.marginTop && SM[props.marginTop]) s.marginTop = SM[props.marginTop];
90
+ if (props.marginBottom && SM[props.marginBottom]) s.marginBottom = SM[props.marginBottom];
91
+ if (props.paddingX && SM[props.paddingX]) {
92
+ const v = SM[props.paddingX];
93
+ if (v.startsWith("-")) {
94
+ s.marginLeft = v;
95
+ s.marginRight = v;
96
+ } else {
97
+ s.paddingLeft = v;
98
+ s.paddingRight = v;
99
+ }
100
+ }
101
+ return s;
102
+ });
103
+ </script>
104
+
105
+ <style scoped>
106
+ .sv-out{opacity:0;transform:translateY(16px)}.sv-in{opacity:1;transform:none;transition:opacity .6s ease,transform .6s ease}
107
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: any;
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: any;
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <section ref="sectionEl" :class="[sectionPad, isVisible ? 'sv-in' : 'sv-out']" :dir="textDirection" :style="[{ backgroundColor: bgColor, color: textColor }, spacingStyle]">
3
+ <div :class="[containerClass]">
4
+
5
+ <!-- Header -->
6
+ <div class="border-b mb-0 pb-6 flex items-end justify-between gap-8" :style="{ borderColor: ca(textColor,'15') }">
7
+ <component :is="titleTag" class="font-black uppercase leading-[0.88]" :style="{ fontSize: titleFontSize, letterSpacing: '-0.03em' }">{{ title }}</component>
8
+ <span class="text-[9px] font-black uppercase tracking-[0.4em] shrink-0 pb-1" :style="{ opacity: 0.3 }">{{ items.length || 3 }} items</span>
9
+ </div>
10
+
11
+ <!-- Grid -->
12
+ <div v-if="items.length" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 border-b" :style="{ borderColor: ca(textColor,'10') }">
13
+ <div v-for="(item, index) in items" :key="index"
14
+ class="p-8 border-b border-r last:border-r-0 md:[&:nth-child(2n)]:border-r-0 lg:[&:nth-child(2n)]:border-r lg:[&:nth-child(3n)]:border-r-0 transition-colors hover:bg-black/[0.02]"
15
+ :style="{ borderColor: ca(textColor,'10') }">
16
+ <div class="flex items-start justify-between mb-6">
17
+ <span class="font-black tabular-nums" :style="{ fontSize: 'clamp(1.8rem,3vw,2.5rem)', opacity: 0.12, letterSpacing: '-0.04em' }">{{ String(index + 1).padStart(2, '0') }}</span>
18
+ <div class="w-px self-stretch" :style="{ backgroundColor: ca(textColor,'10') }"></div>
19
+ </div>
20
+ <component :is="itemTag" class="font-black uppercase tracking-tight mb-3 leading-tight">{{ item.title }}</component>
21
+ <p :class="[bodyClass, 'leading-relaxed']" :style="{ opacity: 0.55 }">{{ item.description || item.text }}</p>
22
+ </div>
23
+ </div>
24
+
25
+ <!-- Placeholder -->
26
+ <div v-else class="grid grid-cols-1 md:grid-cols-3 border-b" :style="{ borderColor: ca(textColor,'10') }">
27
+ <div v-for="n in 3" :key="n" class="p-8 border-r last:border-r-0" :style="{ borderColor: ca(textColor,'10') }">
28
+ <span class="block font-black tabular-nums mb-6" :style="{ fontSize: '2rem', opacity: 0.08 }">0{{ n }}</span>
29
+ <div class="h-4 mb-3" :style="{ backgroundColor: ca(textColor,'12'), width: '60%' }"></div>
30
+ <div class="h-3" :style="{ backgroundColor: ca(textColor,'08'), width: '80%' }"></div>
31
+ </div>
32
+ </div>
33
+
34
+ </div>
35
+ </section>
36
+ </template>
37
+
38
+ <script setup>
39
+ const ca = (c, h) => {
40
+ const m = c?.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
41
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : (c || "") + h;
42
+ };
43
+ import { ref, computed, onMounted } from "vue";
44
+ const props = defineProps({
45
+ title: { type: String, default: "Why choose us?" },
46
+ titleTag: { type: String, default: "h2" },
47
+ itemTag: { type: String, default: "h3" },
48
+ items: { type: Array, default: () => [] },
49
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
50
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
51
+ spacing: { type: String, default: "normal" },
52
+ radius: { type: String, default: "sharp" },
53
+ textDirection: { type: String, default: "ltr" },
54
+ contentWidth: { type: String, default: "normal" },
55
+ textSize: { type: String, default: "md" },
56
+ paddingTop: { type: String, default: "" },
57
+ paddingBottom: { type: String, default: "" },
58
+ marginTop: { type: String, default: "" },
59
+ marginBottom: { type: String, default: "" },
60
+ paddingX: { type: String, default: "" }
61
+ });
62
+ const sectionEl = ref(null);
63
+ const isVisible = ref(false);
64
+ onMounted(() => {
65
+ const obs = new IntersectionObserver(([e]) => {
66
+ if (e.isIntersecting) {
67
+ isVisible.value = true;
68
+ obs.disconnect();
69
+ }
70
+ }, { threshold: 0.06 });
71
+ if (sectionEl.value) obs.observe(sectionEl.value);
72
+ setTimeout(() => {
73
+ if (!isVisible.value) isVisible.value = true;
74
+ }, 300);
75
+ });
76
+ const sectionPad = computed(() => ({ compact: "py-8 px-4 md:px-8", normal: "py-14 px-8 md:px-16", spacious: "py-24 px-8 md:px-16" })[props.spacing] || "py-14 px-8 md:px-16");
77
+ const containerClass = computed(() => ({ narrow: "max-w-3xl mx-auto", normal: "max-w-6xl mx-auto", wide: "max-w-7xl mx-auto", full: "max-w-full" })[props.contentWidth] || "max-w-6xl mx-auto");
78
+ const titleFontSize = computed(() => ({ sm: "clamp(1.2rem,2vw,1.8rem)", md: "clamp(1.8rem,3vw,2.8rem)", lg: "clamp(2.5rem,6vw,5rem)" })[props.textSize] || "clamp(1.8rem,3vw,2.8rem)");
79
+ const bodyClass = computed(() => ({ sm: "text-xs", md: "text-sm", lg: "text-base" })[props.textSize] || "text-sm");
80
+ const SM = { none: "0", xs: "8px", sm: "24px", md: "48px", lg: "80px", xl: "128px", "-xs": "-8px", "-sm": "-24px", "-md": "-48px", "-lg": "-80px", "-xl": "-128px" };
81
+ const spacingStyle = computed(() => {
82
+ const s = {};
83
+ if (props.paddingTop && SM[props.paddingTop]) s.paddingTop = SM[props.paddingTop];
84
+ if (props.paddingBottom && SM[props.paddingBottom]) s.paddingBottom = SM[props.paddingBottom];
85
+ if (props.marginTop && SM[props.marginTop]) s.marginTop = SM[props.marginTop];
86
+ if (props.marginBottom && SM[props.marginBottom]) s.marginBottom = SM[props.marginBottom];
87
+ if (props.paddingX && SM[props.paddingX]) {
88
+ const v = SM[props.paddingX];
89
+ if (v.startsWith("-")) {
90
+ s.marginLeft = v;
91
+ s.marginRight = v;
92
+ } else {
93
+ s.paddingLeft = v;
94
+ s.paddingRight = v;
95
+ }
96
+ }
97
+ return s;
98
+ });
99
+ </script>
100
+
101
+ <style scoped>
102
+ .sv-out{opacity:0;transform:translateY(16px)}.sv-in{opacity:1;transform:none;transition:opacity .6s ease,transform .6s ease}
103
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: any;
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: any;
@@ -0,0 +1,108 @@
1
+ <template>
2
+ <section
3
+ ref="rootEl"
4
+ class="relative overflow-hidden"
5
+ :dir="textDirection"
6
+ :style="[{ backgroundColor: bgColor, color: textColor }, spacingStyle]"
7
+ >
8
+ <div :class="['relative mx-auto px-8 md:px-16', containerClass, variant === 'compact' ? 'py-14 md:py-20' : 'py-20 md:py-28']">
9
+
10
+ <!-- Grid layout: text left, images right -->
11
+ <div class="grid md:grid-cols-2 gap-12 md:gap-16 items-center">
12
+
13
+ <!-- Left: text block -->
14
+ <div>
15
+ <div class="border-l-4 pl-8 mb-10" :style="{ borderColor: textColor }">
16
+ <component :is="titleTag" class="font-black uppercase leading-[0.88]" :style="{ fontSize: titleFontSize, letterSpacing: '-0.04em' }">
17
+ {{ title }}
18
+ <template v-if="titleLine2Prefix || titleHighlight">
19
+ <br />
20
+ <span v-if="titleLine2Prefix">{{ titleLine2Prefix }} </span>
21
+ <span v-if="titleHighlight" :style="{ color: highlightColor }">{{ titleHighlight }}</span>
22
+ </template>
23
+ </component>
24
+ </div>
25
+
26
+ <p v-if="description" class="text-sm leading-relaxed mb-8 max-w-sm" :style="{ opacity: 0.6 }">{{ description }}</p>
27
+
28
+ <div v-if="primaryCtaText || secondaryCtaText" class="flex flex-wrap gap-3">
29
+ <NuxtLink v-if="primaryCtaText" :to="primaryCtaLink || '#'"
30
+ class="inline-flex items-center gap-3 px-7 py-3.5 text-[11px] font-black uppercase tracking-widest border transition-all hover:gap-6"
31
+ :style="{ backgroundColor: textColor, color: bgColor, borderColor: textColor }">
32
+ {{ primaryCtaText }}<span>→</span>
33
+ </NuxtLink>
34
+ <NuxtLink v-if="secondaryCtaText" :to="secondaryCtaLink || '#'"
35
+ class="inline-flex items-center gap-3 px-7 py-3.5 border text-[11px] font-black uppercase tracking-widest transition-all hover:gap-6"
36
+ :style="{ borderColor: ca(textColor,'30'), color: textColor }">
37
+ {{ secondaryCtaText }}
38
+ </NuxtLink>
39
+ </div>
40
+
41
+ <p v-if="socialProof" class="text-xs font-medium mt-4 border-t pt-4" :style="{ opacity: 0.4, borderColor: ca(textColor,'12') }">{{ socialProof }}</p>
42
+ </div>
43
+
44
+ <!-- Right: images grid -->
45
+ <div v-if="images?.length" class="grid grid-cols-2 gap-2">
46
+ <div
47
+ v-for="(img, i) in images.slice(0, 4)" :key="i"
48
+ :class="['overflow-hidden border', i === 0 ? 'col-span-2 aspect-[16/7]' : 'aspect-square']"
49
+ :style="{ borderColor: ca(textColor,'12') }"
50
+ >
51
+ <img :src="typeof img === 'object' ? img.url : img" :alt="typeof img === 'object' ? (img.alt || '') : ''" class="w-full h-full object-cover" />
52
+ </div>
53
+ <div v-if="!images.length" v-for="n in 3" :key="n" :class="['border', n === 1 ? 'col-span-2 aspect-[16/7]' : 'aspect-square']" :style="{ borderColor: ca(textColor,'10'), backgroundColor: ca(textColor,'04') }"></div>
54
+ </div>
55
+ <div v-else class="grid grid-cols-2 gap-2">
56
+ <div v-for="n in 3" :key="n" :class="['border', n === 1 ? 'col-span-2 aspect-[16/7]' : 'aspect-square']" :style="{ borderColor: ca(textColor,'10'), backgroundColor: ca(textColor,'04') }"></div>
57
+ </div>
58
+
59
+ </div>
60
+ </div>
61
+ </section>
62
+ </template>
63
+
64
+ <script setup>
65
+ import { ref, computed } from "vue";
66
+ const ca = (c, h) => {
67
+ if (!c) return "#000" + h;
68
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
69
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
70
+ };
71
+ const props = defineProps({
72
+ titleTag: { type: String, default: "h1" },
73
+ title: { type: String, default: "The Headline" },
74
+ titleLine2Prefix: { type: String, default: "" },
75
+ titleHighlight: { type: String, default: "Highlighted" },
76
+ highlightColor: { type: String, default: "rgba(var(--primary-color), 1)" },
77
+ description: { type: String, default: "A compelling subtitle that explains your value proposition clearly." },
78
+ socialProof: { type: String, default: "" },
79
+ primaryCtaText: { type: String, default: "Get Started" },
80
+ primaryCtaLink: { type: String, default: "#" },
81
+ secondaryCtaText: { type: String, default: "" },
82
+ secondaryCtaLink: { type: String, default: "#" },
83
+ images: { type: Array, default: () => [] },
84
+ variant: { type: String, default: "standard" },
85
+ animation: { type: String, default: "subtle" },
86
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
87
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
88
+ contentWidth: { type: String, default: "normal" },
89
+ textSize: { type: String, default: "md" },
90
+ textDirection: { type: String, default: "ltr" },
91
+ paddingTop: { type: String, default: "" },
92
+ paddingBottom: { type: String, default: "" },
93
+ marginTop: { type: String, default: "" },
94
+ marginBottom: { type: String, default: "" }
95
+ });
96
+ const rootEl = ref(null);
97
+ const containerClass = computed(() => ({ narrow: "max-w-4xl mx-auto", normal: "max-w-6xl mx-auto", wide: "max-w-7xl mx-auto", full: "max-w-full" })[props.contentWidth] || "max-w-6xl mx-auto");
98
+ const titleFontSize = computed(() => ({ sm: "clamp(2rem,4vw,3.5rem)", md: "clamp(2.5rem,5vw,4.5rem)", lg: "clamp(3rem,7vw,6rem)" })[props.textSize] || "clamp(2.5rem,5vw,4.5rem)");
99
+ const SM = { none: "0", xs: "8px", sm: "24px", md: "48px", lg: "80px", xl: "128px", "-xs": "-8px", "-sm": "-24px", "-md": "-48px", "-lg": "-80px", "-xl": "-128px" };
100
+ const spacingStyle = computed(() => {
101
+ const s = {};
102
+ if (props.paddingTop && SM[props.paddingTop]) s.paddingTop = SM[props.paddingTop];
103
+ if (props.paddingBottom && SM[props.paddingBottom]) s.paddingBottom = SM[props.paddingBottom];
104
+ if (props.marginTop && SM[props.marginTop]) s.marginTop = SM[props.marginTop];
105
+ if (props.marginBottom && SM[props.marginBottom]) s.marginBottom = SM[props.marginBottom];
106
+ return s;
107
+ });
108
+ </script>
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: any;
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: any;