From e7b33a2f6cf55edce15cec17a716a58338c9dd23 Mon Sep 17 00:00:00 2001 From: "Joseph.Rawlings" Date: Wed, 17 Dec 2025 11:24:17 -0500 Subject: [PATCH] Refactor Proxmox server views for improved UI consistency and usability - Updated server card component to use new UI elements and improved layout. - Enhanced status display with badges and better status indicators. - Refined quick info row for server details with consistent styling. - Reorganized server configuration statistics into stat cards for clarity. - Improved help modals for statistics and storage management sections. - Streamlined alerts and warnings for better user experience. - Updated storage management view to utilize new UI components and improve readability. --- .../Proxmox/views/components/alert.blade.php | 136 ++++++++++ .../Proxmox/views/components/badge.blade.php | 123 +++++++++ .../Proxmox/views/components/button.blade.php | 122 +++++++++ .../Proxmox/views/components/card.blade.php | 87 ++++++ .../components/dropdown-divider.blade.php | 1 + .../views/components/dropdown-item.blade.php | 41 +++ .../views/components/dropdown.blade.php | 54 ++++ .../views/components/empty-state.blade.php | 24 ++ .../Proxmox/views/components/index.blade.php | 203 ++++++++++++++ .../views/components/info-list.blade.php | 19 ++ .../views/components/info-row.blade.php | 55 ++++ .../Proxmox/views/components/input.blade.php | 116 ++++++++ .../Proxmox/views/components/modal.blade.php | 139 ++++++++++ .../views/components/progress.blade.php | 102 +++++++ .../views/components/section-header.blade.php | 115 ++++++++ .../views/components/spinner.blade.php | 27 ++ .../views/components/stat-card.blade.php | 104 ++++++++ .../views/components/tab-panel.blade.php | 16 ++ .../views/components/table-row.blade.php | 26 ++ .../views/components/table-td.blade.php | 22 ++ .../views/components/table-th.blade.php | 42 +++ .../Proxmox/views/components/table.blade.php | 67 +++++ .../Proxmox/views/components/tabs.blade.php | 41 +++ .../components/ui/action-button.blade.php | 72 +++++ .../components/ui/action-toolbar.blade.php | 25 ++ .../views/components/ui/alert.blade.php | 120 +++++++++ .../components/ui/allocation-card.blade.php | 73 +++++ .../views/components/ui/badge.blade.php | 78 ++++++ .../views/components/ui/button.blade.php | 92 +++++++ .../views/components/ui/card.blade.php | 103 ++++++++ .../components/ui/confirm-dialog.blade.php | 116 ++++++++ .../views/components/ui/copy-button.blade.php | 35 +++ .../views/components/ui/copyable.blade.php | 56 ++++ .../components/ui/dropdown-divider.blade.php | 5 + .../components/ui/dropdown-item.blade.php | 38 +++ .../views/components/ui/dropdown.blade.php | 61 +++++ .../components/ui/editable-field.blade.php | 148 +++++++++++ .../views/components/ui/empty-state.blade.php | 72 +++++ .../views/components/ui/help-modal.blade.php | 83 ++++++ .../views/components/ui/icon-picker.blade.php | 169 ++++++++++++ .../views/components/ui/index.blade.php | 249 ++++++++++++++++++ .../views/components/ui/info-row.blade.php | 51 ++++ .../views/components/ui/input.blade.php | 93 +++++++ .../views/components/ui/modal.blade.php | 115 ++++++++ .../ui/network-address-card.blade.php | 191 ++++++++++++++ .../components/ui/notice-banner.blade.php | 98 +++++++ .../views/components/ui/progress.blade.php | 80 ++++++ .../components/ui/resource-gauge.blade.php | 103 ++++++++ .../components/ui/section-header.blade.php | 109 ++++++++ .../views/components/ui/select.blade.php | 67 +++++ .../components/ui/server-status.blade.php | 139 ++++++++++ .../views/components/ui/spinner.blade.php | 46 ++++ .../views/components/ui/stat-card.blade.php | 75 ++++++ .../views/components/ui/tab-panel.blade.php | 17 ++ .../views/components/ui/table-row.blade.php | 36 +++ .../views/components/ui/table-td.blade.php | 31 +++ .../views/components/ui/table-th.blade.php | 50 ++++ .../views/components/ui/table.blade.php | 53 ++++ .../views/components/ui/tabs.blade.php | 82 ++++++ .../views/components/ui/toggle.blade.php | 45 ++++ .../views/components/ui/tooltip.blade.php | 56 ++++ .../Servers/Proxmox/views/firewall.blade.php | 237 ++++++----------- .../Servers/Proxmox/views/index.blade.php | 23 +- .../Servers/Proxmox/views/network.blade.php | 72 ++--- .../Servers/Proxmox/views/overview.blade.php | 138 +++------- .../Servers/Proxmox/views/server.blade.php | 160 +++++------ .../Proxmox/views/statistics.blade.php | 93 ++----- .../Servers/Proxmox/views/storage.blade.php | 240 +++++------------ 68 files changed, 5127 insertions(+), 650 deletions(-) create mode 100644 extensions/Servers/Proxmox/views/components/alert.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/badge.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/button.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/card.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/dropdown-divider.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/dropdown-item.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/dropdown.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/empty-state.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/index.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/info-list.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/info-row.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/input.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/modal.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/progress.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/section-header.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/spinner.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/stat-card.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/tab-panel.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/table-row.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/table-td.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/table-th.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/table.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/tabs.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/action-button.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/action-toolbar.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/alert.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/allocation-card.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/badge.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/button.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/card.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/confirm-dialog.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/copy-button.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/copyable.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/dropdown-divider.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/dropdown-item.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/dropdown.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/editable-field.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/empty-state.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/help-modal.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/icon-picker.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/index.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/info-row.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/input.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/modal.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/network-address-card.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/notice-banner.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/progress.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/resource-gauge.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/section-header.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/select.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/server-status.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/spinner.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/stat-card.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/tab-panel.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/table-row.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/table-td.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/table-th.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/table.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/tabs.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/toggle.blade.php create mode 100644 extensions/Servers/Proxmox/views/components/ui/tooltip.blade.php diff --git a/extensions/Servers/Proxmox/views/components/alert.blade.php b/extensions/Servers/Proxmox/views/components/alert.blade.php new file mode 100644 index 000000000..b3f22a34f --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/alert.blade.php @@ -0,0 +1,136 @@ +@props([ + 'variant' => 'info', + 'title' => null, + 'icon' => null, + 'dismissible' => false, + 'collapsible' => false, + 'collapsed' => false, + 'storageKey' => null, + 'border' => true, +]) + +@php + // Variant classes + $variantClasses = match($variant) { + 'success' => 'bg-success/10 border-success/30 text-success', + 'danger', 'error' => 'bg-danger/10 border-danger/30 text-danger', + 'warning' => 'bg-warning/10 border-warning/30 text-warning', + 'info' => 'bg-info/10 border-info/30 text-info', + 'neutral' => 'bg-neutral/10 border-neutral/30 text-base/80', + default => 'bg-info/10 border-info/30 text-info', + }; + + // Default icons per variant + $defaultIcon = match($variant) { + 'success' => 'ri-checkbox-circle-fill', + 'danger', 'error' => 'ri-error-warning-fill', + 'warning' => 'ri-alert-fill', + 'info' => 'ri-information-line', + 'neutral' => 'ri-information-line', + default => 'ri-information-line', + }; + + $alertIcon = $icon ?? $defaultIcon; + $borderClasses = $border ? 'border' : ''; + $baseClasses = "$variantClasses $borderClasses rounded-lg p-4"; +@endphp + +
merge(['class' => $baseClasses]) }} + @if($dismissible || $collapsible) + x-data="{ + show: true, + isCollapsed: {{ $collapsed ? 'true' : 'false' }}, + init() { + @if($storageKey) + @if($dismissible) + this.show = localStorage.getItem('{{ $storageKey }}-dismissed') !== 'true'; + @endif + @if($collapsible) + this.isCollapsed = localStorage.getItem('{{ $storageKey }}-collapsed') === 'true'; + @endif + @endif + }, + dismiss() { + this.show = false; + @if($storageKey) + localStorage.setItem('{{ $storageKey }}-dismissed', 'true'); + @endif + }, + toggle() { + this.isCollapsed = !this.isCollapsed; + @if($storageKey) + localStorage.setItem('{{ $storageKey }}-collapsed', this.isCollapsed); + @endif + } + }" + x-show="show" + x-transition:enter="transition ease-out duration-300" + x-transition:enter-start="opacity-0 transform -translate-y-2" + x-transition:enter-end="opacity-100 transform translate-y-0" + x-transition:leave="transition ease-in duration-200" + x-transition:leave-start="opacity-100" + x-transition:leave-end="opacity-0" + @endif +> +
+ {{-- Icon --}} + @if($alertIcon) + + @endif + + {{-- Content --}} +
+ {{-- Header with title and controls --}} + @if($title || $dismissible || $collapsible) +
+ @if($title) +

{{ $title }}

+ @endif + +
+ @if($collapsible) + + @endif + + @if($dismissible) + + @endif +
+
+ @endif + + {{-- Body --}} + @if($collapsible) +
+ {{ $slot }} +
+ @else +
+ {{ $slot }} +
+ @endif +
+
+ + {{-- Actions slot --}} + @if(isset($actions)) +
+ {{ $actions }} +
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/badge.blade.php b/extensions/Servers/Proxmox/views/components/badge.blade.php new file mode 100644 index 000000000..2c2cd2cba --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/badge.blade.php @@ -0,0 +1,123 @@ +@props([ + 'variant' => 'neutral', + 'size' => 'md', + 'rounded' => 'full', + 'dot' => false, + 'pulse' => false, + 'icon' => null, + 'iconPosition' => 'left', + 'removable' => false, + 'outline' => false, +]) + +@php + // Base classes + $baseClasses = 'inline-flex items-center font-medium'; + + // Size classes + $sizeClasses = match($size) { + 'xs' => 'px-1.5 py-0.5 text-xs gap-1', + 'sm' => 'px-2 py-0.5 text-xs gap-1', + 'md' => 'px-2.5 py-1 text-xs gap-1.5', + 'lg' => 'px-3 py-1 text-sm gap-1.5', + default => 'px-2.5 py-1 text-xs gap-1.5', + }; + + // Icon size classes + $iconSizeClasses = match($size) { + 'xs' => 'size-2.5', + 'sm' => 'size-3', + 'md' => 'size-3.5', + 'lg' => 'size-4', + default => 'size-3.5', + }; + + // Dot size classes + $dotSizeClasses = match($size) { + 'xs' => 'size-1.5', + 'sm' => 'size-1.5', + 'md' => 'size-2', + 'lg' => 'size-2', + default => 'size-2', + }; + + // Variant classes + $variantClasses = match($variant) { + 'success' => $outline + ? 'border border-success/50 text-success bg-transparent' + : 'bg-success/10 text-success border border-success/20', + 'danger' => $outline + ? 'border border-danger/50 text-danger bg-transparent' + : 'bg-danger/10 text-danger border border-danger/20', + 'warning' => $outline + ? 'border border-warning/50 text-warning bg-transparent' + : 'bg-warning/10 text-warning border border-warning/20', + 'info' => $outline + ? 'border border-info/50 text-info bg-transparent' + : 'bg-info/10 text-info border border-info/20', + 'primary' => $outline + ? 'border border-primary/50 text-primary bg-transparent' + : 'bg-primary/10 text-primary border border-primary/20', + 'secondary' => $outline + ? 'border border-secondary/50 text-secondary bg-transparent' + : 'bg-secondary/10 text-secondary border border-secondary/20', + 'neutral' => $outline + ? 'border border-neutral/50 text-base/70 bg-transparent' + : 'bg-neutral/10 text-base/70 border border-neutral/20', + default => $outline + ? 'border border-neutral/50 text-base/70 bg-transparent' + : 'bg-neutral/10 text-base/70 border border-neutral/20', + }; + + // Dot color classes + $dotColorClasses = match($variant) { + 'success' => 'bg-success', + 'danger' => 'bg-danger', + 'warning' => 'bg-warning', + 'info' => 'bg-info', + 'primary' => 'bg-primary', + 'secondary' => 'bg-secondary', + 'neutral' => 'bg-base/50', + default => 'bg-base/50', + }; + + // Rounded classes + $roundedClasses = match($rounded) { + 'none' => 'rounded-none', + 'sm' => 'rounded-sm', + 'md' => 'rounded-md', + 'lg' => 'rounded-lg', + 'full' => 'rounded-full', + default => 'rounded-full', + }; + + // Combined classes + $classes = "$baseClasses $sizeClasses $variantClasses $roundedClasses"; +@endphp + +merge(['class' => $classes]) }}> + {{-- Dot indicator --}} + @if($dot) + + @endif + + {{-- Left icon --}} + @if($icon && $iconPosition === 'left') + + @endif + + {{-- Content --}} + {{ $slot }} + + {{-- Right icon --}} + @if($icon && $iconPosition === 'right') + + @endif + + {{-- Remove button --}} + @if($removable) + + @endif + diff --git a/extensions/Servers/Proxmox/views/components/button.blade.php b/extensions/Servers/Proxmox/views/components/button.blade.php new file mode 100644 index 000000000..cb5a8f3a5 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/button.blade.php @@ -0,0 +1,122 @@ +@props([ + 'type' => 'button', + 'variant' => 'primary', + 'size' => 'md', + 'icon' => null, + 'iconPosition' => 'left', + 'iconClass' => null, + 'loading' => false, + 'disabled' => false, + 'fullWidth' => false, + 'href' => null, + 'outline' => false, + 'rounded' => 'lg', +]) + +@php + // Base classes + $baseClasses = 'inline-flex items-center justify-center font-semibold transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed'; + + // Size classes + $sizeClasses = match($size) { + 'xs' => 'px-2 py-1 text-xs gap-1', + 'sm' => 'px-3 py-1.5 text-sm gap-1.5', + 'md' => 'px-4 py-2 text-sm gap-2', + 'lg' => 'px-5 py-2.5 text-base gap-2', + 'xl' => 'px-6 py-3 text-base gap-2.5', + default => 'px-4 py-2 text-sm gap-2', + }; + + // Icon size classes + $iconSizeClasses = $iconClass ?? match($size) { + 'xs' => 'size-3', + 'sm' => 'size-3.5', + 'md' => 'size-4', + 'lg' => 'size-5', + 'xl' => 'size-5', + default => 'size-4', + }; + + // Variant classes + $variantClasses = match($variant) { + 'primary' => $outline + ? 'border-2 border-primary text-primary hover:bg-primary hover:text-white focus:ring-primary/50' + : 'bg-primary text-white hover:bg-primary/90 focus:ring-primary/50', + 'secondary' => $outline + ? 'border-2 border-secondary text-secondary hover:bg-secondary hover:text-white focus:ring-secondary/50' + : 'bg-secondary text-white hover:bg-secondary/90 focus:ring-secondary/50', + 'success' => $outline + ? 'border-2 border-success text-success hover:bg-success hover:text-white focus:ring-success/50' + : 'bg-success text-white hover:bg-success/90 focus:ring-success/50', + 'danger' => $outline + ? 'border-2 border-danger text-danger hover:bg-danger hover:text-white focus:ring-danger/50' + : 'bg-danger text-white hover:bg-danger/90 focus:ring-danger/50', + 'warning' => $outline + ? 'border-2 border-warning text-warning hover:bg-warning hover:text-white focus:ring-warning/50' + : 'bg-warning text-white hover:bg-warning/90 focus:ring-warning/50', + 'info' => $outline + ? 'border-2 border-info text-info hover:bg-info hover:text-white focus:ring-info/50' + : 'bg-info text-white hover:bg-info/90 focus:ring-info/50', + 'ghost' => 'text-base/70 hover:text-base/90 hover:bg-neutral/10 focus:ring-neutral/50', + 'link' => 'text-primary hover:text-primary/80 underline-offset-4 hover:underline focus:ring-primary/50 p-0', + 'neutral' => $outline + ? 'border border-neutral/30 text-base/70 hover:bg-neutral/10 hover:text-base/90 focus:ring-neutral/50' + : 'bg-neutral/10 text-base/80 hover:bg-neutral/20 focus:ring-neutral/50', + default => $outline + ? 'border-2 border-primary text-primary hover:bg-primary hover:text-white focus:ring-primary/50' + : 'bg-primary text-white hover:bg-primary/90 focus:ring-primary/50', + }; + + // Rounded classes + $roundedClasses = match($rounded) { + 'none' => 'rounded-none', + 'sm' => 'rounded-sm', + 'md' => 'rounded-md', + 'lg' => 'rounded-lg', + 'xl' => 'rounded-xl', + 'full' => 'rounded-full', + default => 'rounded-lg', + }; + + // Full width + $widthClasses = $fullWidth ? 'w-full' : ''; + + // Combined classes + $classes = "$baseClasses $sizeClasses $variantClasses $roundedClasses $widthClasses"; + + // Determine tag + $tag = $href ? 'a' : 'button'; +@endphp + +@if($href) + merge(['class' => $classes]) }}> +@else + +@endif diff --git a/extensions/Servers/Proxmox/views/components/card.blade.php b/extensions/Servers/Proxmox/views/components/card.blade.php new file mode 100644 index 000000000..d10f93a51 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/card.blade.php @@ -0,0 +1,87 @@ +@props([ + 'title' => null, + 'subtitle' => null, + 'icon' => null, + 'iconClass' => 'size-5', + 'actions' => null, + 'padding' => true, + 'flush' => false, + 'collapsible' => false, + 'collapsed' => false, + 'storageKey' => null, +]) + +@php + $cardClasses = 'bg-background-secondary rounded-xl border border-neutral/20 shadow-sm'; + $headerClasses = 'flex items-center justify-between gap-4'; + $bodyClasses = $padding ? 'p-5' : ''; + $headerPadding = $flush ? 'px-5 py-4' : ($padding ? 'pb-4' : 'p-5 pb-4'); +@endphp + +
merge(['class' => $cardClasses]) }} + @if($collapsible) + x-data="{ + isCollapsed: {{ $collapsed ? 'true' : 'false' }}, + init() { + @if($storageKey) + this.isCollapsed = localStorage.getItem('{{ $storageKey }}') === 'true'; + @endif + }, + toggle() { + this.isCollapsed = !this.isCollapsed; + @if($storageKey) + localStorage.setItem('{{ $storageKey }}', this.isCollapsed); + @endif + } + }" + @endif +> + @if($title || $icon || $actions || isset($header)) +
+
+ @if($icon) +
+ +
+ @endif +
+ @if($title) +

