Enhance UI components with visual polish, including hover animations and improved skeleton loaders for better user experience

This commit is contained in:
2026-02-01 15:06:49 -05:00
parent abff5a381f
commit 8cf30b5f34
14 changed files with 77 additions and 49 deletions

View File

@@ -2085,6 +2085,32 @@ img {
box-shadow: 0 0 20px hsl(var(--color-primary) / 0.4);
}
/* =============================================================================
VISUAL POLISH ENHANCEMENTS
============================================================================= */
/* Card arrow hover animation - slides right on hover */
.card-arrow-animate {
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
color 0.15s ease;
}
.group:hover .card-arrow-animate,
a:hover .card-arrow-animate {
transform: translateX(4px);
color: hsl(var(--color-primary));
}
/* Status card hover enhancement - subtle lift and glow */
.status-card-hover {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.status-card-hover:hover {
transform: scale(1.02);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
/* Sidebar active indicator bar */
.nav-active-bar {
position: relative;
@@ -2113,6 +2139,8 @@ img {
.ripple::after,
.interactive-lift,
.form-error-shake,
.card-arrow-animate,
.status-card-hover,
[wire\:navigate],
::view-transition-old(page),
::view-transition-new(page) {

View File

@@ -11,7 +11,7 @@
})">
<button
class="flex flex-row items-center px-2 py-1 text-sm font-semibold whitespace-nowrap text-base hover:text-primary transition-colors duration-200"
class="flex flex-row items-center px-2 py-1 text-sm font-semibold whitespace-nowrap text-base hover:text-primary transition-colors duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-md"
x-on:click="open = !open"
:aria-expanded="open">
{{ $trigger }}

View File

@@ -23,7 +23,7 @@
</legend>
@endif
<textarea type="{{ $type ?? 'text' }}" id="{{ $id ?? $name }}" name="{{ $name }}"
class="block w-full text-sm text-primary-100 bg-primary-800 border-2 border-neutral rounded-md outline-none focus:outline-none focus:border-secondary transition-all duration-300 ease-in-out disabled:bg-primary-700 disabled:cursor-not-allowed {{ $class ?? '' }} @if ($type !== 'color') px-2.5 py-2.5 @endif"
class="block w-full text-sm text-base bg-background-secondary/50 border border-neutral rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary transition-all duration-300 ease-in-out disabled:bg-background-secondary/50 disabled:cursor-not-allowed resize-y min-h-[100px] {{ $class ?? '' }} @if ($type !== 'color') px-2.5 py-2.5 @endif"
placeholder="{{ $placeholder ?? ($label ?? '') }}" @if ($dirty && isset($attributes['wire:model']))
wire:dirty.class="!border-yellow-600" @endif {{ $attributes->except(['placeholder', 'label', 'id', 'name', 'type', 'class', 'divClass', 'required', 'hideRequiredIndicator', 'dirty']) }}
@required($required)>{{ $slot }}</textarea>

View File

@@ -3,9 +3,9 @@
<nav role="navigation" aria-label="Pagination Navigation" class="flex gap-2 items-center">
<span>
@if ($paginator->onFirstPage())
<span class="bg-background-secondary text-base/50 px-4 py-2 rounded-lg cursor-not-allowed border border-neutral transition-colors duration-200">Previous</span>
<span class="bg-background-secondary text-base/50 px-4 py-2 rounded-lg cursor-not-allowed border border-neutral/30 opacity-50 transition-colors duration-200">Previous</span>
@else
<button wire:click="previousPage" wire:loading.attr="disabled" rel="prev" class="bg-background-secondary text-base px-4 py-2 rounded-lg border border-neutral hover:bg-background/80 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-primary/50">Previous</button>
<button wire:click="previousPage" wire:loading.attr="disabled" rel="prev" class="bg-background-secondary text-base px-4 py-2 rounded-lg border border-neutral hover:bg-background/80 hover:border-primary/50 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-primary/50">Previous</button>
@endif
</span>
@@ -19,16 +19,16 @@
abs($paginator->currentPage() - $page) <= 1)
<span>
<button wire:click="gotoPage({{ $page }})" wire:loading.attr="disabled"
class="{{ $page === $paginator->currentPage() ? 'bg-primary text-white border-primary' : 'bg-background-secondary text-base border-neutral hover:bg-background/80' }} px-4 py-2 rounded-lg cursor-pointer border transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-primary/50">{{ $page }}</button>
class="{{ $page === $paginator->currentPage() ? 'bg-primary text-white border-primary shadow-sm' : 'bg-background-secondary text-base border-neutral hover:bg-background/80 hover:border-primary/50' }} px-4 py-2 rounded-lg cursor-pointer border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-primary/50">{{ $page }}</button>
</span>
@elseif($page == 3 || $page == $paginator->lastPage() - 3)
<span class="bg-background-secondary text-base/50 px-4 py-2 rounded-lg border border-neutral">
<span class="bg-background-secondary text-base/50 px-4 py-2 rounded-lg border border-neutral/30">
<span>...</span>
</span>
@endif
@endforeach
@else
<span class="bg-background-secondary text-base/50 px-4 py-2 rounded-lg border border-neutral">
<span class="bg-background-secondary text-base/50 px-4 py-2 rounded-lg border border-neutral/30">
<span>...</span>
</span>
@endif
@@ -37,10 +37,10 @@
<span>
@if ($paginator->onLastPage())
<span class="bg-background-secondary text-base/50 px-4 py-2 rounded-lg cursor-not-allowed border border-neutral transition-colors duration-200">Next</span>
<span class="bg-background-secondary text-base/50 px-4 py-2 rounded-lg cursor-not-allowed border border-neutral/30 opacity-50 transition-colors duration-200">Next</span>
@else
<button wire:click="nextPage" wire:loading.attr="disabled" rel="next"
class="bg-background-secondary text-base px-4 py-2 rounded-lg border border-neutral hover:bg-background/80 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-primary/50">Next</button>
class="bg-background-secondary text-base px-4 py-2 rounded-lg border border-neutral hover:bg-background/80 hover:border-primary/50 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-primary/50">Next</button>
@endif
</span>
</nav>

View File

@@ -1,25 +1,25 @@
{{-- Skeleton loader for invoice card --}}
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/50 p-6 rounded-xl shadow-lg
flex flex-col md:flex-row items-start md:items-center justify-between gap-4 animate-pulse">
flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
<div class="flex items-start md:items-center gap-4 flex-grow">
{{-- Icon skeleton --}}
<div class="p-3 rounded-full flex-shrink-0 bg-blue-500/20 w-12 h-12"></div>
<div class="p-3 rounded-full flex-shrink-0 bg-blue-500/20 w-12 h-12 skeleton-shimmer"></div>
<div class="flex flex-col flex-grow">
{{-- Title skeleton --}}
<div class="h-6 bg-neutral/20 rounded-lg w-40 mb-2"></div>
<div class="h-6 bg-neutral/20 rounded-lg w-40 mb-2 skeleton-shimmer"></div>
{{-- Amount and date skeleton --}}
<div class="h-4 bg-neutral/20 rounded w-56 mb-1"></div>
<div class="h-4 bg-neutral/20 rounded w-56 mb-1 skeleton-shimmer"></div>
{{-- Due date skeleton --}}
<div class="h-3 bg-neutral/20 rounded w-36"></div>
<div class="h-3 bg-neutral/20 rounded w-36 skeleton-shimmer"></div>
</div>
</div>
<div class="flex items-center gap-3 flex-shrink-0 mt-3 md:mt-0">
{{-- Status badge skeleton --}}
<div class="h-7 bg-neutral/20 rounded-full w-20"></div>
<div class="h-7 bg-neutral/20 rounded-full w-20 skeleton-shimmer"></div>
{{-- Arrow skeleton --}}
<div class="h-6 w-6 bg-neutral/20 rounded"></div>
<div class="h-6 w-6 bg-neutral/20 rounded skeleton-shimmer"></div>
</div>
</div>

View File

@@ -1,25 +1,25 @@
{{-- Skeleton loader for service card --}}
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/50 p-6 rounded-xl shadow-lg
flex flex-col md:flex-row items-start md:items-center justify-between gap-4 animate-pulse">
flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
<div class="flex items-start md:items-center gap-4 flex-grow">
{{-- Icon skeleton --}}
<div class="p-3 rounded-full flex-shrink-0 bg-neutral/20 w-12 h-12"></div>
<div class="p-3 rounded-full flex-shrink-0 bg-neutral/20 w-12 h-12 skeleton-shimmer"></div>
<div class="flex flex-col flex-grow">
{{-- Title skeleton --}}
<div class="h-6 bg-neutral/20 rounded-lg w-48 mb-2"></div>
<div class="h-6 bg-neutral/20 rounded-lg w-48 mb-2 skeleton-shimmer"></div>
{{-- Description skeleton --}}
<div class="h-4 bg-neutral/20 rounded w-64 mb-1"></div>
<div class="h-4 bg-neutral/20 rounded w-64 mb-1 skeleton-shimmer"></div>
{{-- Date skeleton --}}
<div class="h-3 bg-neutral/20 rounded w-32"></div>
<div class="h-3 bg-neutral/20 rounded w-32 skeleton-shimmer"></div>
</div>
</div>
<div class="flex items-center gap-3 flex-shrink-0 mt-3 md:mt-0">
{{-- Status badge skeleton --}}
<div class="h-7 bg-neutral/20 rounded-full w-20"></div>
<div class="h-7 bg-neutral/20 rounded-full w-20 skeleton-shimmer"></div>
{{-- Arrow skeleton --}}
<div class="h-6 w-6 bg-neutral/20 rounded"></div>
<div class="h-6 w-6 bg-neutral/20 rounded skeleton-shimmer"></div>
</div>
</div>

View File

@@ -5,7 +5,7 @@
</h1>
<div class="grid grid-cols-3 md:grid-cols-3 gap-4 mb-12 bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/50 p-2 rounded-xl">
<div class="bg-success/10 border border-success/50 rounded-xl p-4 text-center">
<div class="bg-success/10 border border-success/50 rounded-xl p-4 text-center status-card-hover">
<div class="flex items-center justify-center mb-2">
<x-ri-checkbox-circle-fill class="size-6 text-success mr-2" />
<span class="text-2xl font-bold text-success">{{ $invoices->where('status', 'paid')->count() }}</span>
@@ -13,7 +13,7 @@
<p class="text-sm font-medium text-success">{{ __('Paid') }}</p>
</div>
<div class="bg-warning/10 border border-warning/50 rounded-xl p-4 text-center">
<div class="bg-warning/10 border border-warning/50 rounded-xl p-4 text-center status-card-hover">
<div class="flex items-center justify-center mb-2">
<x-ri-error-warning-fill class="size-6 text-warning mr-2" />
<span class="text-2xl font-bold text-warning">{{ $invoices->where('status', 'pending')->count() }}</span>
@@ -21,7 +21,7 @@
<p class="text-sm font-medium text-warning">{{ __('Pending') }}</p>
</div>
<div class="bg-inactive/10 border border-inactive/50 rounded-xl p-4 text-center">
<div class="bg-inactive/10 border border-inactive/50 rounded-xl p-4 text-center status-card-hover">
<div class="flex items-center justify-center mb-2">
<x-ri-close-circle-fill class="size-6 text-inactive mr-2" />
<span class="text-2xl font-bold text-inactive">{{ $invoices->where('status', 'cancelled')->count() }}</span>
@@ -80,13 +80,13 @@
{{ __('Pending') }}
@endif
</div>
<x-ri-arrow-right-s-line class="size-6 text-color-muted group-hover:text-primary transition-colors duration-200" />
<x-ri-arrow-right-s-line class="size-6 text-color-muted card-arrow-animate" />
</div>
</div>
</a>
@empty
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 rounded-xl shadow-lg p-8 lg:p-12 border border-neutral/50 text-center group">
<div class="bg-blue-500/10 rounded-full p-6 w-fit mx-auto mb-6 transition-transform duration-300 group-hover:scale-110">
<div class="bg-blue-500/10 rounded-full p-6 w-fit mx-auto mb-6 transition-transform duration-300 group-hover:scale-110 empty-state-float">
<x-ri-file-list-3-line class="size-12 text-blue-500" />
</div>
<h3 class="text-2xl font-bold text-color-base mb-3">No invoices yet</h3>

View File

@@ -6,7 +6,7 @@
{{-- Status Overview --}}
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-12 bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/50 p-2 rounded-xl">
<div class="bg-success/10 border border-success/50 rounded-xl p-4 text-center">
<div class="bg-success/10 border border-success/50 rounded-xl p-4 text-center status-card-hover">
<div class="flex items-center justify-center mb-2">
<x-ri-checkbox-circle-fill class="size-6 text-success mr-2" />
<span class="text-2xl font-bold text-success">{{ $services->where('status', 'active')->count() }}</span>
@@ -14,7 +14,7 @@
<p class="text-sm font-medium text-success">{{ __('Active') }}</p>
</div>
<div class="bg-warning/10 border border-warning/50 rounded-xl p-4 text-center">
<div class="bg-warning/10 border border-warning/50 rounded-xl p-4 text-center status-card-hover">
<div class="flex items-center justify-center mb-2">
<x-ri-error-warning-fill class="size-6 text-warning mr-2" />
<span class="text-2xl font-bold text-warning">{{ $services->where('status', 'pending')->count() }}</span>
@@ -22,7 +22,7 @@
<p class="text-sm font-medium text-warning">{{ __('Pending') }}</p>
</div>
<div class="bg-error/10 border border-error/50 rounded-xl p-4 text-center">
<div class="bg-error/10 border border-error/50 rounded-xl p-4 text-center status-card-hover">
<div class="flex items-center justify-center mb-2">
<x-ri-forbid-fill class="size-6 text-red-500 mr-2" />
<span class="text-2xl font-bold text-red-500">{{ $services->where('status', 'suspended')->count() }}</span>
@@ -30,7 +30,7 @@
<p class="text-sm font-medium text-red-500">{{ __('Suspended') }}</p>
</div>
<div class="bg-inactive/10 border border-inactive/50 rounded-xl p-4 text-center">
<div class="bg-inactive/10 border border-inactive/50 rounded-xl p-4 text-center status-card-hover">
<div class="flex items-center justify-center mb-2">
<x-ri-close-circle-fill class="size-6 text-inactive mr-2" />
<span class="text-2xl font-bold text-inactive">{{ $services->where('status', 'cancelled')->count() }}</span>
@@ -121,13 +121,13 @@
{{ __('Pending') }}
@endif
</div>
<x-ri-arrow-right-s-line class="size-6 text-color-muted group-hover:text-primary transition-colors duration-200" />
<x-ri-arrow-right-s-line class="size-6 text-color-muted card-arrow-animate" />
</div>
</div>
</a>
@empty
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 rounded-xl shadow-lg p-8 lg:p-12 border border-neutral/50 text-center group">
<div class="bg-primary/10 rounded-full p-6 w-fit mx-auto mb-6 transition-transform duration-300 group-hover:scale-110">
<div class="bg-primary/10 rounded-full p-6 w-fit mx-auto mb-6 transition-transform duration-300 group-hover:scale-110 empty-state-float">
<x-ri-server-line class="size-12 text-primary" />
</div>
<h3 class="text-2xl font-bold text-color-base mb-3">No services yet</h3>

View File

@@ -57,13 +57,13 @@
{{ ucfirst($ticket->status) }}
@endif
</div>
<x-ri-arrow-right-s-line class="size-6 text-color-muted group-hover:text-primary transition-colors duration-200" />
<x-ri-arrow-right-s-line class="size-6 text-color-muted card-arrow-animate" />
</div>
</div>
</a>
@empty
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 rounded-xl shadow-lg p-8 lg:p-12 border border-neutral/50 text-center">
<div class="bg-secondary/10 rounded-full p-6 w-fit mx-auto mb-6">
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 rounded-xl shadow-lg p-8 lg:p-12 border border-neutral/50 text-center group">
<div class="bg-secondary/10 rounded-full p-6 w-fit mx-auto mb-6 empty-state-float">
<x-ri-customer-service-2-line class="size-12 text-secondary" />
</div>
<h3 class="text-2xl font-bold text-color-base mb-3">No tickets yet</h3>