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
+ merge(['class' => $classes]) }}
+ >
+@endif
+
+ @if($loading)
+
+
+
+
+ @elseif($icon && $iconPosition === 'left')
+
+ @endif
+
+ @if($slot->isNotEmpty())
+ {{ $slot }}
+ @endif
+
+ @if($icon && $iconPosition === 'right' && !$loading)
+
+ @endif
+
+@if($href)
+
+@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))
+
+ @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
+ merge(['class' => $classes]) }}>
+@endif
+
+ @if($icon)
+
+ @endif
+
+ {{ $slot }}
+
+@if($href && !$disabled)
+
+@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 --}}
+
+
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()))
+
toHtml()) }}');
+ copied = true;
+ setTimeout(() => copied = false, 2000);
+ "
+ class="text-base/50 hover:text-base/70 transition-colors flex-shrink-0"
+ :title="copied ? 'Copied!' : 'Copy to clipboard'"
+ >
+
+
+
+ @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)
+
+ {{ $label }}
+ @if($required)
+ *
+ @endif
+
+ @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 --}}
+
+
+
+
+
+
+
+ @if($icon)
+
+
+
+ @endif
+
+ {{ $helpTitle ?? $title }}
+
+
+
+ @if($helpContent)
+
+ {!! $helpContent !!}
+
+ @endif
+
+ @if(isset($help))
+ {{ $help }}
+ @endif
+
+
+
+ @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
+ merge(['class' => $cardClasses . ' ' . $paddingClasses]) }}>
+@endif
+
+
+
+ {{-- Label --}}
+
{{ $label }}
+
+ {{-- Value --}}
+
+ @if($prefix)
+
{{ $prefix }}
+ @endif
+
+ @if($loading)
+
+ @else
+
{{ $value }}
+ @endif
+
+ @if($suffix)
+
{{ $suffix }}
+ @endif
+
+
+ {{-- Trend --}}
+ @if($trend !== null || $trendLabel)
+
+ @if($trendIcon)
+
+ @endif
+ @if($trend !== null)
+ {{ $trend }}
+ @endif
+ @if($trendLabel)
+ {{ $trendLabel }}
+ @endif
+
+ @endif
+
+ {{-- Slot for additional content --}}
+ @if($slot->isNotEmpty())
+
+ {{ $slot }}
+
+ @endif
+
+
+ {{-- Icon --}}
+ @if($icon)
+
+
+
+ @endif
+
+
+@if($href)
+
+@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)
+
+ {{ $slot }}
+
+ @if($sorted === 'asc')
+
+ @elseif($sorted === 'desc')
+
+ @else
+
+ @endif
+
+
+ @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)
+
+ @else
+
+ @if(isset($head))
+
+ @endif
+
+ @if(isset($body) && $body->isNotEmpty())
+
+ {{ $body }}
+
+ @elseif($slot->isNotEmpty())
+
+ {{ $slot }}
+
+ @else
+
+
+
+
+
+
+
+
{{ $emptyMessage }}
+
+
+
+
+ @endif
+
+ @if(isset($foot))
+
+ {{ $foot }}
+
+ @endif
+
+ @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)
+
+ @if(isset($item['icon']))
+
+ @endif
+ {{ $item['label'] }}
+ @if(isset($item['badge']))
+ {{ $item['badge'] }}
+ @endif
+
+ @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
+
+merge([
+ 'disabled' => $disabled || $loading,
+ ])->class([
+ 'inline-flex items-center gap-2 rounded-xl font-medium transition-all duration-200 hover:-translate-y-0.5 active:translate-y-0 active:scale-95',
+ $variants[$variant] ?? $variants['default'],
+ $sizes[$size] ?? $sizes['md'],
+ 'opacity-50 cursor-not-allowed hover:translate-y-0' => $disabled,
+ 'cursor-wait hover:translate-y-0' => $loading,
+ ]) }}
+>
+ @if($loading)
+
+
+
+
+ @elseif($icon)
+
+ @endif
+ {{ $label }}
+
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
+
+{{ $tag }}>
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)
+
+ @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 }}
+
+
+
+
+ {{ $cancelLabel }}
+
+ whereStartsWith('wire:click') }}
+ class="flex-1 px-4 py-2.5 {{ $config['buttonBg'] }} rounded-xl text-sm font-medium text-white transition-all duration-200 shadow-md hover:shadow-lg active:scale-95"
+ >
+ {{ $confirmLabel }}
+
+
+
+
+
+
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)
+
{{ $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 }}
+{{ $tag }}>
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,
+])
+
+
+
{{ $label }}
+
+
+ {{ $value ?? 'Not set' }}
+ @if($editClick)
+
+
+
+ @endif
+
+
+
+ @if($editing !== false)
+
+
+
+
+
+
+
+
Edit {{ $label }}
+
+
+
+
+
+
+
+ {{ $label }}
+ whereStartsWith('wire:model') }}
+ class="w-full mt-1 px-3 py-2 bg-neutral/5 border border-neutral/20 rounded-lg text-sm text-base placeholder:text-base/40 focus:outline-none focus:ring-2 focus:ring-primary/50"
+ placeholder="{{ $placeholder ?? 'Enter ' . strtolower($label) }}"
+ />
+
+
+ @if($error)
+
{{ $error }}
+ @endif
+
+ @if(isset($hint))
+
{{ $hint }}
+ @endif
+
+
+
+ @if($cancelClick)
+
+ Cancel
+
+ @endif
+ @if($saveClick)
+
+ Save
+
+ @endif
+ @if($applyClick)
+
+ {{ $applyLabel }}
+
+ @endif
+
+
+
+ @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',
+])
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $title }}
+
+
+
+ @if(isset($description))
+
+ {{ $description }}
+
+ @endif
+
+ @if(isset($details))
+
+ {{ $details }}
+
+ @endif
+
+ {{ $slot }}
+
+
+
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Select Icon
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @if(count($categories) > 0)
+
+
+ All
+
+ @foreach($categories as $category)
+
+ {{ $category['name'] }}
+
+ @endforeach
+
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
No icons found matching your search.
+
+
+
+
+
+
+ Clear Selection
+
+
+ Done
+
+
+
+
+
+
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)
+ copied = false, 2000);
+ "
+ class="p-1 rounded hover:bg-neutral/10 transition-colors text-base/40 hover:text-base/70"
+ title="Copy to clipboard"
+ >
+
+
+
+ @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)
+
+ {{ $label }}
+ @if($required)
+ *
+ @endif
+
+ @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 --}}
+
+
+ {{-- 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 --}}
+
+
+
+
+
+
+
+ @if($icon)
+
+
+
+ @endif
+
{{ $title }}
+
+
+ {{ $helpText }}
+
+
+
+
+ @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:
+
+ United States
+ United Kingdom
+
+--}}
+
+@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)
+
+ {{ $label }}
+ @if($required)
+ *
+ @endif
+
+ @endif
+
+
+
except('class')->class([$selectClasses, $sizeClass]) }}
+ >
+ {{ $slot }}
+
+
+
+
+
+
+ @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
+{{ $tag }}>
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 --}}
+
+
+ @foreach($tabs as $tab)
+ @php
+ $tabName = is_array($tab) ? ($tab['name'] ?? $tab['label'] ?? '') : $tab;
+ $tabLabel = is_array($tab) ? ($tab['label'] ?? $tab['name'] ?? '') : $tab;
+ $tabIcon = is_array($tab) ? ($tab['icon'] ?? null) : null;
+ $tabBadge = is_array($tab) ? ($tab['badge'] ?? null) : null;
+ @endphp
+
+ @if($tabIcon)
+
+ @endif
+ {{ $tabLabel }}
+ @if($tabBadge)
+
+ {{ $tabBadge }}
+
+ @endif
+
+ @endforeach
+
+
+
+ {{-- 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,
+])
+
+only('class')->class(['flex items-center justify-between gap-4 cursor-pointer group']) }}>
+ @if($label || $description)
+
+ @if($label)
+ {{ $label }}
+ @endif
+ @if($description)
+ {{ $description }}
+ @endif
+
+ @endif
+
+
+
whereDoesntStartWith('class')->merge(['disabled' => $disabled]) }}
+ class="sr-only peer"
+ />
+
+
+
+
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:
+
+ Hover me
+
+--}}
+
+@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
+
+
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 }}
+
+
+ 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)
-
-
- Disable Firewall
- Disabling...
-
- @else
-
-
- Enable Firewall
- Enabling...
-
- @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 @@
-
-
Incoming Traffic (Policy In)
-
- Accept
- Reject
- Drop
-
-
Default action for incoming traffic not matching any rule
-
+
+ Accept
+ Reject
+ Drop
+
-
-
Outgoing Traffic (Policy Out)
-
- Accept
- Reject
- Drop
-
-
Default action for outgoing traffic not matching any rule
-
+
+ Accept
+ Reject
+ Drop
+
-
+
Update Policies
Updating...
-
+
-
+
{{-- 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)
-
-
+
Disable
...
-
+
@else
-
-
+
Enable
...
-
+
@endif
@@ -241,12 +191,12 @@
@endforeach
@else
-
-
-
No network adapters found
-
+
@endif
-
+
{{-- Policy Info Modal --}}
@@ -1817,19 +1767,14 @@
-
-
+
+
Cancel
-
-
+
+
Delete Rule
Deleting...
-
+
@@ -1894,16 +1839,13 @@
-
+
Cancel
-
-
+
+
Delete
Deleting...
-
+
@@ -1966,16 +1908,13 @@
-
+
Cancel
-
-
+
+
Delete
Deleting...
-
+
@@ -2041,16 +1980,13 @@
-
+
Cancel
-
-
+
+
Remove
Removing...
-
+
@@ -2334,16 +2270,13 @@
-
+
Cancel
-
-
+
+
Delete
Deleting...
-
+
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
-
-
-
-
-
-
+
+
+
+
+ Displays all IP addresses (both IPv4 and IPv6) that have been assigned to this virtual machine. These addresses are configured through the QEMU API and are part of your service allocation.
+
+
+
+ Note: These addresses are managed by the hosting provider and cannot be modified directly. Contact support if you need additional IP addresses or changes to your network configuration.
+
-
-
-
-
-
-
-
-
-
-
-
- Assigned Network Addresses
-
-
-
- Displays all IP addresses (both IPv4 and IPv6) that have been assigned to this virtual machine. These addresses are configured through the QEMU API and are part of your service allocation.
-
-
-
- Note: These addresses are managed by the hosting provider and cannot be modified directly. Contact support if you need additional IP addresses or changes to your network configuration.
-
-
-
-
-
-
-
+
+
+
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
-
-
+
Retry
-
-
+
+
@else