npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xenterprises/nuxt-x-marketing

v1.0.2

Published

A comprehensive Nuxt layer for building marketing websites with 38+ pre-built components. Features dark mode support, responsive design, accessibility, and seamless integration with Nuxt UI.

Readme

@xenterprises/nuxt-x-marketing

A comprehensive Nuxt layer for building marketing websites with 38+ pre-built components. Features dark mode support, responsive design, accessibility, and seamless integration with Nuxt UI.

Features

  • 38+ Marketing Components - Hero, Features, Pricing, Testimonials, Blog, Affiliate/Review, and more
  • Zero Required Props - Every component works out of the box with sensible defaults
  • Dark Mode Support - All components support light and dark themes
  • Responsive Design - Mobile-first approach with tablet and desktop breakpoints
  • Accessible - WCAG 2.0 AA compliant with proper ARIA attributes
  • Customizable - Props-based configuration with slot overrides
  • Nuxt UI v4 Integration - Built on top of Nuxt UI v4 components
  • Animations - Scroll-triggered fade-in animations and parallax effects
  • Two Footer Modes - Generic white-label (XMarkLayoutFooter) and X Enterprises branded (XFooter)

Installation

npm install @xenterprises/nuxt-x-marketing

Add the layer to your nuxt.config.js:

export default defineNuxtConfig({
  extends: "@xenterprises/nuxt-x-marketing",
});

Quick Start

Basic App Layout

Create your app.vue with Navbar, Newsletter, and Footer:

<template>
  <div class="min-h-screen flex flex-col">
    <XMarkNavbar
      :links="navLinks"
      :logo-light="'/logo-white.svg'"
      :logo-dark="'/logo-dark.svg'"
      logo-alt="Company"
    >
      <template #actions>
        <UButton variant="ghost" color="neutral">Sign In</UButton>
        <UButton color="primary">Get Started</UButton>
      </template>
    </XMarkNavbar>

    <main class="flex-grow">
      <NuxtPage />
    </main>

    <XMarkSection bg="subtle" padding="lg">
      <XMarkNewsletter
        title="Stay in the loop"
        description="Get the latest updates delivered to your inbox."
        @submit="handleNewsletterSubmit"
      />
    </XMarkSection>

    <XMarkFooter
      :logo="'/logo-dark.svg'"
      description="Building the future of modern software."
      :social="socialLinks"
      :columns="footerColumns"
      :legal-links="legalLinks"
    />
  </div>
</template>

<script setup>
const navLinks = [
  { label: "Features", to: "/#features" },
  { label: "Pricing", to: "/pricing" },
  { label: "Blog", to: "/blog" },
];

const socialLinks = [
  { name: "Twitter", href: "https://twitter.com", icon: "i-lucide-twitter" },
  { name: "GitHub", href: "https://github.com", icon: "i-lucide-github" },
];

const footerColumns = [
  {
    title: "Product",
    links: [
      { label: "Features", to: "/#features" },
      { label: "Pricing", to: "/pricing" },
    ],
  },
  {
    title: "Company",
    links: [
      { label: "About", to: "/about" },
      { label: "Blog", to: "/blog" },
    ],
  },
];

const legalLinks = [
  { label: "Privacy Policy", to: "/privacy" },
  { label: "Terms of Service", to: "/terms" },
];

const handleNewsletterSubmit = (email) => {
  console.log("Newsletter signup:", email);
};
</script>

Example Landing Page

All components work with zero required props — just drop them in and customize as needed:

<template>
  <div>
    <!-- Hero — works with zero props, or fully customized -->
    <XMarkHero
      :img="{ src: 'https://images.unsplash.com/photo-1551434678-e076c223a692', alt: 'Hero' }"
      eyebrow="Welcome to the future"
      title="Build something amazing today"
      subtitle="The modern platform for teams who want to ship faster."
      align="left"
      overlay="gradient"
      :buttons="[
        { label: 'Get Started Free', color: 'primary' },
        { label: 'Watch Demo', variant: 'outline' }
      ]"
    />

    <!-- Features — works with zero props, or pass your own -->
    <XMarkSection id="features" bg="default" padding="xl">
      <header class="text-center max-w-3xl mx-auto mb-16">
        <h2 class="xText-headline">Everything you need to succeed</h2>
      </header>
      <XMarkFeatures :features="features" layout="grid" :columns="3" />
    </XMarkSection>

    <!-- Testimonials -->
    <XMarkSection bg="subtle" padding="xl">
      <XMarkTestimonials :testimonials="testimonials" layout="grid" />
    </XMarkSection>

    <!-- Pricing -->
    <XMarkSection bg="default" padding="xl">
      <XMarkPricingPlans :plans="pricingPlans" />
    </XMarkSection>
  </div>