{{ $title }}

+ @endif + @if($subtitle) +

{{ $subtitle }}

+ @endif +
+
+
+ @if($actions) + {{ $actions }} + @endif + @if($collapsible) + + @endif +
+ @if(isset($header)) + {{ $header }} + @endif +
+ @endif + + @if($collapsible) +
+ {{ $slot }} +
+ @else +
+ {{ $slot }} +
+ @endif + + @if(isset($footer)) +
+ {{ $footer }} +
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/dropdown-divider.blade.php b/extensions/Servers/Proxmox/views/components/dropdown-divider.blade.php new file mode 100644 index 000000000..957514a9f --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/dropdown-divider.blade.php @@ -0,0 +1 @@ +
merge(['class' => 'border-t border-neutral/10 my-1']) }}>
diff --git a/extensions/Servers/Proxmox/views/components/dropdown-item.blade.php b/extensions/Servers/Proxmox/views/components/dropdown-item.blade.php new file mode 100644 index 000000000..8492699ca --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/dropdown-item.blade.php @@ -0,0 +1,41 @@ +@props([ + 'icon' => null, + 'iconClass' => 'size-4', + 'href' => null, + 'active' => false, + 'disabled' => false, + 'danger' => false, +]) + +@php + $tag = $href ? 'a' : 'button'; + + $baseClasses = 'w-full flex items-center gap-3 px-4 py-2.5 text-sm text-left transition-colors'; + + $stateClasses = match(true) { + $disabled => 'opacity-50 cursor-not-allowed text-base/50', + $danger => 'text-danger hover:bg-danger/10', + $active => 'bg-primary/10 text-primary font-medium', + default => 'text-base/80 hover:bg-neutral/10 hover:text-base/90', + }; + + $classes = "$baseClasses $stateClasses"; +@endphp + +@if($href && !$disabled) + merge(['class' => $classes]) }}> +@else + +@endif diff --git a/extensions/Servers/Proxmox/views/components/dropdown.blade.php b/extensions/Servers/Proxmox/views/components/dropdown.blade.php new file mode 100644 index 000000000..0ea180051 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/dropdown.blade.php @@ -0,0 +1,54 @@ +@props([ + 'align' => 'left', + 'width' => '48', + 'contentClasses' => '', +]) + +@php + $alignClasses = match($align) { + 'left' => 'origin-top-left left-0', + 'right' => 'origin-top-right right-0', + 'center' => 'origin-top left-1/2 -translate-x-1/2', + default => 'origin-top-left left-0', + }; + + $widthClasses = match($width) { + '32' => 'w-32', + '40' => 'w-40', + '48' => 'w-48', + '56' => 'w-56', + '64' => 'w-64', + '72' => 'w-72', + 'auto' => 'w-auto', + default => 'w-48', + }; +@endphp + +
merge(['class' => 'relative inline-block']) }} +> + {{-- Trigger --}} +
+ {{ $trigger }} +
+ + {{-- Dropdown content --}} +
+
+ {{ $slot }} +
+
+
diff --git a/extensions/Servers/Proxmox/views/components/empty-state.blade.php b/extensions/Servers/Proxmox/views/components/empty-state.blade.php new file mode 100644 index 000000000..b8afa70b5 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/empty-state.blade.php @@ -0,0 +1,24 @@ +@props([ + 'icon' => 'ri-inbox-line', + 'iconClass' => 'size-12', + 'title' => 'No data found', + 'description' => null, +]) + +
merge(['class' => 'flex flex-col items-center justify-center py-12 px-6 text-center']) }}> +
+ +
+ +

{{ $title }}

+ + @if($description) +

{{ $description }}

+ @endif + + @if($slot->isNotEmpty()) +
+ {{ $slot }} +
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/index.blade.php b/extensions/Servers/Proxmox/views/components/index.blade.php new file mode 100644 index 000000000..1377ffe12 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/index.blade.php @@ -0,0 +1,203 @@ +{{-- + Proxmox UI Components - Index File + + This file documents all available reusable components in the Proxmox views. + Import components using: + + ============================================ + LAYOUT & STRUCTURE + ============================================ + + card.blade.php + --------------- + Generic card wrapper with consistent styling + Props: title, subtitle, icon, iconClass, actions, padding, flush, collapsible, collapsed, storageKey + Slots: default, header, actions, footer + + Example: + + Content here + + + section-header.blade.php + ------------------------ + Page section headers with title, subtitle, actions + Props: title, subtitle, icon, iconClass, helpIcon, helpTitle, helpContent, border + Slots: default, actions, help + + Example: + + + Add Network + + + + ============================================ + DATA DISPLAY + ============================================ + + stat-card.blade.php + ------------------- + Statistics display card with icon, value, label + Props: label, value, icon, iconClass, iconBg, iconColor, trend, trendUp, trendLabel, suffix, prefix, loading, compact, href, clickable + + Example: + + + table.blade.php + table-th.blade.php + table-td.blade.php + table-row.blade.php + -------------------------------------------------------------------------------- + Styled table components + + Example: + + + Name + Value + + + + Item 1 + 100 + + + + + info-list.blade.php + info-row.blade.php + ---------------------------------------- + Key-value information display + + Example: + + + + Running + + + + progress.blade.php + ------------------ + Progress bar component + Props: value, max, size, variant, label, showValue, animated, striped + + Example: + + + empty-state.blade.php + --------------------- + Empty state placeholder + Props: icon, iconClass, title, description + + Example: + + Create Backup + + + ============================================ + INTERACTIVE ELEMENTS + ============================================ + + button.blade.php + ---------------- + Consistent button styling + Props: type, variant (primary|secondary|success|danger|warning|info|ghost|link|neutral), size (xs|sm|md|lg|xl), icon, iconPosition, iconClass, loading, disabled, fullWidth, href, outline, rounded + + Example: + Start Server + Stop + + badge.blade.php + --------------- + Status badges + Props: variant (success|danger|warning|info|primary|secondary|neutral), size, rounded, dot, pulse, icon, iconPosition, removable, outline + + Example: + Running + Error + + modal.blade.php + --------------- + Modal dialog component + Props: name, show, maxWidth, closeable, title, subtitle, icon, iconClass, iconBg, iconColor, blur, centered + Slots: default, header, footer + + Example: + +

Are you sure you want to delete this item?

+ + Cancel + Delete + +
+ + dropdown.blade.php + dropdown-item.blade.php + dropdown-divider.blade.php + ------------------------------------------------------------------------- + Dropdown menu components + + Example: + + + + + Edit + Duplicate + + Delete + + + tabs.blade.php + tab-panel.blade.php + ------------------------------------ + Tab navigation component + + Example: + + General content + Advanced content + + + input.blade.php + --------------- + Form input component + Props: label, id, name, type, placeholder, hint, error, required, disabled, readonly, prefix, suffix, icon, iconPosition, size + + Example: + + + ============================================ + FEEDBACK + ============================================ + + alert.blade.php + --------------- + Alert/notification component + Props: variant (success|danger|warning|info|neutral), title, icon, dismissible, collapsible, collapsed, storageKey, border + Slots: default, actions + + Example: + + Scheduled maintenance will occur on Sunday at 2:00 AM. + + + spinner.blade.php + ----------------- + Loading spinner + Props: size, variant + + Example: + + +--}} diff --git a/extensions/Servers/Proxmox/views/components/info-list.blade.php b/extensions/Servers/Proxmox/views/components/info-list.blade.php new file mode 100644 index 000000000..0555c4eff --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/info-list.blade.php @@ -0,0 +1,19 @@ +@props([ + 'title' => null, + 'count' => null, +]) + +
merge(['class' => 'divide-y divide-neutral/10']) }}> + @if($title || $count !== null) +
+ @if($title) +

{{ $title }}

