import { useState, useEffect, useRef } from 'react' import { FileText, Save, RefreshCw, AlertTriangle, Check, X, ChevronDown } from 'lucide-react' import { getZomboidConfigs, getZomboidConfig, saveZomboidConfig } from '../api' export default function ZomboidConfigEditor({ token }) { const [files, setFiles] = useState([]) const [selectedFile, setSelectedFile] = useState(null) const [content, setContent] = useState('') const [originalContent, setOriginalContent] = useState('') const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [error, setError] = useState(null) const [success, setSuccess] = useState(null) const [hasChanges, setHasChanges] = useState(false) const textareaRef = useRef(null) const highlightRef = useRef(null) // Load file list useEffect(() => { loadFiles() }, [token]) // Track changes useEffect(() => { setHasChanges(content !== originalContent) }, [content, originalContent]) // Sync scroll between textarea and highlight div const handleScroll = () => { if (highlightRef.current && textareaRef.current) { highlightRef.current.scrollTop = textareaRef.current.scrollTop highlightRef.current.scrollLeft = textareaRef.current.scrollLeft } } async function loadFiles() { setLoading(true) setError(null) try { const data = await getZomboidConfigs(token) setFiles(data.files || []) if (data.files?.length > 0 && !selectedFile) { loadFile(data.files[0].filename) } } catch (err) { setError('Fehler beim Laden der Config-Dateien: ' + err.message) } finally { setLoading(false) } } async function loadFile(filename) { setLoading(true) setError(null) setSuccess(null) try { const data = await getZomboidConfig(token, filename) setSelectedFile(filename) setContent(data.content) setOriginalContent(data.content) } catch (err) { setError('Fehler beim Laden: ' + err.message) } finally { setLoading(false) } } async function handleSave() { if (!selectedFile || !hasChanges) return setSaving(true) setError(null) setSuccess(null) try { await saveZomboidConfig(token, selectedFile, content) setOriginalContent(content) setSuccess('Config gespeichert! Server-Neustart erforderlich für Änderungen.') setTimeout(() => setSuccess(null), 5000) } catch (err) { setError('Fehler beim Speichern: ' + err.message) } finally { setSaving(false) } } function handleDiscard() { setContent(originalContent) setError(null) setSuccess(null) } function getFileDescription(filename) { const descriptions = { 'Project.ini': 'Server-Einstellungen (PVP, Spieler, Netzwerk)', 'Project_SandboxVars.lua': 'Gameplay-Einstellungen (Zombies, Loot, Schwierigkeit)', 'Project_spawnpoints.lua': 'Spawn-Punkte für neue Spieler', 'Project_spawnregions.lua': 'Spawn-Regionen Konfiguration' } return descriptions[filename] || filename } // Highlight syntax based on file type function highlightSyntax(text, filename) { if (!text) return '' const isLua = filename?.endsWith('.lua') const lines = text.split('\n') return lines.map((line, i) => { let highlighted = line .replace(/&/g, '&') .replace(//g, '>') if (isLua) { // Lua: -- comments if (line.trim().startsWith('--')) { highlighted = `${highlighted}` } else if (line.includes('--')) { const idx = line.indexOf('--') const code = highlighted.substring(0, idx) const comment = highlighted.substring(idx) highlighted = `${code}${comment}` } // Highlight true/false/nil highlighted = highlighted .replace(/\b(true|false|nil)\b/g, '$1') // Highlight numbers highlighted = highlighted .replace(/\b(\d+\.?\d*)\b/g, '$1') } else { // INI: # comments if (line.trim().startsWith('#')) { highlighted = `${highlighted}` } // Highlight key=value else if (line.includes('=')) { const idx = line.indexOf('=') const key = highlighted.substring(0, idx) const value = highlighted.substring(idx + 1) highlighted = `${key}=${value}` } } return highlighted }).join('\n') } if (loading && files.length === 0) { return (
Lade Config-Dateien...
) } return (
{/* File selector */}
{/* File description */} {selectedFile && (
{getFileDescription(selectedFile)}
)} {/* Error/Success messages */} {error && (
{error}
)} {success && (
{success}
)} {/* Editor with syntax highlighting */}
{/* Highlighted background layer */}