Innovations
heroes /

Grid Product Preview Hero

Split hero with text on the left and a grid of 6 product UI preview cards on the right. Screenshot-style cards with gradient fills simulate app screenshots.

Preview

Source

tsx
"use client";

import { motion } from "framer-motion";
import { ArrowRight, LayoutGrid } from "lucide-react";
import { Button } from "@/components/ui/button";

const previewCards = [
  {
    gradient: "from-violet-500 via-purple-500 to-indigo-600",
    label: "Analytics",
    bars: [60, 85, 45, 90, 70],
  },
  {
    gradient: "from-sky-400 via-cyan-400 to-teal-500",
    label: "Dashboard",
    bars: [40, 65, 80, 55, 75],
  },
  {
    gradient: "from-rose-400 via-pink-500 to-fuchsia-600",
    label: "Reports",
    bars: [75, 50, 90, 65, 40],
  },
  {
    gradient: "from-amber-400 via-orange-400 to-red-500",
    label: "Campaigns",
    bars: [50, 80, 60, 70, 85],
  },
  {
    gradient: "from-emerald-400 via-green-500 to-teal-600",
    label: "Revenue",
    bars: [85, 60, 75, 90, 55],
  },
  {
    gradient: "from-blue-500 via-indigo-500 to-violet-600",
    label: "Users",
    bars: [65, 90, 55, 80, 70],
  },
];

export default function GridPreviewHero() {
  return (
    <section className="relative min-h-screen flex items-center overflow-hidden bg-background">
      <div className="container mx-auto px-6 py-20 grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
        {/* Left: Text */}
        <motion.div
          initial={{ opacity: 0, x: -30 }}
          animate={{ opacity: 1, x: 0 }}
          transition={{ duration: 0.65, ease: "easeOut" }}
          className="flex flex-col gap-6"
        >
          <span className="inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary bg-primary/10 border border-primary/20 rounded-full px-4 py-2 w-fit">
            <LayoutGrid className="w-3.5 h-3.5" />
            6 powerful modules
          </span>

          <h1 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold tracking-tight text-foreground leading-[1.08]">
            Every tool your
            <br />
            team needs,
            <br />
            <span className="bg-gradient-to-r from-primary to-violet-500 bg-clip-text text-transparent">
              in one place.
            </span>
          </h1>

          <p className="text-lg text-muted-foreground max-w-md leading-relaxed">
            Analytics, reporting, campaign management, and revenue tracking —
            all connected in a single, intuitive workspace. No more tab-switching.
          </p>

          <div className="flex flex-col sm:flex-row gap-3 pt-2">
            <Button size="lg" className="gap-2 text-base">
              Explore the platform
              <ArrowRight className="w-4 h-4" />
            </Button>
            <Button size="lg" variant="outline" className="text-base">
              View pricing
            </Button>
          </div>

          <div className="flex items-center gap-6 pt-2 text-sm text-muted-foreground">
            <div className="flex flex-col">
              <span className="text-2xl font-bold text-foreground">200+</span>
              <span>Integrations</span>
            </div>
            <div className="w-px h-10 bg-border" />
            <div className="flex flex-col">
              <span className="text-2xl font-bold text-foreground">99.9%</span>
              <span>Uptime SLA</span>
            </div>
            <div className="w-px h-10 bg-border" />
            <div className="flex flex-col">
              <span className="text-2xl font-bold text-foreground">SOC 2</span>
              <span>Certified</span>
            </div>
          </div>
        </motion.div>

        {/* Right: Product preview grid */}
        <motion.div
          initial={{ opacity: 0, x: 30 }}
          animate={{ opacity: 1, x: 0 }}
          transition={{ duration: 0.65, ease: "easeOut", delay: 0.15 }}
          className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-2 xl:grid-cols-3 gap-3"
        >
          {previewCards.map((card, i) => (
            <motion.div
              key={i}
              initial={{ opacity: 0, y: 20 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{ duration: 0.5, delay: 0.2 + i * 0.08 }}
              className="relative rounded-xl overflow-hidden border border-border bg-card shadow-sm hover:shadow-md transition-shadow group"
            >
              {/* Gradient header */}
              <div className={`h-24 bg-gradient-to-br ${card.gradient} p-3 relative`}>
                {/* Mini bar chart sim */}
                <div className="absolute bottom-2 left-3 right-3 flex items-end gap-0.5 h-12">
                  {card.bars.map((h, j) => (
                    <div
                      key={j}
                      className="flex-1 bg-white/30 rounded-sm group-hover:bg-white/40 transition-colors"
                      style={{ height: `${h}%` }}
                    />
                  ))}
                </div>
              </div>
              {/* Label */}
              <div className="p-3">
                <p className="text-xs font-semibold text-foreground">{card.label}</p>
                <p className="text-xs text-muted-foreground mt-0.5">Live data</p>
              </div>
            </motion.div>
          ))}
        </motion.div>
      </div>
    </section>
  );
}
Claude Code Instructions

CLI Install

npx innovations add grid-preview

Where to use it

Place as the main hero section on your SaaS or product landing page. In Astro (src/pages/index.astro): import GridPreviewHero from '../components/innovations/heroes/grid-preview'; <GridPreviewHero client:load /> In Next.js (app/page.tsx): import GridPreviewHero from '@/components/innovations/heroes/grid-preview'; // Use as the first section in the page return The previewCards array at the top of the component controls the grid. Each card has a gradient, label, and bar chart data. Swap the gradient classes and labels to reflect your actual product modules or features.