72 lines
2.5 KiB
TypeScript
72 lines
2.5 KiB
TypeScript
import React from 'react';
|
|
|
|
interface IOPanelProps {
|
|
inputs: boolean[];
|
|
outputs: boolean[];
|
|
inputNames: string[];
|
|
outputNames: string[];
|
|
onToggleInput: (index: number) => void;
|
|
onToggleOutput: (index: number) => void;
|
|
}
|
|
|
|
export const IOPanel: React.FC<IOPanelProps> = ({
|
|
inputs,
|
|
outputs,
|
|
inputNames,
|
|
outputNames,
|
|
onToggleInput,
|
|
onToggleOutput
|
|
}) => {
|
|
const renderBits = (
|
|
bits: boolean[],
|
|
names: string[],
|
|
colorClass: string,
|
|
label: string,
|
|
onToggle: (i: number) => void
|
|
) => (
|
|
<div className="mb-6">
|
|
<h3 className="text-xs font-bold text-gray-400 mb-2 uppercase tracking-wider">{label}</h3>
|
|
<div className="grid grid-cols-4 gap-2">
|
|
{bits.map((isActive, i) => (
|
|
<div key={i} className="flex flex-col items-center group relative">
|
|
<button
|
|
onClick={() => onToggle(i)}
|
|
title={`${label} ${i}: ${names[i] || 'Unnamed'}`}
|
|
className={`w-7 h-7 rounded-md border border-gray-700 flex items-center justify-center text-[10px] font-mono transition-all duration-150 active:scale-90 ${
|
|
isActive
|
|
? `${colorClass} shadow-[0_0_10px_rgba(255,255,255,0.3)] border-transparent text-black font-bold`
|
|
: 'bg-gray-850 text-gray-500 hover:bg-gray-700'
|
|
}`}
|
|
>
|
|
{i}
|
|
</button>
|
|
{/* Tooltip on hover */}
|
|
<div className="absolute bottom-full mb-1 hidden group-hover:block z-50 bg-black text-white text-[9px] px-2 py-1 rounded border border-gray-700 whitespace-nowrap pointer-events-none">
|
|
{names[i] || `Port ${i}`}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="w-48 bg-gray-900 border-r border-gray-800 flex flex-col h-full p-4 z-10 shadow-xl select-none custom-scrollbar overflow-y-auto">
|
|
<h2 className="text-sm font-bold text-white mb-4 border-b border-gray-800 pb-2 flex items-center gap-2">
|
|
<div className="w-2 h-2 rounded-full bg-blue-500 animate-pulse" />
|
|
I/O Monitor
|
|
</h2>
|
|
|
|
{renderBits(inputs, inputNames, 'bg-green-500', 'Inputs', onToggleInput)}
|
|
<hr className="border-gray-800 my-4" />
|
|
{renderBits(outputs, outputNames, 'bg-red-500', 'Outputs', onToggleOutput)}
|
|
|
|
<div className="mt-auto pt-4 text-[9px] text-gray-600 border-t border-gray-800">
|
|
<p className="font-bold mb-1">Interactive Panel</p>
|
|
<p>• Click bits to toggle state</p>
|
|
<p>• Hover to see port names</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|