</template>

<script setup>
const features = [
  { icon: 'i-lucide-zap', title: 'Lightning Fast', description: 'Built for speed.' },
  { icon: 'i-lucide-shield-check', title: 'Secure by Default', description: 'Enterprise-grade security.' },
  { icon: 'i-lucide-users', title: 'Team Collaboration', description: 'Real-time collaboration tools.' },
]

const testimonials = [
  { quote: 'This platform transformed how our team works.', name: 'Sarah Chen', title: 'CTO', company: 'TechStart', rating: 5 },
]

const pricingPlans = [
  { name: 'Starter', price: '$19', period: '/month', features: ['5 team members', 'Basic analytics'], button: { label: 'Start Free Trial' } },
  { name: 'Pro', price: '$49', period: '/month', features: ['25 team members', 'Advanced analytics'], button: { label: 'Start Free Trial' }, popular: true },
]
</script>

Components

Core Layout

XMarkNavbar

Fixed navigation header with transparent-to-solid scroll transition.

<XMarkNavbar
  :links="[{ label: 'Features', to: '/#features' }]"
  logo-light="/logo-white.svg"
  logo-dark="/logo-dark.svg"
  logo-alt="Company"
  :transparent="true"
  :scroll-threshold="100"
>
  <template #actions>
    <UButton variant="ghost">Sign In</UButton>
    <UButton color="primary">Get Started</UButton>
  </template>
</XMarkNavbar>

| Prop | Type | Default | Description | |------|------|---------|-------------| | links | Array | [] | Navigation links { label, to } | | logoLight | String | '' | Logo for transparent/dark state | | logoDark | String | '' | Logo for solid/light state | | logoAlt | String | 'Logo' | Logo alt text | | transparent | Boolean | true | Start transparent over hero | | scrollThreshold | Number | 100 | Pixels before transition |

XMarkSection

Section wrapper with background variants and optional patterns.

<XMarkSection bg="subtle" padding="xl" pattern="dots">
  <h2>Section Content</h2>
</XMarkSection>

| Prop | Type | Default | Description | |------|------|---------|-------------| | bg | String | 'default' | default, subtle, elevated, bold, transparent | | padding | String | 'lg' | none, sm, md, lg, xl | | container | String | 'lg' | sm, md, lg, xl, full, none | | pattern | String | '' | dots, grid, diagonal, topography, circuit, waves | | patternOpacity | Number | 0.05 | Pattern opacity (0-1) | | bgImage | String | '' | Background image URL | | parallax | Boolean | false | Enable parallax on bg image |

XMarkFooter

Full footer with brand, link columns, social icons, and newsletter.

<XMarkFooter
  logo="/logo.svg"
  logo-alt="Company"
  description="Building the future of modern software."
  :social="[{ name: 'Twitter', href: 'https://twitter.com', icon: 'i-lucide-twitter' }]"
  :columns="[{ title: 'Product', links: [{ label: 'Features', to: '/features' }] }]"
  :legal-links="[{ label: 'Privacy', to: '/privacy' }]"
  :show-newsletter="true"
  @newsletter-submit="handleSubmit"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | logo | String | '' | Logo image URL | | description | String | '' | Brand description | | social | Array | [] | Social links { name, href, icon } | | columns | Array | [] | Link columns { title, links: [{ label, to }] } | | legalLinks | Array | [] | Legal links { label, to } | | copyright | String | auto | Copyright text | | showNewsletter | Boolean | false | Show newsletter section |

XMarkLegalFooter

Minimal footer with copyright and legal links only.

<XMarkLegalFooter
  company-name="X Enterprises"
  :links="[{ label: 'Privacy', to: '/privacy' }]"
/>

Hero & Landing

XMarkHero

Full-screen hero with image/video background and overlay.

<XMarkHero
  image-src="https://example.com/hero.jpg"
  video-src="https://example.com/hero.mp4"
  eyebrow="Welcome"
  title="Build something amazing"
  subtitle="The modern platform for teams."
  align="left"
  vertical-align="center"
  overlay="gradient"
  :show-scroll-indicator="true"
