refactor: Update UI components to TailAdmin theme

- Changed badge, button, card, dropdown, input, modal, select, table, tabs, toggle, and tooltip components to align with the TailAdmin design system.
- Updated class names and styles for consistency across components.
- Enhanced accessibility and responsiveness in various components.
- Improved hover and focus states for better user experience.
This commit is contained in:
2025-12-17 12:07:54 -05:00
parent 5004408751
commit 7a089f53e2
15 changed files with 184 additions and 180 deletions

View File

@@ -1,5 +1,5 @@
{{--
Alert Component - TailServer Theme (shadcn-inspired)
Alert Component - TailAdmin Theme
Usage:
<x-proxmox::ui.alert>Default alert</x-proxmox::ui.alert>
@@ -19,23 +19,28 @@
@php
$variantConfig = [
'default' => [
'class' => 'bg-card text-card-foreground',
'class' => 'border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03] text-gray-800 dark:text-white/90',
'iconClass' => 'fill-gray-500 dark:fill-gray-400',
'icon' => $icon ?? 'ri-information-line',
],
'info' => [
'class' => 'border-info/20 bg-info/5 text-info [&>svg]:text-info',
'class' => 'border-blue-light-200 bg-blue-light-50 dark:border-blue-light-500/20 dark:bg-blue-light-500/10 text-blue-light-600 dark:text-blue-light-400',
'iconClass' => 'fill-blue-light-500',
'icon' => $icon ?? 'ri-information-line',
],
'success' => [
'class' => 'border-success/20 bg-success/5 text-success [&>svg]:text-success',
'class' => 'border-success-200 bg-success-50 dark:border-success-500/20 dark:bg-success-500/10 text-success-600 dark:text-success-400',
'iconClass' => 'fill-success-500',
'icon' => $icon ?? 'ri-checkbox-circle-line',
],
'warning' => [
'class' => 'border-warning/20 bg-warning/5 text-warning [&>svg]:text-warning',
'class' => 'border-warning-200 bg-warning-50 dark:border-warning-500/20 dark:bg-warning-500/10 text-warning-600 dark:text-orange-400',
'iconClass' => 'fill-warning-500',
'icon' => $icon ?? 'ri-error-warning-line',
],
'danger' => [
'class' => 'border-danger/20 bg-danger/5 text-danger [&>svg]:text-danger',
'class' => 'border-error-200 bg-error-50 dark:border-error-500/20 dark:bg-error-500/10 text-error-600 dark:text-error-400',
'iconClass' => 'fill-error-500',
'icon' => $icon ?? 'ri-error-warning-fill',
],
];
@@ -46,7 +51,7 @@
<div
role="alert"
{{ $attributes->class([
'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5',
'relative w-full rounded-xl border p-4 flex gap-3 items-start',
$config['class'],
]) }}
@if($dismissible || $collapsible)
@@ -55,24 +60,24 @@
@if($collapsible) collapsed: {{ $collapsed ? 'true' : 'false' }} @endif
}"
x-show="show"
x-transition:enter="transition ease-out duration-150"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@endif
>
<x-dynamic-component :component="$config['icon']" class="size-4" />
<x-dynamic-component :component="$config['icon']" class="size-5 mt-0.5 shrink-0 {{ $config['iconClass'] }}" />
<div class="flex-1 min-w-0">
@if($title)
<h5 class="mb-1 font-medium leading-none tracking-tight">{{ $title }}</h5>
<h5 class="mb-1 text-sm font-semibold">{{ $title }}</h5>
@endif
<div
class="text-sm [&_p]:leading-relaxed opacity-90"
class="text-theme-sm"
@if($collapsible)
x-show="!collapsed"
x-transition:enter="transition ease-out duration-150"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
@endif
@@ -81,15 +86,15 @@
</div>
</div>
@if($dismissible || $collapsible)
<div class="absolute top-3 right-3 flex items-center gap-1">
<div class="flex items-center gap-1 shrink-0">
@if($collapsible)
<button
type="button"
@click="collapsed = !collapsed"
class="p-1 rounded hover:bg-black/5 transition-colors"
class="p-1.5 rounded-lg hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
>
<x-ri-arrow-down-s-line
class="size-4 transition-transform duration-150"
class="size-4 transition-transform duration-200"
x-bind:class="collapsed ? 'rotate-180' : ''"
/>
</button>
@@ -98,7 +103,7 @@
<button
type="button"
@click="show = false"
class="p-1 rounded hover:bg-black/5 transition-colors"
class="p-1.5 rounded-lg hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
>
<x-ri-close-line class="size-4" />
</button>

View File

@@ -1,5 +1,5 @@
{{--
Badge Component - TailServer Theme (shadcn-inspired)
Badge Component - TailAdmin Theme
Usage:
<x-proxmox::ui.badge>Default</x-proxmox::ui.badge>
@@ -18,31 +18,31 @@
])
@php
$baseClasses = 'inline-flex items-center rounded-md border font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2';
$baseClasses = 'inline-flex items-center rounded-full font-medium transition-colors';
$variantClasses = [
'default' => 'border-transparent bg-primary text-primary-foreground shadow',
'secondary' => 'border-transparent bg-secondary text-secondary-foreground',
'success' => $outline ? 'border-success/40 text-success bg-transparent' : 'border-transparent bg-success/15 text-success',
'warning' => $outline ? 'border-warning/40 text-warning bg-transparent' : 'border-transparent bg-warning/15 text-warning',
'danger' => $outline ? 'border-danger/40 text-danger bg-transparent' : 'border-transparent bg-danger/15 text-danger',
'info' => $outline ? 'border-info/40 text-info bg-transparent' : 'border-transparent bg-info/15 text-info',
'outline' => 'text-foreground border-neutral/20',
'muted' => 'border-transparent bg-muted text-muted-foreground',
'default' => 'bg-brand-50 text-brand-500 dark:bg-brand-500/15 dark:text-brand-400',
'secondary' => 'bg-gray-100 text-gray-700 dark:bg-white/5 dark:text-white/80',
'success' => $outline ? 'ring-1 ring-success-500/40 text-success-600 bg-transparent dark:text-success-400' : 'bg-success-50 text-success-600 dark:bg-success-500/15 dark:text-success-400',
'warning' => $outline ? 'ring-1 ring-warning-500/40 text-warning-600 bg-transparent dark:text-orange-400' : 'bg-warning-50 text-warning-600 dark:bg-warning-500/15 dark:text-orange-400',
'danger' => $outline ? 'ring-1 ring-error-500/40 text-error-600 bg-transparent dark:text-error-400' : 'bg-error-50 text-error-600 dark:bg-error-500/15 dark:text-error-400',
'info' => $outline ? 'ring-1 ring-blue-light-500/40 text-blue-light-600 bg-transparent dark:text-blue-light-400' : 'bg-blue-light-50 text-blue-light-500 dark:bg-blue-light-500/15 dark:text-blue-light-500',
'outline' => 'text-gray-700 ring-1 ring-gray-300 dark:text-gray-400 dark:ring-gray-700',
'muted' => 'bg-gray-500 text-white dark:bg-white/5 dark:text-white/80',
];
$sizeClasses = [
'xs' => 'px-1.5 py-0.5 text-[10px]',
'sm' => 'px-2 py-0.5 text-[11px]',
'md' => 'px-2.5 py-0.5 text-xs',
'xs' => 'px-2 py-0.5 text-[10px]',
'sm' => 'px-2 py-0.5 text-xs',
'md' => 'px-2.5 py-0.5 text-sm',
'lg' => 'px-3 py-1 text-sm',
];
$iconSizes = [
'xs' => 'size-2.5',
'sm' => 'size-3',
'md' => 'size-3',
'lg' => 'size-3.5',
'md' => 'size-3.5',
'lg' => 'size-4',
];
$dotSizes = [
@@ -72,7 +72,7 @@
</span>
@endif
@if($icon)
<x-dynamic-component :component="$icon" class="{{ $iconSize }}" />
<x-dynamic-component :component="$icon" class="fill-current {{ $iconSize }}" />
@endif
{{ $slot }}
</span>

View File

@@ -1,5 +1,5 @@
{{--
Button Component - shadcn-inspired
Button Component - TailAdmin Theme
Usage:
<x-proxmox::ui.button>Click me</x-proxmox::ui.button>
@@ -24,36 +24,36 @@
@php
$tag = $href ? 'a' : 'button';
$baseClasses = 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50';
$baseClasses = 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg font-medium transition-colors focus-visible:outline-none focus-visible:ring-3 focus-visible:ring-brand-500/10 disabled:pointer-events-none disabled:opacity-50';
$variantClasses = [
'primary' => 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
'secondary' => 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
'outline' => 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
'ghost' => 'hover:bg-accent hover:text-accent-foreground',
'danger' => 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
'success' => 'bg-success text-white shadow-sm hover:bg-success/90',
'warning' => 'bg-warning text-white shadow-sm hover:bg-warning/90',
'info' => 'bg-info text-white shadow-sm hover:bg-info/90',
'link' => 'text-primary underline-offset-4 hover:underline',
'primary' => 'bg-brand-500 text-white shadow-theme-xs hover:bg-brand-600',
'secondary' => 'bg-white text-gray-700 shadow-theme-xs ring-1 ring-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-400 dark:ring-gray-700 dark:hover:bg-white/[0.03]',
'outline' => 'border border-gray-300 bg-white shadow-theme-xs hover:bg-gray-50 hover:text-gray-800 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-gray-200',
'ghost' => 'hover:bg-gray-100 hover:text-gray-700 dark:hover:bg-white/5 dark:hover:text-gray-300',
'danger' => 'bg-error-500 text-white shadow-theme-xs hover:bg-error-600',
'success' => 'bg-success-500 text-white shadow-theme-xs hover:bg-success-600',
'warning' => 'bg-warning-500 text-white shadow-theme-xs hover:bg-warning-600',
'info' => 'bg-blue-light-500 text-white shadow-theme-xs hover:bg-blue-light-600',
'link' => 'text-brand-500 hover:text-brand-600 hover:underline underline-offset-4',
];
$sizeClasses = [
'xs' => 'h-7 px-2 text-xs',
'sm' => 'h-8 px-3 text-xs',
'md' => 'h-9 px-4 py-2',
'lg' => 'h-10 px-8',
'xl' => 'h-11 px-10 text-base',
'icon' => 'h-9 w-9',
'xs' => 'h-8 px-2.5 text-xs',
'sm' => 'h-9 px-3 text-sm',
'md' => 'h-10 px-4 text-sm',
'lg' => 'h-11 px-5 text-sm',
'xl' => 'h-12 px-6 text-base',
'icon' => 'h-10 w-10',
];
$iconSizes = [
'xs' => 'size-3',
'sm' => 'size-3.5',
'xs' => 'size-3.5',
'sm' => 'size-4',
'md' => 'size-4',
'lg' => 'size-4',
'lg' => 'size-5',
'xl' => 'size-5',
'icon' => 'size-4',
'icon' => 'size-5',
];
$classes = collect([
@@ -80,11 +80,11 @@
<span>{{ $loadingText ?? $slot }}</span>
@else
@if($icon)
<x-dynamic-component :component="$icon" class="{{ $iconSize }}" />
<x-dynamic-component :component="$icon" class="fill-current {{ $iconSize }}" />
@endif
{{ $slot }}
@if($iconRight)
<x-dynamic-component :component="$iconRight" class="{{ $iconSize }}" />
<x-dynamic-component :component="$iconRight" class="fill-current {{ $iconSize }}" />
@endif
@endif
</{{ $tag }}>

View File

@@ -1,5 +1,5 @@
{{--
Card Component - shadcn-inspired
Card Component - TailAdmin Theme
Usage:
<x-proxmox::ui.card>Content</x-proxmox::ui.card>
@@ -11,7 +11,7 @@
'title' => null,
'subtitle' => null,
'icon' => null,
'iconColor' => 'text-primary',
'iconColor' => 'text-brand-500',
'actions' => null,
'footer' => null,
'footerClass' => '',
@@ -24,8 +24,8 @@
<div
{{ $attributes->class([
'rounded-xl border bg-card shadow-sm',
'hover:bg-accent/50 transition-colors duration-150' => $hover || $clickable,
'rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]',
'hover:shadow-theme-md transition-shadow duration-200' => $hover || $clickable,
'cursor-pointer' => $clickable,
]) }}
@if($collapsible)
@@ -33,19 +33,19 @@
@endif
>
@if($title || $actions)
<div class="flex items-center justify-between gap-4 p-6 pb-0">
<div class="flex items-center justify-between gap-4 px-6 py-5">
<div class="flex items-center gap-3">
@if($icon)
<div class="flex items-center justify-center size-9 rounded-lg bg-primary/10">
<x-dynamic-component :component="$icon" class="size-4 {{ $iconColor }}" />
<div class="flex items-center justify-center size-10 rounded-xl bg-brand-50 dark:bg-brand-500/10">
<x-dynamic-component :component="$icon" class="size-5 {{ $iconColor }}" />
</div>
@endif
<div class="space-y-1">
<div class="space-y-0.5">
@if($title)
<h3 class="font-semibold leading-none tracking-tight">{{ $title }}</h3>
<h3 class="text-base font-medium text-gray-800 dark:text-white/90">{{ $title }}</h3>
@endif
@if($subtitle)
<p class="text-sm text-muted-foreground">{{ $subtitle }}</p>
<p class="text-theme-sm text-gray-500 dark:text-gray-400">{{ $subtitle }}</p>
@endif
</div>
</div>
@@ -58,10 +58,10 @@
<button
type="button"
@click="isCollapsed = !isCollapsed"
class="p-1.5 rounded-md hover:bg-muted transition-colors duration-150"
class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-white/5 transition-colors duration-200"
>
<x-ri-arrow-down-s-line
class="size-4 text-muted-foreground transition-transform duration-150"
class="size-5 text-gray-500 dark:text-gray-400 transition-transform duration-200"
x-bind:class="isCollapsed ? 'rotate-180' : ''"
/>
</button>
@@ -73,15 +73,15 @@
<div
@class([
'p-6',
'pt-4' => $title,
'border-t border-gray-100 dark:border-gray-800' => $title,
'p-5 sm:p-6',
])
@if($collapsible)
x-show="!isCollapsed"
x-transition:enter="transition ease-out duration-150"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@endif
@@ -90,7 +90,7 @@
</div>
@if($footer)
<div class="flex items-center p-6 pt-0 {{ $footerClass }}">
<div class="flex items-center border-t border-gray-100 dark:border-gray-800 px-6 py-4 {{ $footerClass }}">
{{ $footer }}
</div>
@endif

View File

@@ -1,5 +1,5 @@
{{--
Dropdown Component - shadcn-style
Dropdown Component - TailAdmin style
Usage:
<x-proxmox::ui.dropdown>
@@ -44,17 +44,17 @@
<div
x-show="open"
x-transition:enter="transition ease-out duration-100"
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave="transition ease-in duration-100"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="absolute z-50 mt-1.5 {{ $widthClasses[$width] ?? 'w-48' }} {{ $alignClasses[$align] ?? $alignClasses['right'] }}"
class="absolute z-50 mt-2 {{ $widthClasses[$width] ?? 'w-48' }} {{ $alignClasses[$align] ?? $alignClasses['right'] }}"
style="display: none;"
@click="open = false"
>
<div class="rounded-md border bg-popover p-1 text-popover-foreground shadow-md {{ $contentClasses }}">
<div class="rounded-xl border border-gray-200 bg-white p-2 shadow-theme-lg dark:border-gray-800 dark:bg-gray-900 {{ $contentClasses }}">
{{ $slot }}
</div>
</div>

View File

@@ -1,5 +1,5 @@
{{--
Input Component - shadcn-style
Input Component - TailAdmin Theme
Usage:
<x-proxmox::ui.input name="email" label="Email" />
@@ -24,43 +24,43 @@
@php
$sizeClasses = [
'sm' => 'h-8 text-sm',
'md' => 'h-9 text-sm',
'lg' => 'h-10 text-base',
'sm' => 'h-9 text-sm',
'md' => 'h-11 text-sm',
'lg' => 'h-12 text-base',
];
$sizeClass = $sizeClasses[$size] ?? $sizeClasses['md'];
$inputClasses = 'flex w-full rounded-md border bg-transparent px-3 py-1 text-sm transition-colors duration-150 file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50';
$inputClasses = 'flex w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 text-sm text-gray-800 shadow-theme-xs transition-colors duration-200 placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30 dark:focus:border-brand-800';
if ($error) {
$inputClasses .= ' border-danger focus-visible:ring-danger';
} else {
$inputClasses .= ' border-input';
$inputClasses = str_replace('border-gray-300', 'border-error-300', $inputClasses);
$inputClasses = str_replace('focus:border-brand-300', 'focus:border-error-500', $inputClasses);
$inputClasses = str_replace('focus:ring-brand-500/10', 'focus:ring-error-500/10', $inputClasses);
}
if ($icon) {
$inputClasses .= ' ps-9';
$inputClasses .= ' pl-11';
}
if ($iconRight) {
$inputClasses .= ' pe-9';
$inputClasses .= ' pr-11';
}
@endphp
<div {{ $attributes->only('class')->class(['space-y-2']) }}>
<div {{ $attributes->only('class')->class(['space-y-1.5']) }}>
@if($label)
<label @if($name) for="{{ $name }}" @endif class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
<label @if($name) for="{{ $name }}" @endif class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
{{ $label }}
@if($required)
<span class="text-danger">*</span>
<span class="text-error-500">*</span>
@endif
</label>
@endif
<div class="relative">
@if($icon)
<div class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3 text-muted-foreground">
<x-dynamic-component :component="$icon" class="size-4" />
<div class="pointer-events-none absolute inset-y-0 left-0 flex h-11 w-[46px] items-center justify-center border-r border-gray-200 dark:border-gray-800">
<x-dynamic-component :component="$icon" class="fill-gray-500 dark:fill-gray-400 size-5" />
</div>
@endif
@@ -75,15 +75,15 @@
/>
@if($iconRight)
<div class="pointer-events-none absolute inset-y-0 end-0 flex items-center pe-3 text-muted-foreground">
<x-dynamic-component :component="$iconRight" class="size-4" />
<div class="pointer-events-none absolute inset-y-0 right-0 flex h-11 w-[46px] items-center justify-center border-l border-gray-200 dark:border-gray-800">
<x-dynamic-component :component="$iconRight" class="fill-gray-500 dark:fill-gray-400 size-5" />
</div>
@endif
</div>
@if($error)
<p class="text-[0.8rem] font-medium text-danger">{{ $error }}</p>
<p class="text-sm text-error-500">{{ $error }}</p>
@elseif($hint)
<p class="text-[0.8rem] text-muted-foreground">{{ $hint }}</p>
<p class="text-sm text-gray-500 dark:text-gray-400">{{ $hint }}</p>
@endif
</div>

View File

@@ -1,5 +1,5 @@
{{--
Modal Component - shadcn-style Dialog
Modal Component - TailAdmin Dialog
Usage:
<x-proxmox::ui.modal name="my-modal" title="Modal Title">Content</x-proxmox::ui.modal>
@@ -13,7 +13,7 @@
'title' => null,
'subtitle' => null,
'icon' => null,
'iconColor' => 'text-primary',
'iconColor' => 'text-brand-500',
'maxWidth' => 'md',
'closeable' => true,
'footer' => null,
@@ -41,59 +41,59 @@
x-on:keydown.escape.window="@if($closeable) show = false @endif"
x-show="show"
x-cloak
class="fixed inset-0 z-50 overflow-y-auto"
class="fixed inset-0 z-99999 overflow-y-auto"
{{ $attributes }}
>
{{-- Backdrop --}}
<div
x-show="show"
x-transition:enter="transition ease-out duration-150"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@if($closeable) @click="show = false" @endif
class="fixed inset-0 bg-black/50 backdrop-blur-sm"
class="fixed inset-0 bg-gray-900/50 backdrop-blur-sm dark:bg-gray-900/80"
></div>
{{-- Modal Panel --}}
<div class="fixed inset-0 flex items-center justify-center p-4">
<div
x-show="show"
x-transition:enter="transition ease-out duration-150"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
@click.stop
class="relative w-full {{ $maxWidthClass }} max-h-[90vh] overflow-y-auto rounded-xl border bg-background-secondary shadow-lg"
class="relative w-full {{ $maxWidthClass }} max-h-[90vh] overflow-y-auto rounded-2xl border border-gray-200 bg-white shadow-theme-lg dark:border-gray-800 dark:bg-gray-900"
>
{{-- Header --}}
@if($title || $closeable)
<div class="flex items-start justify-between gap-4 px-6 pt-6 pb-4">
<div class="flex items-center gap-3">
<div class="flex items-start justify-between gap-4 border-b border-gray-200 px-6 py-5 dark:border-gray-800">
<div class="flex items-center gap-3.5">
@if($icon)
<div class="flex-shrink-0 flex items-center justify-center size-9 rounded-lg bg-primary/10">
<x-dynamic-component :component="$icon" class="size-4 {{ $iconColor }}" />
<div class="flex size-11 flex-shrink-0 items-center justify-center rounded-xl bg-brand-50 dark:bg-brand-500/10">
<x-dynamic-component :component="$icon" class="size-5 {{ $iconColor }} dark:text-brand-400" />
</div>
@endif
<div class="space-y-1">
@if($title)
<h3 class="text-lg font-semibold leading-none tracking-tight">{{ $title }}</h3>
<h3 class="text-lg font-semibold text-gray-800 dark:text-white/90">{{ $title }}</h3>
@endif
@if($subtitle)
<p class="text-sm text-muted-foreground">{{ $subtitle }}</p>
<p class="text-theme-sm text-gray-500 dark:text-gray-400">{{ $subtitle }}</p>
@endif
</div>
</div>
@if($closeable)
<button
@click="show = false"
class="rounded-sm opacity-70 ring-offset-background transition-opacity duration-150 hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
class="flex size-9 items-center justify-center rounded-lg text-gray-500 transition-colors duration-150 hover:bg-gray-100 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-brand-500/20 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-300"
>
<x-ri-close-line class="size-4" />
<x-ri-close-line class="size-5" />
<span class="sr-only">Close</span>
</button>
@endif
@@ -101,13 +101,13 @@
@endif
{{-- Content --}}
<div class="px-6 pb-6">
<div class="px-6 py-5">
{{ $slot }}
</div>
{{-- Footer --}}
@if($footer)
<div class="flex items-center justify-end gap-2 px-6 py-4 border-t">
<div class="flex items-center justify-end gap-3 border-t border-gray-200 px-6 py-4 dark:border-gray-800">
{{ $footer }}
</div>
@endif

View File

@@ -1,5 +1,5 @@
{{--
Select Component - shadcn-style
Select Component - TailAdmin style
Usage:
<x-proxmox::ui.select name="country" label="Country">
@@ -20,27 +20,27 @@
@php
$sizeClasses = [
'sm' => 'h-8 text-sm',
'md' => 'h-9 text-sm',
'lg' => 'h-10 text-base',
'sm' => 'h-9 text-theme-xs py-2',
'md' => 'h-11 text-theme-sm py-2.5',
'lg' => 'h-12 text-base py-3',
];
$sizeClass = $sizeClasses[$size] ?? $sizeClasses['md'];
$selectClasses = 'flex w-full items-center justify-between whitespace-nowrap rounded-md border bg-transparent px-3 py-2 text-sm ring-offset-background transition-colors duration-150 placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 appearance-none cursor-pointer';
$selectClasses = 'block w-full appearance-none rounded-lg border bg-transparent px-4 pr-10 shadow-theme-xs transition-colors duration-150 placeholder:text-gray-400 focus:outline-none focus:ring-3 disabled:cursor-not-allowed disabled:bg-gray-50 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-gray-500 dark:disabled:bg-gray-800';
if ($error) {
$selectClasses .= ' border-danger focus:ring-danger';
$selectClasses .= ' border-error-300 focus:border-error-300 focus:ring-error-500/10 dark:border-error-700';
} else {
$selectClasses .= ' border-input';
$selectClasses .= ' border-gray-300 focus:border-brand-300 focus:ring-brand-500/10 dark:border-gray-700 dark:focus:border-brand-600';
}
@endphp
<div {{ $attributes->only('class')->class(['space-y-2']) }}>
@if($label)
<label @if($name) for="{{ $name }}" @endif class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
<label @if($name) for="{{ $name }}" @endif class="text-theme-sm font-medium text-gray-700 dark:text-gray-300">
{{ $label }}
@if($required)
<span class="text-danger">*</span>
<span class="text-error-500">*</span>
@endif
</label>
@endif
@@ -54,14 +54,14 @@
>
{{ $slot }}
</select>
<div class="pointer-events-none absolute inset-y-0 end-0 flex items-center pe-3 text-muted-foreground">
<x-ri-arrow-down-s-line class="size-4 opacity-50" />
<div class="pointer-events-none absolute inset-y-0 end-0 flex items-center pe-4 text-gray-500 dark:text-gray-400">
<x-ri-arrow-down-s-line class="size-5" />
</div>
</div>
@if($error)
<p class="text-[0.8rem] font-medium text-danger">{{ $error }}</p>
<p class="text-theme-xs font-medium text-error-500">{{ $error }}</p>
@elseif($hint)
<p class="text-[0.8rem] text-muted-foreground">{{ $hint }}</p>
<p class="text-theme-xs text-gray-500 dark:text-gray-400">{{ $hint }}</p>
@endif
</div>

View File

@@ -1,5 +1,5 @@
{{--
Table Row Component - shadcn-style
Table Row Component - TailAdmin style
--}}
@props([
@@ -16,9 +16,8 @@
@if($href)
<tr
{{ $attributes->class([
'border-b transition-colors cursor-pointer',
'hover:bg-muted/50' => $isHoverable,
'data-[state=selected]:bg-muted',
'cursor-pointer transition-colors duration-150',
'hover:bg-gray-50 dark:hover:bg-gray-800/50' => $isHoverable,
]) }}
onclick="window.location='{{ $href }}'"
>
@@ -27,10 +26,9 @@
@else
<tr
{{ $attributes->class([
'border-b transition-colors',
'hover:bg-muted/50' => $isHoverable,
'transition-colors duration-150',
'hover:bg-gray-50 dark:hover:bg-gray-800/50' => $isHoverable,
'cursor-pointer' => $clickable,
'data-[state=selected]:bg-muted',
]) }}
>
{{ $slot }}

View File

@@ -1,5 +1,5 @@
{{--
Table Data Cell Component - shadcn-style
Table Data Cell Component - TailAdmin style
--}}
@props([
@@ -20,11 +20,11 @@
<td
{{ $attributes->class([
'p-4 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
'px-5 py-4 text-theme-sm text-gray-700 dark:text-gray-300',
$alignClass,
'whitespace-nowrap' => $nowrap,
'text-muted-foreground' => $muted,
'font-medium' => $strong,
'text-gray-500 dark:text-gray-400' => $muted,
'font-medium text-gray-800 dark:text-white/90' => $strong,
]) }}
>
{{ $slot }}

View File

@@ -1,5 +1,5 @@
{{--
Table Header Cell Component - shadcn-style
Table Header Cell Component - TailAdmin style
--}}
@props([
@@ -23,9 +23,9 @@
<th
{{ $attributes->class([
'h-10 px-4 font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
'px-5 py-3.5 text-theme-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400',
$alignClass,
'cursor-pointer select-none hover:text-foreground transition-colors duration-150' => $sortable,
'cursor-pointer select-none transition-colors duration-150 hover:text-gray-700 dark:hover:text-gray-300' => $sortable,
]) }}
@if($sortable && $sortKey)
wire:click="sort('{{ $sortKey }}')"
@@ -34,7 +34,7 @@
<div class="flex items-center gap-1.5 @if($align === 'end') justify-end @elseif($align === 'center') justify-center @endif">
<span>{{ $slot }}</span>
@if($sortable)
<span class="text-muted-foreground">
<span class="text-gray-400 dark:text-gray-500">
@if($isSorted)
@if($currentDirection === 'asc')
<x-ri-arrow-up-s-line class="size-4" />

View File

@@ -1,5 +1,5 @@
{{--
Table Component - shadcn-style
Table Component - TailAdmin style
Usage:
<x-proxmox::ui.table>
@@ -21,27 +21,27 @@
'compact' => false,
])
<div @class(['relative w-full overflow-auto' => $responsive])>
<div @class(['relative w-full overflow-x-auto rounded-xl border border-gray-200 dark:border-gray-800' => $responsive])>
<table
{{ $attributes->class([
'w-full caption-bottom text-sm',
'[&_tbody_tr:nth-child(even)]:bg-muted/50' => $striped,
'w-full text-theme-sm',
'[&_tbody_tr:nth-child(even)]:bg-gray-50 dark:[&_tbody_tr:nth-child(even)]:bg-gray-800/50' => $striped,
]) }}
data-hoverable="{{ $hoverable ? 'true' : 'false' }}"
data-compact="{{ $compact ? 'true' : 'false' }}"
>
@if(isset($head))
<thead class="[&_tr]:border-b">
<tr class="border-b transition-colors">
<thead class="border-b border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-800/50">
<tr>
{{ $head }}
</tr>
</thead>
@endif
<tbody class="[&_tr:last-child]:border-0">
<tbody class="divide-y divide-gray-200 dark:divide-gray-800">
{{ $slot }}
</tbody>
@if(isset($foot))
<tfoot class="border-t bg-muted/50 font-medium [&>tr]:last:border-b-0">
<tfoot class="border-t border-gray-200 bg-gray-50 font-medium dark:border-gray-800 dark:bg-gray-800/50">
{{ $foot }}
</tfoot>
@endif

View File

@@ -1,5 +1,5 @@
{{--
Tabs Component - shadcn-style
Tabs Component - TailAdmin style
Usage:
<x-proxmox::ui.tabs :tabs="['Overview', 'Settings', 'Logs']" active="Overview">
@@ -18,22 +18,22 @@
@php
$variantClasses = [
'default' => [
'container' => 'inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',
'tab' => 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
'active' => 'bg-background text-foreground shadow',
'inactive' => 'hover:bg-background/50 hover:text-foreground',
'container' => 'inline-flex items-center gap-1 rounded-lg border border-gray-200 bg-gray-50 p-1 dark:border-gray-800 dark:bg-gray-800/50',
'tab' => 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-4 py-2 text-theme-sm font-medium transition-all duration-150',
'active' => 'bg-white text-gray-800 shadow-theme-xs dark:bg-gray-900 dark:text-white/90',
'inactive' => 'text-gray-500 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-300',
],
'pills' => [
'container' => 'inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',
'tab' => 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all duration-150',
'active' => 'bg-background text-foreground shadow',
'inactive' => 'hover:bg-background/50 hover:text-foreground',
'container' => 'inline-flex items-center gap-1 rounded-lg border border-gray-200 bg-gray-50 p-1 dark:border-gray-800 dark:bg-gray-800/50',
'tab' => 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-4 py-2 text-theme-sm font-medium transition-all duration-150',
'active' => 'bg-white text-gray-800 shadow-theme-xs dark:bg-gray-900 dark:text-white/90',
'inactive' => 'text-gray-500 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-300',
],
'buttons' => [
'container' => 'flex gap-2',
'tab' => 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-4 py-2 text-sm font-medium transition-colors duration-150',
'active' => 'bg-primary text-primary-foreground shadow',
'inactive' => 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
'tab' => 'inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-theme-sm font-medium transition-colors duration-150',
'active' => 'bg-brand-500 text-white shadow-theme-xs hover:bg-brand-600',
'inactive' => 'bg-white text-gray-700 shadow-theme-xs ring-1 ring-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:ring-gray-700 dark:hover:bg-gray-700',
],
];
@@ -65,7 +65,7 @@
@endif
<span>{{ $tabLabel }}</span>
@if($tabBadge)
<span class="ml-1.5 rounded-full bg-primary/10 px-1.5 py-0.5 text-xs font-medium text-primary">
<span class="ml-1.5 rounded-full bg-brand-50 px-2 py-0.5 text-theme-xs font-medium text-brand-600 dark:bg-brand-500/15 dark:text-brand-400">
{{ $tabBadge }}
</span>
@endif
@@ -74,7 +74,7 @@
</div>
{{-- Tab Panels --}}
<div class="mt-4">
<div class="mt-5">
{{ $slot }}
</div>
</div>

View File

@@ -1,5 +1,5 @@
{{--
Toggle/Switch Component - shadcn-style
Toggle/Switch Component - TailAdmin style
Usage:
<x-proxmox::ui.toggle wire:model="enabled" label="Enable Feature" />
@@ -11,14 +11,14 @@
'disabled' => false,
])
<label {{ $attributes->only('class')->class(['flex items-center justify-between gap-4 cursor-pointer']) }}>
<label {{ $attributes->only('class')->class(['flex cursor-pointer items-center justify-between gap-4']) }}>
@if($label || $description)
<div class="space-y-0.5">
@if($label)
<span class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">{{ $label }}</span>
<span class="text-theme-sm font-medium text-gray-700 dark:text-gray-300">{{ $label }}</span>
@endif
@if($description)
<p class="text-[0.8rem] text-muted-foreground">{{ $description }}</p>
<p class="text-theme-xs text-gray-500 dark:text-gray-400">{{ $description }}</p>
@endif
</div>
@endif
@@ -27,17 +27,18 @@
<input
type="checkbox"
{{ $attributes->whereDoesntStartWith('class')->merge(['disabled' => $disabled]) }}
class="sr-only peer"
class="peer sr-only"
/>
<div @class([
'inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-150',
'bg-input peer-checked:bg-primary',
'peer-focus-visible:outline-none peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-background',
'block h-6 w-11 rounded-full border-2 border-transparent transition-colors duration-200',
'bg-gray-200 peer-checked:bg-brand-500',
'peer-focus-visible:outline-none peer-focus-visible:ring-3 peer-focus-visible:ring-brand-500/20',
'peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
'dark:bg-gray-700 dark:peer-checked:bg-brand-500',
])></div>
<div @class([
'pointer-events-none absolute top-0.5 left-0.5 block size-4 rounded-full bg-background shadow-lg ring-0 transition-transform duration-150',
'peer-checked:translate-x-4',
'pointer-events-none absolute left-0.5 top-0.5 size-5 rounded-full bg-white shadow-theme-sm ring-0 transition-transform duration-200',
'peer-checked:translate-x-5',
])></div>
</div>
</label>

View File

@@ -1,5 +1,5 @@
{{--
Tooltip Component - shadcn-style
Tooltip Component - TailAdmin style
Usage:
<x-proxmox::ui.tooltip text="This is a tooltip">
@@ -33,15 +33,15 @@
<div
x-show="show"
x-cloak
x-transition:enter="transition ease-out duration-100"
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave="transition ease-in duration-100"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="absolute z-50 {{ $positions[$position] ?? $positions['top'] }} pointer-events-none"
>
<div class="overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground">
<div class="overflow-hidden rounded-lg bg-gray-900 px-3 py-1.5 text-theme-xs font-medium text-white shadow-theme-md dark:bg-gray-700">
{{ $text }}
</div>
</div>