import { useSessionSelector } from '../../context/SessionContext.jsx'; // Utilities function cx(...values) { return values.filter(Boolean).join(' '); } // Color helpers function hexToRgb(hex) { const raw = String(hex || '').trim(); const normalized = raw.startsWith('#') ? raw.slice(1) : raw; if (!/^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$/.test(normalized)) return null; const expanded = normalized.length === 3 ? normalized .split('') .map((ch) => ch + ch) .join('') : normalized; return { r: Number.parseInt(expanded.slice(0, 2), 16), g: Number.parseInt(expanded.slice(2, 4), 16), b: Number.parseInt(expanded.slice(4, 6), 16), }; } function rgba(rgb, alpha) { return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`; } // Component export default function CardFrame({ title = '', meta = null, actions = null, color = null, hideHeader = false, stickyHeader = false, className = '', headerClassName = '', bodyClassName = '', fillHeight = false, clipOverflow = true, children, }) { const showHeader = !hideHeader && (title || meta != null || actions); const greenMode = useSessionSelector((state) => Boolean(state.session?.greenMode)); const ownRoverColor = useSessionSelector((state) => { const roverId = String(state.session?.assignment?.roverId || '').trim(); if (!roverId) return null; const roster = Array.isArray(state.session?.roster) ? state.session.roster : []; const rover = roster.find((entry) => String(entry?.id) === roverId); return rover?.color || null; }); // Callers can supply a structural accent, while ordinary cards continue to // inherit the assigned rover's color without needing to know session state. const accentRgb = hexToRgb(color || ownRoverColor); const cardStyle = greenMode ? { borderColor: '#008a35' } : accentRgb ? { borderColor: rgba(accentRgb, 0.3) } : undefined; const headerStyle = greenMode ? { borderColor: '#008a35' } : accentRgb ? { // The header divider uses the same accent as the outside border. This // makes the color describe the complete CardFrame rather than looking // like an unrelated tint applied only behind its title. borderColor: rgba(accentRgb, 0.3), backgroundImage: `linear-gradient(90deg, ${rgba(accentRgb, 0.2)} 100%)`, } : undefined; return (
{showHeader ? ( // Header row
{title ? (

{title}

) : null} {meta != null ? {meta} : null}
{actions ?
{actions}
: null}
) : null}
{children}
); }