Files
ladill-hosting/resources/views/hosting/panel/domains.blade.php
T
isaaccladandCursor ca60515dfc
Deploy Ladill Hosting / deploy (push) Successful in 28s
Unify primary buttons with gradient pill design across the app.
Add shared btn-primary components and plus icons on create/new actions for a consistent Ladill UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 22:49:27 +00:00

264 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<x-hosting-panel-layout :account="$account">
<x-slot name="title">Domains - {{ $account->username }}</x-slot>
<x-slot name="header">Domains</x-slot>
<div class="space-y-6">
@if(session('success'))
<div class="rounded-lg bg-emerald-50 border border-emerald-200 p-4">
<p class="text-sm text-emerald-800">{{ session('success') }}</p>
</div>
@endif
@if(session('error'))
<div class="rounded-lg bg-red-50 border border-red-200 p-4">
<p class="text-sm text-red-800">{{ session('error') }}</p>
</div>
@endif
@php
$ownedDomainHosts = $ownedDomains->map(fn ($d) => (string) $d)->all();
$oldDomain = trim((string) old('domain', ''));
$initialDomainSource = $ownedDomains->isEmpty()
? 'external'
: ((string) old('is_owned_domain', '1') === '0' ? 'external' : 'ladill');
$selectedOwnedDomain = in_array($oldDomain, $ownedDomainHosts, true) ? $oldDomain : '';
$externalFallbackDomain = ! in_array($oldDomain, $ownedDomainHosts, true) ? $oldDomain : '';
@endphp
<div class="rounded-xl border border-slate-200 bg-white p-6">
<h3 class="text-base font-semibold text-slate-900 mb-4">Add Domain</h3>
<form action="{{ route('hosting.panel.domains.add', $account) }}" method="POST" class="space-y-5"
x-data="{
domainSource: @js($initialDomainSource),
selectedOwnedDomain: @js($selectedOwnedDomain),
externalDomain: @js($externalFallbackDomain),
onboardingMode: '{{ old('onboarding_mode', 'ns_auto') }}'
}">
@csrf
<input type="hidden" name="is_owned_domain" :value="domainSource === 'ladill' ? '1' : '0'">
{{-- Domain Source Toggle --}}
<div>
<div class="mb-2 flex items-center justify-between">
<label class="text-sm font-medium text-slate-700">Domain</label>
<div class="inline-flex items-center rounded-md bg-slate-100 p-0.5 text-[11px] font-medium">
<button type="button" @click="domainSource = 'ladill'"
:class="domainSource === 'ladill' ? 'bg-white text-slate-900 shadow-sm' : 'text-slate-500'"
class="rounded px-2 py-1 transition">Ladill</button>
<button type="button" @click="domainSource = 'external'"
:class="domainSource === 'external' ? 'bg-white text-slate-900 shadow-sm' : 'text-slate-500'"
class="rounded px-2 py-1 transition">External</button>
</div>
</div>
{{-- Ladill (Owned) Domains --}}
<div x-show="domainSource === 'ladill'" x-cloak>
@if($ownedDomains->isNotEmpty())
<select name="domain" x-model="selectedOwnedDomain" :disabled="domainSource !== 'ladill'"
class="block w-full rounded-lg border-slate-200 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value="">Choose a domain...</option>
@foreach($ownedDomains as $domain)
<option value="{{ $domain }}">{{ $domain }}</option>
@endforeach
</select>
<p class="mt-1.5 text-xs text-slate-500">
Don't have a domain?
<a href="{{ ladill_domains_url('/find') }}" class="font-medium text-indigo-600 hover:text-indigo-800">Purchase one first</a>
</p>
@else
<div class="rounded-lg bg-slate-50 px-4 py-3 text-center text-sm text-slate-600">
No domains found in your account.
<a href="{{ ladill_domains_url('/find') }}" class="font-medium text-indigo-600 underline underline-offset-2 hover:text-indigo-800">Register a domain</a>
</div>
@endif
</div>
{{-- External Domain --}}
<div x-show="domainSource === 'external'" x-cloak>
<input type="text" name="domain" x-model="externalDomain" :disabled="domainSource !== 'external'" required placeholder="example.com"
class="block w-full rounded-lg border-slate-200 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('domain') border-red-300 @enderror">
<p class="mt-1.5 text-xs text-slate-500">Enter your domain without www or http (e.g., example.com)</p>
</div>
@error('domain')
<p class="mt-1.5 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
{{-- Onboarding Mode (External only) --}}
<div x-show="domainSource === 'external'" x-cloak>
<label class="block text-sm font-medium text-slate-700 mb-3">Connection Method</label>
<div class="space-y-3">
<label class="relative flex cursor-pointer rounded-lg border border-slate-200 bg-white p-4 hover:bg-slate-50 transition">
<input type="radio" name="onboarding_mode" value="ns_auto" x-model="onboardingMode" class="sr-only peer">
<div class="flex flex-1 items-start gap-3">
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-emerald-100 text-emerald-600">
<svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 0 1-3-3m3 3a3 3 0 1 0 0 6h13.5a3 3 0 1 0 0-6m-16.5-3a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3m-19.5 0a4.5 4.5 0 0 1 .9-2.7L5.737 5.1a3.375 3.375 0 0 1 2.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 0 1 .9 2.7m0 0a3 3 0 0 1-3 3m0 3h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Zm-3 6h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Z"/></svg>
</div>
<div class="flex-1">
<p class="text-sm font-semibold text-slate-900">Point Nameservers</p>
<p class="mt-0.5 text-xs text-slate-500">Point your domain's nameservers to Ladill. We'll manage DNS and SSL automatically.</p>
</div>
</div>
<div class="absolute right-4 top-4 hidden h-5 w-5 items-center justify-center rounded-full bg-indigo-600 text-white peer-checked:flex">
<svg class="h-3 w-3" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>
</div>
<div class="absolute inset-0 rounded-lg border-2 border-transparent peer-checked:border-indigo-600 pointer-events-none"></div>
</label>
<label class="relative flex cursor-pointer rounded-lg border border-slate-200 bg-white p-4 hover:bg-slate-50 transition">
<input type="radio" name="onboarding_mode" value="manual_dns" x-model="onboardingMode" class="sr-only peer">
<div class="flex flex-1 items-start gap-3">
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-blue-100 text-blue-600">
<svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"/></svg>
</div>
<div class="flex-1">
<p class="text-sm font-semibold text-slate-900">Add DNS Records</p>
<p class="mt-0.5 text-xs text-slate-500">Keep your current DNS provider and manually add A records pointing to our server.</p>
</div>
</div>
<div class="absolute right-4 top-4 hidden h-5 w-5 items-center justify-center rounded-full bg-indigo-600 text-white peer-checked:flex">
<svg class="h-3 w-3" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>
</div>
<div class="absolute inset-0 rounded-lg border-2 border-transparent peer-checked:border-indigo-600 pointer-events-none"></div>
</label>
</div>
@error('onboarding_mode')
<p class="mt-1.5 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
{{-- Document Root (optional, both flows) --}}
<div>
<label class="block text-sm font-medium text-slate-700 mb-1">Document Root <span class="font-normal text-slate-400">(optional)</span></label>
<input type="text" name="document_root" placeholder="public_html/example.com" value="{{ old('document_root') }}"
class="w-full rounded-lg border-slate-200 text-sm shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<p class="mt-1 text-xs text-slate-500">Leave empty to use default: public_html/domain.com</p>
</div>
<button type="submit" class="btn-primary">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/></svg>
Add Domain
</button>
</form>
</div>
<div class="rounded-xl border border-slate-200 bg-white overflow-hidden">
<div class="px-6 py-4 border-b border-slate-200">
<h3 class="text-base font-semibold text-slate-900">Your Domains</h3>
</div>
@if($account->sites->count())
<table class="min-w-full divide-y divide-slate-200">
<thead class="bg-slate-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">Domain</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">Document Root</th>
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">Status</th>
<th class="px-6 py-3 text-right text-xs font-medium text-slate-500 uppercase">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200">
@foreach($account->sites as $site)
<tr class="hover:bg-slate-50">
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center gap-2">
<span class="text-sm font-medium text-slate-900">{{ $site->domain }}</span>
<a href="http://{{ $site->domain }}" target="_blank" class="text-slate-400 hover:text-indigo-600">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/></svg>
</a>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="text-sm font-mono text-slate-600">{{ $site->document_root }}</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium {{ $site->status === 'active' ? 'bg-emerald-100 text-emerald-800' : 'bg-slate-100 text-slate-800' }}">
{{ ucfirst($site->status) }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right">
@if((int) $account->user_id === (int) auth()->id())
<x-confirm-dialog
:name="'remove-domain-'.$site->id"
title="Remove domain?"
message="Remove this domain? The files will not be deleted."
:action="route('hosting.panel.domains.remove', [$account, $site])"
method="DELETE"
confirm-label="Remove"
>
<x-slot:trigger>
<button type="button" class="inline-flex items-center gap-1.5 rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 hover:bg-red-50 transition">
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"/></svg>
Remove
</button>
</x-slot:trigger>
</x-confirm-dialog>
@else
<span class="text-xs text-slate-400">Owner only</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="px-6 py-12 text-center">
@include('components.icons.domain-globe', ['class' => 'mx-auto h-12 w-12 text-slate-300'])
<p class="mt-4 text-sm text-slate-500">No addon domains yet. Add one above.</p>
</div>
@endif
</div>
@php
$serverIp = $account->node?->ip_address ?? '161.97.138.149';
@endphp
{{-- DNS Quick Reference --}}
<div class="rounded-xl border border-slate-200 bg-white p-6">
<h3 class="text-base font-semibold text-slate-900 mb-2">DNS Quick Reference</h3>
<p class="text-sm text-slate-600 mb-4">Use one of these methods to connect an external domain:</p>
<div class="grid gap-4 md:grid-cols-2">
<div class="rounded-lg border border-emerald-200 bg-emerald-50/50 p-4">
<div class="flex items-center gap-2 mb-2">
<h4 class="text-sm font-semibold text-slate-900">Nameservers</h4>
<span class="inline-flex items-center rounded-full bg-emerald-100 px-2 py-0.5 text-[10px] font-medium text-emerald-800">Recommended</span>
</div>
<div class="space-y-1.5">
<div class="flex items-center justify-between rounded bg-white border border-emerald-200 px-3 py-1.5">
<span class="text-sm font-mono text-slate-900">ns1.ladill.com</span>
<button type="button" onclick="navigator.clipboard.writeText('ns1.ladill.com')" class="text-xs text-indigo-600 hover:text-indigo-800">Copy</button>
</div>
<div class="flex items-center justify-between rounded bg-white border border-emerald-200 px-3 py-1.5">
<span class="text-sm font-mono text-slate-900">ns2.ladill.com</span>
<button type="button" onclick="navigator.clipboard.writeText('ns2.ladill.com')" class="text-xs text-indigo-600 hover:text-indigo-800">Copy</button>
</div>
</div>
</div>
<div class="rounded-lg border border-slate-200 bg-slate-50/50 p-4">
<h4 class="text-sm font-semibold text-slate-900 mb-2">A Records</h4>
<div class="space-y-1 rounded bg-white border border-slate-200 p-3">
<div class="grid grid-cols-3 gap-2 text-xs">
<span class="font-medium text-slate-500">Type</span>
<span class="font-medium text-slate-500">Name</span>
<span class="font-medium text-slate-500">Value</span>
</div>
<div class="grid grid-cols-3 gap-2 text-xs">
<span class="font-mono text-slate-900">A</span>
<span class="font-mono text-slate-900">@</span>
<span class="font-mono text-slate-900">{{ $serverIp }}</span>
</div>
<div class="grid grid-cols-3 gap-2 text-xs">
<span class="font-mono text-slate-900">A</span>
<span class="font-mono text-slate-900">www</span>
<span class="font-mono text-slate-900">{{ $serverIp }}</span>
</div>
</div>
<p class="mt-2 text-xs text-slate-500">DNS changes can take up to 2448 hours.</p>
</div>
</div>
</div>
</div>
</x-hosting-panel-layout>