feat(ui): Vollbild/Präsentation im Header + Passwortfeld mit Auge & grösseren Punkten (v1.8.7)
- Topbar: Schnellzugriff-Buttons Vollbild und Präsentationsmodus direkt neben Speichern (Desktop; mobil weiterhin im ⋮-Menü) - Login: Passwortfeld mit Anzeigen/Verbergen-Umschalter (Auge) und grösseren, gespreizten Punkten (text-xl tracking) + sanfter Übergang Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lageplan",
|
"name": "lageplan",
|
||||||
"version": "1.8.6",
|
"version": "1.8.7",
|
||||||
"description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation",
|
"description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Button } from '@/components/ui/button'
|
|||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { Label } from '@/components/ui/label'
|
import { Label } from '@/components/ui/label'
|
||||||
import { useToast } from '@/components/ui/use-toast'
|
import { useToast } from '@/components/ui/use-toast'
|
||||||
import { ArrowLeft, Loader2 } from 'lucide-react'
|
import { ArrowLeft, Loader2, Eye, EyeOff } from 'lucide-react'
|
||||||
import { LogoRound } from '@/components/ui/logo'
|
import { LogoRound } from '@/components/ui/logo'
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
@@ -23,6 +23,7 @@ function LoginForm() {
|
|||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
const [password, setPassword] = useState('')
|
const [password, setPassword] = useState('')
|
||||||
const [rememberMe, setRememberMe] = useState(true)
|
const [rememberMe, setRememberMe] = useState(true)
|
||||||
|
const [showPassword, setShowPassword] = useState(false)
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [resendLoading, setResendLoading] = useState(false)
|
const [resendLoading, setResendLoading] = useState(false)
|
||||||
const [resendSuccess, setResendSuccess] = useState(false)
|
const [resendSuccess, setResendSuccess] = useState(false)
|
||||||
@@ -234,15 +235,27 @@ function LoginForm() {
|
|||||||
Passwort vergessen?
|
Passwort vergessen?
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="relative">
|
||||||
<Input
|
<Input
|
||||||
id="password"
|
id="password"
|
||||||
type="password"
|
type={showPassword ? 'text' : 'password'}
|
||||||
placeholder="••••••••"
|
placeholder="••••••••"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
required
|
required
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
|
className={`pr-11 transition-all duration-200 ${showPassword ? '' : 'text-xl tracking-[0.25em]'}`}
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowPassword(v => !v)}
|
||||||
|
tabIndex={-1}
|
||||||
|
aria-label={showPassword ? 'Passwort verbergen' : 'Passwort anzeigen'}
|
||||||
|
className="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 rounded-md text-gray-400 hover:text-gray-200 transition-colors"
|
||||||
|
>
|
||||||
|
{showPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label className="flex items-center gap-2 cursor-pointer select-none">
|
<label className="flex items-center gap-2 cursor-pointer select-none">
|
||||||
|
|||||||
@@ -248,6 +248,28 @@ export function Topbar({
|
|||||||
{isSaving ? <Loader2 className="w-5 h-5 animate-spin" /> : <Save className="w-5 h-5" />}
|
{isSaving ? <Loader2 className="w-5 h-5 animate-spin" /> : <Save className="w-5 h-5" />}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
{/* Schnellzugriff: Vollbild + Präsentationsmodus (Desktop; mobil im ⋮-Menü) */}
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="hidden md:flex h-10 w-10 shrink-0"
|
||||||
|
onClick={onToggleFullscreen}
|
||||||
|
title={isFullscreen ? 'Vollbild verlassen' : 'Vollbild'}
|
||||||
|
>
|
||||||
|
{isFullscreen ? <Minimize className="w-5 h-5" /> : <Maximize className="w-5 h-5" />}
|
||||||
|
</Button>
|
||||||
|
{onTogglePresentationLock && (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className={`hidden md:flex h-10 w-10 shrink-0 ${presentationLocked ? 'border-amber-500 text-amber-600 dark:text-amber-400' : ''}`}
|
||||||
|
onClick={onTogglePresentationLock}
|
||||||
|
title={presentationLocked ? 'Präsentation: gesperrt (zum Entsperren tippen)' : 'Präsentationsmodus'}
|
||||||
|
>
|
||||||
|
{presentationLocked ? <Lock className="w-5 h-5" /> : <Unlock className="w-5 h-5" />}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Freigeben — nur sichtbar, solange ich den Bearbeitungs-Lock halte.
|
{/* Freigeben — nur sichtbar, solange ich den Bearbeitungs-Lock halte.
|
||||||
Speichert und gibt die Karte für andere frei. Grün = ich bin am Zeichnen. */}
|
Speichert und gibt die Karte für andere frei. Grün = ich bin am Zeichnen. */}
|
||||||
{isEditingByMe && onStopEditing && (
|
{isEditingByMe && onStopEditing && (
|
||||||
|
|||||||
Reference in New Issue
Block a user