1"use client";
2
3
10import type { ReactNode } from "react";
11import { cn } from "@/lib/utils";
12
13export interface BlockCardProps {
14 icon?: ReactNode;
15 title: string;
16 meta?: string;
17 description?: string;
18 href?: string;
19 onClick?: () => void;
20
21 variant?: "link" | "action";
22 className?: string;
23 children?: ReactNode;
24}
25
26export function BlockCard({
27 icon,
28 title,
29 meta,
30 description,
31 href,
32 onClick,
33 variant = "action",
34 className,
35 children
36}: BlockCardProps) {
37 const body = (
38 <>
39 {icon ? (
40 <span
41 className={cn(
42 "flex size-9 shrink-0 items-center justify-center rounded-md",
43 variant === "link" ? "bg-muted" : "bg-primary/10"
44 )}
45 aria-hidden
46 >
47 {icon}
48 </span>
49 ) : null}
50 <span className="min-w-0 flex-1">
51 <span className="block truncate text-sm font-medium">{title}</span>
52 {meta ? <span className="block truncate text-xs text-muted-foreground">{meta}</span> : null}
53 {description ? (
54 <span className="mt-0.5 line-clamp-2 block text-xs text-muted-foreground/80">{description}</span>
55 ) : null}
56 </span>
57 {children}
58 </>
59 );
60
61 const classes = cn(
62 "group/card flex w-full gap-3 rounded-md border border-border p-3 text-left transition-colors",
63 variant === "link" ? "bg-card hover:bg-accent/50" : "bg-card hover:border-ring/60",
64 className
65 );
66
67 if (href) {
68 const external = href.startsWith("http");
69 return (
70 <a
71 href={href}
72 className={classes}
73 {...(external ? { target: "_blank", rel: "noopener noreferrer" } : {})}
74 >
75 {body}
76 </a>
77 );
78 }
79
80 return (
81 <button type="button" onClick={onClick} className={cn(classes, "text-left disabled:opacity-50")}>
82 {body}
83 </button>
84 );
85}
86