Feat: Einstellungen mit URL-Tabs (Allgemein, Domains & SSL, Backup, Benachrichtigungen)

main v1.1.411
boban 2026-04-27 03:35:59 +02:00
parent 1f013b6dcd
commit ff6002ca0b
2 changed files with 247 additions and 240 deletions

View File

@ -7,12 +7,16 @@ use App\Models\Setting;
use Illuminate\Support\Facades\Artisan;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
#[Layout('layouts.dvx')]
#[Title('Einstellungen · Mailwolt')]
class SettingsForm extends Component
{
#[Url]
public string $tab = 'allgemein';
// Allgemein
public string $instance_name = '';
public string $locale = 'de';

View File

@ -12,33 +12,56 @@
Einstellungen
</div>
<div class="mbx-page-actions">
<button wire:click="save" class="mbx-btn-primary">
<svg width="12" height="12" viewBox="0 0 14 14" fill="none"><path d="M2 2h8l2 2v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z" stroke="currentColor" stroke-width="1.2"/><path d="M5 2v3h4V2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
<span wire:loading.remove wire:target="save">Speichern</span>
<span wire:loading wire:target="save">Speichert…</span>
</button>
@if($tab === 'domains')
<button wire:click="saveDomains" class="mbx-btn-primary">
<svg width="12" height="12" viewBox="0 0 14 14" fill="none"><path d="M2 2h8l2 2v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z" stroke="currentColor" stroke-width="1.2"/><path d="M5 2v3h4V2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
<span wire:loading.remove wire:target="saveDomains">Domains speichern</span>
<span wire:loading wire:target="saveDomains">Speichert…</span>
</button>
@else
<button wire:click="save" class="mbx-btn-primary">
<svg width="12" height="12" viewBox="0 0 14 14" fill="none"><path d="M2 2h8l2 2v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z" stroke="currentColor" stroke-width="1.2"/><path d="M5 2v3h4V2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
<span wire:loading.remove wire:target="save">Speichern</span>
<span wire:loading wire:target="save">Speichert…</span>
</button>
@endif
</div>
</div>
<div class="sec-layout">
{{-- Tab-Navigation --}}
<div style="display:flex;gap:2px;border-bottom:1px solid var(--mw-b2);margin-bottom:20px">
@php
$tabs = [
'allgemein' => ['label' => 'Allgemein', 'icon' => '<circle cx="8" cy="8" r="2.2" stroke="currentColor" stroke-width="1.3"/><path d="M8 1.5v1.3M8 13.2v1.3M1.5 8h1.3M13.2 8h1.3M3.2 3.2l.9.9M11.9 11.9l.9.9M3.2 12.8l.9-.9M11.9 4.1l.9-.9" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/>'],
'domains' => ['label' => 'Domains & SSL', 'icon' => '<circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.3"/><path d="M8 2C6 4.5 5 6.2 5 8s1 3.5 3 6M8 2c2 2.5 3 4.2 3 6s-1 3.5-3 6M2 8h12" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/>'],
'backup' => ['label' => 'Backup', 'icon' => '<ellipse cx="8" cy="4" rx="5" ry="2" stroke="currentColor" stroke-width="1.3"/><path d="M3 4v4c0 1.1 2.24 2 5 2s5-.9 5-2V4" stroke="currentColor" stroke-width="1.3"/><path d="M3 8v4c0 1.1 2.24 2 5 2s5-.9 5-2V8" stroke="currentColor" stroke-width="1.3"/>'],
'benachrichtigungen' => ['label' => 'Benachrichtigungen', 'icon' => '<path d="M8 14a1.5 1.5 0 0 0 3 0M8 2a4 4 0 0 1 4 4v3l1 1H3l1-1V6a4 4 0 0 1 4-4Z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/>'],
];
@endphp
@foreach($tabs as $key => $cfg)
<button wire:click="$set('tab','{{ $key }}')"
style="display:inline-flex;align-items:center;gap:6px;padding:9px 14px;font-size:12.5px;font-weight:500;border:none;background:transparent;cursor:pointer;border-bottom:2px solid {{ $tab === $key ? 'var(--mw-v)' : 'transparent' }};color:{{ $tab === $key ? 'var(--mw-v2)' : 'var(--mw-t4)' }};margin-bottom:-1px;transition:color .15s">
<svg width="13" height="13" viewBox="0 0 16 16" fill="none">{!! $cfg['icon'] !!}</svg>
{{ $cfg['label'] }}
</button>
@endforeach
</div>
{{-- ═══ Main ═══ --}}
{{-- ═══ Tab: Allgemein ═══ --}}
@if($tab === 'allgemein')
<div class="sec-layout">
<div style="min-width:0">
<div class="mbx-sections">
{{-- Allgemein --}}
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Allgemein</span>
</div>
<div class="mbx-domain-info"><span class="mbx-badge-mute">Allgemein</span></div>
</div>
<div style="padding:16px 18px">
<div class="mw-modal-grid2">
<div>
<label class="mw-modal-label">Instanzname</label>
<input type="text" value="{{ $instance_name }}" class="mw-modal-input" readonly
style="opacity:.55;cursor:default">
<input type="text" value="{{ $instance_name }}" class="mw-modal-input" readonly style="opacity:.55;cursor:default">
<div class="mw-modal-hint">Wird aus config/app.php gelesen (APP_NAME)</div>
</div>
<div>
@ -67,185 +90,11 @@
</div>
</div>
{{-- 2FA --}}
<livewire:ui.system.two-fa-status />
{{-- Backup --}}
<div class="mbx-section" id="backup">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Backup-Zeitplan</span>
</div>
<div style="display:flex;align-items:center;gap:8px">
@if($backup_enabled)
<span class="mbx-badge-ok">Aktiv</span>
@else
<span class="mbx-badge-warn">Deaktiviert</span>
@endif
<a href="{{ route('ui.system.backups') }}" class="mbx-btn-mute" style="font-size:11.5px;padding:4px 12px;text-decoration:none">Verlauf</a>
</div>
</div>
<div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px">
{{-- Enable toggle --}}
<label class="sec-check">
<input type="checkbox" wire:model.live="backup_enabled">
<span style="font-size:12.5px;color:var(--mw-t2)">Automatisches Backup aktivieren</span>
</label>
{{-- Was sichern --}}
<div>
<label class="mw-modal-label" style="margin-bottom:8px;display:block">Was sichern</label>
<div class="bk-src-grid">
<label class="bk-src-card">
<input type="checkbox" wire:model.live="backup_include_db">
<span class="bk-src-icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><ellipse cx="7" cy="3.5" rx="5" ry="2" stroke="currentColor" stroke-width="1.2"/><path d="M2 3.5v7c0 1.1 2.24 2 5 2s5-.9 5-2v-7" stroke="currentColor" stroke-width="1.2"/><path d="M2 7c0 1.1 2.24 2 5 2s5-.9 5-2" stroke="currentColor" stroke-width="1.2"/></svg>
</span>
<span class="bk-src-name">Datenbank</span>
<span class="bk-src-hint">MySQL-Dump</span>
</label>
<label class="bk-src-card">
<input type="checkbox" wire:model.live="backup_include_maildirs">
<span class="bk-src-icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x=".5" y="2.5" width="13" height="9" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M.5 5l6.5 4.5L13.5 5" stroke="currentColor" stroke-width="1.2"/></svg>
</span>
<span class="bk-src-name">E-Mails</span>
<span class="bk-src-hint">Maildirs</span>
</label>
<label class="bk-src-card">
<input type="checkbox" wire:model.live="backup_include_configs">
<span class="bk-src-icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1.5L12.5 4v4.8c0 2.8-2.3 4.8-5.5 5.2C3.8 13.6 1.5 11.6 1.5 8.8V4L7 1.5Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/></svg>
</span>
<span class="bk-src-name">Konfiguration</span>
<span class="bk-src-hint">postfix, dovecot, SSL</span>
</label>
</div>
@if($backup_include_maildirs)
<div style="margin-top:8px">
<input type="text" wire:model.defer="backup_mail_dir"
class="mw-modal-input" placeholder="/var/mail/vhosts">
<div class="mw-modal-hint">Maildir-Pfad leer lassen für automatische Erkennung</div>
</div>
@endif
</div>
@if($backup_enabled)
{{-- Preset buttons --}}
<div>
<label class="mw-modal-label">Häufigkeit</label>
<div style="display:flex;gap:6px;flex-wrap:wrap">
@foreach(['hourly' => 'Stündlich', 'daily' => 'Täglich', 'weekly' => 'Wöchentlich', 'monthly' => 'Monatlich', 'custom' => 'Benutzerdefiniert'] as $val => $label)
<button type="button" wire:click="$set('backup_preset','{{ $val }}')"
style="padding:5px 14px;border-radius:6px;font-size:12px;cursor:pointer;transition:all .1s;
{{ $backup_preset === $val
? 'background:var(--mw-vbg);border:1px solid var(--mw-vbd);color:var(--mw-v2);font-weight:600'
: 'background:transparent;border:1px solid var(--mw-b2);color:var(--mw-t4)' }}">
{{ $label }}
</button>
@endforeach
</div>
</div>
{{-- Time / day pickers --}}
@if($backup_preset !== 'hourly' && $backup_preset !== 'custom')
<div class="mw-modal-grid2">
<div>
<label class="mw-modal-label">Uhrzeit</label>
<input type="time" wire:model.live="backup_time" class="mw-modal-input">
</div>
@if($backup_preset === 'weekly')
<div>
<label class="mw-modal-label">Wochentag</label>
<select wire:model.live="backup_weekday" class="mw-modal-input">
@foreach(['0'=>'Sonntag','1'=>'Montag','2'=>'Dienstag','3'=>'Mittwoch','4'=>'Donnerstag','5'=>'Freitag','6'=>'Samstag'] as $v => $d)
<option value="{{ $v }}">{{ $d }}</option>
@endforeach
</select>
</div>
@elseif($backup_preset === 'monthly')
<div>
<label class="mw-modal-label">Tag des Monats</label>
<select wire:model.live="backup_monthday" class="mw-modal-input">
@for($d = 1; $d <= 28; $d++)
<option value="{{ $d }}">{{ $d }}.</option>
@endfor
</select>
</div>
@endif
</div>
@endif
@if($backup_preset === 'custom')
<div>
<label class="mw-modal-label">Cron-Ausdruck</label>
<input type="text" wire:model.live="backup_cron" class="mw-modal-input"
placeholder="0 3 * * *" style="font-family:monospace">
<div class="mw-modal-hint">Standard Cron-Syntax: Minute Stunde Tag Monat Wochentag</div>
</div>
@endif
{{-- Cron-Vorschau --}}
<div style="display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--mw-bg4);border:1px solid var(--mw-b2);border-radius:7px">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><circle cx="6" cy="6" r="5" stroke="var(--mw-t4)" stroke-width="1.2"/><path d="M6 3.5v3l1.5 1.5" stroke="var(--mw-t4)" stroke-width="1.2" stroke-linecap="round"/></svg>
<span style="font-size:11px;color:var(--mw-t4)">Cron:</span>
<code style="font-family:monospace;font-size:11px;color:var(--mw-v2)">{{ $backup_cron }}</code>
</div>
{{-- Aufbewahrung --}}
<div>
<label class="mw-modal-label">Aufbewahrung (Anzahl Backups)</label>
<input type="number" wire:model.defer="backup_retention" class="mw-modal-input"
min="1" max="365" style="max-width:120px">
<div class="mw-modal-hint">Ältere Backups werden automatisch gelöscht. Empfehlung: 714.</div>
</div>
@endif
</div>
</div>
{{-- Benachrichtigungen --}}
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Benachrichtigungen</span>
</div>
</div>
<div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px">
<div class="mw-modal-grid2">
<div>
<label class="mw-modal-label">Absendername</label>
<input type="text" wire:model.defer="notify_sender_name" class="mw-modal-input" placeholder="CluBird Benachrichtigung">
<div class="mw-modal-hint">Wird als Absender in System-Mails angezeigt</div>
</div>
<div>
<label class="mw-modal-label">Admin-E-Mail</label>
<input type="email" wire:model.defer="notify_admin_email" class="mw-modal-input" placeholder="admin@example.com">
<div class="mw-modal-hint">Empfänger für Update- & Systemmeldungen</div>
</div>
</div>
@php
$sysmailFqdn = \App\Models\Setting::get('notify_from_address')
?: ('no-reply@' . config('mailpool.platform_system_zone','sysmail') . '.' . config('mailpool.platform_zone',''));
@endphp
<div style="display:flex;align-items:center;gap:8px;padding:9px 12px;border-radius:7px;background:var(--mw-bg3);border:1px solid var(--mw-b2)">
<svg width="12" height="12" viewBox="0 0 14 14" fill="none" style="flex-shrink:0;color:var(--mw-t4)"><rect x=".5" y="2.5" width="13" height="9" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M.5 5l6.5 4 6.5-4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
<span style="font-size:11px;color:var(--mw-t4)">Absenderadresse:</span>
<span style="font-family:monospace;font-size:11px;color:var(--mw-t2)">{{ $sysmailFqdn }}</span>
</div>
</div>
</div>
{{-- Sicherheit --}}
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Sicherheit</span>
</div>
<div class="mbx-domain-info"><span class="mbx-badge-mute">Sicherheit</span></div>
</div>
<div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px">
<div class="mw-modal-grid2">
@ -266,16 +115,48 @@
</div>
</div>
{{-- ═══ Sidebar ═══ --}}
<div>
<div class="mbx-sections">
{{-- Domains --}}
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Domains</span>
<div class="mbx-domain-info"><span class="mbx-badge-mute">System-Info</span></div>
</div>
<div style="padding:14px 16px;font-size:11.5px;color:var(--mw-t3);display:flex;flex-direction:column;gap:8px">
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">PHP</span>
<span>{{ PHP_VERSION }}</span>
</div>
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">Laravel</span>
<span>{{ app()->version() }}</span>
</div>
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">Umgebung</span>
<span>{{ app()->environment() }}</span>
</div>
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">Hostname</span>
<span style="font-family:monospace;font-size:10.5px">{{ gethostname() }}</span>
</div>
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">Certbot</span>
<span>{{ trim(@shell_exec('certbot --version 2>&1') ?? '—') ?: '—' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
@endif
{{-- ═══ Tab: Domains & SSL ═══ --}}
@if($tab === 'domains')
<div class="sec-layout">
<div style="min-width:0">
<div class="mbx-sections">
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info"><span class="mbx-badge-mute">Domains</span></div>
</div>
<div style="padding:14px 16px;display:flex;flex-direction:column;gap:12px">
@ -292,40 +173,30 @@
<div>
<label class="mw-modal-label">UI Domain</label>
<input type="text" wire:model="ui_domain" class="mw-modal-input"
placeholder="mail.example.com">
<input type="text" wire:model="ui_domain" class="mw-modal-input" placeholder="mail.example.com">
@error('ui_domain') <div class="mw-modal-error">{{ $message }}</div> @enderror
</div>
<div>
<label class="mw-modal-label">Mailserver Domain</label>
<input type="text" wire:model="mail_domain" class="mw-modal-input"
placeholder="mx.example.com">
<input type="text" wire:model="mail_domain" class="mw-modal-input" placeholder="mx.example.com">
@error('mail_domain') <div class="mw-modal-error">{{ $message }}</div> @enderror
</div>
<div>
<label class="mw-modal-label">Webmail Domain</label>
<input type="text" wire:model="webmail_domain" class="mw-modal-input"
placeholder="webmail.example.com">
<input type="text" wire:model="webmail_domain" class="mw-modal-input" placeholder="webmail.example.com">
@error('webmail_domain') <div class="mw-modal-error">{{ $message }}</div> @enderror
</div>
<button wire:click="saveDomains"
wire:loading.attr="disabled"
wire:target="saveDomains"
class="mbx-btn-primary" style="width:100%;justify-content:center;font-size:12px">
<span wire:loading.remove wire:target="saveDomains" style="display:inline-flex;align-items:center;gap:5px">
<svg width="11" height="11" viewBox="0 0 14 14" fill="none"><path d="M2 2h8l2 2v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z" stroke="currentColor" stroke-width="1.2"/><path d="M5 2v3h4V2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>Domains speichern
</span>
<span wire:loading wire:target="saveDomains">Speichert…</span>
</button>
</div>
</div>
</div>
</div>
{{-- SSL-Zertifikate --}}
<div>
<div class="mbx-sections">
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">SSL-Zertifikate</span>
</div>
<div class="mbx-domain-info"><span class="mbx-badge-mute">SSL-Zertifikate</span></div>
</div>
<div style="padding:10px 14px;display:flex;flex-direction:column;gap:5px">
@foreach(['ui','webmail','mail'] as $key)
@ -351,41 +222,173 @@
</a>
</div>
</div>
</div>
</div>
</div>
@endif
{{-- Info --}}
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">System-Info</span>
</div>
{{-- ═══ Tab: Backup ═══ --}}
@if($tab === 'backup')
<div class="mbx-sections" style="max-width:680px">
<div class="mbx-section" id="backup">
<div class="mbx-domain-head">
<div class="mbx-domain-info"><span class="mbx-badge-mute">Backup-Zeitplan</span></div>
<div style="display:flex;align-items:center;gap:8px">
@if($backup_enabled)
<span class="mbx-badge-ok">Aktiv</span>
@else
<span class="mbx-badge-warn">Deaktiviert</span>
@endif
<a href="{{ route('ui.system.backups') }}" class="mbx-btn-mute" style="font-size:11.5px;padding:4px 12px;text-decoration:none">Verlauf</a>
</div>
</div>
<div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px">
<label class="sec-check">
<input type="checkbox" wire:model.live="backup_enabled">
<span style="font-size:12.5px;color:var(--mw-t2)">Automatisches Backup aktivieren</span>
</label>
<div>
<label class="mw-modal-label" style="margin-bottom:8px;display:block">Was sichern</label>
<div class="bk-src-grid">
<label class="bk-src-card">
<input type="checkbox" wire:model.live="backup_include_db">
<span class="bk-src-icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><ellipse cx="7" cy="3.5" rx="5" ry="2" stroke="currentColor" stroke-width="1.2"/><path d="M2 3.5v7c0 1.1 2.24 2 5 2s5-.9 5-2v-7" stroke="currentColor" stroke-width="1.2"/><path d="M2 7c0 1.1 2.24 2 5 2s5-.9 5-2" stroke="currentColor" stroke-width="1.2"/></svg>
</span>
<span class="bk-src-name">Datenbank</span>
<span class="bk-src-hint">MySQL-Dump</span>
</label>
<label class="bk-src-card">
<input type="checkbox" wire:model.live="backup_include_maildirs">
<span class="bk-src-icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x=".5" y="2.5" width="13" height="9" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M.5 5l6.5 4.5L13.5 5" stroke="currentColor" stroke-width="1.2"/></svg>
</span>
<span class="bk-src-name">E-Mails</span>
<span class="bk-src-hint">Maildirs</span>
</label>
<label class="bk-src-card">
<input type="checkbox" wire:model.live="backup_include_configs">
<span class="bk-src-icon">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1.5L12.5 4v4.8c0 2.8-2.3 4.8-5.5 5.2C3.8 13.6 1.5 11.6 1.5 8.8V4L7 1.5Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/></svg>
</span>
<span class="bk-src-name">Konfiguration</span>
<span class="bk-src-hint">postfix, dovecot, SSL</span>
</label>
</div>
<div style="padding:14px 16px;font-size:11.5px;color:var(--mw-t3);display:flex;flex-direction:column;gap:8px">
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">PHP</span>
<span>{{ PHP_VERSION }}</span>
</div>
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">Laravel</span>
<span>{{ app()->version() }}</span>
</div>
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">Umgebung</span>
<span>{{ app()->environment() }}</span>
</div>
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">Hostname</span>
<span style="font-family:monospace;font-size:10.5px">{{ gethostname() }}</span>
</div>
<div style="display:flex;justify-content:space-between">
<span style="color:var(--mw-t4)">Certbot</span>
<span>{{ trim(@shell_exec('certbot --version 2>&1') ?? '—') ?: '—' }}</span>
</div>
@if($backup_include_maildirs)
<div style="margin-top:8px">
<input type="text" wire:model.defer="backup_mail_dir" class="mw-modal-input" placeholder="/var/mail/vhosts">
<div class="mw-modal-hint">Maildir-Pfad leer lassen für automatische Erkennung</div>
</div>
@endif
</div>
@if($backup_enabled)
<div>
<label class="mw-modal-label">Häufigkeit</label>
<div style="display:flex;gap:6px;flex-wrap:wrap">
@foreach(['hourly' => 'Stündlich', 'daily' => 'Täglich', 'weekly' => 'Wöchentlich', 'monthly' => 'Monatlich', 'custom' => 'Benutzerdefiniert'] as $val => $label)
<button type="button" wire:click="$set('backup_preset','{{ $val }}')"
style="padding:5px 14px;border-radius:6px;font-size:12px;cursor:pointer;transition:all .1s;
{{ $backup_preset === $val
? 'background:var(--mw-vbg);border:1px solid var(--mw-vbd);color:var(--mw-v2);font-weight:600'
: 'background:transparent;border:1px solid var(--mw-b2);color:var(--mw-t4)' }}">
{{ $label }}
</button>
@endforeach
</div>
</div>
@if($backup_preset !== 'hourly' && $backup_preset !== 'custom')
<div class="mw-modal-grid2">
<div>
<label class="mw-modal-label">Uhrzeit</label>
<input type="time" wire:model.live="backup_time" class="mw-modal-input">
</div>
@if($backup_preset === 'weekly')
<div>
<label class="mw-modal-label">Wochentag</label>
<select wire:model.live="backup_weekday" class="mw-modal-input">
@foreach(['0'=>'Sonntag','1'=>'Montag','2'=>'Dienstag','3'=>'Mittwoch','4'=>'Donnerstag','5'=>'Freitag','6'=>'Samstag'] as $v => $d)
<option value="{{ $v }}">{{ $d }}</option>
@endforeach
</select>
</div>
@elseif($backup_preset === 'monthly')
<div>
<label class="mw-modal-label">Tag des Monats</label>
<select wire:model.live="backup_monthday" class="mw-modal-input">
@for($d = 1; $d <= 28; $d++)
<option value="{{ $d }}">{{ $d }}.</option>
@endfor
</select>
</div>
@endif
</div>
@endif
@if($backup_preset === 'custom')
<div>
<label class="mw-modal-label">Cron-Ausdruck</label>
<input type="text" wire:model.live="backup_cron" class="mw-modal-input" placeholder="0 3 * * *" style="font-family:monospace">
<div class="mw-modal-hint">Standard Cron-Syntax: Minute Stunde Tag Monat Wochentag</div>
</div>
@endif
<div style="display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--mw-bg4);border:1px solid var(--mw-b2);border-radius:7px">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><circle cx="6" cy="6" r="5" stroke="var(--mw-t4)" stroke-width="1.2"/><path d="M6 3.5v3l1.5 1.5" stroke="var(--mw-t4)" stroke-width="1.2" stroke-linecap="round"/></svg>
<span style="font-size:11px;color:var(--mw-t4)">Cron:</span>
<code style="font-family:monospace;font-size:11px;color:var(--mw-v2)">{{ $backup_cron }}</code>
</div>
<div>
<label class="mw-modal-label">Aufbewahrung (Anzahl Backups)</label>
<input type="number" wire:model.defer="backup_retention" class="mw-modal-input" min="1" max="365" style="max-width:120px">
<div class="mw-modal-hint">Ältere Backups werden automatisch gelöscht. Empfehlung: 714.</div>
</div>
@endif
</div>
</div>
</div>
@endif
{{-- ═══ Tab: Benachrichtigungen ═══ --}}
@if($tab === 'benachrichtigungen')
<div class="mbx-sections" style="max-width:680px">
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info"><span class="mbx-badge-mute">Benachrichtigungen</span></div>
</div>
<div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px">
<div class="mw-modal-grid2">
<div>
<label class="mw-modal-label">Absendername</label>
<input type="text" wire:model.defer="notify_sender_name" class="mw-modal-input" placeholder="CluBird Benachrichtigung">
<div class="mw-modal-hint">Wird als Absender in System-Mails angezeigt</div>
</div>
<div>
<label class="mw-modal-label">Admin-E-Mail</label>
<input type="email" wire:model.defer="notify_admin_email" class="mw-modal-input" placeholder="admin@example.com">
<div class="mw-modal-hint">Empfänger für Update- & Systemmeldungen</div>
</div>
</div>
@php
$sysmailFqdn = \App\Models\Setting::get('notify_from_address')
?: ('no-reply@' . config('mailpool.platform_system_zone','sysmail') . '.' . config('mailpool.platform_zone',''));
@endphp
<div style="display:flex;align-items:center;gap:8px;padding:9px 12px;border-radius:7px;background:var(--mw-bg3);border:1px solid var(--mw-b2)">
<svg width="12" height="12" viewBox="0 0 14 14" fill="none" style="flex-shrink:0;color:var(--mw-t4)"><rect x=".5" y="2.5" width="13" height="9" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M.5 5l6.5 4 6.5-4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
<span style="font-size:11px;color:var(--mw-t4)">Absenderadresse:</span>
<span style="font-family:monospace;font-size:11px;color:var(--mw-t2)">{{ $sysmailFqdn }}</span>
</div>
</div>
</div>
</div>
@endif
</div>