199 lines
14 KiB
PHP
199 lines
14 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="{{ str_replace('_','-',app()->getLocale()) }}">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
<title>@yield('title', config('app.name'))</title>
|
|
@vite(['resources/css/app.css'])
|
|
@livewireStyles
|
|
</head>
|
|
<body style="color:var(--mw-t1);font-family:-apple-system,BlinkMacSystemFont,'Inter','Segoe UI',sans-serif;font-size:13.5px;-webkit-font-smoothing:antialiased;margin:0;">
|
|
|
|
<div class="mw-sidebar-overlay" id="mw-overlay" onclick="document.getElementById('mw-sidebar').classList.remove('open');this.classList.remove('open');"></div>
|
|
|
|
<div class="mw-shell">
|
|
|
|
{{-- ═══ SIDEBAR ═══ --}}
|
|
<aside class="mw-sidebar" id="mw-sidebar">
|
|
|
|
<div class="mw-sb-head">
|
|
<div class="mw-sb-mark">
|
|
<svg width="15" height="15" viewBox="0 0 18 18" fill="none">
|
|
<path d="M9 2L15.5 5.5v7L9 16 2.5 12.5v-7L9 2Z" stroke="white" stroke-width="1.5" stroke-linejoin="round"/>
|
|
<path d="M9 6L12 7.5v3L9 12 6 10.5v-3L9 6Z" fill="white" opacity=".9"/>
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<div class="mw-sb-name">MAILWOLT</div>
|
|
<div class="mw-sb-sub">Control Panel</div>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="mw-nav">
|
|
|
|
<p class="mw-nav-label">Übersicht</p>
|
|
<a href="{{ route('ui.dashboard') }}" class="mw-nav-item {{ request()->routeIs('ui.dashboard') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x=".5" y=".5" width="5.5" height="5.5" rx="1.2" stroke="currentColor" stroke-width="1.2"/><rect x="8" y=".5" width="5.5" height="5.5" rx="1.2" stroke="currentColor" stroke-width="1.2"/><rect x=".5" y="8" width="5.5" height="5.5" rx="1.2" stroke="currentColor" stroke-width="1.2"/><rect x="8" y="8" width="5.5" height="5.5" rx="1.2" stroke="currentColor" stroke-width="1.2"/></svg>
|
|
Dashboard
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
|
|
<p class="mw-nav-label">Domains</p>
|
|
<a href="{{ route('ui.domains.index') }}" class="mw-nav-item {{ request()->routeIs('ui.domains*') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="7" cy="7" r="5.5" stroke="currentColor" stroke-width="1.2"/><ellipse cx="7" cy="7" rx="2.2" ry="5.5" stroke="currentColor" stroke-width="1.2"/><path d="M1.5 5.5h11M1.5 8.5h11" stroke="currentColor" stroke-width="1.2"/></svg>
|
|
Übersicht
|
|
<span class="mw-nav-badge">{{ $domainCount ?? '—' }}</span>
|
|
</a>
|
|
<a href="{{ route('ui.domains.dns') }}" class="mw-nav-item {{ request()->routeIs('ui.domains.dns') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1.5L11 5.5h-2.5v7H5.5v-7H3L7 1.5Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/></svg>
|
|
DNS / DKIM
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
|
|
<p class="mw-nav-label">Mail</p>
|
|
<a href="{{ route('ui.mail.mailboxes.index') }}" class="mw-nav-item {{ request()->routeIs('ui.mail.mailboxes*') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x=".5" y="2" width="13" height="10" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M.5 4L7 8.5l6.5-4.5" stroke="currentColor" stroke-width="1.2"/></svg>
|
|
Postfächer
|
|
<span class="mw-nav-badge">{{ $mailboxCount ?? '—' }}</span>
|
|
</a>
|
|
<a href="{{ route('ui.mail.aliases.index') }}" class="mw-nav-item {{ request()->routeIs('ui.mail.aliases*') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1 7L5 11 13 3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
Aliasse
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.mail.queues.index') }}" class="mw-nav-item {{ request()->routeIs('ui.mail.queues*') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1 4h12M4 4V2h6v2M4 12V7m6 5V7" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
Mail-Queue
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.mail.quarantine.index') }}" class="mw-nav-item {{ request()->routeIs('ui.mail.quarantine*') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="7" cy="7" r="5.5" stroke="currentColor" stroke-width="1.2"/><path d="M7 4v4l2.5 2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
Quarantäne
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
|
|
<p class="mw-nav-label">Sicherheit</p>
|
|
<a href="{{ route('ui.security.fail2ban') }}" class="mw-nav-item {{ request()->routeIs('ui.security.fail2ban') ? 'active' : '' }}">
|
|
<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>
|
|
Fail2Ban
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.security.ssl') }}" class="mw-nav-item {{ request()->routeIs('ui.security.ssl') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="1.5" y="5" width="11" height="7.5" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M4.5 5V3.5a2.5 2.5 0 0 1 5 0V5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
SSL/TLS
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.security.tls') }}" class="mw-nav-sub-item {{ request()->routeIs('ui.security.tls') ? 'active' : '' }}">
|
|
TLS-Ciphers
|
|
</a>
|
|
<a href="{{ route('ui.security.rspamd') }}" class="mw-nav-item {{ request()->routeIs('ui.security.rspamd') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="7" cy="7" r="5.5" stroke="currentColor" stroke-width="1.2"/><path d="M7 4.5v3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="10" r=".7" fill="currentColor"/></svg>
|
|
Rspamd
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.security.audit') }}" class="mw-nav-item {{ request()->routeIs('ui.security.audit') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1 3.5h12M1 7h12M1 10.5h12" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
Audit-Logs
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
|
|
<p class="mw-nav-label">System</p>
|
|
<a href="{{ route('ui.system.users') }}" class="mw-nav-item {{ request()->routeIs('ui.system.users') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="5.5" cy="4.5" r="2.5" stroke="currentColor" stroke-width="1.2"/><path d="M1 13c0-2.5 2-4.5 4.5-4.5S10 10.5 10 13" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><path d="M11 6v4M9 8h4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
Benutzer
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.system.api') }}" class="mw-nav-item {{ request()->routeIs('ui.system.api') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M6 10a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z" stroke="currentColor" stroke-width="1.2"/><path d="M9.5 8.5L14 13" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
API Keys
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.system.webhooks') }}" class="mw-nav-item {{ request()->routeIs('ui.system.webhooks') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M2 8a6 6 0 1 0 12 0A6 6 0 0 0 2 8Z" stroke="currentColor" stroke-width="1.2"/><path d="M8 5v3l2 2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/><path d="M1 3l2 1.5M15 3l-2 1.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
Webhooks
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.system.sandbox') }}" class="mw-nav-item {{ request()->routeIs('ui.system.sandbox') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 16 16" fill="none"><rect x="1.5" y="3.5" width="13" height="9" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M1.5 5.5l6.5 4 6.5-4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
Mail-Sandbox
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.system.backups') }}" class="mw-nav-item {{ request()->routeIs('ui.system.backups') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2.5 9H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><rect x="3" y="8.5" width="8" height="5" rx="1.5" stroke="currentColor" stroke-width="1.2"/></svg>
|
|
Backups
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
<a href="{{ route('ui.system.update') }}" class="mw-nav-item {{ request()->routeIs('ui.system.update') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M12 7A5 5 0 1 1 9 2.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><path d="M9 .5l2.5 2L9 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
Updates
|
|
@if(!empty($updateAvailable))
|
|
<span style="margin-left:auto;background:rgba(234,179,8,.18);border:1px solid rgba(234,179,8,.4);color:#fbbf24;font-size:10px;font-weight:600;line-height:1;padding:2px 6px;border-radius:99px">1</span>
|
|
@else
|
|
<div class="mw-nav-dot"></div>
|
|
@endif
|
|
</a>
|
|
<a href="{{ route('ui.system.settings') }}" class="mw-nav-item {{ request()->routeIs('ui.system.settings') ? 'active' : '' }}">
|
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="7" cy="7" r="2" stroke="currentColor" stroke-width="1.2"/><path d="M7 1.5v1.2M7 11.3v1.2M1.5 7h1.2M11.3 7h1.2M2.9 2.9l.85.85M10.25 10.25l.85.85M2.9 11.1l.85-.85M10.25 3.75l.85-.85" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
Einstellungen
|
|
<div class="mw-nav-dot"></div>
|
|
</a>
|
|
|
|
</nav>
|
|
|
|
<div class="mw-sb-foot">
|
|
<div class="mw-avatar">{{ strtoupper(substr(auth()->user()->name ?? 'MW', 0, 2)) }}</div>
|
|
<div style="min-width:0;flex:1;overflow:hidden;">
|
|
<div style="font-size:12px;font-weight:500;color:var(--mw-t2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{ auth()->user()->name ?? 'Admin' }}</div>
|
|
<div style="font-size:10px;color:var(--mw-t4);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{ auth()->user()->email ?? '' }}</div>
|
|
</div>
|
|
<form method="POST" action="{{ route('ui.logout') }}" style="flex-shrink:0;">
|
|
@csrf
|
|
<button type="submit" style="background:none;border:none;cursor:pointer;color:var(--mw-t4);padding:4px;" title="Abmelden">
|
|
<svg width="14" height="14" viewBox="0 0 15 15" fill="none"><path d="M10 7.5H2M8 5l2.5 2.5L8 10M6 2H3a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
</aside>
|
|
|
|
{{-- ═══ MAIN ═══ --}}
|
|
<div class="mw-main">
|
|
|
|
<header class="mw-topbar">
|
|
<div class="mw-breadcrumb">
|
|
<button class="mw-hamburger" style="display:none" onclick="document.getElementById('mw-sidebar').classList.add('open');document.getElementById('mw-overlay').classList.add('open');">
|
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none"><path d="M2 4h14M2 9h14M2 14h14" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
|
|
</button>
|
|
@hasSection('breadcrumb-parent')@yield('breadcrumb-parent')@else{{ $breadcrumbParent ?? 'Dashboard' }}@endif
|
|
<svg width="11" height="11" viewBox="0 0 11 11" fill="none"><path d="M3.5 2l4 3.5-4 3.5" stroke="var(--mw-b3)" stroke-width="1.3" stroke-linecap="round"/></svg>
|
|
<b>@hasSection('breadcrumb')@yield('breadcrumb')@else{{ $breadcrumb ?? 'Übersicht' }}@endif</b>
|
|
</div>
|
|
<div class="mw-topbar-right">
|
|
<div class="mw-live"><div class="mw-live-dot"></div>Live</div>
|
|
<button wire:click="$dispatch('openModal',{component:'ui.search.modal.search-palette-modal'})" class="mw-search">
|
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><circle cx="5" cy="5" r="3.8" stroke="currentColor" stroke-width="1.2"/><path d="M8 8l2.5 2.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
Suche <kbd>⌘K</kbd>
|
|
</button>
|
|
<div class="mw-ip">{{ gethostname() ?: '—' }}</div>
|
|
<button class="mw-btn-primary" onclick="Livewire.dispatch('openModal',{component:'ui.domain.modal.domain-create-modal'})">+ Domain</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="mw-content">
|
|
@hasSection('content')
|
|
@yield('content')
|
|
@else
|
|
{{ $slot ?? '' }}
|
|
@endif
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@vite(['resources/js/app.js'])
|
|
@livewireScripts
|
|
@livewire('wire-elements-modal')
|
|
</body>
|
|
</html>
|