cinqcinqdev-seo 0.1.32 → 0.1.34

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/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "0.1.32",
7
+ "version": "0.1.34",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "unknown"
@@ -5,7 +5,7 @@
5
5
  <!-- SPLIT layout -->
6
6
  <div v-if="layout === 'split'" class="grid grid-cols-1 md:grid-cols-2 gap-16 items-start">
7
7
  <div>
8
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
8
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
9
9
  <component :is="titleTag" class="text-3xl md:text-5xl font-black uppercase tracking-tighter leading-[0.9] mb-4">{{ title }}</component>
10
10
  <p v-if="description" class="text-sm leading-relaxed mb-8" :style="{ opacity: 0.55 }">{{ description }}</p>
11
11
  <div v-if="infos && infos.length" class="space-y-4">
@@ -18,17 +18,17 @@
18
18
  </div>
19
19
  </div>
20
20
  </div>
21
- <div :class="['p-8 border', cardRound]" :style="{ backgroundColor: textColor + '04', borderColor: textColor + '10' }">
21
+ <div :class="['p-8 border', cardRound]" :style="{ backgroundColor: ca(textColor, '04'), borderColor: ca(textColor, '10') }">
22
22
  <form @submit.prevent="handleSubmit" class="space-y-5">
23
23
  <slot name="fields">
24
24
  <div v-for="field in fields" :key="field.name" class="flex flex-col gap-1.5">
25
25
  <label class="text-[11px] font-black uppercase tracking-widest" :style="{ opacity: 0.5 }">{{ field.label }}<span v-if="field.required" class="ml-0.5" :style="{ opacity: 0.4 }">*</span></label>
26
26
  <textarea v-if="field.type === 'textarea'" v-model="formData[field.name]" :placeholder="field.placeholder" :required="field.required" rows="4"
27
27
  class="w-full px-4 py-3 rounded-xl text-sm resize-none"
28
- :style="{ backgroundColor: textColor + '08', border: `1px solid ${textColor}15`, color: textColor, outline: 'none' }"></textarea>
28
+ :style="{ backgroundColor: ca(textColor, '08'), border: `1px solid ${ca(textColor, '15')}`, color: textColor, outline: 'none' }"></textarea>
29
29
  <input v-else v-model="formData[field.name]" :type="field.type || 'text'" :placeholder="field.placeholder" :required="field.required"
30
30
  class="w-full px-4 py-3 rounded-xl text-sm"
31
- :style="{ backgroundColor: textColor + '08', border: `1px solid ${textColor}15`, color: textColor, outline: 'none' }" />
31
+ :style="{ backgroundColor: ca(textColor, '08'), border: `1px solid ${ca(textColor, '15')}`, color: textColor, outline: 'none' }" />
32
32
  </div>
33
33
  </slot>
34
34
  <button type="submit" :disabled="submitting"
@@ -43,7 +43,7 @@
43
43
 
44
44
  <!-- CENTERED layout -->
45
45
  <div v-else-if="layout === 'centered'" class="max-w-xl mx-auto text-center">
46
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
46
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
47
47
  <component :is="titleTag" class="text-3xl md:text-5xl font-black uppercase tracking-tighter leading-[0.9] mb-4">{{ title }}</component>
48
48
  <p v-if="description" class="text-sm leading-relaxed mb-10" :style="{ opacity: 0.55 }">{{ description }}</p>
49
49
  <form @submit.prevent="handleSubmit" class="space-y-4 text-left">
@@ -51,10 +51,10 @@
51
51
  <label class="text-[11px] font-black uppercase tracking-widest" :style="{ opacity: 0.5 }">{{ field.label }}<span v-if="field.required" class="ml-0.5" :style="{ opacity: 0.4 }">*</span></label>
52
52
  <textarea v-if="field.type === 'textarea'" v-model="formData[field.name]" :placeholder="field.placeholder" :required="field.required" rows="4"
53
53
  class="w-full px-4 py-3 rounded-xl text-sm resize-none"
54
- :style="{ backgroundColor: textColor + '08', border: `1px solid ${textColor}15`, color: textColor, outline: 'none' }"></textarea>
54
+ :style="{ backgroundColor: ca(textColor, '08'), border: `1px solid ${ca(textColor, '15')}`, color: textColor, outline: 'none' }"></textarea>
55
55
  <input v-else v-model="formData[field.name]" :type="field.type || 'text'" :placeholder="field.placeholder" :required="field.required"
56
56
  class="w-full px-4 py-3 rounded-xl text-sm"
57
- :style="{ backgroundColor: textColor + '08', border: `1px solid ${textColor}15`, color: textColor, outline: 'none' }" />
57
+ :style="{ backgroundColor: ca(textColor, '08'), border: `1px solid ${ca(textColor, '15')}`, color: textColor, outline: 'none' }" />
58
58
  </div>
59
59
  <button type="submit" :disabled="submitting"
60
60
  class="w-full py-3.5 rounded-full text-[11px] font-black uppercase tracking-widest transition-all hover:opacity-80 active:scale-95 disabled:opacity-50"
@@ -67,11 +67,11 @@
67
67
 
68
68
  <!-- MINIMAL layout (default) -->
69
69
  <div v-else class="max-w-2xl">
70
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
70
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
71
71
  <component :is="titleTag" class="text-3xl md:text-5xl font-black uppercase tracking-tighter leading-[0.9] mb-4">{{ title }}</component>
72
72
  <p v-if="description" class="text-sm leading-relaxed mb-10" :style="{ opacity: 0.55 }">{{ description }}</p>
73
73
  <form @submit.prevent="handleSubmit" class="space-y-6">
74
- <div v-for="field in fields" :key="field.name" class="flex flex-col gap-2 border-b pb-6" :style="{ borderColor: textColor + '10' }">
74
+ <div v-for="field in fields" :key="field.name" class="flex flex-col gap-2 border-b pb-6" :style="{ borderColor: ca(textColor, '10') }">
75
75
  <label class="text-[10px] font-black uppercase tracking-widest" :style="{ opacity: 0.4 }">{{ field.label }}<span v-if="field.required" class="ml-0.5">*</span></label>
76
76
  <textarea v-if="field.type === 'textarea'" v-model="formData[field.name]" :placeholder="field.placeholder" :required="field.required" rows="3"
77
77
  class="w-full bg-transparent text-sm resize-none"
@@ -96,6 +96,10 @@
96
96
  </template>
97
97
 
98
98
  <script setup>
99
+ const ca = (c, h) => {
100
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
101
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
102
+ };
99
103
  import { ref, reactive, computed } from "vue";
100
104
  const props = defineProps({
101
105
  layout: { type: String, default: "split" },
@@ -114,8 +118,8 @@ const props = defineProps({
114
118
  ]
115
119
  },
116
120
  infos: { type: Array, default: () => [] },
117
- bgColor: { type: String, default: "#ffffff" },
118
- textColor: { type: String, default: "#000000" },
121
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
122
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
119
123
  spacing: { type: String, default: "normal" },
120
124
  radius: { type: String, default: "rounded" }
121
125
  });
@@ -7,7 +7,7 @@
7
7
  <div class="space-y-3">
8
8
  <div v-for="(item, index) in items" :key="index"
9
9
  :class="['overflow-hidden border transition-all duration-300', cardRound]"
10
- :style="{ backgroundColor: textColor + '04', borderColor: textColor + '10' }">
10
+ :style="{ backgroundColor: ca(textColor, '04'), borderColor: ca(textColor, '10') }">
11
11
  <button @click="toggle(index)" class="w-full flex items-center justify-between p-7 text-left cursor-pointer">
