279 lines
14 KiB
PHP
279 lines
14 KiB
PHP
<div wire:poll.10s="loadData" class="#glass-card #p-5">
|
||
{{-- Header --}}
|
||
<div class="flex items-center justify-between mb-4">
|
||
<h3 class="card-title text-lg">Dienste & Status</h3>
|
||
<span class="text-xs text-white/60">aktualisiert: {{ $updatedAtHuman ?? '–' }}</span>
|
||
</div>
|
||
|
||
{{-- CPU / RAM / Load / Uptime --}}
|
||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
|
||
{{-- CPU --}}
|
||
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
||
<div>
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div
|
||
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||
<i class="ph ph-cpu text-white/70 text-[13px]"></i>
|
||
<span class="text-[11px] tracking-wide uppercase text-white/70">CPU</span>
|
||
</div>
|
||
</div>
|
||
<div class="text-2xl font-semibold">{{ is_numeric($cpuPercent) ? $cpuPercent.'%' : '–' }}</div>
|
||
</div>
|
||
<div class="mt-3 rounded bg-white/5 p-1">
|
||
<div class="grid" style="grid-template-columns: repeat({{ $barSegments }}, minmax(0,1fr)); gap: 4px;">
|
||
@foreach($cpuSeg as $cls)
|
||
<div class="h-2 rounded {{ $cls }}"></div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- RAM --}}
|
||
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
||
<div>
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div
|
||
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||
<i class="ph ph-memory text-white/70 text-[13px]"></i>
|
||
<span class="text-[11px] tracking-wide uppercase text-white/70">RAM</span>
|
||
</div>
|
||
</div>
|
||
<div class="text-2xl font-semibold">{{ is_numeric($ramPercent) ? $ramPercent.'%' : '–' }}</div>
|
||
@if($ramSummary)
|
||
<div class="text-[11px] text-white/50 mt-0.5">{{ $ramSummary }}</div>
|
||
@endif
|
||
</div>
|
||
<div class="mt-3 rounded bg-white/5 p-1">
|
||
<div class="grid" style="grid-template-columns: repeat({{ $barSegments }}, minmax(0,1fr)); gap: 4px;">
|
||
@foreach($ramSeg as $cls)
|
||
<div class="h-2 rounded {{ $cls }}"></div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Load --}}
|
||
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
||
<div>
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div
|
||
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||
<i class="ph ph-activity text-white/70 text-[13px]"></i>
|
||
<span class="text-[11px] tracking-wide uppercase text-white/70">Load</span>
|
||
</div>
|
||
</div>
|
||
<div class="text-2xl font-semibold">{{ $loadBadgeText }}</div>
|
||
</div>
|
||
|
||
<div class="mt-3 flex items-center justify-between">
|
||
<div class="flex items-center gap-3">
|
||
@foreach($loadDots as $d)
|
||
<div class="flex items-center gap-1 text-[11px] text-white/50">
|
||
<span class="w-2 h-2 rounded-full {{ $d['cls'] }}"></span>
|
||
<span>{{ $d['label'] }}</span>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Uptime --}}
|
||
<div class="glass-card p-4 flex flex-col justify-between min-h-[140px]">
|
||
<div>
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div
|
||
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||
<i class="{{ $uptimeIcon }} text-white/70 text-[13px]"></i>
|
||
<span class="text-[11px] tracking-wide uppercase text-white/70">Uptime</span>
|
||
</div>
|
||
</div>
|
||
<div class="text-2xl font-semibold">{{ $uptimeText ?? '–' }}</div>
|
||
</div>
|
||
|
||
<div class="mt-3 flex flex-wrap gap-2">
|
||
@foreach($uptimeChips as $c)
|
||
<span class="px-2 py-0.5 rounded-full text-xs bg-white/5 border border-white/10 text-white/70">
|
||
<span class="font-semibold text-white/90">{{ $c['v'] }}</span> {{ $c['u'] }}
|
||
</span>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-2 #items-center justify-between gap-3">
|
||
{{-- MailGuard Status Card --}}
|
||
<div
|
||
class="glass-card p-4 flex flex-row items-start justify-between gap-4 relative overflow-hidden mb-4">
|
||
{{-- Linke Seite: Icon + Titel --}}
|
||
<div class="flex #items-start gap-3 relative z-10">
|
||
<div class="shrink-0">
|
||
{{-- Modernes Shield-Icon --}}
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
||
<defs>
|
||
<linearGradient id="shieldGradient" x1="0" y1="0" x2="0" y2="1">
|
||
<stop offset="0" stop-color="#4ade80"/>
|
||
<stop offset="1" stop-color="#15803d"/>
|
||
</linearGradient>
|
||
<radialGradient id="shine" cx="30%" cy="20%" r="70%">
|
||
<stop offset="0%" stop-color="rgba(255,255,255,0.4)"/>
|
||
<stop offset="100%" stop-color="rgba(255,255,255,0)"/>
|
||
</radialGradient>
|
||
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
||
<feDropShadow dx="0" dy="0" stdDeviation="3" flood-color="#22c55e"
|
||
flood-opacity="0.6"/>
|
||
</filter>
|
||
</defs>
|
||
<path d="M32 6l20 8v12c0 13.5-8.7 22.7-20 27-11.3-4.3-20-13.5-20-27V14l20-8z"
|
||
fill="url(#shieldGradient)" filter="url(#glow)"/>
|
||
<path d="M32 6l20 8v12c0 13.5-8.7 22.7-20 27-11.3-4.3-20-13.5-20-27V14l20-8z"
|
||
fill="url(#shine)"/>
|
||
<path d="M23 33l7 7 11-14" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round"
|
||
stroke-linejoin="round"/>
|
||
</svg>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 class="text-lg font-semibold text-white/90">WoltGuard</h3>
|
||
<p class="text-sm text-white/50">System-Wächter aktiv und fehlerfrei</p>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Rechte Seite: Status & Avatar --}}
|
||
<div class="flex items-start gap-3 relative z-10">
|
||
{{-- Status Badge --}}
|
||
@if($guardOk ?? false)
|
||
<span
|
||
class="inline-flex #items-center gap-1 px-3 py-1 rounded-full text-sm border border-emerald-400/30 text-emerald-300 bg-emerald-500/10">
|
||
<i class="ph ph-check-circle text-[14px]"></i>
|
||
<span class="text-[11px]">alle Dienste OK</span>
|
||
</span>
|
||
@else
|
||
<span
|
||
class="inline-flex #items-center gap-1 px-3 py-1 rounded-full text-sm border border-rose-400/30 text-rose-300 bg-rose-500/10">
|
||
<i class="ph ph-warning-circle text-[11px]"></i>
|
||
Störung erkannt
|
||
</span>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
|
||
<livewire:ui.system.update-card/>
|
||
</div>
|
||
|
||
{{-- Dienste & Storage: kompakt & bündig --}}
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div class="glass-card relative p-4 max-h-fit">
|
||
{{-- Inhalt: Donut links, Zahlen rechts – stacked auf kleineren Screens --}}
|
||
<div class="grid grid-cols-1 items-center">
|
||
{{-- Donut --}}
|
||
<div class="flex items-center justify-between -mb-3">
|
||
<div
|
||
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||
<i class="ph ph-hard-drives text-white/70 text-[13px]"></i>
|
||
<span class="text-[11px] tracking-wide uppercase text-white/70">Storage</span>
|
||
</div>
|
||
<a href="#"
|
||
class="inline-flex items-center gap-1 rounded-full border border-white/10 bg-white/5 px-2 py-0.5 text-[10px] text-white/70 hover:text-white hover:border-white/20 transition">
|
||
Details <i class="ph ph-caret-right text-[12px]"></i>
|
||
</a>
|
||
</div>
|
||
|
||
<div class="flex items-center justify-center">
|
||
<div class="relative"
|
||
style="width: {{ $diskInnerSize + 80 }}px; height: {{ $diskInnerSize + 80 }}px;">
|
||
{{-- Innerer grauer Kreis --}}
|
||
<div
|
||
class="absolute inset-[36px] rounded-full bg-white/[0.04] backdrop-blur-sm ring-1 ring-white/10"></div>
|
||
|
||
{{-- Prozentanzeige im Zentrum – leicht kleiner & feiner --}}
|
||
<div class="absolute inset-0 flex flex-col items-center justify-center">
|
||
<div class="text-2xl md:text-3xl font-semibold leading-none tracking-tight">
|
||
{{ $diskCenterText['percent'] }}
|
||
</div>
|
||
<div class="text-[10px] md:text-[11px] text-white/60 mt-1 uppercase tracking-wide">
|
||
{{ $diskCenterText['label'] }}
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Segment-Ring – größerer Abstand zum Kreis --}}
|
||
@foreach($diskSegments as $seg)
|
||
<span class="absolute top-1/2 left-1/2 block"
|
||
style="
|
||
transform: rotate({{ $seg['angle'] }}deg) translateX({{ $diskSegOuterRadius + 14 }}px);
|
||
width: 12px; height: 6px; margin:-3px 0 0 -6px;">
|
||
<span class="block w-full h-full rounded-full {{ $seg['class'] }}"></span>
|
||
</span>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Zahlen rechts (kompakter Satz) --}}
|
||
<div class="md:pl-2">
|
||
<dl class="space-y-2">
|
||
<div class="flex items-center justify-between">
|
||
<dt class="text-white/60 text-sm">Gesamt</dt>
|
||
<dd class="font-medium tabular-nums text-base">
|
||
{{ is_numeric($diskTotalGb) ? $diskTotalGb.' GB' : '–' }}
|
||
</dd>
|
||
</div>
|
||
<div class="flex items-center justify-between">
|
||
<dt class="text-white/60 text-sm">Genutzt</dt>
|
||
<dd class="font-medium tabular-nums text-base">
|
||
{{ is_numeric($diskUsedGb) ? $diskUsedGb.' GB' : '–' }}
|
||
</dd>
|
||
</div>
|
||
<div class="flex items-center justify-between">
|
||
<dt class="text-white/60 text-sm">Frei</dt>
|
||
<dd class="font-medium tabular-nums text-base">
|
||
{{ is_numeric($diskFreeGb) ? $diskFreeGb.' GB' : '–' }}
|
||
</dd>
|
||
</div>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="glass-card p-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div
|
||
class="inline-flex items-center gap-2 rounded-full bg-white/5 border border-white/10 px-2.5 py-1">
|
||
<i class="ph ph-gear-six text-white/70 text-[13px]"></i>
|
||
<span class="text-[11px] tracking-wide uppercase text-white/70">Dienste</span>
|
||
</div>
|
||
<span
|
||
class="inline-flex items-center gap-1 rounded-full bg-white/5 border border-white/10 px-2 py-0.5 text-[10px] text-white/60">
|
||
systemctl / TCP
|
||
</span>
|
||
</div>
|
||
<ul class="overflow-auto divide-y divide-white/5">
|
||
@forelse($servicesCompact as $s)
|
||
<li class="grid grid-cols-[auto,1fr,auto] items-center gap-3 py-2">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<div class="flex items-center gap-2">
|
||
<span class="h-2 w-2 rounded-full {{ $s['dotClass'] }}"></span>
|
||
<div class="min-w-0">
|
||
<div class="text-white/90 truncate">{{ $s['label'] }}</div>
|
||
</div>
|
||
</div>
|
||
@if($s['hint'])
|
||
<div class="text-[11px] text-white/45 truncate">{{ $s['hint'] }}</div>
|
||
@endif
|
||
</div>
|
||
<span
|
||
class="justify-self-end inline-flex items-center px-2.5 py-0.5 rounded-full text-xs border {{ $s['pillClass'] }}">
|
||
{{ $s['pillText'] }}
|
||
</span>
|
||
</div>
|
||
</li>
|
||
@empty
|
||
<li class="py-2 text-white/50 text-sm">Keine Daten.</li>
|
||
@endforelse
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|