clupilot/app/resources/views/livewire/pages/auth/login.blade.php

267 lines
15 KiB
PHP

<?php
use App\Livewire\Forms\LoginForm;
use Illuminate\Support\Facades\Session;
use Livewire\Attributes\Layout;
use Livewire\Volt\Component;
new #[Layout('layouts.login')] class extends Component
{
public LoginForm $form;
public function login(): void
{
$this->validate();
$this->form->authenticate();
Session::regenerate();
$this->redirectIntended(default: route('dashboard', absolute: false), navigate: true);
}
}; ?>
<div class="clu-login-grid">
{{-- ===== LEFT: FORM ===== --}}
<section class="clu-form-side flex flex-col min-h-screen">
{{-- Top row --}}
<div class="flex items-center justify-between gap-4 flex-wrap gap-y-2">
<div class="flex items-center gap-[10px] shrink-0">
<div class="clu-brand-mark w-[30px] h-[30px] rounded-[8px]" aria-hidden="true"></div>
<div class="font-semibold text-[15px] tracking-[-0.01em]">
CluPilot<span class="text-t2 font-medium ml-[5px] text-[11.5px]">v2.4</span>
</div>
</div>
<span class="clu-login-status inline-flex items-center gap-[6px] px-[9px] py-1 border border-success/25 bg-success/12 text-success rounded-full text-[11px] font-medium font-mono">
<span class="clu-pulse-dot w-[6px] h-[6px] rounded-full bg-current"></span>
All systems operational
</span>
</div>
{{-- Form wrap --}}
<div class="my-auto flex flex-col gap-6 w-full py-6 sm:py-10 mx-auto" style="max-width:380px;">
<header>
<h1 class="m-0 text-[24px] font-semibold tracking-[-0.02em] leading-[1.2]">Willkommen zurück</h1>
<p class="mt-[6px] text-[13.5px] text-t2">
Bei CluPilot anmelden oder
@if(Route::has('register'))
<a href="{{ route('register') }}" wire:navigate class="text-akzent font-medium hover:underline">neues Konto erstellen</a>
@endif
</p>
</header>
{{-- SSO --}}
<div class="clu-sso-row">
<button class="clu-sso-btn" type="button">
<svg width="15" height="15" viewBox="0 0 24 24" aria-hidden="true">
<path fill="#4285F4" d="M22.5 12.27c0-.79-.07-1.54-.2-2.27H12v4.51h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.32z"/>
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.99.66-2.25 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84A11 11 0 0 0 12 23z"/>
<path fill="#FBBC05" d="M5.84 14.10A6.6 6.6 0 0 1 5.5 12c0-.73.13-1.44.34-2.10V7.06H2.18A11 11 0 0 0 1 12c0 1.77.42 3.45 1.18 4.94l3.66-2.84z"/>
<path fill="#EA4335" d="M12 5.38c1.62 0 3.07.56 4.21 1.64l3.15-3.15C17.45 2.10 14.96 1 12 1A11 11 0 0 0 2.18 7.06l3.66 2.84C6.71 7.30 9.14 5.38 12 5.38z"/>
</svg>
Google
</button>
<button class="clu-sso-btn" type="button">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.11.79-.25.79-.55v-2.02c-3.2.7-3.87-1.36-3.87-1.36-.52-1.33-1.27-1.68-1.27-1.68-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.18 1.76 1.18 1.02 1.75 2.69 1.24 3.35.95.1-.74.4-1.24.73-1.53-2.55-.29-5.24-1.28-5.24-5.69 0-1.26.45-2.28 1.18-3.09-.12-.29-.51-1.46.11-3.05 0 0 .97-.31 3.18 1.18.92-.26 1.91-.39 2.89-.39.98 0 1.97.13 2.89.39 2.20-1.49 3.17-1.18 3.17-1.18.63 1.59.23 2.76.12 3.05.74.81 1.18 1.83 1.18 3.09 0 4.42-2.69 5.40-5.25 5.68.41.36.78 1.06.78 2.14v3.18c0 .31.21.67.79.55C20.21 21.39 23.5 17.08 23.5 12c0-6.35-5.15-11.5-11.5-11.5z"/>
</svg>
GitHub
</button>
</div>
<div class="clu-divider">oder mit E-Mail</div>
{{-- Static dev hint --}}
<div class="flex items-start gap-[9px] px-[12px] py-[10px] rounded-[8px] border border-akzent/20 bg-akzent/8 text-[12px] text-t2">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-akzent flex-none mt-[1px]" aria-hidden="true">
<circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/>
</svg>
<span>Testinstanz &mdash; <span class="font-mono text-t1">admin@clupilot.test</span> / <span class="font-mono text-t1">clupilot</span></span>
</div>
{{-- Session status --}}
<x-auth-session-status :status="session('status')" />
{{-- Form --}}
<form wire:submit="login" class="flex flex-col gap-[14px]">
{{-- Email --}}
<div class="flex flex-col gap-[6px]">
<label for="email" class="text-[11.5px] text-t2 font-medium">E-Mail-Adresse</label>
<div class="clu-input">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-dim flex-none" aria-hidden="true">
<rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 6 9-6"/>
</svg>
<input wire:model="form.email" id="email" name="email" type="text"
placeholder="du@firma.de" autocomplete="email" autofocus />
</div>
<x-input-error :messages="$errors->get('form.email')" class="mt-1" />
</div>
{{-- Password --}}
<div class="flex flex-col gap-[6px]">
<label for="password" class="flex items-center justify-between text-[11.5px] text-t2 font-medium">
Passwort
@if(Route::has('password.request'))
<a href="{{ route('password.request') }}" wire:navigate
class="text-[11.5px] text-t2 font-medium no-underline transition-colors hover:text-t1">Vergessen?</a>
@endif
</label>
<div class="clu-input">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-dim flex-none" aria-hidden="true">
<rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/>
</svg>
<input wire:model="form.password" id="password" name="password" type="password"
placeholder="••••••••••••" autocomplete="current-password" />
<button type="button" id="toggle-eye" aria-label="Passwort anzeigen"
class="text-t2 p-[4px] rounded-[4px] grid place-items-center transition-colors hover:text-t1 hover:bg-surface2">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/>
</svg>
</button>
</div>
<x-input-error :messages="$errors->get('form.password')" class="mt-1" />
</div>
{{-- Remember (CSS peer toggle) --}}
<div class="flex items-center mt-[2px]">
<label class="flex items-center gap-2 text-[12.5px] text-t2 cursor-pointer select-none transition-colors hover:text-t1">
<input wire:model="form.remember" type="checkbox" class="peer sr-only" />
<span class="peer-checked:bg-akzent peer-checked:border-akzent flex-none w-[15px] h-[15px] rounded-[4px] border border-white/10 bg-surface grid place-items-center transition-all">
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"
class="opacity-0 scale-[.6] peer-checked:opacity-100 peer-checked:scale-100 transition-all duration-150">
<path d="M5 12l5 5L20 7"/>
</svg>
</span>
<span>30 Tage angemeldet bleiben</span>
</label>
</div>
{{-- Submit --}}
<button class="clu-btn-primary" type="submit" wire:loading.attr="disabled">
<svg wire:loading class="clu-spin" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true">
<path d="M21 12a9 9 0 1 1-6.2-8.55"/>
</svg>
<span wire:loading.remove>Anmelden</span>
<span wire:loading>Authentifiziere…</span>
<svg class="arrow" wire:loading.remove width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true">
<path d="M5 12h14M13 5l7 7-7 7"/>
</svg>
</button>
{{-- Alt options --}}
<div class="flex flex-col gap-2 mt-1">
<button class="clu-alt-btn" type="button">
<svg class="text-t2 flex-none" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M22 2L11 13"/><path d="M22 2l-7 20-4-9-9-4 20-7z"/>
</svg>
Magic-Link per E-Mail senden
</button>
<button class="clu-alt-btn" type="button">
<svg class="text-t2 flex-none" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M21 12c0-4.97-4.03-9-9-9-2.5 0-4.76 1.02-6.39 2.67M3 12c0 4.97 4.03 9 9 9 2.5 0 4.76-1.02 6.39-2.67"/>
<path d="M9 12a3 3 0 1 0 6 0 3 3 0 1 0-6 0M12 1v4M12 19v4"/>
</svg>
Mit Passkey anmelden
<span class="ml-auto font-mono text-[10px] text-akzent bg-akzent/12 px-[6px] py-[2px] rounded-[4px] border border-akzent/25 font-medium">empfohlen</span>
</button>
</div>
</form>
</div>
{{-- Footer --}}
<footer class="flex items-center justify-between gap-3 text-t2 text-[11.5px] font-mono pt-3 border-t border-white/6 flex-wrap">
<div class="flex items-center gap-[6px]">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true">
<rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/>
</svg>
TLS 1.3 · AES-256 · region eu-central-1
</div>
<div class="flex gap-[14px]">
<a href="#" class="text-t2 hover:text-t1 no-underline transition-colors">Datenschutz</a>
<a href="#" class="text-t2 hover:text-t1 no-underline transition-colors">AGB</a>
<a href="#" class="text-t2 hover:text-t1 no-underline transition-colors">Status</a>
<a href="#" class="text-t2 hover:text-t1 no-underline transition-colors">Hilfe</a>
</div>
</footer>
</section>
{{-- ===== RIGHT: LIVE PANEL ===== --}}
<aside class="clu-live-side relative border-l border-white/6 overflow-hidden flex flex-col gap-[18px] min-h-screen"
style="background:linear-gradient(180deg,#0c0c12 0%,#0a0a0f 100%);padding:32px 36px;"
aria-hidden="true">
<div class="relative flex items-center justify-between">
<div class="text-[11px] text-t2 font-mono uppercase tracking-[.10em]">— live cluster</div>
<div class="text-[11px] text-t2 font-mono">eu-central-1 · build #4f8a32c</div>
</div>
<div class="relative">
<p class="m-0 text-[22px] font-semibold tracking-[-0.015em] leading-[1.3]" style="max-width:480px;">
Verwalte <em class="not-italic text-akzent">87 WordPress-Sites</em> auf 6 Servern. Ein Login. Volle Kontrolle.
</p>
<p class="text-t2 text-[13px] mt-[6px]" style="max-width:460px;">
SSH-Tunnel, Backups, Updates und Security in einer Konsole — von Push-to-Deploy bis Brute-Force-Defense.
</p>
</div>
{{-- Stat strip --}}
<div class="relative grid grid-cols-3 gap-[10px] mt-[6px]">
<div class="bg-s2 border border-white/6 rounded-[9px] p-3">
<div class="text-[10.5px] text-t2 uppercase tracking-[.06em] font-medium">Sites Online</div>
<div class="font-mono text-[18px] font-semibold tracking-[-0.01em] mt-1">
87<span class="text-[12px] text-t2 font-medium ml-[2px]">/87</span>
</div>
<div class="flex items-center gap-1 font-mono text-[10.5px] text-success mt-1">● 100% Uptime · 24h</div>
</div>
<div class="bg-s2 border border-white/6 rounded-[9px] p-3">
<div class="text-[10.5px] text-t2 uppercase tracking-[.06em] font-medium">Ø Response</div>
<div class="font-mono text-[18px] font-semibold tracking-[-0.01em] mt-1">
142<span class="text-[12px] text-t2 font-medium ml-[2px]">ms</span>
</div>
<div class="flex items-center gap-1 font-mono text-[10.5px] text-success mt-1">↓ 8.4% vs. 7d</div>
</div>
<div class="bg-s2 border border-white/6 rounded-[9px] p-3">
<div class="text-[10.5px] text-t2 uppercase tracking-[.06em] font-medium">Blocked / 24h</div>
<div class="font-mono text-[18px] font-semibold tracking-[-0.01em] mt-1">128</div>
<div class="flex items-center gap-1 font-mono text-[10.5px] text-warning mt-1">↑ 23% Brute-force</div>
</div>
</div>
{{-- Terminal card --}}
<div class="relative bg-s2 border border-white/6 rounded-[10px] overflow-hidden flex-1 flex flex-col" style="min-height:280px;">
<div class="flex items-center gap-[10px] border-b border-white/6 bg-surface" style="padding:10px 14px;">
<div class="flex gap-[5px]">
<span class="w-[9px] h-[9px] rounded-full bg-danger"></span>
<span class="w-[9px] h-[9px] rounded-full bg-warning"></span>
<span class="w-[9px] h-[9px] rounded-full bg-success"></span>
</div>
<div class="font-mono text-[11.5px] text-t2 flex-1 text-center">ssh deploy@eu-prod-01</div>
<div class="font-mono text-[10.5px] text-dim">pts/0</div>
</div>
<div id="term-body" class="font-mono text-[11.5px] leading-[1.6] flex-1 overflow-hidden relative" style="padding:14px 16px;"></div>
</div>
{{-- Live tags --}}
<div class="relative flex flex-wrap gap-[6px]">
<span class="inline-flex items-center gap-[5px] px-[7px] py-[3px] text-[10.5px] font-mono text-t2 bg-surface border border-white/6 rounded-[4px]">
<span class="w-[5px] h-[5px] rounded-full bg-success"></span>eu-prod-01 · 23 sites
</span>
<span class="inline-flex items-center gap-[5px] px-[7px] py-[3px] text-[10.5px] font-mono text-t2 bg-surface border border-white/6 rounded-[4px]">
<span class="w-[5px] h-[5px] rounded-full bg-success"></span>eu-prod-02 · 19 sites
</span>
<span class="inline-flex items-center gap-[5px] px-[7px] py-[3px] text-[10.5px] font-mono text-t2 bg-surface border border-white/6 rounded-[4px]">
<span class="w-[5px] h-[5px] rounded-full bg-success"></span>edge-ams · 14 sites
</span>
<span class="inline-flex items-center gap-[5px] px-[7px] py-[3px] text-[10.5px] font-mono text-t2 bg-surface border border-white/6 rounded-[4px]">
<span class="w-[5px] h-[5px] rounded-full bg-warning"></span>us-east-01 · CPU 78%
</span>
<span class="inline-flex items-center gap-[5px] px-[7px] py-[3px] text-[10.5px] font-mono text-t2 bg-surface border border-white/6 rounded-[4px]">
<span class="w-[5px] h-[5px] rounded-full bg-success"></span>staging · 6 sites
</span>
</div>
</aside>
</div>