Components
Loading preview...
Here is Stats cards with links
@ephraimduncan
npx shadcn@latest add https://21st.dev/r/ephraimduncan/stats-cards-with-links"use client";
import * as React from "react";
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
interface CardProps extends React.ComponentProps<"div"> {}
function Card({ className, ...props }: CardProps) {
return (
<div
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
className
)}
{...props}
/>
);
}
Card.displayName = "Card";
interface CardHeaderProps extends React.ComponentProps<"div"> {}
function CardHeader({ className, ...props }: CardHeaderProps) {
return (
<div
data-slot="card-header"
className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className
)}
{...props}
/>
);
}
CardHeader.displayName = "CardHeader";
interface CardTitleProps extends React.ComponentProps<"div"> {}
function CardTitle({ className, ...props }: CardTitleProps) {
return (
<div
data-slot="card-title"
className={cn("leading-none font-semibold", className)}
{...props}
/>
);
}
CardTitle.displayName = "CardTitle";
interface CardDescriptionProps extends React.ComponentProps<"div"> {}
function CardDescription({ className, ...props }: CardDescriptionProps) {
return (
<div
data-slot="card-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
);
}
CardDescription.displayName = "CardDescription";
interface CardActionProps extends React.ComponentProps<"div"> {}
function CardAction({ className, ...props }: CardActionProps) {
return (
<div
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className
)}
{...props}
/>
);
}
CardAction.displayName = "CardAction";
interface CardContentProps extends React.ComponentProps<"div"> {}
function CardContent({ className, ...props }: CardContentProps) {
return (
<div data-slot="card-content" className={cn("px-6", className)} {...props} />
);
}
CardContent.displayName = "CardContent";
interface CardFooterProps extends React.ComponentProps<"div"> {}
function CardFooter({ className, ...props }: CardFooterProps) {
return (
<div
data-slot="card-footer"
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
{...props}
/>
);
}
CardFooter.displayName = "CardFooter";
const data = [
{
name: "Profit",
value: "$287,654.00",
change: "+8.32%",
changeType: "positive",
},
{
name: "Late payments",
value: "$9,435.00",
change: "-12.64%",
changeType: "negative",
},
{
name: "Pending orders",
value: "$173,229.00",
change: "+2.87%",
changeType: "positive",
},
{
name: "Operating costs",
value: "$52,891.00",
change: "-5.73%",
changeType: "negative",
},
];
export default function Stats01() {
return (
<div className="flex items-center justify-center p-10">
<div className="mx-auto grid grid-cols-1 gap-px rounded-xl bg-border sm:grid-cols-2 lg:grid-cols-4">
{data.map((stat, index) => (
<Card
key={stat.name}
className={cn(
"rounded-none border-0 shadow-none py-0",
index === 0 && "rounded-l-xl",
index === data.length - 1 && "rounded-r-xl"
)}
>
<CardContent className="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-2 p-4 sm:p-6">
<div className="text-sm font-medium text-muted-foreground">
{stat.name}
</div>
<div
className={cn(
"text-xs font-medium",
stat.changeType === "positive"
? "text-green-800 dark:text-green-400"
: "text-red-800 dark:text-red-400"
)}
>
{stat.change}
</div>
<div className="w-full flex-none text-3xl font-medium tracking-tight text-foreground">
{stat.value}
</div>
</CardContent>
</Card>
))}
</div>
</div>
);
}