55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
|
|
import { Card, CardContent, CardHeader } from "@repo/shadcn-ui/components/card";
|
||
|
|
import type { ReactNode } from "react";
|
||
|
|
import { useId } from "react";
|
||
|
|
|
||
|
|
/** Panel de consulta con jerarquía común; datos, textos y acciones pertenecen al consumidor. */
|
||
|
|
export function DetailPanel({
|
||
|
|
title,
|
||
|
|
description,
|
||
|
|
icon,
|
||
|
|
count,
|
||
|
|
actions,
|
||
|
|
children,
|
||
|
|
}: {
|
||
|
|
title: string;
|
||
|
|
description?: string;
|
||
|
|
icon: ReactNode;
|
||
|
|
count?: number | undefined;
|
||
|
|
actions?: ReactNode;
|
||
|
|
children: ReactNode;
|
||
|
|
}) {
|
||
|
|
const id = useId();
|
||
|
|
|
||
|
|
return (
|
||
|
|
<section aria-labelledby={id} className="min-w-0">
|
||
|
|
<Card className="@container min-w-0 shadow-none">
|
||
|
|
<CardHeader className="flex flex-wrap items-start justify-between gap-3">
|
||
|
|
<div className="min-w-0 space-y-1">
|
||
|
|
<h2
|
||
|
|
className="flex min-w-0 flex-wrap items-center gap-2 text-base font-semibold"
|
||
|
|
id={id}
|
||
|
|
>
|
||
|
|
<span aria-hidden="true" className="text-primary [&_svg]:size-5">
|
||
|
|
{icon}
|
||
|
|
</span>
|
||
|
|
{title}
|
||
|
|
{count !== undefined && (
|
||
|
|
<span className="rounded-md bg-muted px-2 py-0.5 text-xs font-medium tabular-nums text-muted-foreground">
|
||
|
|
{count}
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
</h2>
|
||
|
|
{description && (
|
||
|
|
<p className="max-w-prose text-sm leading-relaxed text-muted-foreground">
|
||
|
|
{description}
|
||
|
|
</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
{actions && <div className="flex shrink-0 flex-wrap gap-2">{actions}</div>}
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent className="space-y-5">{children}</CardContent>
|
||
|
|
</Card>
|
||
|
|
</section>
|
||
|
|
);
|
||
|
|
}
|