+ @endif + @if($count !== null) + {{ $count }} items + @endif +
+ @endif + + {{ $slot }} +
diff --git a/extensions/Servers/Proxmox/views/components/info-row.blade.php b/extensions/Servers/Proxmox/views/components/info-row.blade.php new file mode 100644 index 000000000..c5a9fff26 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/info-row.blade.php @@ -0,0 +1,55 @@ +@props([ + 'label' => null, + 'value' => null, + 'icon' => null, + 'iconClass' => 'size-4', + 'mono' => false, + 'copyable' => false, + 'truncate' => false, + 'href' => null, + 'vertical' => false, +]) + +@php + $valueClasses = 'text-base/90'; + if ($mono) $valueClasses .= ' font-mono text-sm'; + if ($truncate) $valueClasses .= ' truncate'; +@endphp + +
merge(['class' => $vertical ? 'flex flex-col gap-1' : 'flex items-center justify-between gap-4 py-2']) }}> + {{-- Label --}} +
+ @if($icon) + + @endif + {{ $label }} +
+ + {{-- Value --}} +
+ @if($href) + + {{ $value ?? $slot }} + + @else + {{ $value ?? $slot }} + @endif + + @if($copyable && ($value || $slot->isNotEmpty())) + + @endif +
+
diff --git a/extensions/Servers/Proxmox/views/components/input.blade.php b/extensions/Servers/Proxmox/views/components/input.blade.php new file mode 100644 index 000000000..8aaedd821 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/input.blade.php @@ -0,0 +1,116 @@ +@props([ + 'label' => null, + 'id' => null, + 'name' => null, + 'type' => 'text', + 'placeholder' => null, + 'hint' => null, + 'error' => null, + 'required' => false, + 'disabled' => false, + 'readonly' => false, + 'prefix' => null, + 'suffix' => null, + 'icon' => null, + 'iconPosition' => 'left', + 'size' => 'md', +]) + +@php + $inputId = $id ?? $name ?? Str::random(8); + + // Size classes + $sizeClasses = match($size) { + 'sm' => 'px-3 py-1.5 text-sm', + 'md' => 'px-4 py-2 text-sm', + 'lg' => 'px-4 py-2.5 text-base', + default => 'px-4 py-2 text-sm', + }; + + $iconSizeClasses = match($size) { + 'sm' => 'size-4', + 'md' => 'size-4', + 'lg' => 'size-5', + default => 'size-4', + }; + + // Input base classes + $baseClasses = 'w-full bg-background border rounded-lg transition-all duration-200 outline-none'; + $focusClasses = 'focus:ring-2 focus:ring-primary/20 focus:border-primary'; + $disabledClasses = $disabled ? 'opacity-50 cursor-not-allowed bg-neutral/5' : ''; + $errorClasses = $error ? 'border-danger focus:ring-danger/20 focus:border-danger' : 'border-neutral/30'; + + // Padding adjustments for icons/affixes + $paddingLeft = ($icon && $iconPosition === 'left') || $prefix ? 'pl-10' : ''; + $paddingRight = ($icon && $iconPosition === 'right') || $suffix ? 'pr-10' : ''; + + $inputClasses = "$baseClasses $sizeClasses $focusClasses $disabledClasses $errorClasses $paddingLeft $paddingRight"; +@endphp + +
only('class')->merge(['class' => 'flex flex-col gap-1.5']) }}> + {{-- Label --}} + @if($label) + + @endif + + {{-- Input wrapper --}} +
+ {{-- Left icon --}} + @if($icon && $iconPosition === 'left') +
+ +
+ @endif + + {{-- Prefix --}} + @if($prefix) +
+ {{ $prefix }} +
+ @endif + + {{-- Input --}} + except('class')->merge(['class' => $inputClasses]) }} + > + + {{-- Right icon --}} + @if($icon && $iconPosition === 'right') +
+ +
+ @endif + + {{-- Suffix --}} + @if($suffix) +
+ {{ $suffix }} +
+ @endif +
+ + {{-- Hint text --}} + @if($hint && !$error) +

{{ $hint }}

+ @endif + + {{-- Error message --}} + @if($error) +

+ + {{ $error }} +

+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/modal.blade.php b/extensions/Servers/Proxmox/views/components/modal.blade.php new file mode 100644 index 000000000..3dc526b01 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/modal.blade.php @@ -0,0 +1,139 @@ +@props([ + 'name' => null, + 'show' => false, + 'maxWidth' => 'lg', + 'closeable' => true, + 'title' => null, + 'subtitle' => null, + 'icon' => null, + 'iconClass' => 'size-5', + 'iconBg' => 'bg-primary/10', + 'iconColor' => 'text-primary', + 'blur' => true, + 'centered' => true, +]) + +@php + $maxWidthClasses = match($maxWidth) { + 'xs' => 'max-w-xs', + 'sm' => 'max-w-sm', + 'md' => 'max-w-md', + 'lg' => 'max-w-lg', + 'xl' => 'max-w-xl', + '2xl' => 'max-w-2xl', + '3xl' => 'max-w-3xl', + '4xl' => 'max-w-4xl', + '5xl' => 'max-w-5xl', + 'full' => 'max-w-full mx-4', + default => 'max-w-lg', + }; + + $backdropClasses = $blur ? 'bg-black/50 backdrop-blur-sm' : 'bg-black/50'; + $positionClasses = $centered ? 'items-center' : 'items-start pt-20'; +@endphp + +
+ {{-- Backdrop --}} +
+ + {{-- Modal Container --}} +
+
+ {{-- Close button --}} + @if($closeable) + + @endif + + {{-- Header --}} + @if($title || $icon || isset($header)) +
+ @if(isset($header)) + {{ $header }} + @else +
+ @if($icon) +
+ +
+ @endif +
+ @if($title) +

{{ $title }}

+ @endif + @if($subtitle) +

{{ $subtitle }}

+ @endif +
+
+ @endif +
+ @endif + + {{-- Body --}} +
+ {{ $slot }} +
+ + {{-- Footer --}} + @if(isset($footer)) +
+ {{ $footer }} +
+ @endif +
+
+
diff --git a/extensions/Servers/Proxmox/views/components/progress.blade.php b/extensions/Servers/Proxmox/views/components/progress.blade.php new file mode 100644 index 000000000..584afaace --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/progress.blade.php @@ -0,0 +1,102 @@ +@props([ + 'value' => 0, + 'max' => 100, + 'size' => 'md', + 'variant' => 'primary', + 'label' => null, + 'showValue' => false, + 'animated' => false, + 'striped' => false, +]) + +@php + $percentage = $max > 0 ? min(100, ($value / $max) * 100) : 0; + + // Size classes + $sizeClasses = match($size) { + 'xs' => 'h-1', + 'sm' => 'h-2', + 'md' => 'h-3', + 'lg' => 'h-4', + 'xl' => 'h-5', + default => 'h-3', + }; + + // Variant classes for the fill + $variantClasses = match($variant) { + 'primary' => 'bg-primary', + 'secondary' => 'bg-secondary', + 'success' => 'bg-success', + 'danger' => 'bg-danger', + 'warning' => 'bg-warning', + 'info' => 'bg-info', + 'gradient' => 'bg-gradient-to-r from-primary to-secondary', + default => 'bg-primary', + }; + + // Dynamic color based on percentage + if ($variant === 'auto') { + if ($percentage >= 90) { + $variantClasses = 'bg-danger'; + } elseif ($percentage >= 70) { + $variantClasses = 'bg-warning'; + } else { + $variantClasses = 'bg-success'; + } + } + + // Animation classes + $animationClasses = $animated ? 'transition-all duration-500 ease-out' : ''; + $stripedClasses = $striped ? 'bg-stripes' : ''; +@endphp + +
merge(['class' => 'flex flex-col gap-1.5']) }}> + {{-- Label and value row --}} + @if($label || $showValue) +
+ @if($label) + {{ $label }} + @endif + @if($showValue) + {{ number_format($percentage, 1) }}% + @endif +
+ @endif + + {{-- Progress bar container --}} +
+ {{-- Progress bar fill --}} +
+
+
+ +@once + +@endonce diff --git a/extensions/Servers/Proxmox/views/components/section-header.blade.php b/extensions/Servers/Proxmox/views/components/section-header.blade.php new file mode 100644 index 000000000..6d0b94fe9 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/section-header.blade.php @@ -0,0 +1,115 @@ +@props([ + 'title' => null, + 'subtitle' => null, + 'icon' => null, + 'iconClass' => 'size-5', + 'helpIcon' => false, + 'helpTitle' => null, + 'helpContent' => null, + 'border' => false, +]) + +@php + $containerClasses = 'flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4'; + if ($border) { + $containerClasses .= ' pb-4 border-b border-neutral/10'; + } +@endphp + +
merge(['class' => $containerClasses]) }}> +
+
+ @if($icon) +
+ +
+ @endif + + @if($title) +

{{ $title }}

+ @endif + + {{-- Help modal trigger --}} + @if($helpIcon || $helpContent) +
+ + + {{-- Modal Backdrop --}} + + + {{-- Modal --}} + +
+ @endif +
+ + @if($subtitle) +

{{ $subtitle }}

+ @endif +
+ + {{-- Actions slot --}} + @if(isset($actions)) +
+ {{ $actions }} +
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/spinner.blade.php b/extensions/Servers/Proxmox/views/components/spinner.blade.php new file mode 100644 index 000000000..d293b1d8b --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/spinner.blade.php @@ -0,0 +1,27 @@ +@props([ + 'size' => 'md', + 'variant' => 'primary', +]) + +@php + $sizeClasses = match($size) { + 'xs' => 'h-4 w-4 border-2', + 'sm' => 'h-5 w-5 border-2', + 'md' => 'h-8 w-8 border-2', + 'lg' => 'h-12 w-12 border-3', + 'xl' => 'h-16 w-16 border-4', + default => 'h-8 w-8 border-2', + }; + + $colorClasses = match($variant) { + 'primary' => 'border-primary', + 'secondary' => 'border-secondary', + 'white' => 'border-white', + 'neutral' => 'border-base/50', + default => 'border-primary', + }; +@endphp + +
merge(['class' => 'flex items-center justify-center']) }}> +
+
diff --git a/extensions/Servers/Proxmox/views/components/stat-card.blade.php b/extensions/Servers/Proxmox/views/components/stat-card.blade.php new file mode 100644 index 000000000..f271b46aa --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/stat-card.blade.php @@ -0,0 +1,104 @@ +@props([ + 'label' => '', + 'value' => '', + 'icon' => null, + 'iconClass' => 'size-5', + 'iconBg' => 'bg-primary/10', + 'iconColor' => 'text-primary', + 'trend' => null, + 'trendUp' => null, + 'trendLabel' => null, + 'suffix' => null, + 'prefix' => null, + 'loading' => false, + 'compact' => false, + 'href' => null, + 'clickable' => false, +]) + +@php + $cardClasses = 'bg-background-secondary rounded-xl border border-neutral/20 shadow-sm transition-all duration-200'; + if ($href || $clickable) { + $cardClasses .= ' hover:shadow-md hover:border-primary/30 cursor-pointer'; + } + $paddingClasses = $compact ? 'p-4' : 'p-5'; + + // Determine trend styling + $trendClasses = ''; + $trendIcon = null; + if ($trendUp === true) { + $trendClasses = 'text-success'; + $trendIcon = 'ri-arrow-up-line'; + } elseif ($trendUp === false) { + $trendClasses = 'text-danger'; + $trendIcon = 'ri-arrow-down-line'; + } else { + $trendClasses = 'text-base/50'; + $trendIcon = 'ri-subtract-line'; + } +@endphp + +@if($href) + merge(['class' => $cardClasses . ' ' . $paddingClasses . ' block']) }}> +@else + +@endif diff --git a/extensions/Servers/Proxmox/views/components/tab-panel.blade.php b/extensions/Servers/Proxmox/views/components/tab-panel.blade.php new file mode 100644 index 000000000..df15acdc4 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/tab-panel.blade.php @@ -0,0 +1,16 @@ +@props([ + 'id', +]) + +
merge(['class' => 'mt-4']) }} +> + {{ $slot }} +
diff --git a/extensions/Servers/Proxmox/views/components/table-row.blade.php b/extensions/Servers/Proxmox/views/components/table-row.blade.php new file mode 100644 index 000000000..74a7c21c2 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/table-row.blade.php @@ -0,0 +1,26 @@ +@props([ + 'hoverable' => true, + 'clickable' => false, + 'selected' => false, + 'striped' => false, +]) + +@php + $classes = ''; + + if ($hoverable) { + $classes .= ' hover:bg-neutral/5 transition-colors'; + } + + if ($clickable) { + $classes .= ' cursor-pointer'; + } + + if ($selected) { + $classes .= ' bg-primary/5 border-l-2 border-l-primary'; + } +@endphp + +merge(['class' => trim($classes)]) }}> + {{ $slot }} + diff --git a/extensions/Servers/Proxmox/views/components/table-td.blade.php b/extensions/Servers/Proxmox/views/components/table-td.blade.php new file mode 100644 index 000000000..9bf398dd8 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/table-td.blade.php @@ -0,0 +1,22 @@ +@props([ + 'align' => 'left', + 'compact' => false, + 'truncate' => false, + 'mono' => false, +]) + +@php + $paddingClasses = $compact ? 'px-3 py-2' : 'px-5 py-4'; + $alignClasses = match($align) { + 'center' => 'text-center', + 'right' => 'text-right', + default => 'text-left', + }; + $textClasses = $mono ? 'font-mono text-sm' : 'text-sm'; + $truncateClasses = $truncate ? 'truncate max-w-xs' : ''; + $tdClasses = "$paddingClasses $alignClasses $textClasses $truncateClasses text-base/80"; +@endphp + +merge(['class' => $tdClasses]) }}> + {{ $slot }} + diff --git a/extensions/Servers/Proxmox/views/components/table-th.blade.php b/extensions/Servers/Proxmox/views/components/table-th.blade.php new file mode 100644 index 000000000..3276e8c48 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/table-th.blade.php @@ -0,0 +1,42 @@ +@props([ + 'sortable' => false, + 'sorted' => null, + 'sortKey' => null, + 'align' => 'left', + 'compact' => false, +]) + +@php + $paddingClasses = $compact ? 'px-3 py-2' : 'px-5 py-3'; + $alignClasses = match($align) { + 'center' => 'text-center', + 'right' => 'text-right', + default => 'text-left', + }; + $thClasses = "$paddingClasses $alignClasses text-xs font-semibold text-base/70 uppercase tracking-wider"; +@endphp + +merge(['class' => $thClasses]) }}> + @if($sortable) + + @else + {{ $slot }} + @endif + diff --git a/extensions/Servers/Proxmox/views/components/table.blade.php b/extensions/Servers/Proxmox/views/components/table.blade.php new file mode 100644 index 000000000..be00089ac --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/table.blade.php @@ -0,0 +1,67 @@ +@props([ + 'striped' => false, + 'hoverable' => true, + 'compact' => false, + 'responsive' => true, + 'stickyHeader' => false, + 'emptyMessage' => 'No data available', + 'emptyIcon' => 'ri-inbox-line', + 'loading' => false, +]) + +@php + $tableClasses = 'w-full text-left'; + $wrapperClasses = 'bg-background-secondary rounded-xl border border-neutral/20 shadow-sm overflow-hidden'; + + if ($responsive) { + $wrapperClasses .= ' overflow-x-auto'; + } +@endphp + +
merge(['class' => $wrapperClasses]) }}> + @if($loading) +
+
+

