158 lines
5.8 KiB
TypeScript
158 lines
5.8 KiB
TypeScript
import { useState } from 'react';
|
|
import { Settings, Check, X } from 'lucide-react';
|
|
|
|
interface IndicatorConfig {
|
|
id: string;
|
|
name: string;
|
|
enabled: boolean;
|
|
color: string;
|
|
params: Record<string, number>;
|
|
}
|
|
|
|
interface IndicatorPanelProps {
|
|
indicators: IndicatorConfig[];
|
|
onChange: (indicators: IndicatorConfig[]) => void;
|
|
}
|
|
|
|
export default function IndicatorPanel({ indicators, onChange }: IndicatorPanelProps) {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
const toggleIndicator = (id: string) => {
|
|
const updated = indicators.map((ind) =>
|
|
ind.id === id ? { ...ind, enabled: !ind.enabled } : ind
|
|
);
|
|
onChange(updated);
|
|
};
|
|
|
|
const updateParam = (id: string, param: string, value: number) => {
|
|
// Validate input
|
|
if (isNaN(value) || value <= 0) {
|
|
return; // Don't update with invalid values
|
|
}
|
|
|
|
const updated = indicators.map((ind) =>
|
|
ind.id === id ? { ...ind, params: { ...ind.params, [param]: value } } : ind
|
|
);
|
|
onChange(updated);
|
|
};
|
|
|
|
return (
|
|
<div className="relative">
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="flex items-center gap-2 px-3 py-2 bg-dark-surface rounded-md hover:bg-dark-hover transition-colors"
|
|
>
|
|
<Settings className="w-4 h-4" />
|
|
<span className="text-sm">Indicators</span>
|
|
<span className="text-xs bg-blue-600 px-2 py-0.5 rounded-full">
|
|
{indicators.filter((i) => i.enabled).length}
|
|
</span>
|
|
</button>
|
|
|
|
{isOpen && (
|
|
<>
|
|
{/* Backdrop */}
|
|
<div
|
|
className="fixed inset-0 z-40"
|
|
onClick={() => setIsOpen(false)}
|
|
/>
|
|
|
|
{/* Panel */}
|
|
<div className="absolute top-full mt-2 right-0 w-80 bg-dark-surface border border-dark-border rounded-lg shadow-xl z-50">
|
|
<div className="p-4">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h3 className="font-semibold">Technical Indicators</h3>
|
|
<button
|
|
onClick={() => setIsOpen(false)}
|
|
className="p-1 hover:bg-dark-hover rounded"
|
|
>
|
|
<X className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="space-y-3 max-h-96 overflow-y-auto">
|
|
{indicators.map((indicator) => (
|
|
<div
|
|
key={indicator.id}
|
|
className="p-3 bg-dark-bg rounded-lg border border-dark-border"
|
|
>
|
|
<div className="flex items-center justify-between mb-2">
|
|
<div className="flex items-center gap-2">
|
|
<div
|
|
className="w-3 h-3 rounded-full"
|
|
style={{ backgroundColor: indicator.color }}
|
|
/>
|
|
<span className="font-medium text-sm">{indicator.name}</span>
|
|
</div>
|
|
<button
|
|
onClick={() => toggleIndicator(indicator.id)}
|
|
className={`
|
|
p-1 rounded transition-colors
|
|
${
|
|
indicator.enabled
|
|
? 'bg-green-600 text-white'
|
|
: 'bg-gray-700 text-gray-400'
|
|
}
|
|
`}
|
|
>
|
|
{indicator.enabled ? (
|
|
<Check className="w-4 h-4" />
|
|
) : (
|
|
<X className="w-4 h-4" />
|
|
)}
|
|
</button>
|
|
</div>
|
|
|
|
{indicator.enabled && Object.keys(indicator.params).length > 0 && (
|
|
<div className="space-y-2 mt-3 pt-3 border-t border-dark-border">
|
|
{Object.entries(indicator.params).map(([param, value]) => (
|
|
<div key={param}>
|
|
<label className="block text-xs text-gray-400 mb-1">
|
|
{param.charAt(0).toUpperCase() + param.slice(1)}
|
|
</label>
|
|
<input
|
|
type="number"
|
|
value={value}
|
|
onChange={(e) =>
|
|
updateParam(indicator.id, param, Number(e.target.value))
|
|
}
|
|
min="1"
|
|
step="1"
|
|
className="w-full px-2 py-1 text-sm bg-dark-bg border border-dark-border rounded focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-4 pt-4 border-t border-dark-border">
|
|
<button
|
|
onClick={() => {
|
|
const allEnabled = indicators.map((ind) => ({ ...ind, enabled: true }));
|
|
onChange(allEnabled);
|
|
}}
|
|
className="w-full px-3 py-2 bg-blue-600 hover:bg-blue-700 rounded text-sm font-medium transition-colors"
|
|
>
|
|
Enable All
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
const allDisabled = indicators.map((ind) => ({ ...ind, enabled: false }));
|
|
onChange(allDisabled);
|
|
}}
|
|
className="w-full mt-2 px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded text-sm font-medium transition-colors"
|
|
>
|
|
Disable All
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|