v1.1.0: keyboard shortcuts (CH), onboarding tour, admin projects tab, remember-me login, Luftbild CH removed, hose settings in admin, credit link, font Barlow, map auto-save viewport, rate-limit 10/5min

This commit is contained in:
Pepe Ziberi
2026-02-24 19:49:42 +01:00
parent cb575f9a82
commit d893373bd9
16 changed files with 618 additions and 54 deletions

View File

@@ -39,6 +39,7 @@ import {
Shield,
Building2,
MapPin,
HelpCircle,
} from 'lucide-react'
import { HoseSettingsDialog } from '@/components/dialogs/hose-settings-dialog'
import type { Project, DrawFeature } from '@/app/app/page'
@@ -65,6 +66,7 @@ interface TopbarProps {
userName?: string
userRole?: string
onLogout?: () => void
onStartTour?: () => void
}
export function Topbar({
@@ -87,6 +89,7 @@ export function Topbar({
userName,
userRole,
onLogout,
onStartTour,
}: TopbarProps) {
const [isLoadDialogOpen, setIsLoadDialogOpen] = useState(false)
const [isHoseSettingsOpen, setIsHoseSettingsOpen] = useState(false)
@@ -159,6 +162,7 @@ export function Topbar({
<div className="flex items-center gap-1 md:gap-2">
<Button
data-tour="save"
variant="outline"
className="h-9 md:h-10 px-2 md:px-4 text-sm"
onClick={onSaveProject}
@@ -177,7 +181,7 @@ export function Topbar({
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-52">
<DropdownMenuItem onClick={onNewProject} className="py-2.5 px-3">
<DropdownMenuItem data-tour="new-project" onClick={onNewProject} className="py-2.5 px-3">
<Plus className="w-4 h-4 mr-2" />
Neuer Einsatz
</DropdownMenuItem>
@@ -294,6 +298,12 @@ export function Topbar({
Administration
</DropdownMenuItem>
)}
{onStartTour && (
<DropdownMenuItem onClick={onStartTour}>
<HelpCircle className="w-4 h-4 mr-2" />
Tour starten
</DropdownMenuItem>
)}
<DropdownMenuItem
onClick={() => { setShowDeleteAccountDialog(true); setDeleteAccountPw(''); setDeleteAccountError('') }}
className="text-destructive focus:text-destructive"
@@ -414,6 +424,9 @@ export function Topbar({
</p>
)}
<p className="text-xs text-muted-foreground mt-1">
{(p as any).owner?.name && (
<><span className="font-medium text-foreground/70">{(p as any).owner.name}</span> · </>
)}
Erstellt: {formatDateTime(p.createdAt)} | Geändert: {formatDateTime(p.updatedAt)}
</p>
</button>