Loading data...

+
+ @else + + @if(isset($head)) + + + {{ $head }} + + + @endif + + @if(isset($body) && $body->isNotEmpty()) + + {{ $body }} + + @elseif($slot->isNotEmpty()) + + {{ $slot }} + + @else + + + + + + @endif + + @if(isset($foot)) + + {{ $foot }} + + @endif +
+
+
+ +
+

{{ $emptyMessage }}

+
+
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/tabs.blade.php b/extensions/Servers/Proxmox/views/components/tabs.blade.php new file mode 100644 index 000000000..b8d33c9df --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/tabs.blade.php @@ -0,0 +1,41 @@ +@props([ + 'items' => [], + 'vertical' => false, + 'gap' => '2', +]) + +@php + $containerClasses = $vertical + ? "flex flex-col gap-{$gap}" + : "inline-flex items-center rounded-lg border border-neutral/30 bg-background p-1 gap-1"; +@endphp + +
merge(['class' => $containerClasses]) }} +> + {{-- Tab buttons --}} +
+ @foreach($items as $item) + + @endforeach +
+ + {{-- Tab content --}} + {{ $slot }} +
diff --git a/extensions/Servers/Proxmox/views/components/ui/action-button.blade.php b/extensions/Servers/Proxmox/views/components/ui/action-button.blade.php new file mode 100644 index 000000000..9df746114 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/action-button.blade.php @@ -0,0 +1,72 @@ +{{-- + Action Toolbar Button Component - TailServer Theme + Individual button for VM control actions + + Usage: + +--}} + +@props([ + 'action' => null, + 'icon' => null, + 'label', + 'variant' => 'default', // default, danger, warning, success + 'disabled' => false, + 'loading' => false, + 'confirm' => null, + 'size' => 'md', // sm, md, lg +]) + +@php + $variants = [ + 'default' => 'bg-gradient-to-b from-neutral/5 to-neutral/10 hover:from-neutral/10 hover:to-neutral/15 text-base border border-neutral/20 hover:border-neutral/30 shadow-sm hover:shadow', + 'primary' => 'bg-gradient-to-b from-primary/10 to-primary/15 hover:from-primary/15 hover:to-primary/20 text-primary border border-primary/20 hover:border-primary/30 shadow-sm hover:shadow-md hover:shadow-primary/10', + 'success' => 'bg-gradient-to-b from-success/10 to-success/15 hover:from-success/15 hover:to-success/20 text-success border border-success/20 hover:border-success/30 shadow-sm hover:shadow-md hover:shadow-success/10', + 'warning' => 'bg-gradient-to-b from-warning/10 to-warning/15 hover:from-warning/15 hover:to-warning/20 text-warning border border-warning/20 hover:border-warning/30 shadow-sm hover:shadow-md hover:shadow-warning/10', + 'danger' => 'bg-gradient-to-b from-danger/10 to-danger/15 hover:from-danger/15 hover:to-danger/20 text-danger border border-danger/20 hover:border-danger/30 shadow-sm hover:shadow-md hover:shadow-danger/10', + ]; + + $sizes = [ + 'sm' => 'px-2.5 py-1.5 text-xs', + 'md' => 'px-3.5 py-2 text-sm', + 'lg' => 'px-5 py-2.5 text-base', + ]; + + $iconSizes = [ + 'sm' => 'size-3.5', + 'md' => 'size-4', + 'lg' => 'size-5', + ]; +@endphp + + diff --git a/extensions/Servers/Proxmox/views/components/ui/action-toolbar.blade.php b/extensions/Servers/Proxmox/views/components/ui/action-toolbar.blade.php new file mode 100644 index 000000000..6ee000e25 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/action-toolbar.blade.php @@ -0,0 +1,25 @@ +{{-- + Action Toolbar Component - TailServer Theme + For VM control buttons (Start, Stop, Restart, etc.) + + Usage: + + + +--}} + +@props([ + 'centered' => false, +]) + +
class([ + 'flex flex-wrap gap-2.5', + 'justify-center' => $centered, + 'justify-start' => !$centered, +]) }}> + {{ $slot }} +
diff --git a/extensions/Servers/Proxmox/views/components/ui/alert.blade.php b/extensions/Servers/Proxmox/views/components/ui/alert.blade.php new file mode 100644 index 000000000..945fbb7fb --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/alert.blade.php @@ -0,0 +1,120 @@ +{{-- + Alert Component - TailServer Theme + + Usage: + Default alert + Operation completed + Warning message +--}} + +@props([ + 'variant' => 'info', + 'title' => null, + 'icon' => null, + 'dismissible' => false, + 'collapsible' => false, + 'collapsed' => false, +]) + +@php + $variantConfig = [ + 'info' => [ + 'bg' => 'bg-gradient-to-r from-info/10 via-info/5 to-transparent', + 'border' => 'border-info/20', + 'text' => 'text-info', + 'icon' => $icon ?? 'ri-information-line', + ], + 'success' => [ + 'bg' => 'bg-gradient-to-r from-success/10 via-success/5 to-transparent', + 'border' => 'border-success/20', + 'text' => 'text-success', + 'icon' => $icon ?? 'ri-checkbox-circle-line', + ], + 'warning' => [ + 'bg' => 'bg-gradient-to-r from-warning/10 via-warning/5 to-transparent', + 'border' => 'border-warning/20', + 'text' => 'text-warning', + 'icon' => $icon ?? 'ri-error-warning-line', + ], + 'danger' => [ + 'bg' => 'bg-gradient-to-r from-danger/10 via-danger/5 to-transparent', + 'border' => 'border-danger/20', + 'text' => 'text-danger', + 'icon' => $icon ?? 'ri-error-warning-fill', + ], + 'default' => [ + 'bg' => 'bg-gradient-to-r from-neutral/10 via-neutral/5 to-transparent', + 'border' => 'border-neutral/20', + 'text' => 'text-base/70', + 'icon' => $icon ?? 'ri-information-line', + ], + ]; + + $config = $variantConfig[$variant] ?? $variantConfig['default']; +@endphp + +
class([ + 'rounded-xl p-4 border', + $config['bg'], + $config['border'], + ]) }} + @if($dismissible || $collapsible) + x-data="{ + show: true, + @if($collapsible) collapsed: {{ $collapsed ? 'true' : 'false' }} @endif + }" + x-show="show" + x-transition:enter="transition ease-out duration-300" + x-transition:enter-start="opacity-0 scale-95" + x-transition:enter-end="opacity-100 scale-100" + x-transition:leave="transition ease-in duration-200" + x-transition:leave-start="opacity-100 scale-100" + x-transition:leave-end="opacity-0 scale-95" + @endif +> +
+ +
+
+ @if($title) +

{{ $title }}

+ @endif +
+ @if($collapsible) + + @endif + @if($dismissible) + + @endif +
+
+
+ {{ $slot }} +
+
+
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/allocation-card.blade.php b/extensions/Servers/Proxmox/views/components/ui/allocation-card.blade.php new file mode 100644 index 000000000..09ae20d2e --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/allocation-card.blade.php @@ -0,0 +1,73 @@ +{{-- + Resource Allocation Card Component - TailServer Theme + For displaying CPU, Memory, and other resource allocation vs entitlement + + Usage: + +--}} + +@props([ + 'label', + 'percent' => null, + 'usageSummary', + 'entitlementLabel', + 'description' => null, + 'gradient' => 'linear-gradient(90deg, #6366f1 0%, #8b5cf6 100%)', + 'badge' => null, + 'icon' => null, + 'iconColor' => 'text-primary', +]) + +
class(['group relative border border-neutral/20 rounded-xl p-4 bg-background hover:border-neutral/30 hover:shadow-sm transition-all duration-200']) }}> + {{-- Subtle gradient overlay on hover --}} +
+ +
+
+
+ @if($icon) +
+ +
+ @endif +
+

{{ $label }}

+

{{ $usageSummary }}

+

{{ $entitlementLabel }}

+
+
+ @if($badge) + + {{ $badge['label'] ?? '' }} + + @endif +
+ + @if(!is_null($percent)) +
+
+ Usage + {{ $percent }}% +
+
+
+
+
+ @endif + + @if($description) +

{{ $description }}

+ @endif +
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/badge.blade.php b/extensions/Servers/Proxmox/views/components/ui/badge.blade.php new file mode 100644 index 000000000..c05cf0fe4 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/badge.blade.php @@ -0,0 +1,78 @@ +{{-- + Badge Component - TailServer Theme + + Usage: + Default + Running + Error + Active +--}} + +@props([ + 'variant' => 'default', + 'size' => 'md', + 'icon' => null, + 'dot' => false, + 'pulse' => false, + 'outline' => false, +]) + +@php + $baseClasses = 'inline-flex items-center font-semibold rounded-full transition-colors'; + + $variantClasses = [ + 'default' => $outline ? 'bg-transparent border border-neutral/30 text-base/70' : 'bg-neutral/10 text-base/70', + 'primary' => $outline ? 'bg-transparent border border-primary/40 text-primary' : 'bg-primary/10 text-primary', + 'secondary' => $outline ? 'bg-transparent border border-secondary/40 text-secondary' : 'bg-secondary/10 text-secondary', + 'success' => $outline ? 'bg-transparent border border-success/40 text-success' : 'bg-success/10 text-success', + 'warning' => $outline ? 'bg-transparent border border-warning/40 text-warning' : 'bg-warning/10 text-warning', + 'danger' => $outline ? 'bg-transparent border border-danger/40 text-danger' : 'bg-danger/10 text-danger', + 'info' => $outline ? 'bg-transparent border border-info/40 text-info' : 'bg-info/10 text-info', + 'muted' => 'bg-neutral/5 text-base/40', + ]; + + $sizeClasses = [ + 'xs' => 'px-1.5 py-0.5 text-[10px] leading-tight', + 'sm' => 'px-2 py-0.5 text-[11px] leading-tight', + 'md' => 'px-2.5 py-1 text-xs', + 'lg' => 'px-3 py-1.5 text-sm', + ]; + + $iconSizes = [ + 'xs' => 'size-2.5', + 'sm' => 'size-3', + 'md' => 'size-3.5', + 'lg' => 'size-4', + ]; + + $dotSizes = [ + 'xs' => 'size-1', + 'sm' => 'size-1.5', + 'md' => 'size-1.5', + 'lg' => 'size-2', + ]; + + $classes = collect([ + $baseClasses, + $variantClasses[$variant] ?? $variantClasses['default'], + $sizeClasses[$size] ?? $sizeClasses['md'], + ])->filter()->join(' '); + + $iconSize = $iconSizes[$size] ?? $iconSizes['md']; + $dotSize = $dotSizes[$size] ?? $dotSizes['md']; +@endphp + +class([$classes, 'gap-1.5' => $icon || $dot]) }}> + @if($dot) + + @if($pulse) + + @endif + + + @endif + @if($icon) + + @endif + {{ $slot }} + diff --git a/extensions/Servers/Proxmox/views/components/ui/button.blade.php b/extensions/Servers/Proxmox/views/components/ui/button.blade.php new file mode 100644 index 000000000..48da8425f --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/button.blade.php @@ -0,0 +1,92 @@ +{{-- + Button Component - TailServer Theme + + Usage: + Click me + Add Server + Delete + Processing +--}} + +@props([ + 'variant' => 'secondary', + 'size' => 'md', + 'icon' => null, + 'iconRight' => null, + 'loading' => false, + 'loadingText' => null, + 'disabled' => false, + 'href' => null, + 'type' => 'button', + 'full' => false, +]) + +@php + $tag = $href ? 'a' : 'button'; + + $baseClasses = 'group relative inline-flex items-center justify-center gap-2 rounded-lg font-semibold transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-background disabled:opacity-50 disabled:cursor-not-allowed overflow-hidden'; + + $variantClasses = [ + 'primary' => 'bg-primary text-white border border-primary hover:bg-primary/90 hover:shadow-md hover:shadow-primary/20 active:scale-[0.98] focus:ring-primary/50', + 'secondary' => 'bg-background-secondary text-base border border-neutral/30 hover:bg-background-secondary/80 hover:border-neutral/50 active:scale-[0.98] focus:ring-neutral/30', + 'outline' => 'bg-transparent text-base border border-neutral/30 hover:bg-neutral/10 hover:border-neutral/50 focus:ring-neutral/30', + 'ghost' => 'bg-transparent text-base hover:bg-neutral/10 focus:ring-neutral/20', + 'danger' => 'bg-danger text-white border border-danger hover:bg-danger/90 hover:shadow-md hover:shadow-danger/20 active:scale-[0.98] focus:ring-danger/50', + 'success' => 'bg-success text-white border border-success hover:bg-success/90 hover:shadow-md hover:shadow-success/20 active:scale-[0.98] focus:ring-success/50', + 'warning' => 'bg-warning text-white border border-warning hover:bg-warning/90 hover:shadow-md hover:shadow-warning/20 active:scale-[0.98] focus:ring-warning/50', + 'info' => 'bg-info text-white border border-info hover:bg-info/90 hover:shadow-md hover:shadow-info/20 active:scale-[0.98] focus:ring-info/50', + ]; + + $sizeClasses = [ + 'xs' => 'px-2 py-1 text-xs', + 'sm' => 'px-2.5 py-1.5 text-sm', + 'md' => 'px-3.5 py-2 text-sm', + 'lg' => 'px-4 py-2.5 text-base', + 'xl' => 'px-5 py-3 text-lg', + ]; + + $iconSizes = [ + 'xs' => 'size-3', + 'sm' => 'size-3.5', + 'md' => 'size-4', + 'lg' => 'size-5', + 'xl' => 'size-6', + ]; + + $classes = collect([ + $baseClasses, + $variantClasses[$variant] ?? $variantClasses['secondary'], + $sizeClasses[$size] ?? $sizeClasses['md'], + $full ? 'w-full' : '', + ])->filter()->join(' '); + + $iconSize = $iconSizes[$size] ?? $iconSizes['md']; +@endphp + +<{{ $tag }} + @if($href) href="{{ $href }}" @endif + @if($tag === 'button') type="{{ $type }}" @endif + @if($disabled || $loading) disabled @endif + {{ $attributes->class([$classes]) }} +> + {{-- Subtle shine effect on hover --}} + + + + @if($loading) + + + + + {{ $loadingText ?? $slot }} + @else + @if($icon) + + @endif + {{ $slot }} + @if($iconRight) + + @endif + @endif + + diff --git a/extensions/Servers/Proxmox/views/components/ui/card.blade.php b/extensions/Servers/Proxmox/views/components/ui/card.blade.php new file mode 100644 index 000000000..004c0e312 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/card.blade.php @@ -0,0 +1,103 @@ +{{-- + Card Component - TailServer Theme + + Usage: + Content + Content + Content +--}} + +@props([ + 'title' => null, + 'subtitle' => null, + 'icon' => null, + 'iconColor' => 'text-primary', + 'actions' => null, + 'footer' => null, + 'footerClass' => '', + 'padding' => true, + 'hover' => false, + 'clickable' => false, + 'collapsible' => false, + 'collapsed' => false, +]) + +@php + $cardClasses = 'relative flex flex-col rounded-xl border border-neutral/20 bg-background-secondary shadow-sm'; + if ($hover) { + $cardClasses .= ' hover:bg-background-secondary/90 hover:border-neutral/30 hover:shadow-md transition-all duration-200'; + } + if ($clickable) { + $cardClasses .= ' cursor-pointer'; + } +@endphp + +
class([$cardClasses]) }} + @if($collapsible) + x-data="{ isCollapsed: {{ $collapsed ? 'true' : 'false' }} }" + @endif +> + {{-- Subtle gradient overlay for depth --}} +
+ @if($title || $actions) +
+
+ @if($icon) +
+ +
+ @endif +
+ @if($title) +

