Enhance UI transitions and loading effects across Proxmox views

- Implemented page load animations using Alpine.js for smoother transitions in various views including firewall, help, index, network, overview, reinstall, server, statistics, storage, subdomain, and system.
- Added opacity and translate effects to elements for improved visual feedback during loading.
- Enhanced hover effects on cards and buttons for better user interaction.
- Adjusted transition timings and delays for a more cohesive user experience.
This commit is contained in:
2025-12-17 19:50:05 -05:00
parent 801898e295
commit a7cb561053
21 changed files with 307 additions and 170 deletions

View File

@@ -342,31 +342,42 @@
@endphp
<!-- Resource Stats Grid -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 lg:gap-5" wire:loading.class="opacity-50" wire:target="checkStatus">
@foreach($resourceAllocations as $resource)
<div class="group bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-sm hover:shadow-md hover:border-gray-300 dark:hover:border-gray-700 transition-all duration-200 p-4 lg:p-5">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 lg:gap-5"
wire:loading.class="opacity-50"
wire:target="checkStatus"
x-data="{ loaded: false }"
x-init="setTimeout(() => loaded = true, 100)">
@foreach($resourceAllocations as $index => $resource)
<div class="group bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-sm p-4 lg:p-5
transition-all duration-300 ease-out
hover:shadow-lg hover:border-gray-300 dark:hover:border-gray-700
hover:-translate-y-0.5 hover:scale-[1.01]"
:class="loaded ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'"
:style="loaded ? 'transition-delay: {{ $index * 75 }}ms' : ''">
<div class="flex items-start justify-between mb-4">
<h3 class="text-xs font-bold text-gray-600 dark:text-gray-400 uppercase tracking-widest opacity-75">{{ $resource['label'] }}</h3>
<h3 class="text-xs font-bold text-gray-600 dark:text-gray-400 uppercase tracking-widest opacity-75 group-hover:opacity-100 transition-opacity duration-200">{{ $resource['label'] }}</h3>
@if(isset($resource['badge']))
<span class="text-xs font-bold px-2.5 py-1 rounded-full {{ $resource['badge']['label'] === 'Healthy' ? 'bg-success/15 text-success opacity-90' : ($resource['badge']['label'] === 'Watchlist' ? 'bg-warning/15 text-warning opacity-90' : 'bg-error/15 text-error opacity-90') }}">
<span class="text-xs font-bold px-2.5 py-1 rounded-full transition-transform duration-200 group-hover:scale-105 {{ $resource['badge']['label'] === 'Healthy' ? 'bg-success/15 text-success opacity-90' : ($resource['badge']['label'] === 'Watchlist' ? 'bg-warning/15 text-warning opacity-90' : 'bg-error/15 text-error opacity-90') }}">
{{ $resource['badge']['label'] }}
</span>
@endif
</div>
<div class="mb-3">
<div class="text-3xl font-bold text-gray-900 dark:text-white tracking-tight mb-1">{{ $resource['usage_summary'] }}</div>
<p class="text-xs text-gray-600 dark:text-gray-400 opacity-75 font-medium">{{ $resource['entitlement_label'] }}</p>
<div class="text-3xl font-bold text-gray-900 dark:text-white tracking-tight mb-1 transition-colors duration-200 group-hover:text-primary">{{ $resource['usage_summary'] }}</div>
<p class="text-xs text-gray-600 dark:text-gray-400 opacity-75 font-medium group-hover:opacity-90 transition-opacity duration-200">{{ $resource['entitlement_label'] }}</p>
</div>
@if($resource['used_percent'] !== null)
<div class="space-y-2">
<div class="relative w-full h-2.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden shadow-inner">
<div class="absolute inset-y-0 left-0 rounded-full transition-all duration-500 ease-out"
style="width: {{ min(100, $resource['used_percent']) }}%; background: {{ $resource['gradient'] }}; box-shadow: 0 0 20px {{ $resource['gradient'] }};"></div>
<div class="absolute inset-y-0 left-0 rounded-full transition-all duration-700 ease-out origin-left"
x-data="{ width: 0 }"
x-init="setTimeout(() => width = {{ min(100, $resource['used_percent']) }}, 300)"
:style="'width: ' + width + '%; background: {{ $resource['gradient'] }}; box-shadow: 0 0 20px {{ $resource['gradient'] }};'"></div>
</div>
<div class="flex items-center justify-between">
<span class="text-xs font-semibold text-gray-700 dark:text-gray-300">{{ number_format($resource['used_percent'], 1) }}%</span>
<span class="text-xs font-semibold text-gray-700 dark:text-gray-300 group-hover:text-gray-900 dark:group-hover:text-white transition-colors duration-200">{{ number_format($resource['used_percent'], 1) }}%</span>
@if($resource['used_percent'] > 100)
<span class="text-xs font-bold text-error opacity-85">Over entitlement</span>
<span class="text-xs font-bold text-error opacity-85 animate-pulse">Over entitlement</span>
@endif
</div>
</div>
@@ -376,26 +387,31 @@
</div>
<!-- Main Grid Layout -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-5">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-5"
x-data="{ cardsLoaded: false }"
x-init="setTimeout(() => cardsLoaded = true, 250)">
<!-- Server Information Card -->
<div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-sm hover:shadow-md hover:border-gray-300 dark:hover:border-gray-700 transition-all duration-200 overflow-hidden">
<div class="flex items-center justify-between p-4 lg:p-5 bg-gradient-to-r from-primary/8 to-primary/4 border-b border-primary/20">
<div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-sm overflow-hidden
transition-all duration-300 ease-out
hover:shadow-lg hover:border-gray-300 dark:hover:border-gray-700"
:class="cardsLoaded ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'">
<div class="flex items-center justify-between p-4 lg:p-5 bg-gradient-to-r from-primary/8 to-primary/4 border-b border-primary/20 transition-all duration-200 hover:from-primary/12 hover:to-primary/6">
<div class="flex items-center gap-2.5">
<svg class="size-5 text-primary opacity-80" fill="currentColor" viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="5" rx="1" fill="currentColor"/><rect x="2" y="10" width="20" height="5" rx="1" fill="currentColor"/><circle cx="6" cy="5.5" r="0.7" fill="white" opacity="0.8"/><circle cx="6" cy="12.5" r="0.7" fill="white" opacity="0.8"/></svg>
<svg class="size-5 text-primary opacity-80 transition-transform duration-200 hover:scale-110" fill="currentColor" viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="5" rx="1" fill="currentColor"/><rect x="2" y="10" width="20" height="5" rx="1" fill="currentColor"/><circle cx="6" cy="5.5" r="0.7" fill="white" opacity="0.8"/><circle cx="6" cy="12.5" r="0.7" fill="white" opacity="0.8"/></svg>
<h3 class="text-base sm:text-lg font-bold text-gray-900 dark:text-white">Server Information</h3>
</div>
</div>
<div class="p-4 lg:p-5">
<div class="space-y-3.5">
<!-- Status -->
<div class="flex items-center justify-between py-2.5 px-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
<div class="flex items-center gap-2 text-sm font-semibold text-gray-600 dark:text-gray-400 opacity-80">
<svg class="size-4 opacity-75" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="12" r="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
<div class="flex items-center justify-between py-2.5 px-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition-all duration-200 hover:translate-x-0.5 group">
<div class="flex items-center gap-2 text-sm font-semibold text-gray-600 dark:text-gray-400 opacity-80 group-hover:opacity-100 transition-opacity duration-200">
<svg class="size-4 opacity-75 group-hover:opacity-100 transition-all duration-200 group-hover:scale-110" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="12" r="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>Status</span>
</div>
<div>
@if ($status && $status->status === 'running')
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold bg-success/15 text-success rounded-full opacity-90">
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold bg-success/15 text-success rounded-full opacity-90 transition-all duration-200 hover:opacity-100 hover:bg-success/20">
<span class="w-1.5 h-1.5 bg-success rounded-full animate-pulse"></span>
Running
</span>
@@ -408,22 +424,22 @@
</div>
</div>
<!-- Operating System -->
<div class="flex items-center justify-between py-2.5 px-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
<div class="flex items-center gap-2 text-sm font-semibold text-gray-600 dark:text-gray-400 opacity-80">
<svg class="size-4 opacity-75" fill="currentColor" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="4" r="1.5" fill="currentColor"/><circle cx="18" cy="15" r="1.5" fill="currentColor"/><circle cx="6" cy="15" r="1.5" fill="currentColor"/></svg>
<div class="flex items-center justify-between py-2.5 px-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition-all duration-200 hover:translate-x-0.5 group">
<div class="flex items-center gap-2 text-sm font-semibold text-gray-600 dark:text-gray-400 opacity-80 group-hover:opacity-100 transition-opacity duration-200">
<svg class="size-4 opacity-75 group-hover:opacity-100 transition-all duration-200 group-hover:scale-110" fill="currentColor" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="4" r="1.5" fill="currentColor"/><circle cx="18" cy="15" r="1.5" fill="currentColor"/><circle cx="6" cy="15" r="1.5" fill="currentColor"/></svg>
<span>Operating System</span>
</div>
<span class="text-sm text-gray-900 dark:text-white font-medium opacity-90">{{ $server->os->name }}</span>
<span class="text-sm text-gray-900 dark:text-white font-medium opacity-90 group-hover:opacity-100 transition-opacity duration-200">{{ $server->os->name }}</span>
</div>
<!-- Hostname -->
<div class="flex items-center justify-between py-2.5 px-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors" x-data="{ showHostnameEditModal: @entangle('isEditingHostname') }">
<div class="flex items-center gap-2 text-sm font-semibold text-gray-600 dark:text-gray-400 opacity-80">
<svg class="size-4 opacity-75" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 21h8M12 17v4" stroke-linecap="round" stroke-linejoin="round"/></svg>
<div class="flex items-center justify-between py-2.5 px-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition-all duration-200 hover:translate-x-0.5 group" x-data="{ showHostnameEditModal: @entangle('isEditingHostname') }">
<div class="flex items-center gap-2 text-sm font-semibold text-gray-600 dark:text-gray-400 opacity-80 group-hover:opacity-100 transition-opacity duration-200">
<svg class="size-4 opacity-75 group-hover:opacity-100 transition-all duration-200 group-hover:scale-110" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 21h8M12 17v4" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>Hostname</span>
</div>
<div class="flex items-center gap-2">
<code class="text-sm text-gray-900 dark:text-white font-mono opacity-90">{{ $server->hostname ?? $status->name ?? 'N/A' }}</code>
<button wire:click="startEditingHostname" type="button" class="text-primary opacity-70 hover:opacity-100 transition-opacity">
<code class="text-sm text-gray-900 dark:text-white font-mono opacity-90 group-hover:opacity-100 transition-opacity duration-200">{{ $server->hostname ?? $status->name ?? 'N/A' }}</code>
<button wire:click="startEditingHostname" type="button" class="text-primary opacity-70 hover:opacity-100 transition-all duration-200 hover:scale-110">
<x-ri-edit-line class="size-4" />
</button>
</div>