@xenterprises/nuxt-x-marketing 1.3.0 → 1.4.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.
- package/CHANGELOG.md +30 -0
- package/README.md +8 -180
- package/app/assets/css/x-marketing.css +10 -0
- package/app/components/X/Mark/CTA/index.vue +19 -6
- package/app/pages/index.vue +0 -205
- package/package.json +3 -2
- package/app/components/X/Mark/Affiliate/ComparisonTable.vue +0 -382
- package/app/components/X/Mark/Affiliate/Disclosure.vue +0 -138
- package/app/components/X/Mark/Affiliate/ProductCard.vue +0 -431
- package/app/components/X/Mark/Affiliate/ProductDetail.vue +0 -410
- package/app/components/X/Mark/Affiliate/ProductGrid.vue +0 -101
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ All notable changes to `@xenterprises/nuxt-x-marketing` are documented in this f
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.4.0] - 2026-08-02
|
|
9
|
+
|
|
10
|
+
### Removed
|
|
11
|
+
|
|
12
|
+
> **Released as a minor despite removing public components.** Semver would call
|
|
13
|
+
> this a major. Sites on `^1.3.0` will therefore pick this up automatically —
|
|
14
|
+
> if you import any `XMarkAffiliate*` component, pin to `1.3.0` or migrate to
|
|
15
|
+
> the `XAF*` equivalents below before upgrading.
|
|
16
|
+
|
|
17
|
+
- **Removed the `XMarkAffiliate*` component family** — `XMarkAffiliateDisclosure`,
|
|
18
|
+
`XMarkAffiliateProductCard`, `XMarkAffiliateProductGrid`, `XMarkAffiliateProductDetail`,
|
|
19
|
+
and `XMarkAffiliateComparisonTable` (1,462 lines).
|
|
20
|
+
|
|
21
|
+
They duplicated components `@xenterprises/nuxt-x-affiliate` already ships, without its
|
|
22
|
+
per-merchant tagging (`xAffiliateContent.merchants`), impression tracking, or
|
|
23
|
+
Product/Offer structured data — so a site using them shipped untagged outbound links
|
|
24
|
+
and no product schema.
|
|
25
|
+
|
|
26
|
+
Migrate to `<XAFDisclosure>`, `<XAFProductCard>`, `<XAFRelatedProducts>`,
|
|
27
|
+
`<XAFComparisonTable>`, and (for the detail page) `<XAFHero>` + `<XAFProsCons>` +
|
|
28
|
+
`<XAFVerdict>` + `<XAFSpecsTable>`. Affiliate sites should extend `nuxt-x-affiliate`
|
|
29
|
+
directly — it is now self-contained and ships the site chrome (header, hero, sections,
|
|
30
|
+
cards, footer) that previously required this layer alongside it.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- **`app/pages/index.vue`** no longer showcases the removed affiliate components; the
|
|
35
|
+
section and its sample product data were dropped with them. Every other section of the
|
|
36
|
+
demo page is unchanged.
|
|
37
|
+
|
|
8
38
|
## [1.3.0] - 2026-07-24
|
|
9
39
|
|
|
10
40
|
### BREAKING
|
package/README.md
CHANGED
|
@@ -811,186 +811,14 @@ Chat widget trigger.
|
|
|
811
811
|
|
|
812
812
|
### Affiliate & Review Components
|
|
813
813
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
<XMarkAffiliateDisclosure />
|
|
823
|
-
|
|
824
|
-
<!-- Full-width banner at top of page -->
|
|
825
|
-
<XMarkAffiliateDisclosure variant="banner" :dismissible="true" />
|
|
826
|
-
|
|
827
|
-
<!-- Inline inside blog post prose -->
|
|
828
|
-
<XMarkAffiliateDisclosure variant="inline" />
|
|
829
|
-
```
|
|
830
|
-
|
|
831
|
-
| Prop | Type | Default | Description |
|
|
832
|
-
|------|------|---------|-------------|
|
|
833
|
-
| `text` | `String` | Amazon associate disclosure | Disclosure text |
|
|
834
|
-
| `variant` | `String` | `'subtle'` | `subtle`, `banner`, `inline` |
|
|
835
|
-
| `icon` | `String` | `'i-lucide-info'` | Icon name |
|
|
836
|
-
| `dismissible` | `Boolean` | `false` | Show dismiss button |
|
|
837
|
-
| `storageKey` | `String` | `'affiliate-disclosure-dismissed'` | localStorage key |
|
|
838
|
-
|
|
839
|
-
#### XMarkAffiliateProductCard
|
|
840
|
-
|
|
841
|
-
Product card with affiliate buy button, star rating, price, pros/cons. Three layout variants.
|
|
842
|
-
|
|
843
|
-
```vue
|
|
844
|
-
<XMarkAffiliateProductCard
|
|
845
|
-
:product="{
|
|
846
|
-
name: 'Sony WH-1000XM5',
|
|
847
|
-
image: '/products/sony-wh1000xm5.jpg',
|
|
848
|
-
price: '$279.99',
|
|
849
|
-
originalPrice: '$349.99',
|
|
850
|
-
rating: 4.8,
|
|
851
|
-
reviewCount: 12400,
|
|
852
|
-
pros: ['Best-in-class ANC', '30hr battery', 'Foldable design'],
|
|
853
|
-
cons: ['No IP rating', 'Expensive'],
|
|
854
|
-
affiliateUrl: 'https://amazon.com/dp/B09XS7JWHH',
|
|
855
|
-
affiliateTag: 'mysite-20',
|
|
856
|
-
badge: '#1 Pick',
|
|
857
|
-
}"
|
|
858
|
-
layout="card"
|
|
859
|
-
button-label="Check Price on Amazon"
|
|
860
|
-
/>
|
|
861
|
-
```
|
|
862
|
-
|
|
863
|
-
| Prop | Type | Default | Description |
|
|
864
|
-
|------|------|---------|-------------|
|
|
865
|
-
| `product` | `Object` | sample product | Product data `{ name, image?, price?, originalPrice?, rating?, reviewCount?, pros?, cons?, affiliateUrl?, affiliateTag?, badge? }` |
|
|
866
|
-
| `layout` | `String` | `'card'` | `card` (vertical), `row` (horizontal), `compact` (one-line) |
|
|
867
|
-
| `showPros` | `Boolean` | `true` | Show pros list |
|
|
868
|
-
| `showCons` | `Boolean` | `false` | Show cons list |
|
|
869
|
-
| `showRating` | `Boolean` | `true` | Show star rating |
|
|
870
|
-
| `showPrice` | `Boolean` | `true` | Show price |
|
|
871
|
-
| `buttonLabel` | `String` | `'Check Price on Amazon'` | CTA button text |
|
|
872
|
-
| `buttonIcon` | `String` | `'i-lucide-external-link'` | CTA button icon |
|
|
873
|
-
| `disclosure` | `String` | `''` | Small disclosure text below button |
|
|
874
|
-
|
|
875
|
-
#### XMarkAffiliateProductGrid
|
|
876
|
-
|
|
877
|
-
Grid of product cards for "best X" roundup posts. Automatically injects rank badges.
|
|
878
|
-
|
|
879
|
-
```vue
|
|
880
|
-
<XMarkAffiliateProductGrid
|
|
881
|
-
:products="topHeadphones"
|
|
882
|
-
layout="grid"
|
|
883
|
-
:columns="3"
|
|
884
|
-
:show-ranking="true"
|
|
885
|
-
disclosure="This page contains affiliate links."
|
|
886
|
-
button-label="Check Price on Amazon"
|
|
887
|
-
/>
|
|
888
|
-
```
|
|
889
|
-
|
|
890
|
-
| Prop | Type | Default | Description |
|
|
891
|
-
|------|------|---------|-------------|
|
|
892
|
-
| `products` | `Array` | `[]` | Array of product objects |
|
|
893
|
-
| `layout` | `String` | `'grid'` | `grid` or `list` |
|
|
894
|
-
| `columns` | `Number` | `3` | Grid columns: `2` or `3` |
|
|
895
|
-
| `showRanking` | `Boolean` | `true` | Inject #1/#2/#3 badges on first 3 products |
|
|
896
|
-
| `disclosure` | `String` | `''` | Disclosure shown once at top |
|
|
897
|
-
| `buttonLabel` | `String` | `'Check Price on Amazon'` | CTA label for all cards |
|
|
898
|
-
| `cardLayout` | `String` | `'card'` | Card layout variant |
|
|
899
|
-
|
|
900
|
-
#### XMarkAffiliateProductDetail
|
|
901
|
-
|
|
902
|
-
Full product review page layout — image gallery, editorial score, pros/cons table, specs, sticky buy box.
|
|
903
|
-
|
|
904
|
-
```vue
|
|
905
|
-
<XMarkAffiliateProductDetail
|
|
906
|
-
:product="{
|
|
907
|
-
name: 'Sony WH-1000XM5 Review',
|
|
908
|
-
images: ['/img/sony-1.jpg', '/img/sony-2.jpg'],
|
|
909
|
-
price: '$279.99',
|
|
910
|
-
originalPrice: '$349.99',
|
|
911
|
-
rating: 4.8,
|
|
912
|
-
reviewCount: 12400,
|
|
913
|
-
pros: ['Best-in-class ANC', '30hr battery'],
|
|
914
|
-
cons: ['No IP rating', 'Expensive'],
|
|
915
|
-
specs: { 'Driver Size': '30mm', 'Battery': '30 hours', 'Weight': '250g' },
|
|
916
|
-
description: 'The WH-1000XM5 sets the bar for noise-cancelling headphones.',
|
|
917
|
-
verdict: 'The best ANC headphones money can buy in 2024.',
|
|
918
|
-
affiliateUrl: 'https://amazon.com/dp/B09XS7JWHH',
|
|
919
|
-
affiliateTag: 'mysite-20',
|
|
920
|
-
}"
|
|
921
|
-
:score="9.2"
|
|
922
|
-
:has-buy-box="true"
|
|
923
|
-
:has-specs="true"
|
|
924
|
-
:has-pros-cons-table="true"
|
|
925
|
-
disclosure="This page contains affiliate links."
|
|
926
|
-
>
|
|
927
|
-
<template #after-verdict>
|
|
928
|
-
<!-- Additional content after verdict -->
|
|
929
|
-
</template>
|
|
930
|
-
<template #sidebar>
|
|
931
|
-
<!-- Additional sidebar widgets -->
|
|
932
|
-
</template>
|
|
933
|
-
</XMarkAffiliateProductDetail>
|
|
934
|
-
```
|
|
935
|
-
|
|
936
|
-
| Prop | Type | Default | Description |
|
|
937
|
-
|------|------|---------|-------------|
|
|
938
|
-
| `product` | `Object` | sample product | Full product data including `images[]`, `specs{}`, `verdict` |
|
|
939
|
-
| `score` | `Number` | `null` | Editorial score 0–10 (shown as circular badge) |
|
|
940
|
-
| `hasBuyBox` | `Boolean` | `true` | Show sticky buy box sidebar |
|
|
941
|
-
| `hasSpecs` | `Boolean` | `true` | Show specs table |
|
|
942
|
-
| `hasProsConsTable` | `Boolean` | `true` | Show pros/cons two-column table |
|
|
943
|
-
| `disclosure` | `String` | `''` | Affiliate disclosure text |
|
|
944
|
-
|
|
945
|
-
**Slots:** `buy-box`, `after-verdict`, `sidebar`
|
|
946
|
-
|
|
947
|
-
#### XMarkAffiliateComparisonTable
|
|
948
|
-
|
|
949
|
-
Side-by-side product comparison table for "X vs Y" posts. Highlights best values per row.
|
|
950
|
-
|
|
951
|
-
```vue
|
|
952
|
-
<XMarkAffiliateComparisonTable
|
|
953
|
-
:products="[
|
|
954
|
-
{
|
|
955
|
-
name: 'Sony WH-1000XM5',
|
|
956
|
-
image: '/img/sony.jpg',
|
|
957
|
-
price: '$279.99',
|
|
958
|
-
affiliateUrl: 'https://amazon.com/dp/B09XS7JWHH',
|
|
959
|
-
affiliateTag: 'mysite-20',
|
|
960
|
-
specs: { price: '$279.99', rating: '4.8/5', battery: '30 hours', weight: '250g' },
|
|
961
|
-
},
|
|
962
|
-
{
|
|
963
|
-
name: 'Bose QC45',
|
|
964
|
-
image: '/img/bose.jpg',
|
|
965
|
-
price: '$249.99',
|
|
966
|
-
affiliateUrl: 'https://amazon.com/dp/B098FKXT8L',
|
|
967
|
-
affiliateTag: 'mysite-20',
|
|
968
|
-
specs: { price: '$249.99', rating: '4.6/5', battery: '24 hours', weight: '238g' },
|
|
969
|
-
},
|
|
970
|
-
]"
|
|
971
|
-
:specs="[
|
|
972
|
-
{ label: 'Price', key: 'price' },
|
|
973
|
-
{ label: 'Rating', key: 'rating' },
|
|
974
|
-
{ label: 'Battery Life', key: 'battery' },
|
|
975
|
-
{ label: 'Weight', key: 'weight' },
|
|
976
|
-
]"
|
|
977
|
-
:show-buy-buttons="true"
|
|
978
|
-
:highlight-best="true"
|
|
979
|
-
button-label="Buy on Amazon"
|
|
980
|
-
disclosure="This page contains affiliate links."
|
|
981
|
-
/>
|
|
982
|
-
```
|
|
983
|
-
|
|
984
|
-
| Prop | Type | Default | Description |
|
|
985
|
-
|------|------|---------|-------------|
|
|
986
|
-
| `products` | `Array` | 2 sample products | 2–4 products with `specs` object |
|
|
987
|
-
| `specs` | `Array` | price/rating/battery | `[{ label, key }]` spec rows |
|
|
988
|
-
| `showBuyButtons` | `Boolean` | `true` | Show buy buttons in last row |
|
|
989
|
-
| `highlightBest` | `Boolean` | `true` | Highlight best value per row (lowest price, highest rating) |
|
|
990
|
-
| `buttonLabel` | `String` | `'Buy on Amazon'` | Buy button label |
|
|
991
|
-
| `disclosure` | `String` | `''` | Disclosure shown above table |
|
|
992
|
-
|
|
993
|
-
---
|
|
814
|
+
Removed in favour of [`@xenterprises/nuxt-x-affiliate`](../nuxt-x-affiliate).
|
|
815
|
+
|
|
816
|
+
`XMarkAffiliateDisclosure`, `XMarkAffiliateProductCard`, `XMarkAffiliateProductGrid`,
|
|
817
|
+
`XMarkAffiliateProductDetail`, and `XMarkAffiliateComparisonTable` duplicated components
|
|
818
|
+
the affiliate layer already ships — without its per-merchant tagging
|
|
819
|
+
(`xAffiliateContent.merchants`), impression tracking, or Product/Offer structured data.
|
|
820
|
+
Use `<XAFDisclosure>`, `<XAFProductCard>`, `<XAFRelatedProducts>`, `<XAFBuyButton>`,
|
|
821
|
+
and `<XAFComparisonTable>` instead.
|
|
994
822
|
|
|
995
823
|
## Configuration
|
|
996
824
|
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/* NOTE — the `x*` utilities and `--x-*` tokens in this file are duplicated in
|
|
2
|
+
* `nuxt-x-affiliate` (`app/assets/css/main.css`), which was ported from here.
|
|
3
|
+
* 32 class names overlap with identical values. A site extending BOTH layers
|
|
4
|
+
* loads both stylesheets and gets whichever is injected last — harmless while
|
|
5
|
+
* they match, a silent divergence if either is edited alone. Keep them in sync.
|
|
6
|
+
*
|
|
7
|
+
* Only `.xGlow-divider` / `.xGlow-divider-subtle` are unique to this file;
|
|
8
|
+
* the affiliate layer draws that rule with `<XAFDividerGlow>` instead.
|
|
9
|
+
*/
|
|
10
|
+
|
|
1
11
|
@import "tailwindcss";
|
|
2
12
|
@import "@nuxt/ui";
|
|
3
13
|
@plugin "@tailwindcss/typography";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<section
|
|
3
3
|
:class="[
|
|
4
|
-
'relative overflow-hidden
|
|
4
|
+
'relative overflow-hidden',
|
|
5
|
+
rounded ? 'rounded-2xl' : 'rounded-none',
|
|
5
6
|
paddingClasses,
|
|
6
7
|
bgColorClasses,
|
|
7
8
|
]"
|
|
@@ -127,6 +128,11 @@ const props = defineProps({
|
|
|
127
128
|
default: "md",
|
|
128
129
|
validator: (v) => ["sm", "md", "lg"].includes(v),
|
|
129
130
|
},
|
|
131
|
+
/** Card corners. Set false for full-bleed pre-footer CTAs. */
|
|
132
|
+
rounded: {
|
|
133
|
+
type: Boolean,
|
|
134
|
+
default: true,
|
|
135
|
+
},
|
|
130
136
|
});
|
|
131
137
|
|
|
132
138
|
// Default bg values
|
|
@@ -201,23 +207,30 @@ const containerClasses = computed(() => {
|
|
|
201
207
|
});
|
|
202
208
|
|
|
203
209
|
const iconContainerClasses = computed(() => {
|
|
210
|
+
// Keep the badge square: flex parents (inline/default column layout)
|
|
211
|
+
// default to stretch on the cross axis and can squash fixed width/height.
|
|
212
|
+
const centered = ["stacked", "centered"].includes(props.variant);
|
|
204
213
|
return [
|
|
205
|
-
"flex items-center justify-center rounded-xl",
|
|
206
|
-
|
|
214
|
+
"flex shrink-0 items-center justify-center rounded-xl aspect-square",
|
|
215
|
+
centered ? "self-center" : "self-start",
|
|
216
|
+
props.size === "lg"
|
|
217
|
+
? "size-16 min-w-16 min-h-16"
|
|
218
|
+
: "size-12 min-w-12 min-h-12",
|
|
207
219
|
isBoldBg.value ? "bg-white/20" : "bg-primary-100 dark:bg-primary-900/50",
|
|
208
220
|
];
|
|
209
221
|
});
|
|
210
222
|
|
|
211
223
|
const iconClasses = computed(() => {
|
|
212
224
|
return [
|
|
213
|
-
|
|
225
|
+
"shrink-0 block",
|
|
226
|
+
props.size === "lg" ? "size-8" : "size-6",
|
|
214
227
|
isBoldBg.value ? "text-white" : "text-primary-500",
|
|
215
228
|
];
|
|
216
229
|
});
|
|
217
230
|
|
|
218
231
|
const contentClasses = computed(() => {
|
|
219
|
-
if (props.variant === "default") {
|
|
220
|
-
return "flex-1";
|
|
232
|
+
if (props.variant === "default" || props.variant === "inline") {
|
|
233
|
+
return "flex-1 min-w-0";
|
|
221
234
|
}
|
|
222
235
|
return "";
|
|
223
236
|
});
|
package/app/pages/index.vue
CHANGED
|
@@ -86,114 +86,6 @@
|
|
|
86
86
|
</div>
|
|
87
87
|
</XMarkSection>
|
|
88
88
|
|
|
89
|
-
<!-- ─── Affiliate Components Demo ─── -->
|
|
90
|
-
|
|
91
|
-
<!-- Affiliate Disclosure variants -->
|
|
92
|
-
<XMarkSection bg="subtle" padding="xl">
|
|
93
|
-
<header class="text-center max-w-3xl mx-auto mb-12">
|
|
94
|
-
<p class="xText-eyebrow text-primary-500 mb-4">Affiliate Components</p>
|
|
95
|
-
<h2
|
|
96
|
-
class="xText-headline text-neutral-900 dark:text-white xText-balance"
|
|
97
|
-
>
|
|
98
|
-
Affiliate & Review Components
|
|
99
|
-
</h2>
|
|
100
|
-
<p class="mt-4 text-lg text-neutral-600 dark:text-neutral-400">
|
|
101
|
-
FTC-compliant disclosures, product cards, grids, detail pages, and
|
|
102
|
-
comparison tables.
|
|
103
|
-
</p>
|
|
104
|
-
</header>
|
|
105
|
-
|
|
106
|
-
<!-- Disclosure variants -->
|
|
107
|
-
<div class="max-w-3xl mx-auto space-y-4 mb-16">
|
|
108
|
-
<h3
|
|
109
|
-
class="font-semibold text-neutral-700 dark:text-neutral-300 text-sm uppercase tracking-wider mb-4"
|
|
110
|
-
>
|
|
111
|
-
Disclosure Variants
|
|
112
|
-
</h3>
|
|
113
|
-
<XMarkAffiliateDisclosure variant="subtle" />
|
|
114
|
-
<XMarkAffiliateDisclosure variant="banner" />
|
|
115
|
-
<XMarkAffiliateDisclosure variant="inline" />
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
<!-- Product Cards — all 3 layouts -->
|
|
119
|
-
<div class="mb-16">
|
|
120
|
-
<h3
|
|
121
|
-
class="font-semibold text-neutral-700 dark:text-neutral-300 text-sm uppercase tracking-wider mb-6"
|
|
122
|
-
>
|
|
123
|
-
Product Card Layouts
|
|
124
|
-
</h3>
|
|
125
|
-
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
|
|
126
|
-
<XMarkAffiliateProductCard
|
|
127
|
-
:product="sampleProducts[0]"
|
|
128
|
-
layout="card"
|
|
129
|
-
:show-pros="true"
|
|
130
|
-
/>
|
|
131
|
-
<XMarkAffiliateProductCard
|
|
132
|
-
:product="sampleProducts[1]"
|
|
133
|
-
layout="card"
|
|
134
|
-
:show-pros="true"
|
|
135
|
-
:show-cons="true"
|
|
136
|
-
/>
|
|
137
|
-
<XMarkAffiliateProductCard
|
|
138
|
-
:product="sampleProducts[2]"
|
|
139
|
-
layout="card"
|
|
140
|
-
:show-pros="true"
|
|
141
|
-
/>
|
|
142
|
-
</div>
|
|
143
|
-
<div class="space-y-4 mb-6">
|
|
144
|
-
<XMarkAffiliateProductCard
|
|
145
|
-
:product="sampleProducts[0]"
|
|
146
|
-
layout="row"
|
|
147
|
-
:show-pros="true"
|
|
148
|
-
/>
|
|
149
|
-
<XMarkAffiliateProductCard
|
|
150
|
-
:product="sampleProducts[1]"
|
|
151
|
-
layout="row"
|
|
152
|
-
/>
|
|
153
|
-
</div>
|
|
154
|
-
<div class="space-y-2">
|
|
155
|
-
<XMarkAffiliateProductCard
|
|
156
|
-
v-for="p in sampleProducts"
|
|
157
|
-
:key="p.name"
|
|
158
|
-
:product="p"
|
|
159
|
-
layout="compact"
|
|
160
|
-
/>
|
|
161
|
-
</div>
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
<!-- Product Grid -->
|
|
165
|
-
<div class="mb-16">
|
|
166
|
-
<h3
|
|
167
|
-
class="font-semibold text-neutral-700 dark:text-neutral-300 text-sm uppercase tracking-wider mb-6"
|
|
168
|
-
>
|
|
169
|
-
Product Grid (Roundup Post)
|
|
170
|
-
</h3>
|
|
171
|
-
<XMarkAffiliateProductGrid
|
|
172
|
-
:products="sampleProducts"
|
|
173
|
-
layout="grid"
|
|
174
|
-
:columns="3"
|
|
175
|
-
:show-ranking="true"
|
|
176
|
-
disclosure="This page contains affiliate links. As an Amazon Associate, we earn from qualifying purchases."
|
|
177
|
-
/>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<!-- Comparison Table -->
|
|
181
|
-
<div class="mb-16">
|
|
182
|
-
<h3
|
|
183
|
-
class="font-semibold text-neutral-700 dark:text-neutral-300 text-sm uppercase tracking-wider mb-6"
|
|
184
|
-
>
|
|
185
|
-
Comparison Table (X vs Y)
|
|
186
|
-
</h3>
|
|
187
|
-
<XMarkAffiliateComparisonTable
|
|
188
|
-
:products="comparisonProducts"
|
|
189
|
-
:specs="comparisonSpecs"
|
|
190
|
-
:show-buy-buttons="true"
|
|
191
|
-
:highlight-best="true"
|
|
192
|
-
button-label="Buy on Amazon"
|
|
193
|
-
disclosure="This page contains affiliate links."
|
|
194
|
-
/>
|
|
195
|
-
</div>
|
|
196
|
-
</XMarkSection>
|
|
197
89
|
</div>
|
|
198
90
|
</template>
|
|
199
91
|
|
|
@@ -268,103 +160,6 @@ const testimonials = [
|
|
|
268
160
|
},
|
|
269
161
|
];
|
|
270
162
|
|
|
271
|
-
// Affiliate sample products
|
|
272
|
-
const sampleProducts = [
|
|
273
|
-
{
|
|
274
|
-
name: "Sony WH-1000XM5",
|
|
275
|
-
image:
|
|
276
|
-
"https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=400&q=80",
|
|
277
|
-
price: "$279.99",
|
|
278
|
-
originalPrice: "$349.99",
|
|
279
|
-
rating: 4.8,
|
|
280
|
-
reviewCount: 12400,
|
|
281
|
-
pros: ["Best-in-class ANC", "30hr battery life", "Foldable design"],
|
|
282
|
-
cons: ["No IP rating", "Expensive"],
|
|
283
|
-
affiliateUrl: "https://amazon.com",
|
|
284
|
-
affiliateTag: "mysite-20",
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
name: "Bose QuietComfort 45",
|
|
288
|
-
image:
|
|
289
|
-
"https://images.unsplash.com/photo-1484704849700-f032a568e944?w=400&q=80",
|
|
290
|
-
price: "$249.99",
|
|
291
|
-
rating: 4.6,
|
|
292
|
-
reviewCount: 8900,
|
|
293
|
-
pros: ["Comfortable fit", "Great sound quality", "Easy controls"],
|
|
294
|
-
cons: ["No multipoint", "Older design"],
|
|
295
|
-
affiliateUrl: "https://amazon.com",
|
|
296
|
-
affiliateTag: "mysite-20",
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
name: "Apple AirPods Max",
|
|
300
|
-
image:
|
|
301
|
-
"https://images.unsplash.com/photo-1585386959984-a4155224a1ad?w=400&q=80",
|
|
302
|
-
price: "$449.00",
|
|
303
|
-
rating: 4.7,
|
|
304
|
-
reviewCount: 6200,
|
|
305
|
-
pros: ["Premium build quality", "Excellent ANC", "Spatial audio"],
|
|
306
|
-
cons: ["Very expensive", "Heavy", "No USB-C charging"],
|
|
307
|
-
affiliateUrl: "https://amazon.com",
|
|
308
|
-
affiliateTag: "mysite-20",
|
|
309
|
-
},
|
|
310
|
-
];
|
|
311
|
-
|
|
312
|
-
// Comparison table data
|
|
313
|
-
const comparisonProducts = [
|
|
314
|
-
{
|
|
315
|
-
name: "Sony WH-1000XM5",
|
|
316
|
-
image:
|
|
317
|
-
"https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=200&q=80",
|
|
318
|
-
price: "$279.99",
|
|
319
|
-
affiliateUrl: "https://amazon.com",
|
|
320
|
-
affiliateTag: "mysite-20",
|
|
321
|
-
specs: {
|
|
322
|
-
price: "$279.99",
|
|
323
|
-
rating: "4.8/5",
|
|
324
|
-
battery: "30 hours",
|
|
325
|
-
weight: "250g",
|
|
326
|
-
anc: "Yes",
|
|
327
|
-
},
|
|
328
|
-
},
|
|
329
|
-
{
|
|
330
|
-
name: "Bose QC45",
|
|
331
|
-
image:
|
|
332
|
-
"https://images.unsplash.com/photo-1484704849700-f032a568e944?w=200&q=80",
|
|
333
|
-
price: "$249.99",
|
|
334
|
-
affiliateUrl: "https://amazon.com",
|
|
335
|
-
affiliateTag: "mysite-20",
|
|
336
|
-
specs: {
|
|
337
|
-
price: "$249.99",
|
|
338
|
-
rating: "4.6/5",
|
|
339
|
-
battery: "24 hours",
|
|
340
|
-
weight: "238g",
|
|
341
|
-
anc: "Yes",
|
|
342
|
-
},
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
name: "AirPods Max",
|
|
346
|
-
image:
|
|
347
|
-
"https://images.unsplash.com/photo-1585386959984-a4155224a1ad?w=200&q=80",
|
|
348
|
-
price: "$449.00",
|
|
349
|
-
affiliateUrl: "https://amazon.com",
|
|
350
|
-
affiliateTag: "mysite-20",
|
|
351
|
-
specs: {
|
|
352
|
-
price: "$449.00",
|
|
353
|
-
rating: "4.7/5",
|
|
354
|
-
battery: "20 hours",
|
|
355
|
-
weight: "385g",
|
|
356
|
-
anc: "Yes",
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
];
|
|
360
|
-
|
|
361
|
-
const comparisonSpecs = [
|
|
362
|
-
{ label: "Price", key: "price" },
|
|
363
|
-
{ label: "Rating", key: "rating" },
|
|
364
|
-
{ label: "Battery Life", key: "battery" },
|
|
365
|
-
{ label: "Weight", key: "weight" },
|
|
366
|
-
{ label: "ANC", key: "anc" },
|
|
367
|
-
];
|
|
368
163
|
|
|
369
164
|
// Pricing plans data
|
|
370
165
|
const pricingPlans = [
|
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.
|
|
5
|
+
"version": "1.4.0",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"dev": "nuxi dev .playground",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"test:e2e:headed": "playwright test --config test/playwright.smoke.config.js --headed",
|
|
24
24
|
"test:e2e:full": "playwright test --config test/playwright.config.js",
|
|
25
25
|
"test:visual": "playwright test --config test/playwright.config.js visual-regression",
|
|
26
|
-
"test:visual:update": "playwright test --config test/playwright.config.js visual-regression --update-snapshots"
|
|
26
|
+
"test:visual:update": "playwright test --config test/playwright.config.js visual-regression --update-snapshots",
|
|
27
|
+
"prepublishOnly": "npm run test:run && npm run typecheck && npm run lint"
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"@marker.io/browser": "^0.20.2",
|