12
12
  <span class="text-sm md:text-base font-black uppercase tracking-tight pr-8 leading-snug">{{ item.question }}</span>
13
13
  <span class="text-2xl font-light shrink-0 transition-transform duration-300" :style="{ transform: openIndex === index ? 'rotate(45deg)' : 'none' }">+</span>
@@ -18,8 +18,8 @@
18
18
  </div>
19
19
  <div v-if="!items.length" v-for="n in 3" :key="n"
20
20
  :class="['border p-7', cardRound]"
21
- :style="{ backgroundColor: textColor + '04', borderColor: textColor + '10' }">
22
- <div class="h-4 rounded" :style="{ backgroundColor: textColor + '15', width: n === 1 ? '70%' : n === 2 ? '55%' : '65%' }"></div>
21
+ :style="{ backgroundColor: ca(textColor, '04'), borderColor: ca(textColor, '10') }">
22
+ <div class="h-4 rounded" :style="{ backgroundColor: ca(textColor, '15'), width: n === 1 ? '70%' : n === 2 ? '55%' : '65%' }"></div>
23
23
  </div>
24
24
  </div>
25
25
  </div>
@@ -27,13 +27,17 @@
27
27
  </template>
28
28
 
29
29
  <script setup>
30
+ const ca = (c, h) => {
31
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
32
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
33
+ };
30
34
  import { ref, computed } from "vue";
31
35
  const props = defineProps({
32
36
  title: { type: String, default: "FAQ" },
33
37
  titleTag: { type: String, default: "h2" },
34
38
  items: { type: Array, default: () => [] },
35
- bgColor: { type: String, default: "#F9F9FB" },
36
- textColor: { type: String, default: "#000000" },
39
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
40
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
37
41
  spacing: { type: String, default: "normal" },
38
42
  radius: { type: String, default: "rounded" }
39
43
  });
@@ -4,7 +4,7 @@
4
4
  <div class="mb-16 md:mb-20">
5
5
  <component :is="titleTag" class="text-4xl md:text-6xl font-black uppercase tracking-tighter leading-none max-w-4xl italic">{{ title }}</component>
6
6
  </div>
7
- <div v-if="items.length" :class="['grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-px overflow-hidden', cardRound]" :style="{ backgroundColor: textColor + '10', border: `1px solid ${textColor}10` }">
7
+ <div v-if="items.length" :class="['grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-px overflow-hidden', cardRound]" :style="{ backgroundColor: ca(textColor, '10'), border: `1px solid ${ca(textColor, '10')}` }">
8
8
  <div v-for="(item, index) in items" :key="index" class="p-10 transition-all duration-300 hover:brightness-95" :style="{ backgroundColor: bgColor }">
9
9
  <div class="flex flex-col h-full">
10
10
  <span class="text-[10px] font-black opacity-20 mb-8 tracking-widest">{{ index < 9 ? '0' : '' }}{{ index + 1 }}</span>
@@ -13,11 +13,11 @@
13
13
  </div>
14
14
  </div>
15
15
  </div>
16
- <div v-else :class="['grid grid-cols-1 md:grid-cols-3 gap-px overflow-hidden', cardRound]" :style="{ backgroundColor: textColor + '10', border: `1px solid ${textColor}10` }">
16
+ <div v-else :class="['grid grid-cols-1 md:grid-cols-3 gap-px overflow-hidden', cardRound]" :style="{ backgroundColor: ca(textColor, '10'), border: `1px solid ${ca(textColor, '10')}` }">
17
17
  <div v-for="n in 3" :key="n" class="p-10" :style="{ backgroundColor: bgColor }">
18
18
  <span class="text-[10px] font-black opacity-20 mb-8 tracking-widest block">0{{ n }}</span>
19
- <div class="h-4 rounded mb-3" :style="{ backgroundColor: textColor + '12', width: '60%' }"></div>
20
- <div class="h-3 rounded" :style="{ backgroundColor: textColor + '08', width: '80%' }"></div>
19
+ <div class="h-4 rounded mb-3" :style="{ backgroundColor: ca(textColor, '12'), width: '60%' }"></div>
20
+ <div class="h-3 rounded" :style="{ backgroundColor: ca(textColor, '08'), width: '80%' }"></div>
21
21
  </div>
22
22
  </div>
23
23
  </div>
@@ -25,14 +25,18 @@
25
25
  </template>
26
26
 
27
27
  <script setup>
28
+ const ca = (c, h) => {
29
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
30
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
31
+ };
28
32
  import { computed } from "vue";
29
33
  const props = defineProps({
30
34
  title: { type: String, default: "Why choose us?" },
31
35
  titleTag: { type: String, default: "h2" },
32
36
  itemTag: { type: String, default: "h3" },
33
37
  items: { type: Array, default: () => [] },
34
- bgColor: { type: String, default: "#ffffff" },
35
- textColor: { type: String, default: "#000000" },
38
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
39
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
36
40
  spacing: { type: String, default: "normal" },
37
41
  radius: { type: String, default: "rounded" }
38
42
  });
@@ -4,8 +4,8 @@
4
4
  <!-- CENTERED -->
5
5
  <div v-if="layout === 'centered'" class="px-6 md:px-12 pt-20 pb-16 text-center">
6
6
  <div class="max-w-4xl mx-auto">
7
- <span v-if="badge" class="inline-flex items-center gap-1.5 text-[10px] font-bold tracking-[0.4em] uppercase px-4 py-1.5 rounded-full border mb-8" :style="{ borderColor: textColor + '30', color: textColor + '80' }">
8
- <span class="w-1.5 h-1.5 rounded-full inline-block" :style="{ backgroundColor: textColor + '60' }"></span>{{ badge }}
7
+ <span v-if="badge" class="inline-flex items-center gap-1.5 text-[10px] font-bold tracking-[0.4em] uppercase px-4 py-1.5 rounded-full border mb-8" :style="{ borderColor: ca(textColor, '30'), color: ca(textColor, '80') }">
8
+ <span class="w-1.5 h-1.5 rounded-full inline-block" :style="{ backgroundColor: ca(textColor, '60') }"></span>{{ badge }}
9
9
  </span>
10
10
  <component :is="titleTag" class="font-black uppercase tracking-tighter leading-[0.88] mb-6" :style="{ fontSize: titleSize === 'sm' ? 'clamp(2.5rem,5vw,4rem)' : titleSize === 'lg' ? 'clamp(3.5rem,9vw,8rem)' : 'clamp(3rem,7vw,6rem)' }">{{ title }}</component>
11
11
  <p class="text-sm leading-relaxed max-w-lg mx-auto mb-10" :style="{ opacity: 0.5 }">{{ subtitle }}</p>
@@ -27,7 +27,7 @@
27
27
  </div>
28
28
  <div :class="['aspect-[4/3] overflow-hidden', cardRound]">
29
29
  <img v-if="image" :src="image" class="w-full h-full object-cover" />
30
- <div v-else class="w-full h-full" :style="{ backgroundColor: textColor + '06' }"></div>
30
+ <div v-else class="w-full h-full" :style="{ backgroundColor: ca(textColor, '06') }"></div>
31
31
  </div>
32
32
  </div>
33
33
  </div>
@@ -35,7 +35,7 @@
35
35
  <!-- BENTO -->
36
36
  <div v-else-if="layout === 'bento'" class="p-3 md:p-5">
37
37
  <div class="max-w-6xl mx-auto grid grid-cols-12 gap-3">