{{ $title }}

+ @endif + @if($subtitle) +

{{ $subtitle }}

+ @endif +
+
+
+ @if($actions) + {{ $actions }} + @endif + @if($collapsible) + + @endif +
+
+ @endif + +
$padding, + ]) + @if($collapsible) + x-show="!isCollapsed" + x-transition:enter="transition ease-out duration-200" + x-transition:enter-start="opacity-0 -translate-y-2" + x-transition:enter-end="opacity-100 translate-y-0" + x-transition:leave="transition ease-in duration-150" + x-transition:leave-start="opacity-100 translate-y-0" + x-transition:leave-end="opacity-0 -translate-y-2" + @endif + > + {{ $slot }} +
+ + @if($footer) +
+ {{ $footer }} +
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/ui/confirm-dialog.blade.php b/extensions/Servers/Proxmox/views/components/ui/confirm-dialog.blade.php new file mode 100644 index 000000000..9307da4bd --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/confirm-dialog.blade.php @@ -0,0 +1,116 @@ +{{-- + Confirm Dialog Component - TailServer Theme + For dangerous actions like delete, stop, etc. + + Usage: + +--}} + +@props([ + 'title' => 'Confirm Action', + 'message' => 'Are you sure you want to proceed?', + 'confirmLabel' => 'Confirm', + 'cancelLabel' => 'Cancel', + 'variant' => 'danger', // danger, warning, primary + 'open' => false, +]) + +@php + $variants = [ + 'danger' => [ + 'icon' => 'ri-error-warning-line', + 'iconBg' => 'bg-danger/10', + 'iconColor' => 'text-danger', + 'buttonBg' => 'bg-danger hover:bg-danger/90', + ], + 'warning' => [ + 'icon' => 'ri-alert-line', + 'iconBg' => 'bg-warning/10', + 'iconColor' => 'text-warning', + 'buttonBg' => 'bg-warning hover:bg-warning/90', + ], + 'primary' => [ + 'icon' => 'ri-question-line', + 'iconBg' => 'bg-primary/10', + 'iconColor' => 'text-primary', + 'buttonBg' => 'bg-primary hover:bg-primary/90', + ], + ]; + + $config = $variants[$variant] ?? $variants['danger']; +@endphp + +
whereDoesntStartWith('wire:click') }} +> +
+ +
+ + +
+
+ +
+ +
+ + +

{{ $title }}

+ + +

{{ $message }}

+ + +
+ + +
+
+
+
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/copy-button.blade.php b/extensions/Servers/Proxmox/views/components/ui/copy-button.blade.php new file mode 100644 index 000000000..673c25f8b --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/copy-button.blade.php @@ -0,0 +1,35 @@ +{{-- + Copy Button Component - TailServer Theme + Small inline button to copy text to clipboard + + Usage: + +--}} + +@props([ + 'value', +]) + +
+ +
diff --git a/extensions/Servers/Proxmox/views/components/ui/copyable.blade.php b/extensions/Servers/Proxmox/views/components/ui/copyable.blade.php new file mode 100644 index 000000000..152f5eb9a --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/copyable.blade.php @@ -0,0 +1,56 @@ +{{-- + Copyable Text Component - TailServer Theme + Text field with copy to clipboard functionality + + Usage: + +--}} + +@props([ + 'label' => null, + 'value', + 'masked' => false, +]) + +
+ @if($label) + + @endif +
+ @if($masked) + + + @else + {{ $value }} + @endif + +
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/dropdown-divider.blade.php b/extensions/Servers/Proxmox/views/components/ui/dropdown-divider.blade.php new file mode 100644 index 000000000..3e362f41a --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/dropdown-divider.blade.php @@ -0,0 +1,5 @@ +{{-- + Dropdown Divider Component - TailServer Theme +--}} + +
diff --git a/extensions/Servers/Proxmox/views/components/ui/dropdown-item.blade.php b/extensions/Servers/Proxmox/views/components/ui/dropdown-item.blade.php new file mode 100644 index 000000000..08d46e43f --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/dropdown-item.blade.php @@ -0,0 +1,38 @@ +{{-- + Dropdown Item Component - TailServer Theme +--}} + +@props([ + 'href' => null, + 'icon' => null, + 'variant' => 'default', + 'disabled' => false, +]) + +@php + $tag = $href ? 'a' : 'button'; + + $variantClasses = [ + 'default' => 'text-base/70 hover:bg-gradient-to-r hover:from-neutral/10 hover:to-transparent hover:text-base', + 'danger' => 'text-danger hover:bg-gradient-to-r hover:from-danger/10 hover:to-transparent', + 'success' => 'text-success hover:bg-gradient-to-r hover:from-success/10 hover:to-transparent', + ]; + + $variantClass = $variantClasses[$variant] ?? $variantClasses['default']; +@endphp + +<{{ $tag }} + @if($href) href="{{ $href }}" @endif + @if($tag === 'button') type="button" @endif + @if($disabled) disabled @endif + {{ $attributes->class([ + 'group flex w-full items-center gap-2.5 px-4 py-2.5 text-sm font-medium transition-all duration-150', + $variantClass, + 'opacity-50 cursor-not-allowed' => $disabled, + ]) }} +> + @if($icon) + + @endif + {{ $slot }} + diff --git a/extensions/Servers/Proxmox/views/components/ui/dropdown.blade.php b/extensions/Servers/Proxmox/views/components/ui/dropdown.blade.php new file mode 100644 index 000000000..c3c538a2c --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/dropdown.blade.php @@ -0,0 +1,61 @@ +{{-- + Dropdown Component - TailServer Theme + + Usage: + + + Options + + + Profile + Settings + + Sign out + +--}} + +@props([ + 'align' => 'right', + 'width' => '48', + 'contentClasses' => '', +]) + +@php + $alignClasses = [ + 'left' => 'ltr:origin-top-left rtl:origin-top-right start-0', + 'right' => 'ltr:origin-top-right rtl:origin-top-left end-0', + 'center' => 'origin-top left-1/2 -translate-x-1/2', + ]; + + $widthClasses = [ + '32' => 'w-32', + '40' => 'w-40', + '48' => 'w-48', + '56' => 'w-56', + '64' => 'w-64', + '80' => 'w-80', + ]; +@endphp + +
+
+ {{ $trigger }} +
+ + +
diff --git a/extensions/Servers/Proxmox/views/components/ui/editable-field.blade.php b/extensions/Servers/Proxmox/views/components/ui/editable-field.blade.php new file mode 100644 index 000000000..2a04c7dfc --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/editable-field.blade.php @@ -0,0 +1,148 @@ +{{-- + Editable Field Component - TailServer Theme + A field with display value and edit button that opens a modal + + Usage: + + + Additional information about the field... + + +--}} + +@props([ + 'label', + 'value', + 'placeholder' => null, + 'editing' => false, + 'editClick' => null, + 'cancelClick' => null, + 'saveClick' => null, + 'applyClick' => null, + 'applyLabel' => 'Save & Apply', + 'error' => null, +]) + +
+ +
+
+ {{ $value ?? 'Not set' }} + @if($editClick) + + @endif +
+
+ + @if($editing !== false) + + + + + + @endif +
diff --git a/extensions/Servers/Proxmox/views/components/ui/empty-state.blade.php b/extensions/Servers/Proxmox/views/components/ui/empty-state.blade.php new file mode 100644 index 000000000..7a0a74706 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/empty-state.blade.php @@ -0,0 +1,72 @@ +{{-- + Empty State Component - TailServer Theme + + Usage: + + + Create Server + +--}} + +@props([ + 'title' => 'No data', + 'description' => null, + 'icon' => 'ri-inbox-line', + 'iconClass' => null, + 'compact' => false, +]) + +
class([ + 'flex flex-col items-center justify-center text-center', + 'py-12 px-6' => !$compact, + 'py-6 px-4' => $compact, + ]) }} +> + @if($icon) +
!$compact, + 'mb-3 w-12 h-12 bg-neutral/5' => $compact, + ])> + {{-- Decorative ring --}} +
+ !$compact, + 'size-6' => $compact, + ]) + /> +
+ @endif + +

!$compact, + 'text-sm' => $compact, + ])> + {{ $title }} +

+ + @if($description) +

!$compact, + 'mt-1 text-xs' => $compact, + ])> + {{ $description }} +

+ @endif + + @if($slot->isNotEmpty()) +
!$compact, 'mt-3' => $compact])> + {{ $slot }} +
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/ui/help-modal.blade.php b/extensions/Servers/Proxmox/views/components/ui/help-modal.blade.php new file mode 100644 index 000000000..5a3e1fd50 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/help-modal.blade.php @@ -0,0 +1,83 @@ +{{-- + Help Modal Trigger Component - TailServer Theme + Question mark button that opens an info modal + + Usage: + + + Displays comprehensive information about your virtual machine... + + +

Status: Shows the current power state...

+
+
+--}} + +@props([ + 'title', + 'icon' => 'ri-question-line', +]) + +
+ + + + + + + +
diff --git a/extensions/Servers/Proxmox/views/components/ui/icon-picker.blade.php b/extensions/Servers/Proxmox/views/components/ui/icon-picker.blade.php new file mode 100644 index 000000000..ac0e3459c --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/icon-picker.blade.php @@ -0,0 +1,169 @@ +{{-- + Icon Picker Component - TailServer Theme + Modal-based icon picker with search and categories + + Usage: + +--}} + +@props([ + 'icons' => [], + 'categories' => [], + 'selected' => null, +]) + +
whereDoesntStartWith('wire:model') }} +> + + + + +
+
+ +
+ + +
+ +
+
+

Select Icon

+ +
+ + +
+ + +
+
+ + + @if(count($categories) > 0) +
+ + @foreach($categories as $category) + + @endforeach +
+ @endif + + +
+
+ +
+ + +
+ +

No icons found matching your search.

