@xenterprises/nuxt-x-marketing 1.4.12 → 1.4.14

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/CHANGELOG.md CHANGED
@@ -30,6 +30,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
30
30
  section and its sample product data were dropped with them. Every other section of the
31
31
  demo page is unchanged.
32
32
 
33
+ ## [1.4.14] - 2026-09-06
34
+
35
+ ### Added
36
+
37
+ - `XMarkPricingPlans` `freeTrial` prop for an honest free-trial callout (default off; enable only when the product has a trial).
38
+
39
+ ## [1.4.13] - 2026-09-06
40
+
41
+ ### Changed
42
+
43
+ - Pricing Enterprise CTA default label is **Get a quote** (was Contact Sales); same fallback when Enterprise omits `button.label`.
44
+
33
45
  ## [1.4.12] - 2026-09-06
34
46
 
35
47
  ### Changed
@@ -60,7 +60,7 @@ const props = defineProps({
60
60
  id: "enterprise",
61
61
  name: "Enterprise",
62
62
  price: "$99/mo",
63
- button: { label: "Contact Sales" },
63
+ button: { label: "Get a quote" },
64
64
  },
65
65
  ],
66
66
  },
@@ -140,7 +140,11 @@ const mappedTiers = computed(() => {
140
140
  highlight: plan.highlighted,
141
141
  button: plan.button
142
142
  ? {
143
- label: plan.button.label || "Get Started",
143
+ label:
144
+ plan.button.label
145
+ || (/enterprise/i.test(plan.name || "")
146
+ ? "Get a quote"
147
+ : "Get Started"),
144
148
  color: plan.highlighted ? "primary" : "neutral",
145
149
  variant: plan.highlighted ? "solid" : "outline",
146
150
  onClick: () => emit("select", plan),
@@ -33,6 +33,26 @@
33
33
  </div>
34
34
  </div>
35
35
 
36
+ <!-- Free trial callout (opt-in; never invent a trial) -->
37
+ <div
38
+ v-if="trialCallout"
39
+ class="flex justify-center mb-8"
40
+ data-testid="x-mark-pricing-free-trial"
41
+ >
42
+ <div
43
+ class="inline-flex items-center gap-2 rounded-full border border-primary-200 bg-primary-50 px-4 py-2 text-sm text-primary-800 dark:border-primary-800 dark:bg-primary-950 dark:text-primary-200"
44
+ >
45
+ <UIcon name="i-lucide-gift" class="size-4 shrink-0" />
46
+ <span class="font-medium">{{ trialCallout.label }}</span>
47
+ <span
48
+ v-if="trialCallout.description"
49
+ class="text-primary-700/80 dark:text-primary-300/80"
50
+ >
51
+ {{ trialCallout.description }}
52
+ </span>
53
+ </div>
54
+ </div>
55
+
36
56
  <!-- Badges (top position) -->
37
57
  <div
38
58
  v-if="badges?.length && badgesPosition === 'top'"
@@ -113,7 +133,7 @@ const props = defineProps({
113
133
  "Custom integrations",
114
134
  "SLA guarantee",
115
135
  ],
116
- button: { label: "Contact Sales" },
136
+ button: { label: "Get a quote" },
117
137
  },
118
138
  ],
119
139
  },
@@ -165,12 +185,54 @@ const props = defineProps({
165
185
  default: "center",
166
186
  validator: (v) => ["left", "center", "right"].includes(v),
167
187
  },
188
+ /**
189
+ * Free trial callout. Default off (honest; do not invent trials).
190
+ * true → "Free trial available"
191
+ * number → "Free {n}-day trial"
192
+ * string → custom label
193
+ * { days?, label?, description? }
194
+ */
195
+ freeTrial: {
196
+ type: [Boolean, Number, String, Object],
197
+ default: false,
198
+ },
168
199
  });
169
200
 
170
201
  const emit = defineEmits(["select"]);
171
202
 
172
203
  const billingPeriod = ref("monthly");
173
204
 
205
+ const trialCallout = computed(() => {
206
+ const v = props.freeTrial;
207
+ if (v === false || v === null || v === undefined || v === "") return null;
208
+ if (v === true) {
209
+ return { label: "Free trial available", description: "" };
210
+ }
211
+ if (typeof v === "number" && Number.isFinite(v) && v > 0) {
212
+ const days = Math.floor(v);
213
+ return {
214
+ label: `Free ${days}-day trial`,
215
+ description: "",
216
+ };
217
+ }
218
+ if (typeof v === "string") {
219
+ return { label: v, description: "" };
220
+ }
221
+ if (typeof v === "object") {
222
+ const days = Number(v.days);
223
+ const label =
224
+ v.label
225
+ || (Number.isFinite(days) && days > 0
226
+ ? `Free ${Math.floor(days)}-day trial`
227
+ : "Free trial available");
228
+ return {
229
+ label,
230
+ description: v.description || "",
231
+ };
232
+ }
233
+ return null;
234
+ });
235
+
174
236
  function normalizePeriod(period) {
175
237
  if (!period) return period;
176
238
  const trimmed = String(period).trim().toLowerCase();
@@ -216,7 +278,11 @@ const mappedPlans = computed(() => {
216
278
  scale: shouldScale,
217
279
  badge: isHighlighted ? "Most Popular" : undefined,
218
280
  button: {
219
- label: plan.button?.label || "Get Started",
281
+ label:
282
+ plan.button?.label
283
+ || (/enterprise/i.test(plan.name || "")
284
+ ? "Get a quote"
285
+ : "Get Started"),
220
286
  onClick: () => emit("select", plan),
221
287
  },
222
288
  };
@@ -76,7 +76,7 @@
76
76
  <div class="mt-8 flex flex-wrap justify-center gap-4">
77
77
  <UButton size="xl" color="white"> Start Free Trial </UButton>
78
78
  <UButton size="xl" variant="outline" color="white">
79
- Contact Sales
79
+ Get a quote
80
80
  </UButton>
81
81
  </div>
82
82
  <div class="mt-6 flex flex-wrap justify-center gap-4">
@@ -204,7 +204,7 @@ const pricingPlans = [
204
204
  "Custom integrations",
205
205
  "SLA guarantee",
206
206
  ],
207
- cta: "Contact Sales",
207
+ cta: "Get a quote",
208
208
  },
209
209
  ];
210
210
  </script>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@xenterprises/nuxt-x-marketing",
3
3
  "license": "SEE LICENSE IN LICENSE",
4
4
  "type": "module",
5
- "version": "1.4.12",
5
+ "version": "1.4.14",
6
6
  "main": "./nuxt.config.ts",
7
7
  "scripts": {
8
8
  "dev": "nuxi dev .playground",