38
- <div :class="['col-span-12 md:col-span-7 p-8 md:p-10 border flex flex-col justify-between min-h-[320px]', cardRound]" :style="{ borderColor: textColor + '10', backgroundColor: textColor + '04' }">
38
+ <div :class="['col-span-12 md:col-span-7 p-8 md:p-10 border flex flex-col justify-between min-h-[320px]', cardRound]" :style="{ borderColor: ca(textColor, '10'), backgroundColor: ca(textColor, '04') }">
39
39
  <span v-if="badge" class="text-[9px] font-black uppercase tracking-[0.4em] opacity-30">{{ badge }}</span>
40
40
  <div>
41
41
  <component :is="titleTag" class="font-black uppercase tracking-tighter leading-[0.88] mb-4" :style="{ fontSize: 'clamp(2rem,4.5vw,3.8rem)' }">{{ title }}</component>
@@ -45,7 +45,7 @@
45
45
  </div>
46
46
  <div :class="['col-span-12 md:col-span-5 overflow-hidden min-h-[260px] md:min-h-[320px]', cardRound]">
47
47
  <img v-if="image" :src="image" class="w-full h-full object-cover" />
48
- <div v-else class="w-full h-full" :style="{ backgroundColor: textColor + '08' }"></div>
48
+ <div v-else class="w-full h-full" :style="{ backgroundColor: ca(textColor, '08') }"></div>
49
49
  </div>
50
50
  </div>
51
51
  </div>
@@ -54,15 +54,15 @@
54
54
  <div v-else-if="layout === 'fullscreen'" class="relative min-h-[88vh] flex flex-col justify-end">
55
55
  <div class="absolute inset-0">
56
56
  <img v-if="image" :src="image" class="w-full h-full object-cover" />
57
- <div v-else class="w-full h-full" :style="{ backgroundColor: textColor + '08' }"></div>
58
- <div class="absolute inset-0" :style="{ background: `linear-gradient(to top, ${bgColor} 20%, ${bgColor}cc 40%, ${bgColor}44 65%, transparent 100%)` }"></div>
57
+ <div v-else class="w-full h-full" :style="{ backgroundColor: ca(textColor, '08') }"></div>
58
+ <div class="absolute inset-0" :style="{ background: `linear-gradient(to top, ${bgColor} 20%, ${ca(bgColor, 'cc')} 40%, ${ca(bgColor, '44')} 65%, transparent 100%)` }"></div>
59
59
  </div>
60
60
  <div class="relative z-10 max-w-6xl mx-auto w-full px-6 md:px-12 pb-14">
61
61
  <span v-if="badge" class="inline-block text-[9px] font-black uppercase tracking-[0.5em] opacity-40 mb-4">{{ badge }}</span>
62
62
  <component :is="titleTag" class="font-black uppercase tracking-tighter leading-[0.88] mb-6" :style="{ fontSize: 'clamp(3rem,8vw,7rem)' }">{{ title }}</component>
63
63
  <div class="flex flex-col sm:flex-row sm:items-center gap-6 sm:gap-10">
64
64
  <p class="text-sm leading-relaxed max-w-xs" :style="{ opacity: 0.6 }">{{ subtitle }}</p>
65
- <NuxtLink :to="ctaLink || '#'" class="inline-flex items-center gap-2.5 px-7 py-3 rounded-full text-[11px] font-black uppercase tracking-widest border transition-all hover:gap-5 shrink-0" :style="{ borderColor: textColor + '50', color: textColor }">{{ ctaText }}<span>→</span></NuxtLink>
65
+ <NuxtLink :to="ctaLink || '#'" class="inline-flex items-center gap-2.5 px-7 py-3 rounded-full text-[11px] font-black uppercase tracking-widest border transition-all hover:gap-5 shrink-0" :style="{ borderColor: ca(textColor, '50'), color: textColor }">{{ ctaText }}<span>→</span></NuxtLink>
66
66
  </div>
67
67
  </div>
68
68
  </div>
@@ -70,16 +70,16 @@
70
70
  <!-- MINIMAL -->
71
71
  <div v-else-if="layout === 'minimal'" class="px-6 md:px-12 py-14">
72
72
  <div class="max-w-6xl mx-auto">
73
- <div class="flex items-center gap-4 mb-10 border-b pb-5" :style="{ borderColor: textColor + '10' }">
73
+ <div class="flex items-center gap-4 mb-10 border-b pb-5" :style="{ borderColor: ca(textColor, '10') }">
74
74
  <span v-if="badge" class="text-[9px] font-black uppercase tracking-[0.5em] opacity-30">{{ badge }}</span>
75
- <div class="flex-1 h-px" :style="{ backgroundColor: textColor + '08' }"></div>
75
+ <div class="flex-1 h-px" :style="{ backgroundColor: ca(textColor, '08') }"></div>
76
76
  <span class="text-[9px] font-black uppercase tracking-[0.5em] opacity-20">{{ ctaText }}</span>
77
77
  </div>
78
78
  <component :is="titleTag" class="font-black uppercase tracking-tighter leading-[0.85] mb-10" :style="{ fontSize: 'clamp(3.5rem,10vw,9rem)' }">{{ title }}</component>
79
79
  <div v-if="image" :class="['mb-10 overflow-hidden aspect-video', cardRound]">
80
80
  <img :src="image" class="w-full h-full object-cover" />
81
81
  </div>
82
- <div class="flex flex-col md:flex-row items-start md:items-end justify-between gap-6 border-t pt-8" :style="{ borderColor: textColor + '10' }">
82
+ <div class="flex flex-col md:flex-row items-start md:items-end justify-between gap-6 border-t pt-8" :style="{ borderColor: ca(textColor, '10') }">
83
83
  <p class="text-sm leading-relaxed max-w-xs" :style="{ opacity: 0.5 }">{{ subtitle }}</p>
84
84
  <NuxtLink :to="ctaLink || '#'" class="inline-flex items-center gap-2.5 text-[11px] font-black uppercase tracking-widest transition-all hover:gap-5 shrink-0">{{ ctaText }}<span>→</span></NuxtLink>
85
85
  </div>
@@ -90,7 +90,7 @@
90
90
  <div v-else class="px-6 md:px-12 py-14">
91
91
  <div class="max-w-6xl mx-auto">
92
92
  <div class="flex items-center gap-4 mb-8">
93
- <div class="w-8 h-px" :style="{ backgroundColor: textColor + '30' }"></div>
93
+ <div class="w-8 h-px" :style="{ backgroundColor: ca(textColor, '30') }"></div>
94
94
  <span class="text-[9px] font-black uppercase tracking-[0.5em] opacity-30">{{ badge || '—' }}</span>
95
95
  </div>
96
96
  <div class="flex flex-col md:flex-row md:items-end gap-8 mb-8">
@@ -99,7 +99,7 @@
99
99
  <img :src="image" class="w-full h-full object-cover" />
100
100
  </div>
101
101
  </div>
102
- <div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-6 border-t pt-8" :style="{ borderColor: textColor + '10' }">
102
+ <div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-6 border-t pt-8" :style="{ borderColor: ca(textColor, '10') }">
103
103
  <p class="text-sm leading-relaxed max-w-sm" :style="{ opacity: 0.5 }">{{ subtitle }}</p>
104
104
  <NuxtLink :to="ctaLink || '#'" class="inline-flex items-center gap-2.5 px-7 py-3 rounded-full text-[11px] font-black uppercase tracking-widest transition-all hover:gap-5 shrink-0 active:scale-95" :style="{ backgroundColor: textColor, color: bgColor }">{{ ctaText }}<span>→</span></NuxtLink>
105
105
  </div>
@@ -110,6 +110,10 @@
110
110
  </template>
111
111
 
112
112
  <script setup>
113
+ const ca = (c, h) => {
114
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
115
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
116
+ };
113
117
  import { computed } from "vue";
