# Case Study Showcase

> A grid of case study cards with logos, results, and short summaries. Use it to present customer stories and proof on a results focused blog page.

A shadcn/ui block from the [@shadcn-ui-blocks](https://www.shadcn-ui-blocks.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcn-ui-blocks/marketing-blog-sections-case-study-showcase).

- Page, with a live preview: https://shadcn.exchange/r/shadcn-ui-blocks/marketing-blog-sections-case-study-showcase
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcn-ui-blocks/marketing-blog-sections-case-study-showcase-light-8345032b40be9dfb.png
- Registry item: https://www.shadcn-ui-blocks.com/r/marketing-blog-sections-case-study-showcase.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://www.shadcn-ui-blocks.com/r/marketing-blog-sections-case-study-showcase.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `class-variance-authority`, `lucide-react`, `radix-ui`

## Files

### `components/blocks/marketing/blog-sections/case-study-showcase.tsx`

```tsx
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import {
  Card,
  CardContent,
  CardFooter,
  CardHeader,
} from '@/components/ui/card';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import {
  BarChart2,
  Clock,
  Calendar,
  Quote,
  Building,
  Award,
  Share2,
  ArrowRight,
  Download,
} from 'lucide-react';
import {
  HoverCard,
  HoverCardContent,
  HoverCardTrigger,
} from '@/components/ui/hover-card';

// Types for our case study data
interface Metric {
  label: string;
  value: string;
  previous?: string;
  percentageChange?: number;
  isPositive?: boolean;
}

interface CaseStudyContent {
  challenge: string[];
  solution: string[];
  results: string[];
}

interface Testimonial {
  quote: string;
  author: string;
  position: string;
  company: string;
  avatarUrl?: string;
}

interface CaseStudy {
  id: string;
  title: string;
  subtitle: string;
  client: {
    name: string;
    industry: string;
    size: string;
    logoUrl: string;
  };
  publishDate: string;
  duration: string;
  coverImageUrl: string;
  projectType: string[];
  metrics: Metric[];
  content: CaseStudyContent;
  testimonial?: Testimonial;
  relatedCaseStudies?: { id: string; title: string }[];
  downloadUrl?: string;
}

// Sample data for a case study
const caseStudyData: CaseStudy = {
  id: 'ecommerce-platform-optimization',
  title: 'Boosting E-Commerce Conversion with Data-Driven UX Redesign',
  subtitle:
    'How OptimizeNow helped Retail Giant increase mobile conversions by 37%',
  client: {
    name: 'FashionHub',
    industry: 'Retail / Fashion',
    size: 'Mid Enterprise (500-1000 employees)',
    logoUrl:
      'https://images.unsplash.com/photo-1526948128573-703ee1aeb6fa?q=80&w=100&h=100&auto=format&fit=crop',
  },
  publishDate: 'March 14, 2023',
  duration: '3 months',
  coverImageUrl:
    'https://images.unsplash.com/photo-1600132806370-bf17e65e942f?q=80&w=2069&auto=format&fit=crop',
  projectType: ['UX Optimization', 'Mobile Conversion', 'A/B Testing'],
  metrics: [
    {
      label: 'Mobile Conversion Rate',
      value: '3.8%',
      previous: '2.3%',
      percentageChange: 37,
      isPositive: true,
    },
    {
      label: 'Cart Abandonment',
      value: '58%',
      previous: '72%',
      percentageChange: 19,
      isPositive: true,
    },
    {
      label: 'Average Order Value',
      value: '$78.50',
      previous: '$67.25',
      percentageChange: 16,
      isPositive: true,
    },
    {
      label: 'Page Load Speed',
      value: '1.2s',
      previous: '3.5s',
      percentageChange: 65,
      isPositive: true,
    },
  ],
  content: {
    challenge: [
      "FashionHub's mobile conversion rates were significantly lower than desktop, despite 68% of traffic coming from mobile devices.",
      'The checkout process had a 72% abandonment rate, much higher than industry average.',
      'Customer feedback indicated friction points in the product selection and payment processes.',
      'The site suffered from slow load times on mobile, especially on 3G connections in key markets.',
    ],
    solution: [
      'Conducted comprehensive user testing with 50 customers to identify specific pain points in the mobile journey.',
      'Implemented a streamlined checkout process, reducing steps from 5 to 3 without sacrificing data collection.',
      'Redesigned the product page layout with a focus on mobile-first interaction patterns.',
      'Optimized image loading and implemented progressive web app features to improve performance.',
      'Developed a robust A/B testing framework to validate all changes before full deployment.',
    ],
    results: [
      'Increased mobile conversion rate by 37%, exceeding the initial goal of 25%.',
      'Reduced cart abandonment rate from 72% to 58%, recovering an estimated $1.2M in monthly revenue.',
      'Improved average order value by 16% through strategic cross-sell implementation.',
      "Decreased page load time by 65%, bringing the site well within Google's recommended performance metrics.",
      'Achieved a 98% customer satisfaction score for the new mobile checkout experience.',
    ],
  },
  testimonial: {
    quote:
      'The OptimizeNow team went beyond simple UI tweaks to deliver a fundamental rethinking of our mobile experience. Their data-driven approach gave us confidence at every step, and the results speak for themselves.',
    author: 'Sarah Chen',
    position: 'Chief Digital Officer',
    company: 'FashionHub',
    avatarUrl:
      'https://images.unsplash.com/photo-1494790108377-be9c29b29330?q=80&w=100&h=100&auto=format&fit=crop',
  },
  relatedCaseStudies: [
    {
      id: 'omnichannel-retail-strategy',
      title: 'Omnichannel Retail Strategy for BoutiqueBrands',
    },
    {
      id: 'personalization-engine',
      title: 'AI-Powered Personalization Engine Implementation',
    },
  ],
  downloadUrl: '#',
};

export default function BlogSectionCaseStudyShowcase() {
  const {
    title,
    subtitle,
    client,
    publishDate,
    duration,
    coverImageUrl,
    projectType,
    metrics,
    content,
    testimonial,
    relatedCaseStudies,
    downloadUrl,
  } = caseStudyData;

  return (
    <section className="bg-background py-24">
      <div className="container mx-auto max-w-6xl px-4 md:px-6 2xl:max-w-[1400px]">
        {/* Header and Cover */}
        <div className="mb-12">
          <div className="mb-8 flex flex-col justify-between gap-8 lg:flex-row lg:items-center">
            <div className="space-y-4">
              <div className="flex items-center gap-2">
                <div className="relative h-8 w-8 overflow-hidden rounded">
                  <img
                    src={client.logoUrl}
                    alt={client.name}
                    className="object-cover"
                  />
                </div>
                <HoverCard>
                  <HoverCardTrigger asChild>
                    <Button
                      variant="link"
                      className="text-muted-foreground hover:text-foreground h-auto p-0"
                    >
                      {client.name}
                    </Button>
                  </HoverCardTrigger>
                  <HoverCardContent className="w-80">
                    <div className="flex justify-between space-x-4">
                      <div className="space-y-1">
                        <h4 className="text-sm font-semibold">{client.name}</h4>
                        <div className="text-muted-foreground flex items-center gap-2 text-xs">
                          <Building className="h-3.5 w-3.5" />
                          <span>{client.industry}</span>
                        </div>
                        <div className="text-muted-foreground text-xs">
                          Company Size: {client.size}
                        </div>
                      </div>
                      <div className="relative h-16 w-16 overflow-hidden rounded">
                        <img
                          src={client.logoUrl}
                          alt={client.name}
                          className="object-cover"
                        />
                      </div>
                    </div>
                  </HoverCardContent>
                </HoverCard>
              </div>
              <h1 className="text-4xl font-bold tracking-tight">{title}</h1>
              <p className="text-muted-foreground text-xl">{subtitle}</p>
              <div className="flex flex-wrap items-center gap-3 text-sm">
                <div className="text-muted-foreground flex items-center gap-1">
                  <Calendar className="h-4 w-4" />
                  <span>{publishDate}</span>
                </div>
                <div className="text-muted-foreground flex items-center gap-1">
                  <Clock className="h-4 w-4" />
                  <span>{duration}</span>
                </div>
              </div>
            </div>
            <div className="flex flex-col gap-3 sm:flex-row">
              {downloadUrl && (
                <Button variant="outline" size="sm" className="gap-2" asChild>
                  <a href={downloadUrl}>
                    <Download className="h-4 w-4" />
                    Download PDF
                  </a>
                </Button>
              )}
              <Button variant="outline" size="sm" className="gap-2">
                <Share2 className="h-4 w-4" />
                Share Case Study
              </Button>
            </div>
          </div>

          {/* Project Type Tags */}
          <div className="mb-8 flex flex-wrap gap-2">
            {projectType.map((type, index) => (
              <Badge key={index} variant="secondary">
                {type}
              </Badge>
            ))}
          </div>

          {/* Cover Image */}
          <div className="relative aspect-[21/9] w-full overflow-hidden rounded-lg">
            <img
              src={coverImageUrl}
              alt={title}
              className="object-cover"
            />
          </div>
        </div>

        {/* Key Metrics */}
        <div className="mb-16">
          <h2 className="mb-6 flex items-center gap-2 text-2xl font-bold">
            <BarChart2 className="text-primary h-5 w-5" />
            Key Results
          </h2>
          <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
            {metrics.map((metric, index) => (
              <Card key={index} className="bg-background border">
                <CardHeader className="pb-2">
                  <h3 className="text-muted-foreground text-sm font-medium">
                    {metric.label}
                  </h3>
                </CardHeader>
                <CardContent>
                  <div className="text-3xl font-bold">{metric.value}</div>
                  {metric.previous && metric.percentageChange && (
                    <div
                      className={`mt-1 flex items-center text-sm ${
                        metric.isPositive ? 'text-green-500' : 'text-red-500'
                      }`}
                    >
                      <span>
                        {metric.isPositive ? '+' : ''}
                        {metric.percentageChange}%
                      </span>
                      <span className="text-muted-foreground ml-2">
                        from {metric.previous}
                      </span>
                    </div>
                  )}
                </CardContent>
              </Card>
            ))}
          </div>
        </div>

        {/* Case Study Tabs */}
        <div className="mb-16">
          <Tabs defaultValue="challenge">
            <TabsList className="grid w-full grid-cols-3">
              <TabsTrigger value="challenge">Challenge</TabsTrigger>
              <TabsTrigger value="solution">Solution</TabsTrigger>
              <TabsTrigger value="results">Results</TabsTrigger>
            </TabsList>

            <TabsContent value="challenge" className="mt-6 space-y-4">
              {content.challenge.map((paragraph, i) => (
                <p key={i} className="text-muted-foreground">
                  {paragraph}
                </p>
              ))}
            </TabsContent>

            <TabsContent value="solution" className="mt-6 space-y-4">
              {content.solution.map((paragraph, i) => (
                <p key={i} className="text-muted-foreground">
                  {paragraph}
                </p>
              ))}
            </TabsContent>

            <TabsContent value="results" className="mt-6 space-y-4">
              {content.results.map((paragraph, i) => (
                <p key={i} className="text-muted-foreground">
                  {paragraph}
                </p>
              ))}
            </TabsContent>
          </Tabs>
        </div>

        {/* Testimonial */}
        {testimonial && (
          <div className="mb-16">
            <Card className="bg-muted/50">
              <CardContent className="pt-6">
                <div className="flex flex-col items-start gap-6 md:flex-row">
                  {testimonial.avatarUrl && (
                    <div className="border-background relative h-16 w-16 overflow-hidden rounded-full border-4">
                      <img
                        src={testimonial.avatarUrl}
                        alt={testimonial.author}
                        className="object-cover"
                      />
                    </div>
                  )}
                  <div className="space-y-4">
                    <div className="relative">
                      <Quote className="text-primary/20 absolute -top-4 -left-2 h-8 w-8" />
                      <p className="relative z-10 pl-7 text-lg italic">
                        &quot;{testimonial.quote}&quot;
                      </p>
                    </div>
                    <div>
                      <div className="font-semibold">{testimonial.author}</div>
                      <div className="text-muted-foreground text-sm">
                        {testimonial.position}, {testimonial.company}
                      </div>
                    </div>
                  </div>
                </div>
              </CardContent>
            </Card>
          </div>
        )}

        {/* Related Case Studies */}
        {relatedCaseStudies && relatedCaseStudies.length > 0 && (
          <div>
            <h2 className="mb-6 flex items-center gap-2 text-2xl font-bold">
              <Award className="text-primary h-5 w-5" />
              Related Case Studies
            </h2>
            <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
              {relatedCaseStudies.map((study, index) => (
                <Card
                  key={index}
                  className="group gap-3 transition-all hover:shadow-md"
                >
                  <CardContent className="">
                    <h3 className="group-hover:text-primary mb-2 text-xl font-medium transition-colors">
                      {study.title}
                    </h3>
                  </CardContent>
                  <CardFooter>
                    <Button
                      variant="ghost"
                      className="group-hover:text-primary gap-1 p-0"
                      asChild
                    >
                      <a href={`/case-studies/${study.id}`}>
                        View Case Study
                        <ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-1" />
                      </a>
                    </Button>
                  </CardFooter>
                </Card>
              ))}
            </div>
          </div>
        )}
      </div>
    </section>
  );
}
```

### `components/ui/button.tsx`

```tsx
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"

import { cn } from "@/lib/utils"

const buttonVariants = cva(
  "group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/80",
        outline:
          "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
        secondary:
          "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
        ghost:
          "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
        destructive:
          "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default:
          "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
        xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
        sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
        lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
        icon: "size-9",
        "icon-xs":
          "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
        "icon-sm":
          "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md",
        "icon-lg": "size-10",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

function Button({
  className,
  variant = "default",
  size = "default",
  asChild = false,
  ...props
}: React.ComponentProps<"button"> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean
  }) {
  const Comp = asChild ? Slot.Root : "button"

  return (
    <Comp
      data-slot="button"
      data-variant={variant}
      data-size={size}
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    />
  )
}

export { Button, buttonVariants }
```

### `components/ui/badge.tsx`

```tsx
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"

import { cn } from "@/lib/utils"

const badgeVariants = cva(
  "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
        secondary:
          "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
        destructive:
          "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
        outline:
          "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
        ghost:
          "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
        link: "text-primary underline-offset-4 hover:underline",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
)

function Badge({
  className,
  variant = "default",
  asChild = false,
  ...props
}: React.ComponentProps<"span"> &
  VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
  const Comp = asChild ? Slot.Root : "span"

  return (
    <Comp
      data-slot="badge"
      data-variant={variant}
      className={cn(badgeVariants({ variant }), className)}
      {...props}
    />
  )
}

export { Badge, badgeVariants }
```

### `components/ui/card.tsx`

```tsx
import * as React from "react"

import { cn } from "@/lib/utils"

function Card({
  className,
  size = "default",
  ...props
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
  return (
    <div
      data-slot="card"
      data-size={size}
      className={cn(
        "group/card flex flex-col gap-6 overflow-hidden rounded-xl bg-card py-6 text-sm text-card-foreground shadow-xs ring-1 ring-foreground/10 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
        className
      )}
      {...props}
    />
  )
}

function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-header"
      className={cn(
        "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-6 group-data-[size=sm]/card:px-4 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-6 group-data-[size=sm]/card:[.border-b]:pb-4",
        className
      )}
      {...props}
    />
  )
}

function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-title"
      className={cn(
        "font-heading text-base leading-normal font-medium group-data-[size=sm]/card:text-sm",
        className
      )}
      {...props}
    />
  )
}

function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-description"
      className={cn("text-sm text-muted-foreground", className)}
      {...props}
    />
  )
}

function CardAction({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-action"
      className={cn(
        "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
        className
      )}
      {...props}
    />
  )
}

function CardContent({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-content"
      className={cn("px-6 group-data-[size=sm]/card:px-4", className)}
      {...props}
    />
  )
}

function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-footer"
      className={cn(
        "flex items-center rounded-b-xl px-6 group-data-[size=sm]/card:px-4 [.border-t]:pt-6 group-data-[size=sm]/card:[.border-t]:pt-4",
        className
      )}
      {...props}
    />
  )
}

export {
  Card,
  CardHeader,
  CardFooter,
  CardTitle,
  CardAction,
  CardDescription,
  CardContent,
}
```

### `components/ui/tabs.tsx`

```tsx
"use client"

import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Tabs as TabsPrimitive } from "radix-ui"

import { cn } from "@/lib/utils"

function Tabs({
  className,
  orientation = "horizontal",
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
  return (
    <TabsPrimitive.Root
      data-slot="tabs"
      data-orientation={orientation}
      className={cn(
        "group/tabs flex gap-2 data-horizontal:flex-col",
        className
      )}
      {...props}
    />
  )
}

const tabsListVariants = cva(
  "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-9 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
  {
    variants: {
      variant: {
        default: "bg-muted",
        line: "gap-1 bg-transparent",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
)

function TabsList({
  className,
  variant = "default",
  ...props
}: React.ComponentProps<typeof TabsPrimitive.List> &
  VariantProps<typeof tabsListVariants>) {
  return (
    <TabsPrimitive.List
      data-slot="tabs-list"
      data-variant={variant}
      className={cn(tabsListVariants({ variant }), className)}
      {...props}
    />
  )
}

function TabsTrigger({
  className,
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
  return (
    <TabsPrimitive.Trigger
      data-slot="tabs-trigger"
      className={cn(
        "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
        "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
        "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
        "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
        className
      )}
      {...props}
    />
  )
}

function TabsContent({
  className,
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
  return (
    <TabsPrimitive.Content
      data-slot="tabs-content"
      className={cn("flex-1 text-sm outline-none", className)}
      {...props}
    />
  )
}

export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
```

### `components/ui/hover-card.tsx`

```tsx
"use client"

import * as React from "react"
import { HoverCard as HoverCardPrimitive } from "radix-ui"

import { cn } from "@/lib/utils"

function HoverCard({
  ...props
}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
  return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
}

function HoverCardTrigger({
  ...props
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
  return (
    <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
  )
}

function HoverCardContent({
  className,
  align = "center",
  sideOffset = 4,
  ...props
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
  return (
    <HoverCardPrimitive.Portal data-slot="hover-card-portal">
      <HoverCardPrimitive.Content
        data-slot="hover-card-content"
        align={align}
        sideOffset={sideOffset}
        className={cn(
          "z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-lg bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
          className
        )}
        {...props}
      />
    </HoverCardPrimitive.Portal>
  )
}

export { HoverCard, HoverCardTrigger, HoverCardContent }
```
