* feat: extract PanelCard from ChartCard for reusability - Create base PanelCard and PanelCardItem components in UI package - Refactor ChartCard to use PanelCard as foundation while keeping legend functionality - Add headerActions prop to PanelCard for extensibility - Maintain backward compatibility for existing ChartCard usage - Export PanelCard and PanelCardItem from UI card components Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * chore: update yarn.lock after dependency resolution Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: rename prop from actions to headerContent - Rename 'actions' prop to 'headerContent' in PanelCard component - Update ChartCard to use new 'headerContent' prop name - More accurate naming since content can be text or other elements, not just buttons Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * clean up * revert yarn.lock * fix type error * type fix --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import { Fragment, type ReactNode } from "react";
|
|
|
|
import classNames from "@calcom/ui/classNames";
|
|
import { PanelCard } from "@calcom/ui/components/card";
|
|
import { Tooltip } from "@calcom/ui/components/tooltip";
|
|
|
|
type LegendItem = {
|
|
label: string;
|
|
color: string; // hex format
|
|
};
|
|
|
|
export type LegendSize = "sm" | "default";
|
|
|
|
export function ChartCard({
|
|
title,
|
|
subtitle,
|
|
cta,
|
|
legend,
|
|
legendSize,
|
|
children,
|
|
}: {
|
|
title: string | ReactNode;
|
|
subtitle?: string;
|
|
cta?: { label: string; onClick: () => void };
|
|
legend?: Array<LegendItem>;
|
|
legendSize?: LegendSize;
|
|
children: ReactNode;
|
|
}) {
|
|
const legendComponent = legend && legend.length > 0 ? <Legend items={legend} size={legendSize} /> : null;
|
|
|
|
return (
|
|
<PanelCard title={title} subtitle={subtitle} cta={cta} headerContent={legendComponent}>
|
|
{children}
|
|
</PanelCard>
|
|
);
|
|
}
|
|
|
|
export function ChartCardItem({
|
|
count,
|
|
className,
|
|
children,
|
|
}: {
|
|
count?: number | string;
|
|
className?: string;
|
|
children: ReactNode;
|
|
}) {
|
|
return (
|
|
<div
|
|
className={classNames(
|
|
"text-default border-muted flex items-center justify-between border-b px-3 py-3.5 last:border-b-0",
|
|
className
|
|
)}>
|
|
<div className="text-sm font-medium">{children}</div>
|
|
{count !== undefined && <div className="text-sm font-medium">{count}</div>}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function Legend({ items, size = "default" }: { items: LegendItem[]; size?: LegendSize }) {
|
|
return (
|
|
<div className="bg-default flex items-center gap-2 rounded-lg px-1.5 py-1">
|
|
{items.map((item, index) => (
|
|
<Fragment key={item.label}>
|
|
<div
|
|
className="relative flex items-center gap-2 rounded-md px-1.5 py-0.5"
|
|
style={{ backgroundColor: `${item.color}33` }}>
|
|
<div className="h-2 w-2 rounded-full" style={{ backgroundColor: item.color }} />
|
|
<Tooltip content={item.label}>
|
|
<p
|
|
className={classNames(
|
|
"text-default truncate py-0.5 text-sm font-medium leading-none",
|
|
size === "sm" ? "w-16" : ""
|
|
)}>
|
|
{item.label}
|
|
</p>
|
|
</Tooltip>
|
|
</div>
|
|
{index < items.length - 1 && <div className="bg-muted h-5 w-[1px]" />}
|
|
</Fragment>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|