114
118
  const props = defineProps({
115
119
  layout: { type: String, default: "centered" },
@@ -124,8 +128,8 @@ const props = defineProps({
124
128
  image: { type: String, default: "" },
125
129
  imageStyle: { type: String, default: "cover" },
126
130
  imagePosition: { type: String, default: "center" },
127
- bgColor: { type: String, default: "#3d35ff" },
128
- textColor: { type: String, default: "#ffffff" },
131
+ bgColor: { type: String, default: "rgba(var(--primary-color), 1)" },
132
+ textColor: { type: String, default: "rgba(var(--body-bg), 1)" },
129
133
  spacing: { type: String, default: "normal" },
130
134
  radius: { type: String, default: "rounded" }
131
135
  });
@@ -3,7 +3,7 @@
3
3
  <div class="max-w-6xl mx-auto">
4
4
 
5
5
  <div v-if="title || description" class="mb-12 text-center max-w-2xl mx-auto">
6
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
6
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
7
7
  <component :is="titleTag" class="text-3xl md:text-5xl font-black uppercase tracking-tighter leading-[0.9] mb-4">{{ title }}</component>
8
8
  <p v-if="description" class="text-sm leading-relaxed" :style="{ opacity: 0.55 }">{{ description }}</p>
9
9
  </div>
@@ -12,7 +12,7 @@
12
12
  <div v-if="layout === 'cards'" class="grid grid-cols-1 md:grid-cols-3 gap-6 items-end">
13
13
  <div v-for="(plan, i) in items" :key="i"
14
14
  :class="['border p-8 flex flex-col transition-all duration-300 relative', cardRound, plan.highlighted ? 'md:-translate-y-4 shadow-2xl' : '']"
15
- :style="plan.highlighted ? { backgroundColor: textColor, color: bgColor, borderColor: textColor } : { backgroundColor: textColor + '04', borderColor: textColor + '12' }">
15
+ :style="plan.highlighted ? { backgroundColor: textColor, color: bgColor, borderColor: textColor } : { backgroundColor: ca(textColor, '04'), borderColor: ca(textColor, '12') }">
16
16
  <div v-if="plan.highlighted" class="absolute -top-3 left-1/2 -translate-x-1/2">
17
17
  <span class="px-4 py-1 rounded-full text-[9px] font-black uppercase tracking-widest" :style="{ backgroundColor: bgColor, color: textColor }">Populaire</span>
18
18
  </div>
@@ -38,8 +38,8 @@
38
38
  </div>
39
39
 
40
40
  <!-- MINIMAL -->
41
- <div v-else-if="layout === 'minimal'" class="divide-y max-w-2xl mx-auto" :style="{ borderColor: textColor + '12' }">
42
- <div v-for="(plan, i) in items" :key="i" class="flex items-center gap-6 py-7" :style="{ borderColor: textColor + '12' }">
41
+ <div v-else-if="layout === 'minimal'" class="divide-y max-w-2xl mx-auto" :style="{ borderColor: ca(textColor, '12') }">
42
+ <div v-for="(plan, i) in items" :key="i" class="flex items-center gap-6 py-7" :style="{ borderColor: ca(textColor, '12') }">
43
43
  <div class="flex-1">
44
44
  <p class="font-black uppercase tracking-tight text-lg leading-none mb-1">{{ plan.name }}</p>
45
45
  <p v-if="plan.description" class="text-xs" :style="{ opacity: 0.5 }">{{ plan.description }}</p>
@@ -60,7 +60,7 @@
60
60
  <div v-else class="overflow-x-auto">
61
61
  <table class="w-full text-sm border-collapse">
62
62
  <thead>
63
- <tr class="border-b" :style="{ borderColor: textColor + '12' }">
63
+ <tr class="border-b" :style="{ borderColor: ca(textColor, '12') }">
64
64
  <th class="text-left py-4 pr-6 font-black uppercase tracking-widest text-[10px]" :style="{ opacity: 0.4 }">Plan</th>
65
65
  <th v-for="(plan, i) in items" :key="i" class="text-center py-4 px-4 font-black uppercase tracking-tight text-sm" :style="plan.highlighted ? { color: textColor } : { opacity: 0.7 }">
66
66
  {{ plan.name }}<br/><span class="text-2xl font-black tracking-tighter">{{ plan.price }}</span>
@@ -68,7 +68,7 @@
68
68
  </tr>
69
69
  </thead>
70
70
  <tbody>
71
- <tr v-for="(feat, fi) in allFeatures" :key="fi" class="border-b" :style="{ borderColor: textColor + '08' }">
71
+ <tr v-for="(feat, fi) in allFeatures" :key="fi" class="border-b" :style="{ borderColor: ca(textColor, '08') }">
72
72
  <td class="py-4 pr-6 text-xs" :style="{ opacity: 0.6 }">{{ typeof feat === 'object' ? (feat.fr || feat) : feat }}</td>
73
73
  <td v-for="(plan, pi) in items" :key="pi" class="py-4 px-4 text-center text-sm">
74
74
  <span v-if="planHasFeature(plan, feat)">✓</span>
@@ -84,6 +84,10 @@
84
84
  </template>
85
85
 
86
86
  <script setup>
87
+ const ca = (c, h) => {
88
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
89
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
90
+ };
87
91
  import { computed } from "vue";
88
92
  const props = defineProps({
89
93
  layout: { type: String, default: "cards" },
@@ -92,8 +96,8 @@ const props = defineProps({
92
96
  badge: { type: String, default: "" },
93
97
  description: { type: String, default: "" },
94
98
  items: { type: Array, default: () => [] },
95
- bgColor: { type: String, default: "#ffffff" },
96
- textColor: { type: String, default: "#000000" },
99
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
100
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
97
101
  spacing: { type: String, default: "normal" },
98
102
  radius: { type: String, default: "rounded" }
99
103
  });
@@ -3,14 +3,14 @@
3
3
  <div class="max-w-6xl mx-auto">
4
4
 
5
5
  <div v-if="title || description" class="mb-12" :class="['horizontal','cards'].includes(layout) ? 'text-center max-w-2xl mx-auto' : 'max-w-xl'">
6
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
6
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
7
7
  <component :is="titleTag" class="text-3xl md:text-5xl font-black uppercase tracking-tighter leading-[0.9] mb-4">{{ title }}</component>
8
8
  <p v-if="description" class="text-sm leading-relaxed" :style="{ opacity: 0.55 }">{{ description }}</p>
9
9
  </div>
10
10
 
11
11
  <!-- STEPS (vertical) -->
12
12
  <div v-if="layout === 'steps'" class="relative max-w-2xl">
13
- <div class="absolute left-5 top-0 bottom-0 w-px" :style="{ backgroundColor: textColor + '12' }"></div>
13
+ <div class="absolute left-5 top-0 bottom-0 w-px" :style="{ backgroundColor: ca(textColor, '12') }"></div>
14
14
  <div v-for="(step, i) in items" :key="i" class="relative flex gap-8 pb-12 last:pb-0">
15
15
  <div class="relative z-10 w-10 h-10 rounded-full flex items-center justify-center text-[11px] font-black shrink-0" :style="{ backgroundColor: textColor, color: bgColor }">
16
16
  {{ step.icon || String(i+1).padStart(2,'0') }}
@@ -25,7 +25,7 @@
25
25
  <!-- HORIZONTAL -->
26
26
  <div v-else-if="layout === 'horizontal'" class="flex flex-col md:flex-row gap-8">
27
27
  <div v-for="(step, i) in items" :key="i" class="flex-1 flex flex-col items-center text-center relative">
28
- <div v-if="i < items.length - 1" class="hidden md:block absolute top-5 left-1/2 w-full h-px" :style="{ backgroundColor: textColor + '15' }"></div>
28
+ <div v-if="i < items.length - 1" class="hidden md:block absolute top-5 left-1/2 w-full h-px" :style="{ backgroundColor: ca(textColor, '15') }"></div>
29
29
  <div class="relative z-10 w-10 h-10 rounded-full flex items-center justify-center text-[11px] font-black mb-5 shrink-0" :style="{ backgroundColor: textColor, color: bgColor }">
30
30
  {{ step.icon || String(i+1).padStart(2,'0') }}
31
31
  </div>
@@ -36,7 +36,7 @@
36
36
 
37
37
  <!-- CARDS -->
38
38
  <div v-else-if="layout === 'cards'" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
39
- <div v-for="(step, i) in items" :key="i" :class="['p-7 border', cardRound]" :style="{ backgroundColor: textColor + '04', borderColor: textColor + '10' }">
39
+ <div v-for="(step, i) in items" :key="i" :class="['p-7 border', cardRound]" :style="{ backgroundColor: ca(textColor, '04'), borderColor: ca(textColor, '10') }">
40
40
  <div class="w-10 h-10 rounded-full flex items-center justify-center text-[11px] font-black mb-5" :style="{ backgroundColor: textColor, color: bgColor }">
41
41
  {{ step.icon || String(i+1).padStart(2,'0') }}
42
42
  </div>
@@ -47,7 +47,7 @@
47
47
 
48
48
  <!-- TIMELINE -->
49
49
  <div v-else-if="layout === 'timeline'" class="relative max-w-3xl mx-auto">
50
- <div class="absolute left-1/2 -translate-x-1/2 top-0 bottom-0 w-px" :style="{ backgroundColor: textColor + '12' }"></div>
50
+ <div class="absolute left-1/2 -translate-x-1/2 top-0 bottom-0 w-px" :style="{ backgroundColor: ca(textColor, '12') }"></div>
51
51
  <div v-for="(step, i) in items" :key="i" :class="['relative flex items-start gap-8 pb-12 last:pb-0', i % 2 === 0 ? 'flex-row' : 'flex-row-reverse']">
52
52
  <div class="flex-1 text-right" :class="i % 2 === 0 ? '' : 'text-left'">
53
53
  <component :is="itemTag" class="font-black uppercase tracking-tight mb-2 leading-tight">{{ step.title }}</component>
@@ -61,8 +61,8 @@
61
61
  </div>
62
62
 
63
63
  <!-- MINIMAL -->
64
- <div v-else class="divide-y max-w-2xl" :style="{ borderColor: textColor + '10' }">
65
- <div v-for="(step, i) in items" :key="i" class="flex items-start gap-6 py-6" :style="{ borderColor: textColor + '10' }">
64
+ <div v-else class="divide-y max-w-2xl" :style="{ borderColor: ca(textColor, '10') }">
65
+ <div v-for="(step, i) in items" :key="i" class="flex items-start gap-6 py-6" :style="{ borderColor: ca(textColor, '10') }">
66
66
  <span class="text-[11px] font-black opacity-20 shrink-0 w-5">{{ String(i+1).padStart(2,'0') }}</span>
67
67
  <div>
68
68
  <component :is="itemTag" class="font-black uppercase tracking-tight mb-1 leading-tight">{{ step.title }}</component>
@@ -76,6 +76,10 @@
76
76
  </template>
77
77
 
78
78
  <script setup>
79
+ const ca = (c, h) => {
80
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
81
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
82
+ };
79
83
  import { computed } from "vue";
80
84
  const props = defineProps({
81
85
  layout: { type: String, default: "steps" },
@@ -85,8 +89,8 @@ const props = defineProps({
85
89
  description: { type: String, default: "" },
86
90
  itemTag: { type: String, default: "h3" },
87
91
  items: { type: Array, default: () => [] },
88
- bgColor: { type: String, default: "#ffffff" },
89
- textColor: { type: String, default: "#000000" },
92
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
93
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
90
94
  spacing: { type: String, default: "normal" },
91
95
  radius: { type: String, default: "rounded" }
92
96
  });
@@ -3,13 +3,13 @@
3
3
  <div class="max-w-6xl mx-auto">
4
4
 
5
5
  <div v-if="title || description" class="mb-12" :class="headerAlign === 'center' ? 'text-center max-w-2xl mx-auto' : 'max-w-xl'">
6
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
6
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
7
7
  <component :is="titleTag" class="text-3xl md:text-5xl font-black uppercase tracking-tighter leading-[0.9] mb-4">{{ title }}</component>
8
8
  <p v-if="description" class="text-sm leading-relaxed mb-6" :style="{ opacity: 0.55 }">{{ description }}</p>
9
9
  <div v-if="ctas && ctas.length" class="flex flex-wrap gap-3">
10
10
  <NuxtLink v-for="(cta, i) in ctas" :key="i" :to="cta.link || '#'"
11
11
  class="inline-flex items-center gap-2.5 px-6 py-3 rounded-full text-[11px] font-black uppercase tracking-widest transition-all hover:gap-5"
12
- :style="i === 0 ? { backgroundColor: textColor, color: bgColor } : { border: `1px solid ${textColor}40`, color: textColor }">
12
+ :style="i === 0 ? { backgroundColor: textColor, color: bgColor } : { border: `1px solid ${ca(textColor, '40')}`, color: textColor }">
13
13
  {{ cta.text }}<span>→</span>
14
14
  </NuxtLink>
15
15
  </div>
@@ -19,7 +19,7 @@
19
19
  <div v-if="layout === 'grid'" class="grid grid-cols-1 md:grid-cols-3 gap-6">
20
20
  <div v-for="(service, idx) in items" :key="idx"
21
21
  :class="['group relative p-8 border transition-all duration-300 overflow-hidden hover:-translate-y-1 hover:shadow-lg', cardRound]"
22
- :style="{ backgroundColor: textColor + '04', borderColor: textColor + '12' }">
22
+ :style="{ backgroundColor: ca(textColor, '04'), borderColor: ca(textColor, '12') }">
23
23
  <span class="absolute -top-6 -right-2 text-[100px] font-black italic opacity-[0.04] select-none">{{ String(idx+1).padStart(2,'0') }}</span>
24
24
  <img v-if="service.image" :src="service.image" class="w-10 h-10 object-contain mb-5 rounded-xl" />
25
25
  <component :is="itemTag" class="text-lg font-black uppercase tracking-tight mb-3 leading-tight">{{ service.title }}</component>
@@ -30,8 +30,8 @@
30
30
  </div>
31
31
 
32
32
  <!-- LIST -->
33
- <div v-else-if="layout === 'list'" :style="{ borderColor: textColor + '12' }">
34
- <div v-for="(service, idx) in items" :key="idx" class="group flex items-start gap-8 py-8 border-b last:border-b-0" :style="{ borderColor: textColor + '10' }">
33
+ <div v-else-if="layout === 'list'" :style="{ borderColor: ca(textColor, '12') }">
34
+ <div v-for="(service, idx) in items" :key="idx" class="group flex items-start gap-8 py-8 border-b last:border-b-0" :style="{ borderColor: ca(textColor, '10') }">
35
35
  <span class="text-[11px] font-black opacity-20 pt-1 w-6 shrink-0">{{ String(idx+1).padStart(2,'0') }}</span>
36
36
  <img v-if="service.image" :src="service.image" class="w-12 h-12 object-contain rounded-xl shrink-0" />
37
37
  <div class="flex-1 min-w-0">
@@ -47,8 +47,8 @@
47
47
  <div v-else-if="layout === 'cards'" class="grid grid-cols-1 md:grid-cols-2 gap-6">
48
48
  <div v-for="(service, idx) in items" :key="idx"
49
49
  :class="['flex gap-6 p-7 border transition-all hover:shadow-md', cardRound]"
50
- :style="{ backgroundColor: textColor + '03', borderColor: textColor + '10' }">
51
- <div class="w-12 h-12 rounded-2xl flex items-center justify-center shrink-0" :style="{ backgroundColor: textColor + '10' }">
50
+ :style="{ backgroundColor: ca(textColor, '03'), borderColor: ca(textColor, '10') }">
51
+ <div class="w-12 h-12 rounded-2xl flex items-center justify-center shrink-0" :style="{ backgroundColor: ca(textColor, '10') }">
52
52
  <img v-if="service.image" :src="service.image" class="w-7 h-7 object-contain" />
53
53
  <span v-else class="text-lg font-black opacity-30">{{ String(idx+1).padStart(2,'0') }}</span>
54
54
  </div>
@@ -62,7 +62,7 @@
62
62
 
63
63
  <!-- MINIMAL -->
64
64
  <div v-else class="max-w-2xl">
65
- <div v-for="(service, idx) in items" :key="idx" class="flex items-start justify-between gap-6 py-6 border-b last:border-b-0" :style="{ borderColor: textColor + '10' }">
65
+ <div v-for="(service, idx) in items" :key="idx" class="flex items-start justify-between gap-6 py-6 border-b last:border-b-0" :style="{ borderColor: ca(textColor, '10') }">
66
66
  <div>
67
67
  <component :is="itemTag" class="font-black uppercase tracking-tight mb-1">{{ service.title }}</component>
68
68
  <p v-if="service.description" class="text-sm" :style="{ opacity: 0.5 }">{{ service.description }}</p>
@@ -76,6 +76,10 @@
76
76
  </template>
77
77
 
78
78
  <script setup>
79
+ const ca = (c, h) => {
80
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
81
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
82
+ };
79
83
  import { computed } from "vue";
80
84
  const props = defineProps({
81
85
  layout: { type: String, default: "grid" },
@@ -87,8 +91,8 @@ const props = defineProps({
87
91
  itemTag: { type: String, default: "h3" },
88
92
  items: { type: Array, default: () => [] },
89
93
  ctas: { type: Array, default: () => [] },
90
- bgColor: { type: String, default: "#ffffff" },
91
- textColor: { type: String, default: "#000000" },
94
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
95
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
92
96
  spacing: { type: String, default: "normal" },
93
97
  radius: { type: String, default: "rounded" }
94
98
  });
@@ -3,21 +3,21 @@
3
3
  <div class="max-w-6xl mx-auto">
4
4
 
5
5
  <div v-if="title || description" class="mb-12 max-w-xl">
6
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
6
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border mb-4" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
7
7
  <component :is="titleTag" class="text-3xl md:text-5xl font-black uppercase tracking-tighter leading-[0.9] mb-3">{{ title }}</component>
8
8
  <p v-if="description" class="text-sm leading-relaxed" :style="{ opacity: 0.55 }">{{ description }}</p>
9
9
  </div>
10
10
 
11
11
  <!-- GRID -->
12
12
  <div v-if="layout === 'grid'" class="grid grid-cols-1 md:grid-cols-3 gap-6">
13
- <div v-for="(item, i) in items" :key="i" :class="['flex flex-col p-7 border transition-all hover:-translate-y-1', cardRound]" :style="{ backgroundColor: textColor + '04', borderColor: textColor + '10' }">
13
+ <div v-for="(item, i) in items" :key="i" :class="['flex flex-col p-7 border transition-all hover:-translate-y-1', cardRound]" :style="{ backgroundColor: ca(textColor, '04'), borderColor: ca(textColor, '10') }">
14
14
  <div v-if="item.rating" class="flex gap-0.5 mb-4">
15
15
  <span v-for="s in 5" :key="s" class="text-xs" :style="{ opacity: s <= item.rating ? 1 : 0.15 }">★</span>
16
16
  </div>
17
17
  <p class="text-sm leading-relaxed flex-1 italic mb-6" :style="{ opacity: 0.7 }">"{{ item.quote }}"</p>
18
- <div class="flex items-center gap-3 pt-4 border-t" :style="{ borderColor: textColor + '10' }">
18
+ <div class="flex items-center gap-3 pt-4 border-t" :style="{ borderColor: ca(textColor, '10') }">
19
19
  <img v-if="item.avatar" :src="item.avatar" class="w-9 h-9 rounded-full object-cover shrink-0" />
20
- <div v-else class="w-9 h-9 rounded-full flex items-center justify-center text-[11px] font-black shrink-0" :style="{ backgroundColor: textColor + '15' }">{{ (item.name || '?')[0] }}</div>
20
+ <div v-else class="w-9 h-9 rounded-full flex items-center justify-center text-[11px] font-black shrink-0" :style="{ backgroundColor: ca(textColor, '15') }">{{ (item.name || '?')[0] }}</div>
21
21
  <div>
22
22
  <p class="text-[11px] font-black uppercase tracking-wide leading-none">{{ item.name }}</p>
23
23
  <p v-if="item.role || item.company" class="text-[9px] mt-0.5" :style="{ opacity: 0.4 }">{{ [item.role, item.company].filter(Boolean).join(' · ') }}</p>
@@ -28,14 +28,14 @@
28
28
 
29
29
  <!-- FEATURED -->
30
30
  <div v-else-if="layout === 'featured'">
31
- <div v-if="items[0]" :class="['p-10 border mb-6', cardRound]" :style="{ backgroundColor: textColor + '05', borderColor: textColor + '10' }">
31
+ <div v-if="items[0]" :class="['p-10 border mb-6', cardRound]" :style="{ backgroundColor: ca(textColor, '05'), borderColor: ca(textColor, '10') }">
32
32
  <div v-if="items[0].rating" class="flex gap-0.5 mb-6">
33
33
  <span v-for="s in 5" :key="s" class="text-base" :style="{ opacity: s <= items[0].rating ? 1 : 0.15 }">★</span>
34
34
  </div>
35
35
  <p class="text-xl md:text-3xl font-bold italic leading-snug mb-8 max-w-3xl" :style="{ opacity: 0.8 }">"{{ items[0].quote }}"</p>
36
36
  <div class="flex items-center gap-4">
37
37
  <img v-if="items[0].avatar" :src="items[0].avatar" class="w-12 h-12 rounded-full object-cover" />
38
- <div v-else class="w-12 h-12 rounded-full flex items-center justify-center text-sm font-black" :style="{ backgroundColor: textColor + '15' }">{{ (items[0].name || '?')[0] }}</div>
38
+ <div v-else class="w-12 h-12 rounded-full flex items-center justify-center text-sm font-black" :style="{ backgroundColor: ca(textColor, '15') }">{{ (items[0].name || '?')[0] }}</div>
39
39
  <div>
40
40
  <p class="text-sm font-black uppercase tracking-wide">{{ items[0].name }}</p>
41
41
  <p v-if="items[0].role || items[0].company" class="text-[10px]" :style="{ opacity: 0.4 }">{{ [items[0].role, items[0].company].filter(Boolean).join(' · ') }}</p>
@@ -43,11 +43,11 @@
43
43
  </div>
44
44
  </div>
45
45
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
46
- <div v-for="(item, i) in items.slice(1)" :key="i" :class="['p-7 border', cardRound]" :style="{ backgroundColor: textColor + '03', borderColor: textColor + '08' }">
46
+ <div v-for="(item, i) in items.slice(1)" :key="i" :class="['p-7 border', cardRound]" :style="{ backgroundColor: ca(textColor, '03'), borderColor: ca(textColor, '08') }">
47
47
  <p class="text-sm italic leading-relaxed mb-5" :style="{ opacity: 0.7 }">"{{ item.quote }}"</p>
48
48
  <div class="flex items-center gap-3">
49
49
  <img v-if="item.avatar" :src="item.avatar" class="w-8 h-8 rounded-full object-cover" />
50
- <div v-else class="w-8 h-8 rounded-full flex items-center justify-center text-[10px] font-black" :style="{ backgroundColor: textColor + '12' }">{{ (item.name || '?')[0] }}</div>
50
+ <div v-else class="w-8 h-8 rounded-full flex items-center justify-center text-[10px] font-black" :style="{ backgroundColor: ca(textColor, '12') }">{{ (item.name || '?')[0] }}</div>
51
51
  <div>
52
52
  <p class="text-[10px] font-black uppercase">{{ item.name }}</p>
53
53
  <p v-if="item.role" class="text-[9px]" :style="{ opacity: 0.4 }">{{ item.role }}</p>
@@ -59,14 +59,14 @@
59
59
 
60
60
  <!-- WALL / MINIMAL -->
61
61
  <div v-else class="columns-1 md:columns-2 lg:columns-3 gap-6 space-y-6">
62
- <div v-for="(item, i) in items" :key="i" :class="['break-inside-avoid p-6 border mb-6', cardRound]" :style="{ backgroundColor: textColor + '04', borderColor: textColor + '08' }">
62
+ <div v-for="(item, i) in items" :key="i" :class="['break-inside-avoid p-6 border mb-6', cardRound]" :style="{ backgroundColor: ca(textColor, '04'), borderColor: ca(textColor, '08') }">
63
63
  <div v-if="item.rating" class="flex gap-0.5 mb-3">
64
64
  <span v-for="s in 5" :key="s" class="text-[10px]" :style="{ opacity: s <= item.rating ? 1 : 0.15 }">★</span>
65
65
  </div>
66
66
  <p class="text-sm italic leading-relaxed mb-4" :style="{ opacity: 0.7 }">"{{ item.quote }}"</p>
67
67
  <div class="flex items-center gap-2.5">
68
68
  <img v-if="item.avatar" :src="item.avatar" class="w-7 h-7 rounded-full object-cover" />
69
- <div v-else class="w-7 h-7 rounded-full flex items-center justify-center text-[9px] font-black" :style="{ backgroundColor: textColor + '15' }">{{ (item.name || '?')[0] }}</div>
69
+ <div v-else class="w-7 h-7 rounded-full flex items-center justify-center text-[9px] font-black" :style="{ backgroundColor: ca(textColor, '15') }">{{ (item.name || '?')[0] }}</div>
70
70
  <p class="text-[10px] font-black uppercase">{{ item.name }}</p>
71
71
  </div>
72
72
  </div>
@@ -77,6 +77,10 @@
77
77
  </template>
78
78
 
79
79
  <script setup>
80
+ const ca = (c, h) => {
81
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
82
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
83
+ };
80
84
  import { computed } from "vue";
81
85
  const props = defineProps({
82
86
  layout: { type: String, default: "grid" },
@@ -85,8 +89,8 @@ const props = defineProps({
85
89
  badge: { type: String, default: "" },
86
90
  description: { type: String, default: "" },
87
91
  items: { type: Array, default: () => [] },
88
- bgColor: { type: String, default: "#ffffff" },
89
- textColor: { type: String, default: "#000000" },
92
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
93
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
90
94
  spacing: { type: String, default: "normal" },
91
95
  radius: { type: String, default: "rounded" }
92
96
  });
@@ -4,20 +4,20 @@
4
4
  <!-- SPLIT -->
5
5
  <div v-if="layout === 'split'" :class="['max-w-6xl mx-auto flex flex-col md:flex-row gap-12 items-center', reverse ? 'md:flex-row-reverse' : '']">
6
6
  <div class="flex-1 space-y-6">
7
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
7
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
8
8
  <component :is="titleTag" class="text-3xl md:text-4xl font-black uppercase tracking-tighter leading-[0.9]">{{ title }}</component>
9
9
  <p class="leading-relaxed text-sm max-w-md" :style="{ opacity: 0.55 }">{{ content }}</p>
10
10
  <div v-if="ctas && ctas.length" class="flex flex-wrap gap-3 pt-1">
11
11
  <NuxtLink v-for="(cta, i) in ctas" :key="i" :to="cta.link || '#'"
12
12
  class="inline-flex items-center gap-2.5 px-6 py-3 rounded-full text-[11px] font-black uppercase tracking-widest transition-all hover:gap-5"
13
- :style="i === 0 ? { backgroundColor: textColor, color: bgColor } : { border: `1px solid ${textColor}40`, color: textColor }">
13
+ :style="i === 0 ? { backgroundColor: textColor, color: bgColor } : { border: `1px solid ${ca(textColor, '40')}`, color: textColor }">
14
14
  {{ cta.text }}<span>→</span>
15
15
  </NuxtLink>
16
16
  </div>
17
17
  </div>
18
18
  <div :class="['flex-1 overflow-hidden relative', imageContainerClass]">
19
19
  <img v-if="image" :src="image" :alt="imageAlt || title" class="w-full h-full object-cover transition-transform duration-700 hover:scale-105" />
20
- <div v-else class="w-full h-full" :style="{ backgroundColor: textColor + '08' }"></div>
20
+ <div v-else class="w-full h-full" :style="{ backgroundColor: ca(textColor, '08') }"></div>
21
21
  </div>
22
22
  </div>
23
23
 
@@ -25,16 +25,16 @@
25
25
  <div v-else-if="layout === 'stacked'" class="max-w-3xl mx-auto space-y-8">
26
26
  <div :class="['w-full overflow-hidden relative', imageContainerClass]">
27
27
  <img v-if="image" :src="image" class="w-full h-full object-cover" />
28
- <div v-else class="w-full h-full" :style="{ backgroundColor: textColor + '08' }"></div>
28
+ <div v-else class="w-full h-full" :style="{ backgroundColor: ca(textColor, '08') }"></div>
29
29
  </div>
30
30
  <div class="space-y-5">
31
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
31
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
32
32
  <component :is="titleTag" class="text-3xl md:text-4xl font-black uppercase tracking-tighter leading-[0.9]">{{ title }}</component>
33
33
  <p class="leading-relaxed text-sm" :style="{ opacity: 0.55 }">{{ content }}</p>
34
34
  <div v-if="ctas && ctas.length" class="flex flex-wrap gap-3 pt-1">
35
35
  <NuxtLink v-for="(cta, i) in ctas" :key="i" :to="cta.link || '#'"
36
36
  class="inline-flex items-center gap-2.5 px-6 py-3 rounded-full text-[11px] font-black uppercase tracking-widest transition-all hover:gap-5"
37
- :style="i === 0 ? { backgroundColor: textColor, color: bgColor } : { border: `1px solid ${textColor}40`, color: textColor }">
37
+ :style="i === 0 ? { backgroundColor: textColor, color: bgColor } : { border: `1px solid ${ca(textColor, '40')}`, color: textColor }">
38
38
  {{ cta.text }}<span>→</span>
39
39
  </NuxtLink>
40
40
  </div>
@@ -45,16 +45,16 @@
45
45
  <div v-else :class="['max-w-6xl mx-auto flex flex-col md:flex-row gap-10 items-center', reverse ? 'md:flex-row-reverse' : '']">
46
46
  <div :class="['md:w-2/3 w-full overflow-hidden relative', imageContainerClass]">
47
47
  <img v-if="image" :src="image" class="w-full h-full object-cover transition-transform duration-700 hover:scale-105" />
48
- <div v-else class="w-full h-full" :style="{ backgroundColor: textColor + '08' }"></div>
48
+ <div v-else class="w-full h-full" :style="{ backgroundColor: ca(textColor, '08') }"></div>
49
49
  </div>
50
50
  <div class="md:w-1/3 space-y-5">
51
- <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border" :style="{ borderColor: textColor + '25', color: textColor + 'aa' }">{{ badge }}</span>
51
+ <span v-if="badge" class="inline-block text-[10px] font-bold tracking-[0.5em] uppercase px-3 py-1 rounded-full border" :style="{ borderColor: ca(textColor, '25'), color: ca(textColor, 'aa') }">{{ badge }}</span>
52
52
  <component :is="titleTag" class="text-2xl md:text-3xl font-black uppercase tracking-tighter leading-[0.9]">{{ title }}</component>
53
53
  <p class="leading-relaxed text-sm" :style="{ opacity: 0.55 }">{{ content }}</p>
54
54
  <div v-if="ctas && ctas.length" class="flex flex-wrap gap-3 pt-1">
55
55
  <NuxtLink v-for="(cta, i) in ctas" :key="i" :to="cta.link || '#'"
56
56
  class="inline-flex items-center gap-2.5 px-6 py-3 rounded-full text-[11px] font-black uppercase tracking-widest transition-all hover:gap-5"
57
- :style="i === 0 ? { backgroundColor: textColor, color: bgColor } : { border: `1px solid ${textColor}40`, color: textColor }">
57
+ :style="i === 0 ? { backgroundColor: textColor, color: bgColor } : { border: `1px solid ${ca(textColor, '40')}`, color: textColor }">
58
58
  {{ cta.text }}<span>→</span>
59
59
  </NuxtLink>
60
60
  </div>
@@ -65,6 +65,10 @@
65
65
  </template>
66
66
 
67
67
  <script setup>
68
+ const ca = (c, h) => {
69
+ const m = c.match(/rgba\((var\([^)]+\)),\s*[\d.]+\)/);
70
+ return m ? `rgba(${m[1]}, ${Math.round(parseInt(h, 16) / 255 * 1e3) / 1e3})` : c + h;
71
+ };
68
72
  import { computed } from "vue";
69
73
  const props = defineProps({
70
74
  layout: { type: String, default: "split" },
@@ -78,8 +82,8 @@ const props = defineProps({
78
82
  imageFit: { type: String, default: "cover" },
79
83
  imageShadow: { type: Boolean, default: false },
80
84
  reverse: { type: Boolean, default: false },
81
- bgColor: { type: String, default: "#ffffff" },
82
- textColor: { type: String, default: "#000000" },
85
+ bgColor: { type: String, default: "rgba(var(--body-bg), 1)" },
86
+ textColor: { type: String, default: "rgba(var(--text-color), 1)" },
83
87
  ctas: { type: Array, default: () => [] },
84
88
  spacing: { type: String, default: "normal" },
85
89
  radius: { type: String, default: "rounded" }
@@ -49,8 +49,8 @@ export const DEFAULT_SECTIONS = {
49
49
  image: "",
50
50
  imageStyle: "cover",
51
51
  imagePosition: "center",
52
- bgColor: "#3d35ff",
53
- textColor: "#ffffff",
52
+ bgColor: "rgba(var(--primary-color), 1)",
53
+ textColor: "rgba(var(--body-bg), 1)",
54
54
  ctaText: i18n0("Get Started"),
55
55
  ctaLink: "/",
56
56
  spacing: "normal",
@@ -102,8 +102,8 @@ export const DEFAULT_SECTIONS = {
102
102
  imageFit: "cover",
103
103
  imageShadow: false,
104
104
  reverse: false,
105
- bgColor: "#ffffff",
106
- textColor: "#000000",
105
+ bgColor: "rgba(var(--body-bg), 1)",
106
+ textColor: "rgba(var(--text-color), 1)",
107
107
  ctas: [],
108
108
  spacing: "normal",
109
109
  radius: "rounded"
@@ -154,8 +154,8 @@ export const DEFAULT_SECTIONS = {
154
154
  ctas: [],
155
155
  itemTag: "h3",
156
156
  items: [],
157
- bgColor: "#ffffff",
158
- textColor: "#000000",
157
+ bgColor: "rgba(var(--body-bg), 1)",
158
+ textColor: "rgba(var(--text-color), 1)",
159
159
  spacing: "normal",
160
160
  radius: "rounded"
161
161
  },
@@ -191,8 +191,8 @@ export const DEFAULT_SECTIONS = {
191
191
  defaultProps: {
192
192
  title: i18n0("Why choose us?"),
193
193
  items: [],
194
- bgColor: "#ffffff",
195
- textColor: "#000000",
194
+ bgColor: "rgba(var(--body-bg), 1)",
195
+ textColor: "rgba(var(--text-color), 1)",
196
196
  spacing: "normal",
197
197
  radius: "rounded"
198
198
  },
@@ -214,8 +214,8 @@ export const DEFAULT_SECTIONS = {
214
214
  defaultProps: {
215
215
  title: i18n0("FAQ"),
216
216
  items: [],
217
- bgColor: "#F9F9FB",
218
- textColor: "#000000",
217
+ bgColor: "rgba(var(--body-bg), 1)",
218
+ textColor: "rgba(var(--text-color), 1)",
219
219
  spacing: "normal",
220
220
  radius: "rounded"
221
221
  },
@@ -241,8 +241,8 @@ export const DEFAULT_SECTIONS = {
241
241
  badge: i18n0(),
242
242
  description: i18n0(),
243
243
  items: [],
244
- bgColor: "#ffffff",
245
- textColor: "#000000",
244
+ bgColor: "rgba(var(--body-bg), 1)",
245
+ textColor: "rgba(var(--text-color), 1)",
246
246
  spacing: "normal",
247
247
  radius: "rounded"
248
248
  },
@@ -279,8 +279,8 @@ export const DEFAULT_SECTIONS = {
279
279
  badge: i18n0(),
280
280
  description: i18n0(),
281
281
  items: [],
282
- bgColor: "#ffffff",
283
- textColor: "#000000",
282
+ bgColor: "rgba(var(--body-bg), 1)",
283
+ textColor: "rgba(var(--text-color), 1)",
284
284
  spacing: "normal",
285
285
  radius: "rounded"
286
286
  },
@@ -319,8 +319,8 @@ export const DEFAULT_SECTIONS = {
319
319
  badge: i18n0(),
320
320
  description: i18n0(),
321
321
  items: [],
322
- bgColor: "#ffffff",
323
- textColor: "#000000",
322
+ bgColor: "rgba(var(--body-bg), 1)",
323
+ textColor: "rgba(var(--text-color), 1)",
324
324
  spacing: "normal",
325
325
  radius: "rounded"
326
326
  },
@@ -358,8 +358,8 @@ export const DEFAULT_SECTIONS = {
358
358
  subtitle: i18n0("Describe your project and we'll get back to you within 24h."),
359
359
  badge: i18n0(),
360
360
  button_text: i18n0("Send"),
361
- bgColor: "#ffffff",
362
- textColor: "#000000",
361
+ bgColor: "rgba(var(--body-bg), 1)",
362
+ textColor: "rgba(var(--text-color), 1)",
363
363
  spacing: "normal",
364
364
  radius: "rounded"
365
365
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cinqcinqdev-seo",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
4
4
  "description": "A reusable Nuxt 3 admin CMS module with visual page editor powered by Supabase",
5
5
  "license": "MIT",
6
6
  "module": "./dist/module.mjs",