diff --git a/frontend/src/tools/kalkulator3d.jsx b/frontend/src/tools/kalkulator3d.jsx index ef38c6d..03b7544 100644 --- a/frontend/src/tools/kalkulator3d.jsx +++ b/frontend/src/tools/kalkulator3d.jsx @@ -48,8 +48,14 @@ function compressImage(file) { // ── Stepper ─────────────────────────────────────────────────────────────────── function Stepper({ label, value, onChange, step, unit, min = 0, hint }) { - const dec = () => onChange(Math.max(min, Math.round((value - step) * 10000) / 10000)); - const inc = () => onChange(Math.round((value + step) * 10000) / 10000); + const [raw, setRaw] = useState(String(value)); + + // Sync wenn value sich von außen ändert (z.B. beim Bearbeiten eines Archiv-Eintrags) + useEffect(() => { setRaw(String(value)); }, [value]); + + const dec = () => { const v = Math.max(min, Math.round((value - step) * 10000) / 10000); onChange(v); setRaw(String(v)); }; + const inc = () => { const v = Math.round((value + step) * 10000) / 10000; onChange(v); setRaw(String(v)); }; + return (
@@ -57,8 +63,18 @@ function Stepper({ label, value, onChange, step, unit, min = 0, hint }) {
- onChange(parseFloat(e.target.value) || 0)} + { + setRaw(e.target.value); + const parsed = parseFloat(e.target.value); + if (!isNaN(parsed)) onChange(Math.max(min, parsed)); + }} + onBlur={() => { + const parsed = parseFloat(raw); + const safe = isNaN(parsed) ? min : Math.max(min, parsed); + onChange(safe); setRaw(String(safe)); + }} style={{ flex:1, background:'transparent', border:'none', color:'#fff', fontSize:15, fontFamily:"'Space Mono',monospace", textAlign:'center', outline:'none', minWidth:0, padding:'10px 4px' }} /> @@ -69,11 +85,23 @@ function Stepper({ label, value, onChange, step, unit, min = 0, hint }) { } function SmallInput({ label, value, onChange, step = 0.01 }) { + const [raw, setRaw] = useState(String(value)); + useEffect(() => { setRaw(String(value)); }, [value]); return (
{label}
- onChange(parseFloat(e.target.value) || 0)} + { + setRaw(e.target.value); + const parsed = parseFloat(e.target.value); + if (!isNaN(parsed)) onChange(parsed); + }} + onBlur={() => { + const parsed = parseFloat(raw); + if (!isNaN(parsed)) { onChange(parsed); setRaw(String(parsed)); } + else setRaw(String(value)); + }} style={{ ...S.inp, padding:'7px 8px', fontSize:13 }} />
@@ -125,10 +153,12 @@ export default function Kalkulator3D({ toast, editData, onEditDone, mobile }) { const handleImagePick = async e => { const file = e.target.files?.[0]; if (!file) return; + if (!file.type.startsWith('image/')) { toast('Nur Bilddateien erlaubt (JPG, PNG, …)', 'error'); e.target.value = ''; return; } + if (file.size > 20 * 1024 * 1024) { toast(`Bild zu groß (${(file.size/1024/1024).toFixed(1)} MB) – max. 20 MB`, 'error'); e.target.value = ''; return; } try { const compressed = await compressImage(file); setImage(compressed); - } catch { toast('Bild konnte nicht geladen werden', 'error'); } + } catch { toast('Bild konnte nicht verarbeitet werden – ist die Datei beschädigt?', 'error'); } e.target.value = ''; };