Add AdminLTE-style CSS framework to app.css

- Introduced AdminLTE CSS variables for color palette, body colors, card styles, and button styles.
- Implemented card components with variants for primary, success, warning, danger, and info.
- Added button styles including sizes and outline variants.
- Created form controls, select inputs, and input groups with consistent styling.
- Included utility classes for text and background colors, gradients, and shadows.
- Developed components for badges, alerts, callouts, progress bars, tables, small boxes, and info boxes.
- Integrated modal, dropdown, spinner, tooltip, and direct chat styles.
- Established timeline and close button styles, with dark mode support for specific components.
This commit is contained in:
2025-12-17 13:45:56 -05:00
parent 3219d4d7f3
commit 760cf84451
52 changed files with 4525 additions and 1537 deletions

View File

@@ -31,12 +31,12 @@
<div class="flex-1 space-y-2">
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-base">Cloud-init Configuration Notice</h3>
<button @click="toggle()" type="button" class="text-base/60 hover:text-base transition-colors">
<button @click="toggle()" type="button" class="text-gray-500 dark:text-gray-400 hover:text-base transition-colors">
<x-ri-arrow-down-s-line x-bind:class="isCollapsed ? 'size-4 transition-transform rotate-180' : 'size-4 transition-transform'" />
</button>
</div>
<div x-show="!isCollapsed" x-transition>
<p class="text-xs text-base/70 leading-relaxed">
<p class="text-xs text-gray-600 dark:text-gray-400 leading-relaxed">
Cloud-init controls the metadata injected into your VM on first boot and whenever you regenerate the cloud-init drive.
Use <strong>Apply</strong> to save and regenerate the ISO, <strong>Refresh</strong> to pull fresh values, and <strong>Reset</strong> to discard local edits.
Manual installs (ISO workflows, Windows, or images without cloud-init) still require in-guest configuration.
@@ -50,12 +50,12 @@
<div class="flex items-center gap-2 min-w-0">
<h2 class="text-xl font-semibold break-words">Cloud-init Settings</h2>
<div class="relative" x-data="{ open: false }" x-cloak>
<button type="button" @click="open = true" class="text-base/50 hover:text-base/70 transition-colors">
<button type="button" @click="open = true" class="text-base/50 hover:text-gray-600 dark:text-gray-400 transition-colors">
<x-ri-question-line class="size-4" />
</button>
<div x-show="open" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="open = false"></div>
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6"
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-gray-200 dark:border-gray-800 shadow-2xl p-6"
x-on:keydown.escape.window="open = false">
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
<x-ri-close-line class="size-5" />
@@ -71,7 +71,7 @@
<p class="block font-sans text-sm font-normal leading-relaxed text-base/90 mb-4">
Configure cloud-init metadata that is injected into your virtual machine. These settings control user accounts, SSH keys, hostname, networking, and other first-boot configuration.
</p>
<div class="pt-4 mt-4 border-t border-neutral/30 space-y-2.5">
<div class="pt-4 mt-4 border-t border-gray-200 dark:border-gray-800 space-y-2.5">
<p class="block font-sans text-xs font-normal leading-relaxed text-base/75">
<span class="font-semibold text-base/90">Apply:</span> Saves your changes and regenerates the cloud-init ISO drive. Changes take effect on the next boot.
</p>
@@ -86,25 +86,25 @@
</div>
</div>
</div>
<p class="text-sm text-base/60">
<p class="text-sm text-gray-500 dark:text-gray-400">
These values map directly to the QEMU configuration (`ciuser`, `nameserver`, `ipconfigX`, etc.). Changes take effect on the next cloud-init run or boot.
</p>
</div>
<div class="grid grid-cols-1 xl:grid-cols-2 gap-6">
<div class="bg-background-secondary border border-neutral rounded-lg p-4 space-y-4"
<div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm p-4 space-y-4"
x-data="{ showNetworkModal: @entangle('showNetworkModal') }">
<div class="flex items-center justify-between">
<div>
<div class="flex items-center gap-2 min-w-0">
<h3 class="text-lg font-semibold break-words">Access &amp; Credentials</h3>
<div class="relative" x-data="{ open: false }" x-cloak>
<button type="button" @click="open = true" class="text-base/50 hover:text-base/70 transition-colors">
<button type="button" @click="open = true" class="text-base/50 hover:text-gray-600 dark:text-gray-400 transition-colors">
<x-ri-question-line class="size-4" />
</button>
<div x-show="open" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="open = false"></div>
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6"
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-gray-200 dark:border-gray-800 shadow-2xl p-6"
x-on:keydown.escape.window="open = false">
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
<x-ri-close-line class="size-5" />
@@ -120,7 +120,7 @@
<p class="block font-sans text-sm font-normal leading-relaxed text-base/90 mb-4">
Configure the default user account and SSH access for your virtual machine. These settings are used by cloud-init to create accounts and configure SSH keys on first boot.
</p>
<div class="pt-4 mt-4 border-t border-neutral/30 space-y-2.5">
<div class="pt-4 mt-4 border-t border-gray-200 dark:border-gray-800 space-y-2.5">
<p class="block font-sans text-xs font-normal leading-relaxed text-base/75">
<span class="font-semibold text-base/90">Username:</span> The default user account created by cloud-init. This user typically has sudo privileges.
</p>
@@ -135,7 +135,7 @@
</div>
</div>
</div>
<p class="text-xs text-base/60 mt-1">Defaults used by cloud-init to create accounts and authorize SSH.</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Defaults used by cloud-init to create accounts and authorize SSH.</p>
</div>
@if($this->accessCredentialsSynced)
<span class="text-xs font-semibold text-success">Synced</span>
@@ -153,18 +153,18 @@
{{ $ciUser !== '' ? $ciUser : 'Template default (uses image-defined user)' }}
</span>
<button type="button"
class="text-base/70 hover:text-base/60 ml-2"
class="text-gray-600 dark:text-gray-400 hover:text-gray-500 dark:text-gray-400 ml-2"
@click="showCiUserModal = true"
aria-label="Edit Cloud-init user">
<x-ri-edit-fill class="inline size-4" />
</button>
</div>
</div>
<p class="text-xs text-base/60">Use distro-friendly names. Leave blank to keep the template default.</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Use distro-friendly names. Leave blank to keep the template default.</p>
<div x-cloak x-show="showCiUserModal" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="showCiUserModal = false"></div>
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
<div class="relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
x-on:keydown.escape.window="showCiUserModal = false">
<div class="flex items-center justify-between">
<h4 class="text-base font-semibold text-base/90">Edit Cloud-init User</h4>
@@ -176,12 +176,12 @@
</button>
</div>
<div class="space-y-2">
<label class="text-xs font-semibold text-base/70">Username</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">Username</label>
<input type="text"
wire:model.live="ciUser"
class="form-input w-full"
placeholder="e.g. ubuntu" />
<p class="text-xs text-base/60">Leave blank to retain the template default user.</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Leave blank to retain the template default user.</p>
</div>
<div class="flex justify-end gap-2">
<x-button.secondary type="button" @click="showCiUserModal = false">
@@ -208,26 +208,26 @@
</span>
@if(isset($server->password) && $server->password)
<button type="button"
class="text-base/70 hover:text-base/60 ml-2"
class="text-gray-600 dark:text-gray-400 hover:text-gray-500 dark:text-gray-400 ml-2"
@click="showPasswordViewModal = true"
aria-label="View Root Password">
<x-ri-eye-line class="inline size-4" />
</button>
@endif
<button type="button"
class="text-base/70 hover:text-base/60 ml-2"
class="text-gray-600 dark:text-gray-400 hover:text-gray-500 dark:text-gray-400 ml-2"
wire:click="startEditingPassword"
aria-label="Edit Root Password">
<x-ri-edit-fill class="inline size-4" />
</button>
</div>
</div>
<p class="text-xs text-base/60">Matches the Overview tab control. Use Save for database only, Save &amp; Apply to push via cloud-init.</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Matches the Overview tab control. Use Save for database only, Save &amp; Apply to push via cloud-init.</p>
@if(isset($server->password) && $server->password)
<div x-cloak x-show="showPasswordViewModal" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="showPasswordViewModal = false"></div>
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
<div class="relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
x-on:keydown.escape.window="showPasswordViewModal = false"
x-data="{
copied: false,
@@ -264,7 +264,7 @@
<div x-cloak x-show="showPasswordEditModal" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="showPasswordEditModal = false; $wire.cancelEditingPassword()"></div>
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
<div class="relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
x-on:keydown.escape.window="showPasswordEditModal = false; $wire.cancelEditingPassword()">
<div class="flex items-center justify-between">
<h4 class="text-base font-semibold text-base/90">Edit Root Password</h4>
@@ -277,14 +277,14 @@
</div>
<div class="space-y-3">
<div>
<label class="text-xs font-semibold text-base/70">New Password</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">New Password</label>
<input type="password"
wire:model.defer="password"
class="form-input w-full mt-1"
placeholder="Enter new password" />
</div>
<div>
<label class="text-xs font-semibold text-base/70">Confirm Password</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">Confirm Password</label>
<input type="password"
wire:model.defer="password_confirmation"
class="form-input w-full mt-1"
@@ -293,7 +293,7 @@
@if($passwordError)
<div class="text-sm text-error">{{ $passwordError }}</div>
@endif
<p class="text-xs text-base/60">
<p class="text-xs text-gray-500 dark:text-gray-400">
Save writes the password to the database. Save &amp; Apply also pushes it to the hypervisor; reboot for cloud-init to configure the guest OS.
</p>
</div>
@@ -316,7 +316,7 @@
<label class="text-sm font-semibold text-base/80">SSH Public Keys</label>
<div class="space-y-2">
@forelse($sshKeys as $keyIndex => $key)
<div class="flex items-center gap-2 border border-neutral rounded-md bg-background px-3 py-2 text-xs text-base/70 relative"
<div class="flex items-center gap-2 border border-neutral rounded-md bg-background px-3 py-2 text-xs text-gray-600 dark:text-gray-400 relative"
x-data="{
showKeyModal: false,
copied: false,
@@ -329,7 +329,7 @@
}">
<span class="truncate flex-1" title="{{ $key }}">{{ $key }}</span>
<button type="button"
class="text-base/70 hover:text-base/60 ml-2"
class="text-gray-600 dark:text-gray-400 hover:text-gray-500 dark:text-gray-400 ml-2"
@click="showKeyModal = true"
aria-label="View SSH key">
<x-ri-eye-line class="inline size-4" />
@@ -342,7 +342,7 @@
<div x-cloak x-show="showKeyModal" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="showKeyModal = false"></div>
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
<div class="relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
x-on:keydown.escape.window="showKeyModal = false">
<div class="flex items-center justify-between">
<h4 class="text-base font-semibold text-base/90">SSH Public Key</h4>
@@ -376,11 +376,11 @@
Add Key
</x-button.secondary>
</div>
<p class="text-xs text-base/60">Add as many keys as needed. The platform management key is always kept but never shown.</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Add as many keys as needed. The platform management key is always kept but never shown.</p>
<div x-cloak x-show="showAddKeyModal" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="showAddKeyModal = false"></div>
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
<div class="relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
x-on:keydown.escape.window="showAddKeyModal = false">
<div class="flex items-center justify-between">
<h4 class="text-base font-semibold text-base/90">Add SSH Public Key</h4>
@@ -392,7 +392,7 @@
</button>
</div>
<div class="space-y-2">
<label class="text-xs font-semibold text-base/70">SSH Key</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">SSH Key</label>
<textarea wire:model.defer="newSshKey"
class="form-input w-full h-28 resize-y"
placeholder="ssh-ed25519 AAAA... user@host"></textarea>
@@ -415,24 +415,24 @@
<input id="ci-upgrade" type="checkbox" wire:model.live="upgradePackages" class="form-checkbox" />
<label for="ci-upgrade" class="text-sm font-semibold text-base/80">Upgrade packages on first boot</label>
</div>
<p class="text-xs text-base/60">
<p class="text-xs text-gray-500 dark:text-gray-400">
Runs <code>apt/yum update &amp;&amp; upgrade</code> when cloud-init executes. Enable only if your template supports unattended upgrades.
</p>
</div>
</div>
<div class="bg-background-secondary border border-neutral rounded-lg p-4 space-y-4"
<div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm p-4 space-y-4"
x-data="{ showNetworkModal: @entangle('showNetworkModal') }">
<div class="flex items-center justify-between">
<div>
<div class="flex items-center gap-2 min-w-0">
<h3 class="text-lg font-semibold break-words">Network Configuration</h3>
<div class="relative" x-data="{ open: false }" x-cloak>
<button type="button" @click="open = true" class="text-base/50 hover:text-base/70 transition-colors">
<button type="button" @click="open = true" class="text-base/50 hover:text-gray-600 dark:text-gray-400 transition-colors">
<x-ri-question-line class="size-4" />
</button>
<div x-show="open" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="open = false"></div>
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6"
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-gray-200 dark:border-gray-800 shadow-2xl p-6"
x-on:keydown.escape.window="open = false">
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
<x-ri-close-line class="size-5" />
@@ -448,7 +448,7 @@
<p class="block font-sans text-sm font-normal leading-relaxed text-base/90 mb-4">
Configure network interfaces for your virtual machine. Each network card corresponds to an <code>ipconfigX</code> parameter in the QEMU configuration, allowing you to set IPv4 and IPv6 addresses independently.
</p>
<div class="pt-4 mt-4 border-t border-neutral/30 space-y-2.5">
<div class="pt-4 mt-4 border-t border-gray-200 dark:border-gray-800 space-y-2.5">
<p class="block font-sans text-xs font-normal leading-relaxed text-base/75">
<span class="font-semibold text-base/90">IP Configuration:</span> Each network interface can have separate IPv4 and IPv6 configurations. Use CIDR notation (e.g., 192.168.1.100/24) for IP addresses.
</p>
@@ -463,9 +463,9 @@
</div>
</div>
</div>
<p class="text-xs text-base/60 mt-1">Each card corresponds to an <code>ipconfigX</code>. Configure IPv4 and IPv6 independently.</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Each card corresponds to an <code>ipconfigX</code>. Configure IPv4 and IPv6 independently.</p>
</div>
<span class="text-xs text-base/60">{{ count($networks) }} interfaces</span>
<span class="text-xs text-gray-500 dark:text-gray-400">{{ count($networks) }} interfaces</span>
</div>
<div class="grid grid-cols-1 gap-4">
@@ -474,12 +474,12 @@
<div class="flex items-center justify-between">
<div>
<span class="text-sm font-semibold text-base/80 uppercase">{{ $network['key'] }}</span>
<p class="text-xs text-base/60">
<p class="text-xs text-gray-500 dark:text-gray-400">
Network Device: NET{{ str_replace('ipconfig', '', $network['key']) }}
</p>
</div>
<button wire:click="startEditingNetwork({{ $index }})" type="button"
class="text-base/70 hover:text-base/60 ml-2"
class="text-gray-600 dark:text-gray-400 hover:text-gray-500 dark:text-gray-400 ml-2"
@click="showNetworkModal = true">
<x-ri-edit-fill class="inline size-4" />
</button>
@@ -487,25 +487,25 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div>
<label class="text-xs font-semibold text-base/70">IPv4 Address (CIDR)</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">IPv4 Address (CIDR)</label>
<div class="text-sm text-base/80 mt-1">
{{ !empty($network['ip']) ? $network['ip'] : '—' }}
</div>
</div>
<div>
<label class="text-xs font-semibold text-base/70">IPv4 Gateway</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">IPv4 Gateway</label>
<div class="text-sm text-base/80 mt-1">
{{ !empty($network['gw']) ? $network['gw'] : '—' }}
</div>
</div>
<div>
<label class="text-xs font-semibold text-base/70">IPv6 Address (CIDR)</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">IPv6 Address (CIDR)</label>
<div class="text-sm text-base/80 mt-1">
{{ !empty($network['ip6']) ? $network['ip6'] : '—' }}
</div>
</div>
<div>
<label class="text-xs font-semibold text-base/70">IPv6 Gateway</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">IPv6 Gateway</label>
<div class="text-sm text-base/80 mt-1">
{{ !empty($network['gw6']) ? $network['gw6'] : '—' }}
</div>
@@ -513,12 +513,12 @@
</div>
@if(($network['dhcp'] ?? false))
<div class="text-xs text-base/60">
<div class="text-xs text-gray-500 dark:text-gray-400">
<span class="font-semibold">DHCP:</span> Enabled
</div>
@endif
<p class="text-xs text-base/60">
<p class="text-xs text-gray-500 dark:text-gray-400">
Leave fields blank to remove static addressing. If both IPv4 fields are empty, cloud-init omits the IPv4 stanza.
</p>
</div>
@@ -527,7 +527,7 @@
<div x-cloak x-show="showNetworkModal" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="showNetworkModal = false; $wire.cancelEditingNetwork()"></div>
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-2xl mx-4 p-5 space-y-4"
<div class="relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm shadow-xl w-full max-w-2xl mx-4 p-5 space-y-4"
x-on:keydown.escape.window="showNetworkModal = false; $wire.cancelEditingNetwork()">
<div class="flex items-center justify-between">
<h4 class="text-base font-semibold text-base/90">Edit Network Configuration</h4>
@@ -542,27 +542,27 @@
<div class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div>
<label class="text-xs font-semibold text-base/70">IPv4 Address (CIDR)</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">IPv4 Address (CIDR)</label>
<input type="text" wire:model="editingNetwork.ip" class="form-input w-full mt-1"
placeholder="45.154.99.28/24" />
</div>
<div>
<label class="text-xs font-semibold text-base/70">IPv4 Gateway</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">IPv4 Gateway</label>
<input type="text" wire:model="editingNetwork.gw" class="form-input w-full mt-1"
placeholder="45.154.99.17" />
</div>
<div>
<label class="text-xs font-semibold text-base/70">IPv6 Address (CIDR)</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">IPv6 Address (CIDR)</label>
<input type="text" wire:model="editingNetwork.ip6" class="form-input w-full mt-1"
placeholder="2a0b:4e07::2:10/64" />
</div>
<div>
<label class="text-xs font-semibold text-base/70">IPv6 Gateway</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">IPv6 Gateway</label>
<input type="text" wire:model="editingNetwork.gw6" class="form-input w-full mt-1"
placeholder="2a0b:4e07::1" />
</div>
</div>
<p class="text-xs text-base/60">
<p class="text-xs text-gray-500 dark:text-gray-400">
Leave fields blank to remove static addressing. If both IPv4 fields are empty, cloud-init omits the IPv4 stanza.
</p>
<div class="flex justify-end gap-2">
@@ -580,18 +580,18 @@
</div>
<div class="grid grid-cols-1 xl:grid-cols-2 gap-6">
<div class="bg-background-secondary border border-neutral rounded-lg p-4 space-y-4">
<div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm p-4 space-y-4">
<div class="flex items-center justify-between">
<div>
<div class="flex items-center gap-2 min-w-0">
<h3 class="text-lg font-semibold break-words">DNS Settings</h3>
<div class="relative" x-data="{ open: false }" x-cloak>
<button type="button" @click="open = true" class="text-base/50 hover:text-base/70 transition-colors">
<button type="button" @click="open = true" class="text-base/50 hover:text-gray-600 dark:text-gray-400 transition-colors">
<x-ri-question-line class="size-4" />
</button>
<div x-show="open" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="open = false"></div>
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6"
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-gray-200 dark:border-gray-800 shadow-2xl p-6"
x-on:keydown.escape.window="open = false">
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
<x-ri-close-line class="size-5" />
@@ -607,7 +607,7 @@
<p class="block font-sans text-sm font-normal leading-relaxed text-base/90 mb-4">
Configure DNS (Domain Name System) settings for your virtual machine. These settings control how the guest OS resolves domain names to IP addresses.
</p>
<div class="pt-4 mt-4 border-t border-neutral/30 space-y-2.5">
<div class="pt-4 mt-4 border-t border-gray-200 dark:border-gray-800 space-y-2.5">
<p class="block font-sans text-xs font-normal leading-relaxed text-base/75">
<span class="font-semibold text-base/90">Search Domain:</span> The default domain suffix appended to hostnames that don't contain a domain. For example, with "example.com" as search domain, "server" resolves to "server.example.com".
</p>
@@ -622,7 +622,7 @@
</div>
</div>
</div>
<p class="text-xs text-base/60 mt-1">Configures <code>searchdomain</code> and <code>nameserver</code> values.</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Configures <code>searchdomain</code> and <code>nameserver</code> values.</p>
</div>
@if($this->dnsSettingsSynced)
<span class="text-xs font-semibold text-success">Synced</span>
@@ -640,18 +640,18 @@
{{ $dnsDomain !== '' ? $dnsDomain : 'Not configured (system default will be used)' }}
</span>
<button type="button"
class="text-base/70 hover:text-base/60 ml-2"
class="text-gray-600 dark:text-gray-400 hover:text-gray-500 dark:text-gray-400 ml-2"
@click="showDnsDomainModal = true"
aria-label="Edit DNS Domain">
<x-ri-edit-fill class="inline size-4" />
</button>
</div>
</div>
<p class="text-xs text-base/60">Appended to short hostnames for resolution.</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Appended to short hostnames for resolution.</p>
<div x-cloak x-show="showDnsDomainModal" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="showDnsDomainModal = false"></div>
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
<div class="relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
x-on:keydown.escape.window="showDnsDomainModal = false">
<div class="flex items-center justify-between">
<h4 class="text-base font-semibold text-base/90">Edit DNS Domain</h4>
@@ -663,12 +663,12 @@
</button>
</div>
<div class="space-y-2">
<label class="text-xs font-semibold text-base/70">DNS Domain (searchdomain)</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">DNS Domain (searchdomain)</label>
<input type="text"
wire:model.live="dnsDomain"
class="form-input w-full"
placeholder="example.internal" />
<p class="text-xs text-base/60">Leave blank to use system default. Appended to short hostnames for resolution.</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Leave blank to use system default. Appended to short hostnames for resolution.</p>
</div>
<div class="flex justify-end gap-2">
<x-button.secondary type="button" @click="showDnsDomainModal = false">
@@ -686,7 +686,7 @@
<label class="text-sm font-semibold text-base/80">DNS Nameservers</label>
<div class="space-y-2">
@forelse($dnsServers as $dnsIndex => $resolver)
<div class="flex items-center gap-2 border border-neutral rounded-md bg-background px-3 py-2 text-xs text-base/70">
<div class="flex items-center gap-2 border border-neutral rounded-md bg-background px-3 py-2 text-xs text-gray-600 dark:text-gray-400">
<span class="truncate flex-1" title="{{ $resolver }}">{{ $resolver }}</span>
<button type="button" wire:click="removeDnsServer({{ $dnsIndex }})"
class="text-error hover:text-error/80 ml-2">
@@ -702,11 +702,11 @@
Add Nameserver
</x-button.secondary>
</div>
<p class="text-xs text-base/60 mt-1">Entries are applied in order. Add one IPv4/IPv6 resolver per line.</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Entries are applied in order. Add one IPv4/IPv6 resolver per line.</p>
<div x-cloak x-show="showAddDnsModal" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="showAddDnsModal = false"></div>
<div class="relative bg-background-secondary border border-neutral rounded-lg shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
<div class="relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm shadow-xl w-full max-w-xl mx-4 p-5 space-y-4"
x-on:keydown.escape.window="showAddDnsModal = false">
<div class="flex items-center justify-between">
<h4 class="text-base font-semibold text-base/90">Add DNS Nameserver</h4>
@@ -719,12 +719,12 @@
</div>
<div class="space-y-3">
<div class="space-y-2">
<label class="text-xs font-semibold text-base/70">Quick Add</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">Quick Add</label>
<div class="grid grid-cols-2 gap-2">
<button type="button"
wire:click="quickAddDnsServers('cloudflare')"
@click="showAddDnsModal = false"
class="flex items-center gap-2 px-3 py-2 bg-background border border-neutral rounded-md hover:bg-background/80 text-sm text-base/70 transition-colors">
class="flex items-center gap-2 px-3 py-2 bg-background border border-neutral rounded-md hover:bg-background/80 text-sm text-gray-600 dark:text-gray-400 transition-colors">
<svg viewBox="0 -70 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" fill="#000000" class="size-4">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
@@ -743,7 +743,7 @@
<button type="button"
wire:click="quickAddDnsServers('google')"
@click="showAddDnsModal = false"
class="flex items-center gap-2 px-3 py-2 bg-background border border-neutral rounded-md hover:bg-background/80 text-sm text-base/70 transition-colors">
class="flex items-center gap-2 px-3 py-2 bg-background border border-neutral rounded-md hover:bg-background/80 text-sm text-gray-600 dark:text-gray-400 transition-colors">
<svg viewBox="-3 0 262 262" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" fill="currentColor" class="size-4">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
@@ -759,7 +759,7 @@
<button type="button"
wire:click="quickAddDnsServers('quad9')"
@click="showAddDnsModal = false"
class="flex items-center gap-2 px-3 py-2 bg-background border border-neutral rounded-md hover:bg-background/80 text-sm text-base/70 transition-colors">
class="flex items-center gap-2 px-3 py-2 bg-background border border-neutral rounded-md hover:bg-background/80 text-sm text-gray-600 dark:text-gray-400 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" class="size-4">
<path d="M18.235 63.971h14.953l16.888-25.26c3.897-5.83 6.091-11.2 6.091-17.06C56.167 9.238 45.746 0 32.034 0S7.9 9.295 7.9 21.882c0 12.586 9.209 21.333 22.228 21.333.953 0 1.934-.058 2.887-.173L18.205 64Zm13.799-31.639c-6.467 0-11.23-4.36-11.23-10.537s4.763-10.537 11.23-10.537c6.466 0 11.23 4.302 11.23 10.537s-4.822 10.537-11.23 10.537" style="fill:#dc205e;stroke-width:2.88678"/>
<path d="M0 0h150v150H0Z" style="fill:none"/>
@@ -769,7 +769,7 @@
<button type="button"
wire:click="quickAddDnsServers('nat64')"
@click="showAddDnsModal = false"
class="flex items-center gap-2 px-3 py-2 bg-background border border-neutral rounded-md hover:bg-background/80 text-sm text-base/70 transition-colors">
class="flex items-center gap-2 px-3 py-2 bg-background border border-neutral rounded-md hover:bg-background/80 text-sm text-gray-600 dark:text-gray-400 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" height="512" width="512" viewBox="0 0 512 512" class="size-4">
<circle style="fill:#FFDA44;" cx="256" cy="256" r="256"></circle>
<path style="fill:#338AF3;" d="M0,256C0,114.616,114.616,0,256,0s256,114.616,256,256"></path>
@@ -779,7 +779,7 @@
</div>
</div>
<div class="space-y-2">
<label class="text-xs font-semibold text-base/70">Nameserver</label>
<label class="text-xs font-semibold text-gray-600 dark:text-gray-400">Nameserver</label>
<input type="text"
wire:model.defer="newDnsServer"
class="form-input w-full"
@@ -802,18 +802,18 @@
</div>
</div>
<div class="bg-background-secondary border border-neutral rounded-lg p-4 space-y-4">
<div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-theme-sm p-4 space-y-4">
<div class="flex items-center justify-between">
<div>
<div class="flex items-center gap-2 min-w-0">
<h3 class="text-lg font-semibold break-words">OS Type</h3>
<div class="relative" x-data="{ open: false }" x-cloak>
<button type="button" @click="open = true" class="text-base/50 hover:text-base/70 transition-colors">
<button type="button" @click="open = true" class="text-base/50 hover:text-gray-600 dark:text-gray-400 transition-colors">
<x-ri-question-line class="size-4" />
</button>
<div x-show="open" x-transition.opacity class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm" @click="open = false"></div>
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6"
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-gray-200 dark:border-gray-800 shadow-2xl p-6"
x-on:keydown.escape.window="open = false">
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
<x-ri-close-line class="size-5" />
@@ -829,7 +829,7 @@
<p class="block font-sans text-sm font-normal leading-relaxed text-base/90 mb-4">
Specifies the operating system type for cloud-init metadata generation. This setting helps cloud-init apply the correct configuration format and optimizations for your guest OS.
</p>
<div class="pt-4 mt-4 border-t border-neutral/30 space-y-2.5">
<div class="pt-4 mt-4 border-t border-gray-200 dark:border-gray-800 space-y-2.5">
<p class="block font-sans text-xs font-normal leading-relaxed text-base/75">
<span class="font-semibold text-base/90">Linux:</span> Standard Linux distributions (Ubuntu, Debian, CentOS, etc.). Uses standard cloud-init configuration format.
</p>
@@ -844,7 +844,7 @@
</div>
</div>
</div>
<p class="text-xs text-base/60 mt-1">Controls the <code>ostype</code> option used when generating cloud-init media.</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Controls the <code>ostype</code> option used when generating cloud-init media.</p>
</div>
@if($this->osTypeSynced)
<span class="text-xs font-semibold text-success">Synced</span>
@@ -863,10 +863,10 @@
@endforeach
</select>
</div>
<p class="text-xs text-base/60 mt-1">
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
Determines whether the guest receives nocloud or config-drive metadata. Choose the entry that matches your template.
</p>
<div class="bg-warning/10 border border-warning/30 rounded-lg p-3 text-xs text-base/70 leading-relaxed mt-2">
<div class="bg-warning/10 border border-warning/30 rounded-lg p-3 text-xs text-gray-600 dark:text-gray-400 leading-relaxed mt-2">
<strong>Tip:</strong> Pick a Windows option only for cloud-ready Windows images (cloudbase-init). Using a Windows entry on Linux templates prevents the nocloud ISO from mounting.
</div>
</div>