+
+
+ + +
+ + +
+
+
+
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/index.blade.php b/extensions/Servers/Proxmox/views/components/ui/index.blade.php new file mode 100644 index 000000000..738fd9c13 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/index.blade.php @@ -0,0 +1,249 @@ +{{-- + Proxmox UI Component Library Index + =================================== + + This file documents all available UI components for the Proxmox server views. + All components follow the TailServer theme using CSS variables for consistent styling. + + CSS Variables Used: + - --color-background: Page background color + - --color-neutral: Neutral/gray tones + - --color-primary: Primary accent color (purple) + - --color-base: Text color + - --color-success: Success/positive states + - --color-warning: Warning states + - --color-danger: Error/danger states + - --color-info: Informational states + + === LAYOUT COMPONENTS === + + 1. Card (ui.card) + @props(['title', 'subtitle', 'icon', 'collapsible', 'collapsed', 'padding', 'noPadding']) + Container component for grouping related content. + + 2. Section Header (ui.section-header) + @props(['title', 'subtitle', 'icon', 'help', 'helpTitle', 'helpContent']) + Page/section titles with optional help modal. + + 3. Modal (ui.modal) + @props(['name', 'title', 'maxWidth', 'closeable']) + Overlay dialog with Alpine.js transitions. + + 4. Tabs (ui.tabs) + @props(['tabs', 'active', 'variant']) + Tab navigation (default, pills, buttons variants). + + 5. Tab Panel (ui.tab-panel) + @props(['name', 'active']) + Tab content panel with transitions. + + 6. Help Modal (ui.help-modal) + @props(['title', 'icon']) + Question mark trigger that opens info modal with description and details slots. + + === DATA DISPLAY COMPONENTS === + + 7. Stat Card (ui.stat-card) + @props(['label', 'value', 'icon', 'trend', 'progress', 'variant']) + Statistics display with progress bar support. + + 8. Badge (ui.badge) + @props(['variant', 'dot', 'icon', 'size', 'rounded']) + Status/label badges with icons. + + 9. Progress (ui.progress) + @props(['value', 'max', 'showLabel', 'size', 'variant', 'animated']) + Progress bars with auto-coloring thresholds. + + 10. Server Status (ui.server-status) + @props(['status', 'size', 'showLabel']) + VM status indicator (running, stopped, paused, etc). + + 11. Resource Gauge (ui.resource-gauge) + @props(['label', 'value', 'max', 'unit', 'icon', 'showPercentage', 'size']) + Resource usage display with progress bar. + + 12. Info Row (ui.info-row) + @props(['label', 'value', 'copyable', 'icon', 'muted']) + Key-value pair display with copy functionality. + + 13. Empty State (ui.empty-state) + @props(['title', 'description', 'icon']) + Placeholder for empty content areas. + + 14. Allocation Card (ui.allocation-card) + @props(['label', 'percent', 'usageSummary', 'entitlementLabel', 'description', 'gradient', 'badge']) + Resource allocation vs entitlement display with gradient progress bar. + + 15. Network Address Card (ui.network-address-card) + @props(['type', 'ip', 'gateway', 'netmask', 'cidr', 'isPublic', 'isIpv6', 'guestInterface', 'fromGuestAgent']) + IP address card with gateway, netmask, network tools, and guest agent details. + + === TABLE COMPONENTS === + + 16. Table (ui.table) + @props(['striped', 'hoverable', 'compact', 'bordered']) + Table wrapper with styling options. + + 17. Table Row (ui.table-row) + @props(['hoverable', 'clickable', 'selected']) + Table row with interaction states. + + 18. Table Header Cell (ui.table-th) + @props(['sortable', 'sorted', 'direction', 'align']) + Table header with sorting support. + + 19. Table Data Cell (ui.table-td) + @props(['align', 'nowrap']) + Table cell with alignment options. + + === FORM COMPONENTS === + + 20. Button (ui.button) + @props(['variant', 'size', 'icon', 'iconPosition', 'loading', 'disabled', 'full']) + Multi-variant buttons with loading states. + + 21. Input (ui.input) + @props(['label', 'error', 'icon', 'iconPosition', 'hint']) + Form text input with icon support. + + 22. Select (ui.select) + @props(['label', 'error', 'options', 'placeholder', 'icon', 'hint']) + Form select dropdown. + + 23. Toggle (ui.toggle) + @props(['label', 'description', 'disabled']) + Toggle/switch input. + + 24. Editable Field (ui.editable-field) + @props(['label', 'value', 'editing', 'editClick', 'cancelClick', 'saveClick', 'applyClick', 'error']) + Display field with edit button that opens a modal editor. + + === INTERACTIVE COMPONENTS === + + 25. Dropdown (ui.dropdown) + @props(['align', 'width', 'contentClasses']) + Dropdown menu container. + + 26. Dropdown Item (ui.dropdown-item) + @props(['icon', 'danger', 'disabled']) + Dropdown menu item. + + 27. Dropdown Divider (ui.dropdown-divider) + Dropdown menu separator. + + 28. Action Toolbar (ui.action-toolbar) + @props(['centered']) + Container for VM action buttons. + + 29. Action Button (ui.action-button) + @props(['action', 'icon', 'label', 'variant', 'disabled', 'loading', 'confirm', 'size']) + VM control action button. + + 30. Icon Picker (ui.icon-picker) + @props(['icons', 'categories', 'selected']) + Modal-based icon selection. + + 31. Tooltip (ui.tooltip) + @props(['text', 'position']) + Hover tooltip. + + 32. Confirm Dialog (ui.confirm-dialog) + @props(['title', 'message', 'confirmLabel', 'cancelLabel', 'variant', 'open']) + Confirmation modal for dangerous actions. + + 33. Copy Button (ui.copy-button) + @props(['value']) + Small inline button to copy text to clipboard. + + 34. Copyable (ui.copyable) + @props(['label', 'value', 'masked']) + Text field with copy to clipboard and optional masking. + + === FEEDBACK COMPONENTS === + + 35. Alert (ui.alert) + @props(['variant', 'title', 'dismissible', 'icon']) + Alert/notification messages. + + 36. Spinner (ui.spinner) + @props(['size', 'color']) + Loading spinner animation. + + 37. Notice Banner (ui.notice-banner) + @props(['title', 'variant', 'collapsible', 'storageKey', 'icon', 'showCondition']) + Collapsible notice/alert banner with localStorage persistence. + + === USAGE EXAMPLES === + + -- Server Status Badge -- + + + -- Resource Usage -- + + + -- Allocation Card -- + + + -- Action Toolbar -- + + + + + + -- Card with Stats -- + +
+ + +
+
+ + -- Notice Banner -- + +

Your notice content here...

+
+ + -- Help Modal -- + + + Brief description of the feature. + + +

Item: Detailed explanation...

+
+
+ + -- Copyable Field -- + + +--}} diff --git a/extensions/Servers/Proxmox/views/components/ui/info-row.blade.php b/extensions/Servers/Proxmox/views/components/ui/info-row.blade.php new file mode 100644 index 000000000..a591509a5 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/info-row.blade.php @@ -0,0 +1,51 @@ +{{-- + Info Row / Key-Value Pair Component - TailServer Theme + + Usage: + + + Active + +--}} + +@props([ + 'label', + 'value' => null, + 'copyable' => false, + 'icon' => null, + 'muted' => false, +]) + +
class(['flex items-center justify-between py-2 border-b border-neutral/10 last:border-b-0']) }}> +
+ @if($icon) + + @endif + {{ $label }} +
+
+ $muted, + 'text-base' => !$muted, + ])> + {{ $value ?? $slot }} + + @if($copyable && $value) + + @endif +
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/input.blade.php b/extensions/Servers/Proxmox/views/components/ui/input.blade.php new file mode 100644 index 000000000..22eeb2320 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/input.blade.php @@ -0,0 +1,93 @@ +{{-- + Input Component - TailServer Theme + + Usage: + + + +--}} + +@props([ + 'type' => 'text', + 'name' => null, + 'label' => null, + 'placeholder' => null, + 'icon' => null, + 'iconRight' => null, + 'error' => null, + 'hint' => null, + 'disabled' => false, + 'readonly' => false, + 'required' => false, + 'size' => 'md', +]) + +@php + $sizeClasses = [ + 'sm' => 'py-1.5 text-sm', + 'md' => 'py-2 text-sm', + 'lg' => 'py-2.5 text-base', + ]; + $sizeClass = $sizeClasses[$size] ?? $sizeClasses['md']; + + $inputClasses = 'block w-full rounded-xl border bg-background leading-6 placeholder-base/40 shadow-sm transition-all duration-200 focus:ring-2 focus:ring-offset-0 focus:shadow-md hover:border-neutral/50 hover:shadow'; + + if ($error) { + $inputClasses .= ' border-danger/50 focus:border-danger focus:ring-danger/25 focus:shadow-danger/10'; + } else { + $inputClasses .= ' border-neutral/30 focus:border-primary focus:ring-primary/25 focus:shadow-primary/10'; + } + + if ($icon) { + $inputClasses .= ' ps-10'; + } else { + $inputClasses .= ' ps-3'; + } + + if ($iconRight) { + $inputClasses .= ' pe-10'; + } else { + $inputClasses .= ' pe-3'; + } +@endphp + +
only('class')->class(['']) }}> + @if($label) + + @endif + +
+ @if($icon) +
+ +
+ @endif + + except('class')->class([$inputClasses, $sizeClass]) }} + /> + + @if($iconRight) +
+ +
+ @endif +
+ + @if($error) +

{{ $error }}

+ @elseif($hint) +

{{ $hint }}

+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/ui/modal.blade.php b/extensions/Servers/Proxmox/views/components/ui/modal.blade.php new file mode 100644 index 000000000..cef36f467 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/modal.blade.php @@ -0,0 +1,115 @@ +{{-- + Modal Component - TailServer Theme + + Usage: + Content + + Open with: $dispatch('open-modal', { name: 'my-modal' }) + Close with: $dispatch('close-modal', { name: 'my-modal' }) +--}} + +@props([ + 'name', + 'title' => null, + 'subtitle' => null, + 'icon' => null, + 'iconColor' => 'text-primary', + 'maxWidth' => 'md', + 'closeable' => true, + 'footer' => null, +]) + +@php + $maxWidthClasses = [ + 'sm' => 'max-w-sm', + 'md' => 'max-w-md', + 'lg' => 'max-w-lg', + 'xl' => 'max-w-xl', + '2xl' => 'max-w-2xl', + '3xl' => 'max-w-3xl', + '4xl' => 'max-w-4xl', + '5xl' => 'max-w-5xl', + 'full' => 'max-w-full mx-4', + ]; + $maxWidthClass = $maxWidthClasses[$maxWidth] ?? $maxWidthClasses['md']; +@endphp + +
+ {{-- Backdrop --}} +
+ + {{-- Modal Panel --}} +
+
+ {{-- Header --}} + @if($title || $closeable) +
+
+ @if($icon) +
+ /> +
+ @endif +
+ @if($title) +

{{ $title }}

+ @endif + @if($subtitle) +

{{ $subtitle }}

+ @endif +
+
+ @if($closeable) + + @endif +
+ @endif + + {{-- Content --}} +
+ {{ $slot }} +
+ + {{-- Footer --}} + @if($footer) +
+ {{ $footer }} +
+ @endif +
+
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/network-address-card.blade.php b/extensions/Servers/Proxmox/views/components/ui/network-address-card.blade.php new file mode 100644 index 000000000..d58517d00 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/network-address-card.blade.php @@ -0,0 +1,191 @@ +{{-- + Network Address Card Component - TailServer Theme + For displaying IP address information with gateway, netmask, and tools + + Usage: + +--}} + +@props([ + 'type' => 'ipv4', + 'ip', + 'gateway' => null, + 'netmask' => null, + 'cidr' => null, + 'isPublic' => false, + 'isIpv6' => false, + 'guestInterface' => null, + 'fromGuestAgent' => false, +]) + + + {{-- Header --}} +
+

{{ strtoupper($type) }} Address

+ + {{ $type === 'ipv6' ? 'IPv6' : 'IPv4' }} + +
+ + {{-- Address Grid --}} +
+ {{-- IP Address --}} +
+

IP Address

+
+ {{ $ip }} + +
+ @if($cidr) +

CIDR: {{ $ip }}{{ $cidr }}

+ @endif +
+ + {{-- Gateway --}} +
+

Gateway

+
+ {{ $gateway ?? 'N/A' }} + @if($gateway) + + @endif +
+

+ {{ $fromGuestAgent && !$gateway ? 'Not configured in database' : 'Default route for this network' }} +

+
+ + {{-- Netmask --}} +
+

Subnet Mask

+
+ {{ $netmask ?? 'N/A' }} + @if($netmask) + + @endif +
+

+ {{ $fromGuestAgent && !$netmask ? 'Not configured in database' : 'Network address range mask' }} +

+
+ + {{-- Network Tools (for public IPs) --}} + @if($isPublic) +
+
+
+ @if($isIpv6) + + Ping + + + MTR + + + BGP + + @else + + Ping + + + MTR + + + BGP + + @endif +
+
+ @endif +
+ + {{-- Guest Agent Technical Details --}} + @if($guestInterface) +
+

Technical Details (Guest Agent)

+
+ @if(isset($guestInterface['hardware-address'])) +
+ MAC Address +
+ {{ $guestInterface['hardware-address'] }} + +
+

Hardware address for this interface

+
+ @endif + + @if(isset($guestInterface['name'])) +
+ Interface Name + {{ $guestInterface['name'] }} +

Network interface identifier within the guest OS

+
+ @endif + + @if(isset($guestInterface['statistics'])) +
+ Statistics +
+ @if(isset($guestInterface['statistics']['rx-bytes'])) +
RX: {{ number_format($guestInterface['statistics']['rx-bytes']) }} bytes
+ @endif + @if(isset($guestInterface['statistics']['tx-bytes'])) +
TX: {{ number_format($guestInterface['statistics']['tx-bytes']) }} bytes
+ @endif + @if(isset($guestInterface['statistics']['rx-packets'])) +
RX Packets: {{ number_format($guestInterface['statistics']['rx-packets']) }}
+ @endif + @if(isset($guestInterface['statistics']['tx-packets'])) +
TX Packets: {{ number_format($guestInterface['statistics']['tx-packets']) }}
+ @endif +
+

Network traffic statistics from guest OS

+
+ @endif +
+
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/ui/notice-banner.blade.php b/extensions/Servers/Proxmox/views/components/ui/notice-banner.blade.php new file mode 100644 index 000000000..6aa4c4c69 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/notice-banner.blade.php @@ -0,0 +1,98 @@ +{{-- + Info Notice / Alert Banner Component - TailServer Theme + Collapsible notice banners for important information + + Usage: + +

Your notice content here...

+
+--}} + +@props([ + 'title' => null, + 'variant' => 'info', // info, warning, danger, success + 'collapsible' => false, + 'storageKey' => null, + 'icon' => null, + 'showCondition' => null, // Alpine.js expression for conditional display +]) + +@php + $variants = [ + 'info' => [ + 'bg' => 'bg-info/10', + 'border' => 'border-info/30', + 'icon' => $icon ?? 'ri-information-line', + 'iconColor' => 'text-info', + ], + 'warning' => [ + 'bg' => 'bg-warning/10', + 'border' => 'border-warning/30', + 'icon' => $icon ?? 'ri-alert-line', + 'iconColor' => 'text-warning', + ], + 'danger' => [ + 'bg' => 'bg-danger/10', + 'border' => 'border-danger/30', + 'icon' => $icon ?? 'ri-error-warning-line', + 'iconColor' => 'text-danger', + ], + 'success' => [ + 'bg' => 'bg-success/10', + 'border' => 'border-success/30', + 'icon' => $icon ?? 'ri-checkbox-circle-line', + 'iconColor' => 'text-success', + ], + ]; + + $config = $variants[$variant] ?? $variants['info']; +@endphp + +
class([ + $config['bg'], + 'border', + $config['border'], + 'rounded-lg p-4', + ]) }} +> +
+ +
+ @if($title) +
+