>
  <template #actions>
    <UButton size="xl" color="white">Get Started</UButton>
  </template>
</XMarkHero>

| Prop | Type | Default | Description | |------|------|---------|-------------| | imageSrc | String | '' | Background image URL | | videoSrc | String | '' | Background video URL | | eyebrow | String | '' | Small text above title | | title | String | required | Main headline | | subtitle | String | '' | Supporting text | | align | String | 'left' | left, center, right | | verticalAlign | String | 'center' | center, bottom | | overlay | String | 'gradient' | light, heavy, gradient, none | | showScrollIndicator | Boolean | true | Show scroll arrow |


Content Sections

XMarkFeatures

Feature grid with icons, images, and optional links.

<XMarkFeatures
  :features="[
    { icon: 'i-lucide-zap', title: 'Fast', description: 'Lightning fast performance.' },
    { icon: 'i-lucide-shield', title: 'Secure', description: 'Enterprise security.' },
  ]"
  layout="grid"
  :columns="3"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | features | Array | required | Features { icon?, image?, title, description, link? } | | layout | String | 'grid' | grid, list, alternating | | columns | Number | 3 | Grid columns (2, 3, or 4) |

XMarkTestimonials

Testimonial cards in grid or carousel layout.

<XMarkTestimonials
  :testimonials="[
    {
      quote: 'Amazing product!',
      name: 'John Doe',
      title: 'CEO',
      company: 'Acme Inc',
      avatar: 'https://example.com/avatar.jpg',
    },
  ]"
  layout="grid"
/>

XMarkPricing

Pricing cards with billing toggle and popular badge.

<XMarkPricing
  :plans="[
    {
      name: 'Starter',
      price: '$19',
      period: 'month',
      description: 'Perfect for small teams.',
      features: ['5 team members', 'Basic analytics'],
      cta: 'Start Free Trial',
    },
    {
      name: 'Pro',
      price: '$49',
      period: 'month',
      features: ['25 team members', 'Advanced analytics'],
      cta: 'Start Free Trial',
      popular: true,
    },
  ]"
  :show-billing-toggle="true"
  :yearly-discount="20"
  @select="handlePlanSelect"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | plans | Array | required | Pricing plans | | highlighted | String | '' | Plan name to highlight | | showBillingToggle | Boolean | false | Show monthly/yearly toggle | | yearlyDiscount | Number | 20 | Yearly discount percentage |

XMarkComparison

Feature comparison table across plans.

<XMarkComparison
  :plans="['Starter', 'Pro', 'Enterprise']"
  :highlighted="'Pro'"
  :feature-groups="[
    {
      name: 'Core Features',
      features: [
        { name: 'Users', values: ['5', '25', 'Unlimited'] },
        { name: 'Storage', values: ['1GB', '10GB', 'Unlimited'] },
      ],
    },
  ]"
/>

XMarkNewsletter

Email signup form with variants.

<XMarkNewsletter
  title="Subscribe to our newsletter"
  description="Get the latest updates."
  :button="{ label: 'Subscribe' }"
  placeholder="Enter your email"
  variant="default"
  @submit="handleSubmit"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | title | String | 'Subscribe...' | Form title | | description | String | '' | Form description | | button | Object | { label: 'Subscribe' } | Button config { label, color? } | | variant | String | 'default' | default, minimal, inline |


Blog Components

XMarkBlogCard

Blog post card with image, title, excerpt, and author.

<XMarkBlogCard
  :post="{
    title: 'Getting Started with Nuxt',
    slug: 'getting-started',
    excerpt: 'Learn how to build modern web apps.',
    image: '/blog/cover.jpg',
    date: '2024-01-15',
    author: { name: 'John Doe', avatar: '/avatars/john.jpg' },
    category: 'Tutorial',
  }"
  variant="default"
/>

XMarkBlogList

Blog listing grid with optional featured post.

<XMarkBlogList
  :posts="posts"
  :columns="3"
  :show-featured="true"
/>

XMarkBlogDetail

Full blog post view with author, share buttons, and navigation.

<XMarkBlogDetail
  :post="post"
  :author="author"
  :related-posts="relatedPosts"
/>

XMarkBlogSidebar

Blog sidebar with search, categories, tags, and recent posts.

