135 lines
4.2 KiB
TypeScript
135 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { Building2 } from "lucide-react";
|
|
import { Card, Badge, Button } from "../../";
|
|
import { HeaderProps } from "./type";
|
|
|
|
function Avatar({
|
|
avatar,
|
|
initials,
|
|
icon,
|
|
}: Pick<HeaderProps, "avatar" | "initials" | "icon">) {
|
|
if (avatar) return <>{avatar}</>;
|
|
|
|
if (initials) {
|
|
return (
|
|
<div className="flex h-14 w-14 shrink-0 items-center justify-center rounded-xl bg-accent text-lg font-bold uppercase text-accent-foreground">
|
|
{initials}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-14 w-14 shrink-0 items-center justify-center rounded-xl bg-accent">
|
|
{icon ?? <Building2 className="h-7 w-7" />}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function HeaderDetails({
|
|
title,
|
|
subtitle,
|
|
subtitleIcon,
|
|
avatar,
|
|
initials,
|
|
icon,
|
|
badges,
|
|
actions,
|
|
actionsSlot,
|
|
meta,
|
|
accent = true,
|
|
className = "",
|
|
}: HeaderProps) {
|
|
const hasActions = actionsSlot || (actions && actions.length > 0);
|
|
const hasMeta = meta && meta.length > 0;
|
|
|
|
return (
|
|
<Card className={`relative overflow-hidden p-0 ${className}`}>
|
|
{accent && (
|
|
<div className="h-1 w-full bg-accent" />
|
|
)}
|
|
|
|
<div className="p-5 sm:p-6">
|
|
{/* Top row: identity + actions */}
|
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
<div className="flex items-center gap-4">
|
|
<Avatar avatar={avatar} initials={initials} icon={icon} />
|
|
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex flex-wrap items-center gap-2.5">
|
|
<h1 className="text-xl sm:text-2xl font-bold leading-tight">
|
|
{title}
|
|
</h1>
|
|
{/* {badges?.map((badge, i) => (
|
|
<Badge
|
|
key={i}
|
|
variant={badge.variant ?? "default"}
|
|
className={`rounded-full text-xs font-medium ${badge.className ?? ""}`}
|
|
>
|
|
{badge.icon && (
|
|
<span className="mr-1.5 flex items-center">
|
|
{badge.icon}
|
|
</span>
|
|
)}
|
|
{badge.label}
|
|
</Badge>
|
|
))} */}
|
|
</div>
|
|
|
|
{subtitle && (
|
|
<p className="flex items-center gap-1.5 text-sm text-muted-foreground">
|
|
<span className="flex items-center">
|
|
{subtitleIcon ?? <Building2 className="h-4 w-4" />}
|
|
</span>
|
|
{subtitle}
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{hasActions && (
|
|
<div className="flex items-center justify-end gap-2 shrink-0">
|
|
{actionsSlot}
|
|
{actions?.map((action, i) => (
|
|
<Button
|
|
key={i}
|
|
variant={action.variant ?? "default"}
|
|
onClick={action.onClick}
|
|
disabled={action.disabled}
|
|
>
|
|
{action.icon && (
|
|
<span className="flex items-center">{action.icon}</span>
|
|
)}
|
|
{action.label}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Lower meta section: Owner / Industry / Deal Value / Created, etc. */}
|
|
{hasMeta && (
|
|
<div className="mt-5 border-t pt-4">
|
|
<div className="flex flex-wrap gap-x-12 gap-y-4">
|
|
{meta!.map((item, i) => (
|
|
<div key={i} className="flex items-center gap-3">
|
|
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground">
|
|
{item.icon}
|
|
</div>
|
|
<div className="flex flex-col">
|
|
<span className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
|
{item.label}
|
|
</span>
|
|
<span className="text-sm font-semibold">{item.value}</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|