{{ $title }}

+ @if($collapsible) + + @endif +
+ @endif + +
+ {{ $slot }} +
+
+
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/progress.blade.php b/extensions/Servers/Proxmox/views/components/ui/progress.blade.php new file mode 100644 index 000000000..919efa12f --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/progress.blade.php @@ -0,0 +1,80 @@ +{{-- + Progress Bar Component - TailServer Theme + + Usage: + + + +--}} + +@props([ + 'value' => 0, + 'max' => 100, + 'color' => 'primary', + 'size' => 'md', + 'showLabel' => false, + 'label' => null, + 'gradient' => null, + 'animated' => false, + 'striped' => false, +]) + +@php + $percent = $max > 0 ? min(100, ($value / $max) * 100) : 0; + + $colorClasses = [ + 'primary' => 'bg-primary', + 'secondary' => 'bg-secondary', + 'success' => 'bg-success', + 'warning' => 'bg-warning', + 'danger' => 'bg-danger', + 'info' => 'bg-info', + ]; + + $sizeClasses = [ + 'xs' => 'h-1', + 'sm' => 'h-1.5', + 'md' => 'h-2', + 'lg' => 'h-2.5', + 'xl' => 'h-3', + ]; + + $colorClass = $colorClasses[$color] ?? $colorClasses['primary']; + $sizeClass = $sizeClasses[$size] ?? $sizeClasses['md']; + + // Auto-select color based on value if specified + if ($color === 'auto') { + if ($percent >= 90) { + $colorClass = $colorClasses['danger']; + } elseif ($percent >= 70) { + $colorClass = $colorClasses['warning']; + } else { + $colorClass = $colorClasses['success']; + } + } +@endphp + +
class(['w-full']) }}> + @if($showLabel || $label) +
+ {{ $label ?? 'Usage' }} + {{ number_format($percent, 1) }}% +
+ @endif +
+
!$gradient, + 'animate-pulse' => $animated, + 'bg-[length:1rem_1rem] bg-gradient-to-r from-white/20 via-transparent to-transparent' => $striped, + ]) + @if($gradient) + style="width: {{ $percent }}%; background-image: {{ $gradient }};" + @else + style="width: {{ $percent }}%;" + @endif + >
+
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/resource-gauge.blade.php b/extensions/Servers/Proxmox/views/components/ui/resource-gauge.blade.php new file mode 100644 index 000000000..6841fa36b --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/resource-gauge.blade.php @@ -0,0 +1,103 @@ +{{-- + Resource Gauge Component - TailServer Theme + Shows a circular or linear gauge for resource usage + + Usage: + + +--}} + +@props([ + 'value' => 0, + 'max' => 100, + 'label', + 'sublabel' => null, + 'suffix' => '%', + 'prefix' => null, + 'icon' => null, + 'gradient' => null, + 'color' => 'auto', +]) + +@php + $percent = $max > 0 ? min(100, ($value / $max) * 100) : 0; + + // Auto-color based on usage + if ($color === 'auto') { + if ($percent >= 90) { + $color = 'danger'; + } elseif ($percent >= 70) { + $color = 'warning'; + } else { + $color = 'success'; + } + } + + $colorClasses = [ + 'primary' => 'text-primary', + 'success' => 'text-success', + 'warning' => 'text-warning', + 'danger' => 'text-danger', + 'info' => 'text-info', + ]; + + $bgColorClasses = [ + 'primary' => 'bg-primary', + 'success' => 'bg-success', + 'warning' => 'bg-warning', + 'danger' => 'bg-danger', + 'info' => 'bg-info', + ]; + + $textColor = $colorClasses[$color] ?? $colorClasses['primary']; + $bgColor = $bgColorClasses[$color] ?? $bgColorClasses['primary']; + + $badgeLabel = match(true) { + $percent >= 100 => 'Over entitlement', + $percent >= 85 => 'Watchlist', + default => 'Healthy', + }; + + $badgeClass = match(true) { + $percent >= 100 => 'text-danger bg-danger/15', + $percent >= 85 => 'text-warning bg-warning/15', + default => 'text-success bg-success/15', + }; +@endphp + +
class(['border border-neutral/15 rounded-2xl p-5 bg-gradient-to-br from-background to-neutral/5 shadow-sm hover:shadow-md transition-shadow duration-300 flex flex-col gap-4']) }}> +
+
+

{{ $label }}

+

+ @if($prefix){{ $prefix }}@endif{{ is_numeric($value) ? number_format($value, 1) : $value }}@if($suffix){{ $suffix }}@endif +

+ @if($sublabel) +

{{ $sublabel }}

+ @endif +
+ + {{ $badgeLabel }} + +
+ +
+
+ Usage + {{ number_format($percent, 1) }}% +
+
+
+
+
+
+
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/section-header.blade.php b/extensions/Servers/Proxmox/views/components/ui/section-header.blade.php new file mode 100644 index 000000000..2d8337c9d --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/section-header.blade.php @@ -0,0 +1,109 @@ +{{-- + Section Header Component - TailServer Theme + + Usage: + + + + Action + + +--}} + +@props([ + 'title', + 'subtitle' => null, + 'icon' => null, + 'iconColor' => 'text-primary', + 'actions' => null, + 'helpText' => null, + 'size' => 'lg', +]) + +@php + $titleSizes = [ + 'sm' => 'text-base font-semibold', + 'md' => 'text-lg font-semibold', + 'lg' => 'text-xl font-semibold', + 'xl' => 'text-2xl font-bold', + ]; + $titleClass = $titleSizes[$size] ?? $titleSizes['lg']; +@endphp + +
class(['flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between']) }}> +
+ @if($icon) +
+ +
+ @endif +
+
+

{{ $title }}

+ @if($helpText) +
+ + {{-- Help Modal --}} + + +
+ @endif +
+ @if($subtitle) +

{{ $subtitle }}

+ @endif +
+
+ + @if($actions) +
+ {{ $actions }} +
+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/ui/select.blade.php b/extensions/Servers/Proxmox/views/components/ui/select.blade.php new file mode 100644 index 000000000..c075e2a91 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/select.blade.php @@ -0,0 +1,67 @@ +{{-- + Select Component - TailServer Theme + + Usage: + + + + +--}} + +@props([ + 'name' => null, + 'label' => null, + 'error' => null, + 'hint' => null, + 'disabled' => false, + 'required' => false, + 'size' => 'md', +]) + +@php + $sizeClasses = [ + 'sm' => 'py-1.5 text-sm', + 'md' => 'py-2 text-sm', + 'lg' => 'py-2.5 text-base', + ]; + $sizeClass = $sizeClasses[$size] ?? $sizeClasses['md']; + + $selectClasses = 'block w-full rounded-xl border bg-background px-3 leading-6 shadow-sm transition-all duration-200 focus:ring-2 focus:ring-offset-0 focus:shadow-md hover:border-neutral/50 hover:shadow appearance-none cursor-pointer'; + + if ($error) { + $selectClasses .= ' border-danger/50 focus:border-danger focus:ring-danger/25 focus:shadow-danger/10'; + } else { + $selectClasses .= ' border-neutral/30 focus:border-primary focus:ring-primary/25 focus:shadow-primary/10'; + } +@endphp + +
only('class')->class(['']) }}> + @if($label) + + @endif + +
+ +
+ +
+
+ + @if($error) +

{{ $error }}

+ @elseif($hint) +

{{ $hint }}

