diff --git a/ROADMAP.md b/ROADMAP.md index 4c6cef8..31ab16a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -76,7 +76,11 @@ Legende Aufwand: 🟢 klein · 🟡 mittel · 🔴 gross ## Phase 5 – Kür -- [ ] **5.1 – Linien-Typ-Abfrage** 🟡 (Rettungsachse / Leitung / normal) +- [x] **5.1 – Linien-Typ-Abfrage** 🟡 ✅ + - Beim Zeichnen einer Linie/eines Pfeils fragt der Dialog nun den Typ ab: + **Normal** (gewählte Farbe), **Leitung** (blau, dicker), **Rettungsachse** (grün, + gestrichelt – als freizuhaltende Achse klar erkennbar). + - Typ in `properties.lineType`; eigener MapLibre-Layer mit Dash-Muster für Rettungsachse. --- diff --git a/package.json b/package.json index 3fe06c4..eb12f26 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lageplan", - "version": "1.4.12", + "version": "1.4.13", "description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation", "private": true, "scripts": { diff --git a/src/app/app/page.tsx b/src/app/app/page.tsx index 04ca8f0..b186624 100644 --- a/src/app/app/page.tsx +++ b/src/app/app/page.tsx @@ -13,7 +13,7 @@ import { RightSidebar } from '@/components/layout/right-sidebar' import { ProjectDialog } from '@/components/dialogs/project-dialog' import { ExerciseCockpit } from '@/components/exercise/exercise-cockpit' import { TextDialog } from '@/components/dialogs/text-dialog' -import { LineLabelDialog } from '@/components/dialogs/line-label-dialog' +import { LineLabelDialog, LINE_KINDS, type LineKind } from '@/components/dialogs/line-label-dialog' import { useToast } from '@/components/ui/use-toast' import { useAuth } from '@/components/providers/auth-provider' import { Button } from '@/components/ui/button' @@ -668,22 +668,38 @@ export default function AppPage() { broadcastFeatures(newFeatures) }, [addAudit, broadcastFeatures]) - const handleLineLabelConfirm = useCallback((label: string) => { - if (pendingLineFeature && label) { - setFeatures(prev => prev.map(f => - f.id === pendingLineFeature.id - ? { ...f, properties: { ...f.properties, label } } - : f - )) + // Wendet den gewählten Linientyp an: setzt properties.lineType und – bei Leitung/ + // Rettungsachse – die konventionelle Farbe/Stärke (Normal behält die Zeichenfarbe). + const applyLineKind = useCallback((f: DrawFeature, kind: LineKind, label: string): DrawFeature => { + const def = LINE_KINDS.find(k => k.value === kind) + const properties: Record = { ...f.properties, lineType: kind } + if (def && kind !== 'normal') { + properties.color = def.color + properties.width = def.width + } + if (label) properties.label = label + return { ...f, properties } + }, []) + + const finalizeLineFeature = useCallback((kind: LineKind, label: string) => { + if (pendingLineFeature) { + const next = featuresRef.current.map(f => + f.id === pendingLineFeature.id ? applyLineKind(f, kind, label) : f + ) + setFeatures(next) + broadcastFeatures(next) } setPendingLineFeature(null) setIsLineLabelDialogOpen(false) - }, [pendingLineFeature]) + }, [pendingLineFeature, applyLineKind, broadcastFeatures]) - const handleLineLabelSkip = useCallback(() => { - setPendingLineFeature(null) - setIsLineLabelDialogOpen(false) - }, []) + const handleLineLabelConfirm = useCallback((label: string, kind: LineKind) => { + finalizeLineFeature(kind, label) + }, [finalizeLineFeature]) + + const handleLineLabelSkip = useCallback((kind: LineKind) => { + finalizeLineFeature(kind, '') + }, [finalizeLineFeature]) const handleSymbolDrop = useCallback((iconId: string, coordinates: [number, number], imageUrl?: string) => { const currentZoom = mapRef.current?.getZoom() || 17 diff --git a/src/components/dialogs/line-label-dialog.tsx b/src/components/dialogs/line-label-dialog.tsx index 9b5e1fc..5570175 100644 --- a/src/components/dialogs/line-label-dialog.tsx +++ b/src/components/dialogs/line-label-dialog.tsx @@ -4,6 +4,7 @@ import { useState, useEffect } from 'react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' +import { cn } from '@/lib/utils' import { Dialog, DialogContent, @@ -12,28 +13,44 @@ import { DialogFooter, } from '@/components/ui/dialog' +export type LineKind = 'normal' | 'leitung' | 'rettungsachse' + +// Zentrale Definition der Linientypen — Farbe/Stärke werden beim Zeichnen übernommen. +export const LINE_KINDS: { value: LineKind; label: string; color: string; width: number; dashed: boolean; hint: string }[] = [ + { value: 'normal', label: 'Normal', color: '', width: 0, dashed: false, hint: 'Freie Linie in gewählter Farbe' }, + { value: 'leitung', label: 'Leitung', color: '#2563eb', width: 4, dashed: false, hint: 'Schlauchleitung (blau)' }, + { value: 'rettungsachse', label: 'Rettungsachse', color: '#16a34a', width: 6, dashed: true, hint: 'Freihalten — Rettungs-/Zufahrtsachse (grün, gestrichelt)' }, +] + interface LineLabelDialogProps { open: boolean onOpenChange: (open: boolean) => void - onConfirm: (label: string) => void - onSkip: () => void - lineType: 'linestring' | 'arrow' | 'polygon' + onConfirm: (label: string, kind: LineKind) => void + onSkip: (kind: LineKind) => void + lineType: 'linestring' | 'arrow' | 'polygon' | 'dangerzone' } export function LineLabelDialog({ open, onOpenChange, onConfirm, onSkip, lineType }: LineLabelDialogProps) { const [label, setLabel] = useState('') + const [kind, setKind] = useState('normal') + + // Linientyp-Auswahl nur für echte Linien/Pfeile (nicht für Flächen/Gefahrenzonen) + const showKindSelector = lineType === 'linestring' || lineType === 'arrow' useEffect(() => { - if (open) setLabel('') + if (open) { + setLabel('') + setKind('normal') + } }, [open]) const handleConfirm = () => { - onConfirm(label.trim()) + onConfirm(label.trim(), kind) setLabel('') } const handleSkip = () => { - onSkip() + onSkip(kind) setLabel('') } @@ -47,8 +64,10 @@ export function LineLabelDialog({ open, onOpenChange, onConfirm, onSkip, lineTyp } } - const title = lineType === 'polygon' ? 'Fläche beschriften' : 'Leitung beschriften' - const placeholder = lineType === 'polygon' + const title = lineType === 'polygon' || lineType === 'dangerzone' + ? 'Fläche beschriften' + : showKindSelector ? 'Linie festlegen' : 'Leitung beschriften' + const placeholder = lineType === 'polygon' || lineType === 'dangerzone' ? 'z.B. Brandzone, Sperrgebiet...' : 'z.B. 1, L2, Zuleitung...' @@ -58,7 +77,41 @@ export function LineLabelDialog({ open, onOpenChange, onConfirm, onSkip, lineTyp {title} -
+
+ {showKindSelector && ( +
+ +
+ {LINE_KINDS.map((k) => ( + + ))} +
+

{LINE_KINDS.find(k => k.value === kind)?.hint}

+
+ )} +
setLabel(e.target.value)} onKeyDown={handleKeyDown} placeholder={placeholder} - autoFocus + autoFocus={!showKindSelector} /> +

+ Wird am Mittelpunkt auf der Karte angezeigt. Leer lassen für keine Beschriftung. +

-

- Wird am Mittelpunkt der Leitung auf der Karte angezeigt. Leer lassen für keine Beschriftung. -