56 lines
2.2 KiB
TypeScript
56 lines
2.2 KiB
TypeScript
import React from 'react';
|
||
|
||
interface HeaderProps {
|
||
title: string;
|
||
onEdit: () => void;
|
||
onDelete: () => void;
|
||
}
|
||
|
||
export function Header({ title, onEdit, onDelete }: HeaderProps) {
|
||
return (
|
||
<div className="flex items-center justify-between px-3 py-1.5 border-b border-gray-700 shrink-0">
|
||
<span className="text-sm font-medium text-gray-200 truncate">{title}</span>
|
||
<div className="flex gap-1 ml-2 shrink-0">
|
||
<button onClick={onEdit} className="text-xs text-gray-400 hover:text-white px-1.5 py-0.5 rounded hover:bg-gray-700">✏️</button>
|
||
<button onClick={onDelete} className="text-xs text-gray-400 hover:text-red-400 px-1.5 py-0.5 rounded hover:bg-gray-700">🗑</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function EmptyState() {
|
||
return (
|
||
<div className="flex-1 flex items-center justify-center text-gray-500 text-sm">No data</div>
|
||
);
|
||
}
|
||
|
||
interface CardShellProps extends HeaderProps {
|
||
empty: boolean;
|
||
children: React.ReactNode;
|
||
/** Ref to the div where the uPlot legend will be mounted */
|
||
legendContainerRef?: React.RefObject<HTMLDivElement>;
|
||
}
|
||
|
||
export function CardShell({ title, onEdit, onDelete, empty, children, legendContainerRef }: CardShellProps) {
|
||
return (
|
||
<div className="h-full flex flex-col bg-gray-900 rounded border border-gray-700 overflow-hidden">
|
||
<Header title={title} onEdit={onEdit} onDelete={onDelete} />
|
||
{empty ? (
|
||
<EmptyState />
|
||
) : (
|
||
<>
|
||
{/* Plot fills remaining space */}
|
||
<div className="flex-1 min-h-0">
|
||
{children}
|
||
</div>
|
||
{/* Legend scrolls independently, capped at 25% card height */}
|
||
<div
|
||
ref={legendContainerRef}
|
||
className="shrink-0 max-h-[25%] overflow-y-auto border-t border-gray-800 px-2 py-1 text-[10px] text-gray-400 [&_.u-legend]:w-full [&_.u-series]:flex [&_.u-series]:items-center [&_.u-series_th]:flex [&_.u-series_th]:items-center [&_.u-series_th]:gap-1 [&_.u-marker]:w-3 [&_.u-marker]:h-0.5 [&_.u-marker]:shrink-0 [&_.u-label]:truncate [&_.u-value]:ml-auto [&_.u-value]:font-mono [&_.u-value]:shrink-0"
|
||
/>
|
||
<style>{'.u-legend .u-series:first-child { display: none; }'}</style>
|
||
</>
|
||
)}
|
||
</div>
|
||
);
|
||
} |