import { useRef, useState } from 'react'; import { Plus, Save, Trash2 } from 'lucide-react'; interface Pair { id: string; key: string; value: string; } function parse(text: string): Pair[] { let n = 0; return text.split('\n') .filter(line => { const t = line.trim(); return t && !t.startsWith('#'); }) .map(line => { const eq = line.indexOf('='); return eq < 0 ? { id: String(n++), key: line.trim(), value: '' } : { id: String(n++), key: line.slice(0, eq).trim(), value: line.slice(eq + 1).trim() }; }); } function serialize(pairs: Pair[]): string { return pairs.map(p => `${p.key}=${p.value}`).join('\n') + (pairs.length ? '\n' : ''); } interface ConfigEditorProps { text: string; onSave?: (text: string) => Promise; } export default function ConfigEditor({ text, onSave }: ConfigEditorProps) { const [pairs, setPairs] = useState(() => parse(text)); const [saving, setSaving] = useState(false); const counter = useRef(parse(text).length); const newId = () => String(counter.current++); const updateKey = (id: string, key: string) => setPairs(ps => ps.map(p => p.id === id ? { ...p, key } : p)); const updateValue = (id: string, value: string) => setPairs(ps => ps.map(p => p.id === id ? { ...p, value } : p)); const deleteRow = (id: string) => setPairs(ps => ps.filter(p => p.id !== id)); const addRow = () => setPairs(ps => [...ps, { id: newId(), key: '', value: '' }]); const handleSave = async () => { if (!onSave) return; setSaving(true); try { await onSave(serialize(pairs)); } finally { setSaving(false); } }; return (
{onSave && ( )}
{pairs.length === 0 && (
No entries — click Add to create one
)}
{pairs.map(pair => (
updateKey(pair.id, e.target.value)} placeholder="name" className="w-36 flex-shrink-0 px-2 py-1.5 bg-neutral-800 border border-neutral-600 rounded text-sm text-neutral-200 placeholder:text-neutral-600 focus:outline-none focus:border-blue-500" /> = updateValue(pair.id, e.target.value)} placeholder="value" className="flex-1 min-w-0 px-2 py-1.5 bg-neutral-800 border border-neutral-600 rounded text-sm text-neutral-200 placeholder:text-neutral-600 focus:outline-none focus:border-blue-500" />
))}
); }