<XMarkBlogSidebar
  :categories="['Tutorials', 'News', 'Updates']"
  :tags="['vue', 'nuxt', 'javascript']"
  :recent-posts="recentPosts"
  :show-search="true"
  @search="handleSearch"
  @category-click="handleCategoryClick"
/>

XMarkBlogAuthor

Author bio with social links.

<XMarkBlogAuthor
  :author="{
    name: 'John Doe',
    title: 'Senior Developer',
    avatar: '/avatars/john.jpg',
    bio: 'Passionate about building great software.',
    social: { twitter: 'https://twitter.com/johndoe' },
  }"
  variant="full"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | author | Object | required | Author data | | variant | String | 'inline' | inline, sm, full, card |

XMarkBlogNavigation

Previous/next post navigation.

<XMarkBlogNavigation
  :previous="{ title: 'Previous Post', slug: 'prev-post' }"
  :next="{ title: 'Next Post', slug: 'next-post' }"
  base-path="/blog"
/>

XMarkBlogCTA

In-article newsletter signup.

<XMarkBlogCTA
  title="Enjoyed this article?"
  description="Subscribe for more content."
  variant="featured"
  @submit="handleSubmit"
/>

UI Elements

XMarkBadge

Trust and feature badges with presets.

<XMarkBadge preset="no-credit-card" variant="subtle" />
<XMarkBadge preset="cancel-anytime" />
<XMarkBadge icon="i-lucide-star" label="5-star rated" />

| Prop | Type | Default | Description | |------|------|---------|-------------| | preset | String | '' | no-credit-card, cancel-anytime, money-back, free-trial, secure | | icon | String | '' | Custom icon (if no preset) | | label | String | '' | Custom label (if no preset) | | variant | String | 'default' | default, subtle, outline |

XMarkGlassCard

Glassmorphism card with blur effect.

<XMarkGlassCard :blur="10" :opacity="0.1">
  <h3>Card Content</h3>
</XMarkGlassCard>

XMarkPromoCard

Promotional card with image and CTA.

<XMarkPromoCard
  title="Special Offer"
  description="Get 50% off your first month."
  image="/promo.jpg"
  cta-text="Claim Offer"
  cta-link="/pricing"
/>

XMarkGlowDivider

Glowing section divider.

<XMarkGlowDivider color="primary" :intensity="0.5" />

XMarkPatternBg

SVG background patterns.

<XMarkPatternBg pattern="dots" :opacity="0.05" />

| Prop | Type | Default | Description | |------|------|---------|-------------| | pattern | String | 'dots' | dots, grid, diagonal, topography, circuit, waves | | opacity | Number | 0.05 | Pattern opacity |

XMarkSectionStitch

Section divider shapes.

<XMarkSectionStitch shape="wave" position="top" :flip="false" />

| Prop | Type | Default | Description | |------|------|---------|-------------| | shape | String | 'wave' | angle, wave, curve, triangle, zigzag | | position | String | 'bottom' | top, bottom | | flip | Boolean | false | Flip horizontally |


Modals & Overlays

XMarkVideoModal

Video lightbox supporting YouTube, Vimeo, and direct URLs.

<XMarkVideoModal
  v-model="showVideo"
  url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  title="Product Demo"
/>

XMarkImageLightbox

Image gallery lightbox with keyboard navigation.

<XMarkImageLightbox
  v-model="showLightbox"
  :images="[
    { src: '/gallery/1.jpg', alt: 'Image 1', caption: 'First image' },
    { src: '/gallery/2.jpg', alt: 'Image 2' },
  ]"
  :start-index="0"
/>

XMarkFeatureModal

Feature detail modal.

<XMarkFeatureModal
  v-model="showFeature"
  :feature="{
    icon: 'i-lucide-zap',
    title: 'Lightning Fast',
    description: 'Detailed description...',
    image: '/features/speed.jpg',
  }"
/>

Notifications & Banners

XMarkAnnouncementBar

Dismissible top announcement banner.

<XMarkAnnouncementBar
  message="New feature available!"
  link-text="Learn more"
  link-url="/features"
  variant="primary"
  :dismissible="true"
  @dismiss="handleDismiss"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | message | String | required | Announcement text | | linkText | String | '' | Optional link text | | linkUrl | String | '' | Optional link URL | | variant | String | 'primary' | primary, neutral, success, warning, error | | dismissible | Boolean | true | Show dismiss button |

XMarkCookieBanner

Cookie consent banner.

