feat: add global loader styles and replace SVG loaders with CSS loaders for improved performance

This commit is contained in:
2025-12-04 23:06:57 -05:00
parent 30fcf527d0
commit dff21ea7cc

View File

@@ -1,4 +1,59 @@
<x-proxmox::layout :server="$server" view="firewall" :status="$status" :status-polling="true" :status-polling-interval="'2s'">
{{-- Global Loader Styles --}}
<style>
.fw-loader {
width: 24px;
aspect-ratio: 1;
border-radius: 50%;
padding: 3px;
background:
conic-gradient(from 135deg at top, currentColor 90deg, #0000 0) 0 calc(50% - 2px)/10px 5px,
radial-gradient(farthest-side at bottom left, #0000 calc(100% - 3px), currentColor calc(100% - 2px) 99%, #0000) top right/50% 50% content-box content-box,
radial-gradient(farthest-side at top, #0000 calc(100% - 3px), currentColor calc(100% - 2px) 99%, #0000) bottom/100% 50% content-box content-box;
background-repeat: no-repeat;
animation: fw-loader-spin 1s infinite linear;
}
.fw-loader-sm {
width: 16px;
aspect-ratio: 1;
border-radius: 50%;
padding: 2px;
background:
conic-gradient(from 135deg at top, currentColor 90deg, #0000 0) 0 calc(50% - 1.5px)/6px 3px,
radial-gradient(farthest-side at bottom left, #0000 calc(100% - 2px), currentColor calc(100% - 1.5px) 99%, #0000) top right/50% 50% content-box content-box,
radial-gradient(farthest-side at top, #0000 calc(100% - 2px), currentColor calc(100% - 1.5px) 99%, #0000) bottom/100% 50% content-box content-box;
background-repeat: no-repeat;
animation: fw-loader-spin 1s infinite linear;
}
.fw-loader-lg {
width: 32px;
aspect-ratio: 1;
border-radius: 50%;
padding: 4px;
background:
conic-gradient(from 135deg at top, currentColor 90deg, #0000 0) 0 calc(50% - 3px)/12px 6px,
radial-gradient(farthest-side at bottom left, #0000 calc(100% - 4px), currentColor calc(100% - 3px) 99%, #0000) top right/50% 50% content-box content-box,
radial-gradient(farthest-side at top, #0000 calc(100% - 4px), currentColor calc(100% - 3px) 99%, #0000) bottom/100% 50% content-box content-box;
background-repeat: no-repeat;
animation: fw-loader-spin 1s infinite linear;
}
.fw-loader-xl {
width: 50px;
aspect-ratio: 1;
border-radius: 50%;
padding: 6px;
background:
conic-gradient(from 135deg at top, currentColor 90deg, #0000 0) 0 calc(50% - 4px)/17px 8.5px,
radial-gradient(farthest-side at bottom left, #0000 calc(100% - 6px), currentColor calc(100% - 5px) 99%, #0000) top right/50% 50% content-box content-box,
radial-gradient(farthest-side at top, #0000 calc(100% - 6px), currentColor calc(100% - 5px) 99%, #0000) bottom/100% 50% content-box content-box;
background-repeat: no-repeat;
animation: fw-loader-spin 1s infinite linear;
}
@keyframes fw-loader-spin {
100% { transform: rotate(1turn); }
}
</style>
<div class="flex flex-col gap-6">
{{-- Page Header --}}
<div class="mb-6">
@@ -425,9 +480,7 @@
<h3 class="text-lg font-semibold">IP Address: <span class="font-mono">{{ $ruleSourceIP }}</span></h3>
</div>
<div x-show="loading" class="text-center py-8">
<svg fill="currentColor" stroke="currentColor" viewBox="0 0 128 128" class="size-6 mx-auto mb-2">
<g><path stroke-width="5" d="M31.6 8.98a4.02 4.02 0 0 0 1.7 5.3l6.12 3.22a52.56 52.56 0 1 0 63.13 10.73L96 33.97a43.88 43.88 0 1 1-53-8.5l-3.65 7.4a4.02 4.02 0 0 0 1.72 5.3 3.73 3.73 0 0 0 5.13-1.67l7.66-15.63a4.18 4.18 0 0 0-1.75-5.4L36.74 7.32a3.73 3.73 0 0 0-5.13 1.66z" fill="currentColor" stroke="currentColor"/><animateTransform attributeName="transform" type="rotate" from="0 64 64" to="360 64 64" dur="1000ms" repeatCount="indefinite"></animateTransform></g>
</svg>
<div class="fw-loader size-6 mx-auto mb-2 text-primary"></div>
<p class="text-sm text-base/60">Loading location data...</p>
</div>
<div x-show="ipData && !loading">
@@ -505,9 +558,7 @@
<h3 class="text-lg font-semibold">IP Address: <span class="font-mono">{{ $ruleDestIP }}</span></h3>
</div>
<div x-show="loading" class="text-center py-8">
<svg fill="currentColor" stroke="currentColor" viewBox="0 0 128 128" class="size-6 mx-auto mb-2">
<g><path stroke-width="5" d="M31.6 8.98a4.02 4.02 0 0 0 1.7 5.3l6.12 3.22a52.56 52.56 0 1 0 63.13 10.73L96 33.97a43.88 43.88 0 1 1-53-8.5l-3.65 7.4a4.02 4.02 0 0 0 1.72 5.3 3.73 3.73 0 0 0 5.13-1.67l7.66-15.63a4.18 4.18 0 0 0-1.75-5.4L36.74 7.32a3.73 3.73 0 0 0-5.13 1.66z" fill="currentColor" stroke="currentColor"/><animateTransform attributeName="transform" type="rotate" from="0 64 64" to="360 64 64" dur="1000ms" repeatCount="indefinite"></animateTransform></g>
</svg>
<div class="fw-loader size-6 mx-auto mb-2 text-primary"></div>
<p class="text-sm text-base/60">Loading location data...</p>
</div>
<div x-show="ipData && !loading">
@@ -762,33 +813,7 @@
<span wire:loading.remove wire:target="loadFirewallLogs">
<x-ri-refresh-line class="size-4" />
</span>
<div wire:loading wire:target="loadFirewallLogs" class="loader-container">
<style>
.loader-container {
width: 16px;
height: 16px;
display: flex;
align-items: center;
justify-content: center;
}
.loader {
width: 16px;
aspect-ratio: 1;
border-radius: 50%;
padding: 2px;
background:
conic-gradient(from 135deg at top, currentColor 90deg, #0000 0) 0 calc(50% - 1.5px)/6px 3px,
radial-gradient(farthest-side at bottom left, #0000 calc(100% - 2px), currentColor calc(100% - 1.5px) 99%, #0000) top right/50% 50% content-box content-box,
radial-gradient(farthest-side at top, #0000 calc(100% - 2px), currentColor calc(100% - 1.5px) 99%, #0000) bottom/100% 50% content-box content-box;
background-repeat: no-repeat;
animation: loader-spin 1s infinite linear;
}
@keyframes loader-spin {
100% { transform: rotate(1turn); }
}
</style>
<div class="loader"></div>
</div>
<div wire:loading wire:target="loadFirewallLogs" class="fw-loader-sm"></div>
<span wire:loading.remove wire:target="loadFirewallLogs">Refresh</span>
<span wire:loading wire:target="loadFirewallLogs">Loading...</span>
</button>
@@ -806,31 +831,7 @@
@if(!$logsLoaded && count($firewallLogs) === 0)
<div class="text-center py-12 text-base/60">
<div class="loader-container-large" style="width: 50px; height: 50px; margin: 0 auto 1rem;">
<style>
.loader-container-large {
display: flex;
align-items: center;
justify-content: center;
}
.loader-large {
width: 50px;
aspect-ratio: 1;
border-radius: 50%;
padding: 6px;
background:
conic-gradient(from 135deg at top, currentColor 90deg, #0000 0) 0 calc(50% - 4px)/17px 8.5px,
radial-gradient(farthest-side at bottom left, #0000 calc(100% - 6px), currentColor calc(100% - 5px) 99%, #0000) top right/50% 50% content-box content-box,
radial-gradient(farthest-side at top, #0000 calc(100% - 6px), currentColor calc(100% - 5px) 99%, #0000) bottom/100% 50% content-box content-box;
background-repeat: no-repeat;
animation: loader-spin-large 1s infinite linear;
}
@keyframes loader-spin-large {
100% { transform: rotate(1turn); }
}
</style>
<div class="loader-large"></div>
</div>
<div class="fw-loader-xl text-primary mx-auto mb-4"></div>
<p class="text-sm">Loading firewall logs...</p>
</div>
@elseif(count($firewallLogs) > 0)
@@ -939,9 +940,7 @@
<h3 class="text-lg font-semibold">IP Address: <span class="font-mono">{{ $sourceIP }}</span></h3>
</div>
<div x-show="loading" class="text-center py-8">
<svg fill="currentColor" stroke="currentColor" viewBox="0 0 128 128" class="size-6 mx-auto mb-2">
<g><path stroke-width="5" d="M31.6 8.98a4.02 4.02 0 0 0 1.7 5.3l6.12 3.22a52.56 52.56 0 1 0 63.13 10.73L96 33.97a43.88 43.88 0 1 1-53-8.5l-3.65 7.4a4.02 4.02 0 0 0 1.72 5.3 3.73 3.73 0 0 0 5.13-1.67l7.66-15.63a4.18 4.18 0 0 0-1.75-5.4L36.74 7.32a3.73 3.73 0 0 0-5.13 1.66z" fill="currentColor" stroke="currentColor"/><animateTransform attributeName="transform" type="rotate" from="0 64 64" to="360 64 64" dur="1000ms" repeatCount="indefinite"></animateTransform></g>
</svg>
<div class="fw-loader text-primary mx-auto mb-2"></div>
<p class="text-sm text-base/60">Loading location data...</p>
</div>
<div x-show="ipData && !loading">
@@ -1019,9 +1018,7 @@
<h3 class="text-lg font-semibold">IP Address: <span class="font-mono">{{ $destIP }}</span></h3>
</div>
<div x-show="loading" class="text-center py-8">
<svg fill="currentColor" stroke="currentColor" viewBox="0 0 128 128" class="size-6 mx-auto mb-2">
<g><path stroke-width="5" d="M31.6 8.98a4.02 4.02 0 0 0 1.7 5.3l6.12 3.22a52.56 52.56 0 1 0 63.13 10.73L96 33.97a43.88 43.88 0 1 1-53-8.5l-3.65 7.4a4.02 4.02 0 0 0 1.72 5.3 3.73 3.73 0 0 0 5.13-1.67l7.66-15.63a4.18 4.18 0 0 0-1.75-5.4L36.74 7.32a3.73 3.73 0 0 0-5.13 1.66z" fill="currentColor" stroke="currentColor"/><animateTransform attributeName="transform" type="rotate" from="0 64 64" to="360 64 64" dur="1000ms" repeatCount="indefinite"></animateTransform></g>
</svg>
<div class="fw-loader text-primary mx-auto mb-2"></div>
<p class="text-sm text-base/60">Loading location data...</p>
</div>
<div x-show="ipData && !loading">
@@ -1128,13 +1125,8 @@
:disabled="loading"
class="w-9 h-9 flex items-center justify-center text-base/50 hover:text-primary transition-colors bg-background/80 backdrop-blur-sm rounded-full hover:bg-background disabled:opacity-50 disabled:cursor-not-allowed"
title="Refresh data">
<template x-if="!loading">
<x-ri-refresh-line class="size-5" />
</template>
<template x-if="loading">
<div class="w-5 h-5 rounded-full p-[3px] text-primary"
style="background: conic-gradient(from 135deg at top, currentColor 90deg, transparent 0) 0 calc(50% - 2px)/8.5px 4.25px, radial-gradient(farthest-side at bottom left, transparent calc(100% - 3px), currentColor calc(100% - 2px) 99%, transparent) top right/50% 50% content-box content-box, radial-gradient(farthest-side at top, transparent calc(100% - 3px), currentColor calc(100% - 2px) 99%, transparent) bottom/100% 50% content-box content-box; background-repeat: no-repeat; animation: refreshSpin 1s infinite linear;"></div>
</template>
<x-ri-refresh-line x-show="!loading" class="size-5" />
<div x-show="loading" x-cloak class="fw-loader-sm text-primary"></div>
</button>
<button @click="open = false"
class="w-9 h-9 flex items-center justify-center text-base/50 hover:text-base transition-colors bg-background/80 backdrop-blur-sm rounded-full hover:bg-background">
@@ -1142,12 +1134,6 @@
</button>
</div>
<style>
@keyframes refreshSpin {
100% { transform: rotate(1turn); }
}
</style>
{{-- Modal Header --}}
<div class="bg-gradient-to-r from-primary/10 to-secondary/10 border-b border-primary/20 p-6">
<div class="flex items-center gap-3">
@@ -1166,10 +1152,7 @@
{{-- Loading State --}}
<div x-show="loading && !connectionData" class="text-center py-12">
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-primary/10 mb-4">
<svg class="animate-spin size-8 text-primary" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<div class="fw-loader-lg text-primary"></div>
</div>
<p class="text-sm text-base/60">Fetching connection data...</p>
</div>