+ @endif +
diff --git a/extensions/Servers/Proxmox/views/components/ui/server-status.blade.php b/extensions/Servers/Proxmox/views/components/ui/server-status.blade.php new file mode 100644 index 000000000..7fee27282 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/server-status.blade.php @@ -0,0 +1,139 @@ +{{-- + Server Status Indicator Component - TailServer Theme + + Usage: + + + +--}} + +@props([ + 'status', + 'showLabel' => true, + 'size' => 'md', + 'minimal' => false, +]) + +@php + $statusConfig = [ + 'running' => [ + 'color' => 'success', + 'label' => 'Running', + 'pulse' => true, + ], + 'stopped' => [ + 'color' => 'muted', + 'label' => 'Stopped', + 'pulse' => false, + ], + 'paused' => [ + 'color' => 'warning', + 'label' => 'Paused', + 'pulse' => false, + ], + 'suspended' => [ + 'color' => 'warning', + 'label' => 'Suspended', + 'pulse' => false, + ], + 'migrating' => [ + 'color' => 'info', + 'label' => 'Migrating', + 'pulse' => true, + ], + 'starting' => [ + 'color' => 'info', + 'label' => 'Starting', + 'pulse' => true, + ], + 'stopping' => [ + 'color' => 'warning', + 'label' => 'Stopping', + 'pulse' => true, + ], + 'unknown' => [ + 'color' => 'danger', + 'label' => 'Unknown', + 'pulse' => false, + ], + ]; + + $config = $statusConfig[strtolower($status)] ?? $statusConfig['unknown']; + + $colorClasses = [ + 'success' => 'text-success', + 'warning' => 'text-warning', + 'danger' => 'text-danger', + 'info' => 'text-info', + 'muted' => 'text-base/40', + ]; + + $bgClasses = [ + 'success' => 'bg-success/10', + 'warning' => 'bg-warning/10', + 'danger' => 'bg-danger/10', + 'info' => 'bg-info/10', + 'muted' => 'bg-neutral/10', + ]; + + $dotColorClasses = [ + 'success' => 'bg-success', + 'warning' => 'bg-warning', + 'danger' => 'bg-danger', + 'info' => 'bg-info', + 'muted' => 'bg-base/40', + ]; + + $sizeClasses = [ + 'sm' => 'text-xs px-2 py-1 gap-1.5', + 'md' => 'text-sm px-2.5 py-1.5 gap-2', + 'lg' => 'text-base px-3 py-2 gap-2', + ]; + + $dotSizes = [ + 'sm' => 'h-1.5 w-1.5', + 'md' => 'h-2 w-2', + 'lg' => 'h-2.5 w-2.5', + ]; + + $textSizes = [ + 'sm' => 'text-xs', + 'md' => 'text-sm', + 'lg' => 'text-base', + ]; +@endphp + +@if($minimal) + {{-- Minimal dot-only variant --}} +
class(['inline-flex items-center', 'gap-1.5' => $showLabel]) }}> + + @if($config['pulse']) + + @endif + + + @if($showLabel) + {{ $config['label'] }} + @endif +
+@else + {{-- Full badge variant --}} +
class([ + 'inline-flex items-center font-semibold rounded-lg', + $bgClasses[$config['color']] ?? $bgClasses['muted'], + $colorClasses[$config['color']] ?? $colorClasses['muted'], + $sizeClasses[$size] ?? $sizeClasses['md'], + ]) }} + > + + @if($config['pulse']) + + @endif + + + @if($showLabel) + {{ $config['label'] }} + @endif +
+@endif diff --git a/extensions/Servers/Proxmox/views/components/ui/spinner.blade.php b/extensions/Servers/Proxmox/views/components/ui/spinner.blade.php new file mode 100644 index 000000000..c03ca0dd8 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/spinner.blade.php @@ -0,0 +1,46 @@ +{{-- + Spinner Component - TailServer Theme + + Usage: + + +--}} + +@props([ + 'size' => 'md', + 'color' => 'current', +]) + +@php + $sizeClasses = [ + 'xs' => 'size-3', + 'sm' => 'size-4', + 'md' => 'size-6', + 'lg' => 'size-8', + 'xl' => 'size-12', + ]; + + $colorClasses = [ + 'current' => 'text-current', + 'primary' => 'text-primary', + 'secondary' => 'text-secondary', + 'success' => 'text-success', + 'warning' => 'text-warning', + 'danger' => 'text-danger', + 'info' => 'text-info', + 'muted' => 'text-base/50', + ]; + + $sizeClass = $sizeClasses[$size] ?? $sizeClasses['md']; + $colorClass = $colorClasses[$color] ?? $colorClasses['current']; +@endphp + +class(['animate-spin drop-shadow-sm', $sizeClass, $colorClass]) }} + xmlns="http://www.w3.org/2000/svg" + fill="none" + viewBox="0 0 24 24" +> + + + diff --git a/extensions/Servers/Proxmox/views/components/ui/stat-card.blade.php b/extensions/Servers/Proxmox/views/components/ui/stat-card.blade.php new file mode 100644 index 000000000..535234110 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/stat-card.blade.php @@ -0,0 +1,75 @@ +{{-- + Stat Card Component - TailServer Theme + + Usage: + + + +--}} + +@props([ + 'value', + 'label', + 'suffix' => null, + 'prefix' => null, + 'icon' => null, + 'iconClass' => 'text-primary/30', + 'status' => null, + 'statusText' => null, + 'href' => null, + 'progress' => null, + 'progressColor' => 'bg-primary', + 'clickable' => false, + 'compact' => false, +]) + +@php + $tag = $href ? 'a' : 'div'; + $statusClasses = [ + 'success' => 'text-success bg-success/10', + 'warning' => 'text-warning bg-warning/10', + 'danger' => 'text-danger bg-danger/10', + 'info' => 'text-info bg-info/10', + 'muted' => 'text-base/50 bg-neutral/10', + ]; + $statusClass = $statusClasses[$status] ?? $statusClasses['muted']; +@endphp + +<{{ $tag }} + @if($href) href="{{ $href }}" @endif + {{ $attributes->class([ + 'group relative flex flex-col rounded-xl border border-neutral/20 bg-background-secondary overflow-hidden', + 'hover:bg-background-secondary/80 hover:border-neutral/30 hover:shadow-sm cursor-pointer transition-all duration-200' => $href || $clickable, + ]) }} +> + {{-- Subtle gradient overlay --}} +
+ +
!$compact, 'p-4' => $compact])> +
+
!$compact, 'text-xl' => $compact])> + @if($prefix){{ $prefix }}@endif{{ $value }}@if($suffix) !$compact, 'text-base' => $compact])>{{ $suffix }}@endif +
+
!$compact, 'text-xs' => $compact])>{{ $label }}
+
+ @if($icon) +
+ !$compact, 'size-8' => $compact]) /> +
+ @endif +
+ + @if($progress !== null) +
+
+
+
+
+ @endif + + @if($statusText) +
+ {{ $statusText }} +
+ @endif + diff --git a/extensions/Servers/Proxmox/views/components/ui/tab-panel.blade.php b/extensions/Servers/Proxmox/views/components/ui/tab-panel.blade.php new file mode 100644 index 000000000..bb29b4416 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/tab-panel.blade.php @@ -0,0 +1,17 @@ +{{-- + Tab Panel Component - TailServer Theme +--}} + +@props([ + 'name', +]) + +
+ {{ $slot }} +
diff --git a/extensions/Servers/Proxmox/views/components/ui/table-row.blade.php b/extensions/Servers/Proxmox/views/components/ui/table-row.blade.php new file mode 100644 index 000000000..0a52fd089 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/table-row.blade.php @@ -0,0 +1,36 @@ +{{-- + Table Row Component - TailServer Theme +--}} + +@props([ + 'clickable' => false, + 'href' => null, + 'hoverable' => null, +]) + +@php + // Check parent table's hoverable attribute if not explicitly set + $isHoverable = $hoverable ?? true; +@endphp + +@if($href) + class([ + 'border-b border-neutral/10 cursor-pointer transition-colors duration-150', + 'hover:bg-primary/5' => $isHoverable, + ]) }} + onclick="window.location='{{ $href }}'" + > + {{ $slot }} + +@else + class([ + 'border-b border-neutral/10 transition-colors duration-150', + 'hover:bg-neutral/5' => $isHoverable, + 'cursor-pointer hover:bg-primary/5' => $clickable, + ]) }} + > + {{ $slot }} + +@endif diff --git a/extensions/Servers/Proxmox/views/components/ui/table-td.blade.php b/extensions/Servers/Proxmox/views/components/ui/table-td.blade.php new file mode 100644 index 000000000..d94327ad4 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/table-td.blade.php @@ -0,0 +1,31 @@ +{{-- + Table Data Cell Component - TailServer Theme +--}} + +@props([ + 'align' => 'start', + 'nowrap' => false, + 'muted' => false, + 'strong' => false, +]) + +@php + $alignClasses = [ + 'start' => 'text-start', + 'center' => 'text-center', + 'end' => 'text-end', + ]; + $alignClass = $alignClasses[$align] ?? $alignClasses['start']; +@endphp + +class([ + 'px-3 py-3', + $alignClass, + 'whitespace-nowrap' => $nowrap, + 'text-base/50' => $muted, + 'font-semibold text-base' => $strong, + ]) }} +> + {{ $slot }} + diff --git a/extensions/Servers/Proxmox/views/components/ui/table-th.blade.php b/extensions/Servers/Proxmox/views/components/ui/table-th.blade.php new file mode 100644 index 000000000..feab7263c --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/table-th.blade.php @@ -0,0 +1,50 @@ +{{-- + Table Header Cell Component - TailServer Theme +--}} + +@props([ + 'align' => 'start', + 'sortable' => false, + 'sortKey' => null, + 'currentSort' => null, + 'currentDirection' => 'asc', +]) + +@php + $alignClasses = [ + 'start' => 'text-start', + 'center' => 'text-center', + 'end' => 'text-end', + ]; + $alignClass = $alignClasses[$align] ?? $alignClasses['start']; + + $isSorted = $sortable && $sortKey === $currentSort; +@endphp + +class([ + 'px-3 py-3 text-xs font-semibold tracking-wider text-base/60 uppercase', + $alignClass, + 'cursor-pointer hover:text-base hover:bg-neutral/5 select-none transition-colors duration-150' => $sortable, + ]) }} + @if($sortable && $sortKey) + wire:click="sort('{{ $sortKey }}')" + @endif +> +
+ {{ $slot }} + @if($sortable) + + @if($isSorted) + @if($currentDirection === 'asc') + + @else + + @endif + @else + + @endif + + @endif +
+ diff --git a/extensions/Servers/Proxmox/views/components/ui/table.blade.php b/extensions/Servers/Proxmox/views/components/ui/table.blade.php new file mode 100644 index 000000000..6ae7c9348 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/table.blade.php @@ -0,0 +1,53 @@ +{{-- + Table Component - TailServer Theme + + Usage: + + + Name + Status + + + Server 1 + Running + + +--}} + +@props([ + 'striped' => false, + 'hoverable' => true, + 'responsive' => true, + 'compact' => false, +]) + +@php + $wrapperClasses = $responsive ? 'min-w-full overflow-x-auto rounded-xl border border-neutral/10' : ''; +@endphp + +
+ class([ + 'min-w-full align-middle text-sm', + '[&_tbody_tr:nth-child(even)]:bg-neutral/3' => $striped, + ]) }} + data-hoverable="{{ $hoverable ? 'true' : 'false' }}" + data-compact="{{ $compact ? 'true' : 'false' }}" + > + @if(isset($head)) + + + {{ $head }} + + + @endif + + {{ $slot }} + + @if(isset($foot)) + + {{ $foot }} + + @endif +
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/tabs.blade.php b/extensions/Servers/Proxmox/views/components/ui/tabs.blade.php new file mode 100644 index 000000000..58c540cb1 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/tabs.blade.php @@ -0,0 +1,82 @@ +{{-- + Tabs Component - TailServer Theme + + Usage: + + Overview content + Settings content + Logs content + +--}} + +@props([ + 'tabs' => [], + 'active' => null, + 'variant' => 'default', +]) + +@php + $variantClasses = [ + 'default' => [ + 'container' => 'border-b border-neutral/15', + 'tab' => 'px-4 py-3 text-sm font-medium border-b-2 -mb-px transition-all duration-200', + 'active' => 'text-primary border-primary', + 'inactive' => 'text-base/50 border-transparent hover:text-base hover:border-neutral/30', + ], + 'pills' => [ + 'container' => 'flex gap-1.5 p-1.5 bg-neutral/5 rounded-xl border border-neutral/10', + 'tab' => 'px-4 py-2 text-sm font-medium rounded-lg transition-all duration-200', + 'active' => 'bg-background-secondary text-base shadow-md', + 'inactive' => 'text-base/50 hover:text-base hover:bg-neutral/10', + ], + 'buttons' => [ + 'container' => 'flex gap-2', + 'tab' => 'px-4 py-2.5 text-sm font-medium rounded-xl border transition-all duration-200', + 'active' => 'bg-primary text-white border-primary shadow-md shadow-primary/25', + 'inactive' => 'bg-background-secondary text-base/60 border-neutral/20 hover:border-neutral/40 hover:text-base hover:shadow-sm', + ], + ]; + + $styles = $variantClasses[$variant] ?? $variantClasses['default']; + $activeTab = $active ?? ($tabs[0] ?? null); +@endphp + +
+ {{-- Tab Navigation --}} +
+ +
+ + {{-- Tab Panels --}} +
+ {{ $slot }} +
+
diff --git a/extensions/Servers/Proxmox/views/components/ui/toggle.blade.php b/extensions/Servers/Proxmox/views/components/ui/toggle.blade.php new file mode 100644 index 000000000..c4d5940e7 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/toggle.blade.php @@ -0,0 +1,45 @@ +{{-- + Toggle/Switch Component - TailServer Theme + + Usage: + +--}} + +@props([ + 'label' => null, + 'description' => null, + 'disabled' => false, +]) + + diff --git a/extensions/Servers/Proxmox/views/components/ui/tooltip.blade.php b/extensions/Servers/Proxmox/views/components/ui/tooltip.blade.php new file mode 100644 index 000000000..48ffc8a51 --- /dev/null +++ b/extensions/Servers/Proxmox/views/components/ui/tooltip.blade.php @@ -0,0 +1,56 @@ +{{-- + Tooltip Component - TailServer Theme + + Usage: + + + +--}} + +@props([ + 'text', + 'position' => 'top', // top, bottom, left, right +]) + +@php + $positions = [ + 'top' => 'bottom-full left-1/2 -translate-x-1/2 mb-2', + 'bottom' => 'top-full left-1/2 -translate-x-1/2 mt-2', + 'left' => 'right-full top-1/2 -translate-y-1/2 mr-2', + 'right' => 'left-full top-1/2 -translate-y-1/2 ml-2', + ]; + + $arrows = [ + 'top' => 'top-full left-1/2 -translate-x-1/2 border-t-zinc-800 border-x-transparent border-b-transparent border-4', + 'bottom' => 'bottom-full left-1/2 -translate-x-1/2 border-b-zinc-800 border-x-transparent border-t-transparent border-4', + 'left' => 'left-full top-1/2 -translate-y-1/2 border-l-zinc-800 border-y-transparent border-r-transparent border-4', + 'right' => 'right-full top-1/2 -translate-y-1/2 border-r-zinc-800 border-y-transparent border-l-transparent border-4', + ]; +@endphp + +
+ {{ $slot }} + +
+
+ {{ $text }} +
+
+
+
diff --git a/extensions/Servers/Proxmox/views/firewall.blade.php b/extensions/Servers/Proxmox/views/firewall.blade.php index 284587ff4..8b16ff3b4 100644 --- a/extensions/Servers/Proxmox/views/firewall.blade.php +++ b/extensions/Servers/Proxmox/views/firewall.blade.php @@ -56,85 +56,36 @@
{{-- Page Header --}} -
-

Firewall Management

-

Configure firewall rules, policies, aliases, and IPSets for your virtual machine

-
+ {{-- Error Modal --}} @if($error && $showErrorModal) -
-
+ + -
-
- -
-
-

Error

-

{{ $error }}

-
-
-
- -
-
-
+ +

{{ $error }}

+ + + Close + + + @endif - {{-- Main Firewall Toggle & Status --}} -
-
-
-
- -
-
-

Master Firewall Control

-

- @if($firewallEnabled) - ✓ Active - Your VM is protected by firewall rules - @else - ⚠ Disabled - Your VM has no firewall protection - @endif -

-
-
-
- @if($firewallEnabled) - - @else - - @endif -
-
-
+ {{-- Main Firewall Toggle & Status --}}\n
\n {{-- Decorative elements --}}\n
\n
\n \n
\n
\n
\n \n
\n
\n

Master Firewall Control

\n

\n @if($firewallEnabled)\n \n \n \n \n \n Active - Your VM is protected\n \n @else\n \n \n Disabled - No firewall protection\n \n @endif\n

\n
\n
\n
\n @if($firewallEnabled)\n \n Disable\n Disabling...\n \n @else\n \n Enable Firewall\n Enabling...\n \n @endif\n
\n
\n
{{-- Firewall Policies & Network Adapters Grid --}} @if($firewallEnabled)
{{-- Default Policies Card --}} -
+
@@ -151,35 +102,36 @@
-
- - -

Default action for incoming traffic not matching any rule

-
+ + + + + -
- - -

Default action for outgoing traffic not matching any rule

-
+ + + + + - +
-
+ {{-- Network Adapters --}} -
+
@@ -198,11 +150,9 @@
{{ $adapter['name'] }} - @if($adapterFirewallStates[$adapter['name']] ?? false) - Active - @else - Off - @endif + + {{ ($adapterFirewallStates[$adapter['name']] ?? false) ? 'Active' : 'Off' }} +
{{ ucfirst($adapter['model'] ?? 'Unknown') }} @@ -213,27 +163,27 @@
@if($adapterFirewallStates[$adapter['name']] ?? false) - + @else - + @endif
@@ -241,12 +191,12 @@ @endforeach
@else -
- -

No network adapters found

-
+ @endif -
+
{{-- Policy Info Modal --}} @@ -1817,19 +1767,14 @@
-
- - +
@@ -1894,16 +1839,13 @@
- - +
@@ -1966,16 +1908,13 @@
- - +
@@ -2041,16 +1980,13 @@
- - +
@@ -2334,16 +2270,13 @@
- - +
diff --git a/extensions/Servers/Proxmox/views/index.blade.php b/extensions/Servers/Proxmox/views/index.blade.php index a55262ac4..e6a99b8ff 100644 --- a/extensions/Servers/Proxmox/views/index.blade.php +++ b/extensions/Servers/Proxmox/views/index.blade.php @@ -1,11 +1,22 @@ +{{-- Server Listing - TailServer Theme --}}
-
- Servers -
+ {{-- Page Header --}} + -
- @foreach($servers as $server) + {{-- Server Cards Grid --}} +
+ @forelse($servers as $server) - @endforeach + @empty + + @endforelse
\ No newline at end of file diff --git a/extensions/Servers/Proxmox/views/network.blade.php b/extensions/Servers/Proxmox/views/network.blade.php index 02a9169f6..1edfd0b25 100644 --- a/extensions/Servers/Proxmox/views/network.blade.php +++ b/extensions/Servers/Proxmox/views/network.blade.php @@ -101,63 +101,23 @@
-
-
-

Assigned Network Addresses

-
- - - -
-
+ + +
diff --git a/extensions/Servers/Proxmox/views/overview.blade.php b/extensions/Servers/Proxmox/views/overview.blade.php index 75f2fda26..881b1364b 100644 --- a/extensions/Servers/Proxmox/views/overview.blade.php +++ b/extensions/Servers/Proxmox/views/overview.blade.php @@ -7,22 +7,18 @@ > @if(!$status) {{-- Error state when status cannot be loaded --}} -
-
- -

Unable to Load Server Status

-
+ + Unable to Load Server Status

We couldn't retrieve the current status from the hypervisor. This may be due to:

  • Temporary connectivity issues with the Proxmox cluster
  • The VM may be in an intermediate state
  • Network timeout while fetching data
- -
+ + @else