<XMarkCookieBanner
  message="We use cookies to improve your experience."
  accept-text="Accept All"
  decline-text="Decline"
  :show-preferences="true"
  @accept="handleAccept"
  @decline="handleDecline"
  @preferences="handlePreferences"
/>

XMarkCookieToast

Cookie toast notification.

<XMarkCookieToast
  message="We use cookies"
  @accept="handleAccept"
/>

XMarkGDPR

GDPR cookie preference modal.

<XMarkGDPR
  v-model="showGDPR"
  :categories="[
    { id: 'necessary', name: 'Necessary', description: 'Required for the site to work.', required: true },
    { id: 'analytics', name: 'Analytics', description: 'Help us improve.', default: false },
  ]"
  @save="handleSavePreferences"
/>

XMarkSocialProofToast

Social proof notification toasts.

<XMarkSocialProofToast
  :notifications="[
    { name: 'John', location: 'New York', action: 'signed up', time: '2 minutes ago' },
  ]"
  :interval="5000"
  position="bottom-left"
/>

Utilities

XMarkBackToTop

Scroll to top button.

<XMarkBackToTop :show-after="300" :smooth="true" />

XMarkPopupChat

Chat widget trigger.

<XMarkPopupChat
  provider="intercom"
  :config="{ app_id: 'your-app-id' }"
/>

Affiliate & Review Components

For affiliate marketing, product review sites, and "best X" roundup posts.

XMarkAffiliateDisclosure

FTC/Amazon-required affiliate disclosure banner. Three variants for different placements.

<!-- Subtle bar (default) -->
<XMarkAffiliateDisclosure />

<!-- Full-width banner at top of page -->
<XMarkAffiliateDisclosure variant="banner" :dismissible="true" />

<!-- Inline inside blog post prose -->
<XMarkAffiliateDisclosure variant="inline" />

| Prop | Type | Default | Description | |------|------|---------|-------------| | text | String | Amazon associate disclosure | Disclosure text | | variant | String | 'subtle' | subtle, banner, inline | | icon | String | 'i-lucide-info' | Icon name | | dismissible | Boolean | false | Show dismiss button | | storageKey | String | 'affiliate-disclosure-dismissed' | localStorage key |

XMarkAffiliateProductCard

Product card with affiliate buy button, star rating, price, pros/cons. Three layout variants.

<XMarkAffiliateProductCard
  :product="{
    name: 'Sony WH-1000XM5',
    image: '/products/sony-wh1000xm5.jpg',
    price: '$279.99',
    originalPrice: '$349.99',
    rating: 4.8,
    reviewCount: 12400,
    pros: ['Best-in-class ANC', '30hr battery', 'Foldable design'],
    cons: ['No IP rating', 'Expensive'],
    affiliateUrl: 'https://amazon.com/dp/B09XS7JWHH',
    affiliateTag: 'mysite-20',
    badge: '#1 Pick',
  }"
  layout="card"
  button-label="Check Price on Amazon"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | product | Object | sample product | Product data { name, image?, price?, originalPrice?, rating?, reviewCount?, pros?, cons?, affiliateUrl?, affiliateTag?, badge? } | | layout | String | 'card' | card (vertical), row (horizontal), compact (one-line) | | showPros | Boolean | true | Show pros list | | showCons | Boolean | false | Show cons list | | showRating | Boolean | true | Show star rating | | showPrice | Boolean | true | Show price | | buttonLabel | String | 'Check Price on Amazon' | CTA button text | | buttonIcon | String | 'i-lucide-external-link' | CTA button icon | | disclosure | String | '' | Small disclosure text below button |

XMarkAffiliateProductGrid

Grid of product cards for "best X" roundup posts. Automatically injects rank badges.

<XMarkAffiliateProductGrid
  :products="topHeadphones"
  layout="grid"
  :columns="3"
  :show-ranking="true"
  disclosure="This page contains affiliate links."
  button-label="Check Price on Amazon"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | products | Array | [] | Array of product objects | | layout | String | 'grid' | grid or list | | columns | Number | 3 | Grid columns: 2 or 3 | | showRanking | Boolean | true | Inject #1/#2/#3 badges on first 3 products | | disclosure | String | '' | Disclosure shown once at top | | buttonLabel | String | 'Check Price on Amazon' | CTA label for all cards | | cardLayout | String | 'card' | Card layout variant |

