@xenterprises/nuxt-x-cards
v0.1.2
Published
A premium card component library for Nuxt 4 with cinematic image filters, warm surfaces, and accessible design.
Readme
nuxt-x-cards
A premium card component library for Nuxt 4 with cinematic image filters, warm surfaces, and accessible design.
Built on Nuxt UI v4 and Tailwind CSS v4. Inspired by Oura Ring and Rivian visual identities.
Quick Start
Install the layer in your Nuxt 4 project:
# From git (recommended during development)
pnpm add nuxt-x-cards@github:your-org/nuxt-x-cardsAdd to your nuxt.config.ts:
export default defineNuxtConfig({
extends: ['nuxt-x-cards']
})All components, CSS utilities, and fonts are now available in your app.
Configuration
Customize the design system via app.config.ts under the x.cards namespace. Every key has a sensible default — override only what you need.
// app.config.ts
export default defineAppConfig({
x: {
cards: {
colors: {
primary: 'blue', // your Tailwind palette name
accents: { gold: '#FF6B00' } // override just the gold accent
},
fonts: {
sans: "'Geist', system-ui, sans-serif",
googleFontsUrl: 'https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&display=swap'
},
brand: {
appName: 'My App',
logoIcon: 'i-lucide-zap'
}
}
}
})Full Config Reference
| Key | Type | Default | Description |
|---|---|---|---|
| colors.primary | string | 'cream' | Tailwind palette name for primary surfaces |
| colors.neutral | string | 'olive' | Tailwind palette name for text and borders |
| colors.accents.gold | string | '#FFAC00' | Primary accent (ratings, CTAs, highlights) |
| colors.accents.goldHover | string | '#E69B00' | Gold hover state |
| colors.accents.blue | string | '#8BA8BD' | Secondary cool accent |
| colors.accents.green | string | '#1BC651' | Success/positive accent |
| fonts.sans | string | 'Inter', ... | Sans-serif font stack |
| fonts.serif | string | 'Playfair Display', ... | Serif font stack (italic accents) |
| fonts.display | string | 'Inter', ... | Display font stack (large headings) |
| fonts.googleFontsUrl | string | Google Fonts URL | Stylesheet URL for web fonts |
| radius.card | string | '0.75rem' | Card corner radius (12px) |
| radius.panel | string | '1.5rem' | Panel corner radius (24px) |
| radius.pill | string | '9999px' | Pill/button radius |
| spacing.baseUnit | number | 4 | Base grid unit in px |
| defaults.filter | string | 'cinematic' | Default image filter for cards |
| defaults.overlay | string | 'bottom-blur' | Default gradient overlay |
| defaults.mediaAspectRatio | string | 'landscape' | Default XCardMedia aspect ratio |
| defaults.productAspectRatio | string | 'product' | Default XCardProduct aspect ratio |
| brand.appName | string | 'nuxt-x-cards' | App name in footer/SEO |
| brand.logoIcon | string | 'i-lucide-square-x' | Iconify icon for logo |
Accessing Config in Components
Use the auto-imported useXCards() composable:
<script setup>
const xCards = useXCards()
// xCards.colors.primary → 'cream'
// xCards.defaults.filter → 'cinematic'
</script>Color Customization
The layer ships with two custom palettes defined in CSS (@theme static):
- Cream (primary) — warm Oura-inspired surfaces
- Olive (neutral) — warm Rivian charcoal tones
Using Built-in Palettes
Set colors.primary and colors.neutral in your config. These must match palette names defined in your CSS @theme static block.
Creating Custom Palettes
To use your own colors, create a CSS file with your palette and import it:
/* assets/css/my-theme.css */
@theme static {
--color-ocean-50: #F0F9FF;
--color-ocean-100: #E0F2FE;
/* ... shades 200-950 ... */
--color-ocean-950: #0C1D29;
}Then set:
// app.config.ts
x: {
cards: {
colors: { primary: 'ocean' }
}
}Note: The
@theme staticblock is resolved at build time. The config values tell components which palette name to reference in utility classes (e.g.,text-primary-200), but the actual hex values come from CSS.
Accent Colors
Accent colors (gold, blue, green) are defined as standalone CSS custom properties (--color-accent-gold, etc.) in the layer's CSS. Override them in your own CSS:
@theme static {
--color-accent-gold: #FF6B00;
--color-accent-gold-hover: #E05A00;
}Font Customization
Fonts are configured in three parts that must stay in sync:
fonts.sans/fonts.serif— CSS font-family stacksfonts.googleFontsUrl— URL that loads the web fonts- CSS
@theme static—--font-sans,--font-serif,--font-display
To change fonts:
// app.config.ts
x: {
cards: {
fonts: {
sans: "'Geist', system-ui, sans-serif",
serif: "'Lora', 'Georgia', serif",
googleFontsUrl: 'https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&family=Lora:ital,wght@0,400;0,700;1,400&display=swap'
}
}
}And override the CSS custom properties:
@theme static {
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Lora', 'Georgia', serif;
}Set googleFontsUrl to an empty string to disable Google Fonts loading (for self-hosted fonts).
Components
XCardHeroFullscreen
Full-viewport hero with cinematic overlay and optional CTAs.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | required | Main heading |
| titleAccent | string | — | Italic serif phrase within heading |
| subtitle | string | — | Subheading text |
| pretitle | string | — | Section label above heading |
| imageUrl | string | required | Background image URL |
| imageAlt | string | — | Alt text |
| theme | 'dark' \| 'light' | 'dark' | Text color scheme |
| filter | string | config default | CSS image filter |
| overlay | string | config default | Gradient overlay |
| primaryCta | { label, to } | — | Primary button |
| secondaryCta | { label, to } | — | Secondary button |
| height | 'full' \| 'tall' \| 'medium' | 'full' | Viewport height |
XCardHeroSplit
Split-layout hero with image on one side, text on the other.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | required | Main heading |
| titleAccent | string | — | Italic serif phrase |
| description | string | — | Body text |
| pretitle | string | — | Section label |
| imageUrl | string | required | Image URL |
| imageAlt | string | — | Alt text |
| variant | 'left-image' \| 'right-image' | 'left-image' | Image position |
| filter | string | config default | CSS image filter |
| cta | { label, to } | — | CTA button |
| theme | 'dark' \| 'light' | 'light' | Color scheme |
XCardMedia
Immersive media card with full-bleed image and text overlay.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | required | Heading |
| description | string | — | Body text |
| imageUrl | string | required | Image URL |
| imageAlt | string | — | Alt text |
| filter | string | config default | CSS image filter |
| overlay | string | config default | Gradient overlay |
| cta | { label, to } | — | CTA button |
| aspectRatio | 'cinematic' \| 'landscape' \| 'square' \| 'portrait' | config default | Aspect ratio |
| size | 'sm' \| 'md' \| 'lg' | 'md' | Padding scale |
XCardProduct
Product showcase with color swatches and image switching.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | required | Product name |
| description | string | — | Product description |
| price | string | — | Price display |
| imageUrl | string | required | Default image |
| imageAlt | string | — | Alt text |
| badge | string | — | Badge text (e.g., "New") |
| colors | Array<{ name, hex, imageUrl? }> | — | Color swatches |
| cta | { label, to } | — | CTA button |
| aspectRatio | 'square' \| 'product' \| 'portrait' \| 'landscape' | config default | Aspect ratio |
XCardFeature
Versatile feature card with icon, stat, or image variants.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | required | Feature name |
| description | string | — | Feature description |
| icon | string | — | Iconify icon name |
| imageUrl | string | — | Feature image |
| stat | { value, label } | — | Stat display |
| variant | 'default' \| 'elevated' \| 'bordered' \| 'glass' | 'default' | Card style |
XCardTestimonial
Story-driven testimonial with lifestyle imagery and serif quotes.
| Prop | Type | Default | Description |
|---|---|---|---|
| quote | string | required | Testimonial text |
| author | string | required | Author name |
| role | string | — | Author role/title |
| imageUrl | string | — | Lifestyle image |
| imageAlt | string | — | Alt text |
XCardTeam
Team member card with portrait and social links.
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | required | Person's name |
| role | string | required | Job title |
| bio | string | — | Short bio |
| imageUrl | string | required | Portrait photo |
| imageAlt | string | — | Alt text |
| socials | Array<{ icon, to, label }> | — | Social links |
XCardPricing
Pricing tier card with feature list and optional highlighting.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | required | Plan name |
| description | string | — | Plan description |
| price | string | required | Price display |
| period | string | — | Billing period |
| features | string[] | [] | Feature list |
| cta | { label, to } | — | CTA button |
| highlighted | boolean | false | Dark inverted styling |
| badge | string | — | Badge text |
XCardComparison
Feature comparison table with highlighted "ours" column.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | — | Section heading |
| description | string | — | Section description |
| features | Array<{ name, ours, theirs }> | required | Feature rows (boolean or string) |
| ourLabel | string | 'Us' | Our column header |
| theirLabel | string | 'Them' | Their column header |
| ourLogo | string | — | Iconify icon for our brand |
| theirLogo | string | — | Iconify icon for competitor |
XCardReview
Multi-source review card with star ratings.
| Prop | Type | Default | Description |
|---|---|---|---|
| reviewText | string | required | Review body |
| reviewerName | string | required | Reviewer name |
| reviewerAvatar | string | — | Avatar image URL |
| rating | 1-5 | required | Star rating |
| source | 'google' \| 'yelp' \| 'trustpilot' \| 'appstore' \| 'generic' | 'generic' | Review source |
| date | string | — | Review date |
| aspectRatio | 'auto' \| 'square' \| '4:3' \| '3:4' \| '16:9' \| '9:16' | 'auto' | Card aspect ratio |
XCardImageFilter
Filter showcase card with before/after hover effect.
| Prop | Type | Default | Description |
|---|---|---|---|
| imageUrl | string | required | Image URL |
| imageAlt | string | — | Alt text |
| filter | string | required | Filter name |
| title | string | — | Filter display name |
| description | string | — | Filter description |
| cssValues | string | — | CSS filter values display |
XCardGrid
Responsive grid layout wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
| columns | 1 \| 2 \| 3 \| 4 | 3 | Column count |
| gap | 'sm' \| 'md' \| 'lg' | 'md' | Gap size |
SectionHeading
Section intro with optional label and serif accent.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | required | Section heading |
| titleAccent | string | — | Italic serif phrase |
| description | string | — | Section description |
| label | string | — | Uppercase label above heading |
| align | 'left' \| 'center' | 'left' | Text alignment |
CSS Utilities
Image Filters
| Class | Effect |
|---|---|
| .filter-x-cinematic | saturate(0.7) contrast(1.15) brightness(0.95) |
| .filter-x-moody | saturate(0.5) contrast(1.25) brightness(0.85) sepia(0.1) |
| .filter-x-golden | saturate(0.65) contrast(1.1) brightness(1.05) sepia(0.15) |
| .filter-x-cool | saturate(0.6) contrast(1.2) brightness(0.9) hue-rotate(10deg) |
| .filter-x-dramatic | saturate(0.4) contrast(1.35) brightness(0.8) |
| .filter-x-clean | saturate(1.05) contrast(1.05) brightness(1.02) |
| .filter-x-product | saturate(0.95) contrast(1.1) brightness(1.08) |
| .filter-x-warm | saturate(0.9) contrast(1.05) brightness(1.05) sepia(0.08) |
Gradient Overlays
| Class | Use |
|---|---|
| .overlay-bottom | Strong bottom gradient for text |
| .overlay-bottom-fade | Smooth 5-stop bottom fade |
| .overlay-bottom-blur | Gradient + backdrop blur with mask |
| .overlay-top | Top gradient for header text |
| .overlay-full | Solid semi-transparent overlay |
| .overlay-cinematic | Rivian-style bottom-heavy gradient |
| .overlay-oura | Oura-style gradient |
Blur Panels
| Class | Use |
|---|---|
| .text-blur-panel | Dark frosted glass for white text |
| .text-blur-panel-heavy | Maximum readability on busy images |
| .text-blur-panel-light | Light frosted glass for dark text |
| .blur-badge | Inline pill-shaped blur badge |
Typography
| Class | Description |
|---|---|
| .heading-tight | Tight letter-spacing (-0.03em), condensed line-height |
| .body-tight | Slight letter-spacing tightening (-0.01em) |
| .serif-accent | Italic Playfair Display for emotional phrases |
| .section-label | Uppercase bold 12px label |
| .text-heading | Contrast-safe heading color (13.6:1) |
| .text-body | Contrast-safe body color (6.6:1) |
| .text-secondary | Contrast-safe secondary color (4.8:1) |
| .text-caption | Caption color (3.5:1, bold/large only) |
Button Variants
| Class | Style |
|---|---|
| .btn-oura-dark | Dark pill button, cream text |
| .btn-oura-olive | Olive pill button, cream text |
| .btn-oura-light | Cream pill button, dark text |
| .btn-oura-outline | Outline pill, inverts on hover |
| .btn-rivian-primary | Gold rectangular CTA, uppercase |
| .btn-rivian-text | Underlined text link |
Card Animations
| Class | Effect |
|---|---|
| .card-zoom-out | Image starts scaled 1.05, zooms to 1 on hover |
| .card-zoom-in | Image starts at 1, zooms to 1.05 on hover |
| .card-text-reveal | Text fades up from 85% opacity on hover |
| .fade-in-up | Scroll reveal: fade in + slide up 24px |
Surfaces & Gradients
| Class | Description |
|---|---|
| .bg-surface | Primary-200 background |
| .bg-surface-light | Primary-100 background |
| .bg-surface-dark | Primary-300 background |
| .bg-rivian-dark | #151515 dark background |
| .bg-gradient-oura-warm | Radial warm gradient |
| .bg-gradient-oura-cool | Radial cool gradient |
| .bg-gradient-oura-hero | Combined warm+cool hero gradient |
Aspect Ratios
| Class | Ratio |
|---|---|
| .aspect-cinematic | 21:9 |
| .aspect-landscape | 16:9 |
| .aspect-portrait | 2:3 |
| .aspect-product | 10:7 |
Image Prompt Templates
The prompts/ directory contains base photography descriptions for generating consistent imagery with AI image models (Nano Banana 2 or similar).
| Template | Style | Paired Filter |
|---|---|---|
| hero-lifestyle | Cinematic outdoor adventure | .filter-x-cinematic |
| product-studio | Clean studio photography | .filter-x-product |
| portrait-team | Natural light portraits | .filter-x-warm |
| testimonial-lifestyle | Candid golden hour | .filter-x-golden |
| media-editorial | Moody editorial | .filter-x-moody |
| food-wellness | Bright wellness | .filter-x-clean |
Each file includes camera simulation, lighting setup, color grading notes, a copy-paste base prompt, and variation modifiers.
Design System
Color Palettes
Cream (Primary)
| Shade | Hex | Use |
|---|---|---|
| 50 | #FDFCFA | Lightest surface |
| 100 | #FAF8F4 | Light surface |
| 200 | #F7F1E8 | Default surface / body bg |
| 300 | #EDE4D5 | Dark surface |
| 400 | #DDD0BB | Muted accent |
| 500 | #C9B896 | Disabled state |
| 600 | #B5A07A | Secondary text |
| 700 | #9A8362 | Body text |
| 800 | #7D6A4F | Strong text |
| 900 | #655543 | Heading text |
| 950 | #2D261E | Darkest |
Olive (Neutral)
| Shade | Hex | Use |
|---|---|---|
| 50 | #F7F6F4 | Lightest |
| 100 | #EDECEA | Light border |
| 200 | #D3D1CE | Border |
| 300 | #B5B2AD | Muted text |
| 400 | #918D86 | Placeholder |
| 500 | #74716A | Caption text |
| 600 | #5C5952 | Secondary text |
| 700 | #4A4741 | Body text |
| 800 | #3A3834 | Strong text |
| 900 | #1E2427 | Dark surface |
| 950 | #1C1B1A | Darkest surface |
Typography Scale
All line-heights are multiples of the 4px base grid:
| Step | Size | Line-height | Grid | |---|---|---|---| | xs | 12px | 16px | 4 x 4 | | sm | 14px | 20px | 4 x 5 | | base | 16px | 24px | 4 x 6 | | lg | 20px | 28px | 4 x 7 | | xl | 24px | 32px | 4 x 8 | | 2xl | 32px | 40px | 4 x 10 | | 3xl | 40px | 48px | 4 x 12 | | 4xl | 48px | 52px | 4 x 13 | | 5xl | 64px | 68px | 4 x 17 |
WCAG Contrast Ratios
All text-on-surface combinations meet WCAG AA:
| Combination | Ratio | Standard | |---|---|---| | neutral-950 on primary-200 | 13.6:1 | AAA (headings) | | neutral-700 on primary-200 | 6.6:1 | AA (body) | | neutral-600 on primary-200 | 4.8:1 | AA (body) | | neutral-500 on primary-200 | 3.5:1 | AA (large/bold) | | primary-100 on neutral-900 | 14.5:1 | AAA (inverted) |
Demo Pages
Run the layer standalone to browse all demo pages:
pnpm devRoutes: /, /hero-cards, /product-cards, /feature-cards, /media-cards, /testimonial-cards, /review-cards, /pricing-cards, /comparison-cards, /team-cards, /image-filters
Dependencies
- Nuxt 4 (
^4.4.2) - Nuxt UI v4 (
^4.5.1) - Tailwind CSS v4 (
^4.2.1) - Lucide Icons (
@iconify-json/lucide) - Simple Icons (
@iconify-json/simple-icons)
License
MIT
