44 lines · 1.7 KB
import { LayerCard } from "@cloudflare/kumo/components/layer-card";
import { cn } from "~/utils/cn";

const PADDING = { none: "", sm: "p-3", md: "p-4", lg: "p-5", xl: "p-8" } as const;

/** Card surface shared by `Panel` and ad-hoc containers (popovers, link cards). */
export function panelClass(className?: string): string {
  return cn("rounded-lg bg-kumo-base shadow-xs ring ring-kumo-line", className);
}

type Props = {
  /** `danger` frames destructive settings (danger zone, transfers, renames). */
  tone?: "neutral" | "danger";
  title?: React.ReactNode;
  actions?: React.ReactNode;
  /** Inner padding. With a header, it pads the body below the header rather than the whole panel. */
  padding?: keyof typeof PADDING;
  children: React.ReactNode;
  className?: string;
};

export function Panel({ tone = "neutral", title, actions, padding = "none", children, className }: Props) {
  const hasHeader = Boolean(title || actions);
  const dangerRing = tone === "danger" && "ring-kumo-danger/40";
  if (!hasHeader) {
    return (
      <LayerCard render={<section />} className={cn(dangerRing, PADDING[padding], className)}>
        {children}
      </LayerCard>
    );
  }
  return (
    <LayerCard render={<section />} className={cn(dangerRing, className)}>
      <LayerCard.Secondary className="my-0 justify-between gap-3 px-4 py-2.5 text-sm">
        <header className={cn("min-w-0 font-medium", tone === "danger" ? "text-kumo-danger" : "text-kumo-default")}>
          {title}
        </header>
        {actions && <div className="flex shrink-0 items-center gap-2">{actions}</div>}
      </LayerCard.Secondary>
      <LayerCard.Primary className={cn("block gap-0 p-0 pr-0", PADDING[padding])}>{children}</LayerCard.Primary>