XMarkAffiliateProductDetail

Full product review page layout — image gallery, editorial score, pros/cons table, specs, sticky buy box.

<XMarkAffiliateProductDetail
  :product="{
    name: 'Sony WH-1000XM5 Review',
    images: ['/img/sony-1.jpg', '/img/sony-2.jpg'],
    price: '$279.99',
    originalPrice: '$349.99',
    rating: 4.8,
    reviewCount: 12400,
    pros: ['Best-in-class ANC', '30hr battery'],
    cons: ['No IP rating', 'Expensive'],
    specs: { 'Driver Size': '30mm', 'Battery': '30 hours', 'Weight': '250g' },
    description: 'The WH-1000XM5 sets the bar for noise-cancelling headphones.',
    verdict: 'The best ANC headphones money can buy in 2024.',
    affiliateUrl: 'https://amazon.com/dp/B09XS7JWHH',
    affiliateTag: 'mysite-20',
  }"
  :score="9.2"
  :has-buy-box="true"
  :has-specs="true"
  :has-pros-cons-table="true"
  disclosure="This page contains affiliate links."
>
  <template #after-verdict>
    <!-- Additional content after verdict -->
  </template>
  <template #sidebar>
    <!-- Additional sidebar widgets -->
  </template>
</XMarkAffiliateProductDetail>

| Prop | Type | Default | Description | |------|------|---------|-------------| | product | Object | sample product | Full product data including images[], specs{}, verdict | | score | Number | null | Editorial score 0–10 (shown as circular badge) | | hasBuyBox | Boolean | true | Show sticky buy box sidebar | | hasSpecs | Boolean | true | Show specs table | | hasProsConsTable | Boolean | true | Show pros/cons two-column table | | disclosure | String | '' | Affiliate disclosure text |

Slots: buy-box, after-verdict, sidebar

XMarkAffiliateComparisonTable

Side-by-side product comparison table for "X vs Y" posts. Highlights best values per row.

<XMarkAffiliateComparisonTable
  :products="[
    {
      name: 'Sony WH-1000XM5',
      image: '/img/sony.jpg',
      price: '$279.99',
      affiliateUrl: 'https://amazon.com/dp/B09XS7JWHH',
      affiliateTag: 'mysite-20',
      specs: { price: '$279.99', rating: '4.8/5', battery: '30 hours', weight: '250g' },
    },
    {
      name: 'Bose QC45',
      image: '/img/bose.jpg',
      price: '$249.99',
      affiliateUrl: 'https://amazon.com/dp/B098FKXT8L',
      affiliateTag: 'mysite-20',
      specs: { price: '$249.99', rating: '4.6/5', battery: '24 hours', weight: '238g' },
    },
  ]"
  :specs="[
    { label: 'Price', key: 'price' },
    { label: 'Rating', key: 'rating' },
    { label: 'Battery Life', key: 'battery' },
    { label: 'Weight', key: 'weight' },
  ]"
  :show-buy-buttons="true"
  :highlight-best="true"
  button-label="Buy on Amazon"
  disclosure="This page contains affiliate links."
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | products | Array | 2 sample products | 2–4 products with specs object | | specs | Array | price/rating/battery | [{ label, key }] spec rows | | showBuyButtons | Boolean | true | Show buy buttons in last row | | highlightBest | Boolean | true | Highlight best value per row (lowest price, highest rating) | | buttonLabel | String | 'Buy on Amazon' | Buy button label | | disclosure | String | '' | Disclosure shown above table |


Configuration

Configure the layer in your app.config.js:

export default defineAppConfig({
  xMarketing: {
    name: "X Enterprises",
    config: {
      markerProjectId: "your-marker-project-id", // Optional: Marker.io integration
    },
  },
});

Testing

Unit Tests

Run unit tests with Vitest:

npm run test:unit

E2E Tests

Run end-to-end tests with Playwright:

npm run test:e2e

CSS Classes

The layer provides utility classes for consistent styling:

| Class | Description | |-------|-------------| | xText-display | Large display heading | | xText-headline | Section headline | | xText-title | Card/feature title | | xText-eyebrow | Small uppercase label | | xText-balance | Text wrap balance | | xFadeUp | Scroll-triggered fade-in animation | | xHover-zoom | Zoom on hover effect | | xParallax | Parallax scroll effect | | xGlass | Glassmorphism effect |


License

MIT License - see LICENSE file for details.