mirror of
https://github.com/twinpath/app.git
synced 2026-01-26 13:21:59 +07:00
Initial commit
This commit is contained in:
72
resources/views/pages/admin/root-ca/index.blade.php
Normal file
72
resources/views/pages/admin/root-ca/index.blade.php
Normal file
@@ -0,0 +1,72 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Root CA Management</h1>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Manage your Root and Intermediate Certificates.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white dark:bg-gray-800 shadow-theme-xs rounded-xl border border-gray-100 dark:border-gray-700 overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
|
||||
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3">Type</th>
|
||||
<th scope="col" class="px-6 py-3">Common Name</th>
|
||||
<th scope="col" class="px-6 py-3">Serial Number</th>
|
||||
<th scope="col" class="px-6 py-3">Valid From</th>
|
||||
<th scope="col" class="px-6 py-3">Valid To</th>
|
||||
<th scope="col" class="px-6 py-3">Status</th>
|
||||
<th scope="col" class="px-6 py-3">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($certificates as $cert)
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700">
|
||||
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
{{ ucfirst(str_replace('_', ' ', $cert->ca_type)) }}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
{{ $cert->common_name }}
|
||||
</td>
|
||||
<td class="px-6 py-4 font-mono text-xs">
|
||||
{{ $cert->serial_number }}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
{{ \Carbon\Carbon::parse($cert->valid_from)->format('Y-m-d H:i') }}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
{{ \Carbon\Carbon::parse($cert->valid_to)->format('Y-m-d H:i') }}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
@if($cert->status === 'valid')
|
||||
<span class="bg-green-100 text-green-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded dark:bg-green-900 dark:text-green-300">Valid</span>
|
||||
@else
|
||||
<span class="bg-red-100 text-red-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded dark:bg-red-900 dark:text-red-300">Expired</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<form action="{{ route('admin.root-ca.renew', $cert->id) }}" method="POST" class="inline-block" onsubmit="return confirm('Are you sure you want to renew this certificate?');">
|
||||
@csrf
|
||||
<input type="hidden" name="days" value="3650">
|
||||
<button type="submit" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-xs px-3 py-1.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">
|
||||
Renew (10 Years)
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||
<td colspan="7" class="px-6 py-4 text-center">
|
||||
No Root CA certificates found.
|
||||
<span class="text-gray-400">(Run Setup first)</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
213
resources/views/pages/admin/users/index.blade.php
Normal file
213
resources/views/pages/admin/users/index.blade.php
Normal file
@@ -0,0 +1,213 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="mx-auto max-w-(--breakpoint-2xl) p-4 md:p-6" x-data="{
|
||||
showEditEmailModal: false,
|
||||
selectedUserId: null,
|
||||
selectedUserEmail: '',
|
||||
editEmailUrl: '',
|
||||
openEditEmailModal(userId, userEmail) {
|
||||
this.selectedUserId = userId;
|
||||
this.selectedUserEmail = userEmail;
|
||||
this.editEmailUrl = '{{ route('admin.users.update-email', ':id') }}'.replace(':id', userId);
|
||||
this.showEditEmailModal = true;
|
||||
$nextTick(() => $refs.emailInput.focus());
|
||||
}
|
||||
}">
|
||||
<!-- Breadcrumb -->
|
||||
<div class="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<h2 class="text-title-md2 font-semibold text-black dark:text-white">
|
||||
User Management
|
||||
</h2>
|
||||
|
||||
<nav>
|
||||
<ol class="flex items-center gap-2">
|
||||
<li>
|
||||
<a class="font-medium text-gray-500 hover:text-brand-500 dark:text-gray-400 dark:hover:text-brand-500"
|
||||
href="{{ route('dashboard') }}">
|
||||
Dashboard /
|
||||
</a>
|
||||
</li>
|
||||
<li class="font-medium text-brand-500">Users</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Table Section -->
|
||||
<div class="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div class="max-w-full overflow-x-auto custom-scrollbar">
|
||||
<table class="w-full min-w-[1102px]">
|
||||
<thead class="bg-gray-50 dark:bg-gray-800">
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<th class="px-5 py-3 text-left sm:px-6">
|
||||
<p class="font-medium text-gray-500 text-theme-xs dark:text-gray-400">
|
||||
User
|
||||
</p>
|
||||
</th>
|
||||
<th class="px-5 py-3 text-left sm:px-6">
|
||||
<p class="font-medium text-gray-500 text-theme-xs dark:text-gray-400">
|
||||
Role
|
||||
</p>
|
||||
</th>
|
||||
<th class="px-5 py-3 text-left sm:px-6">
|
||||
<p class="font-medium text-gray-500 text-theme-xs dark:text-gray-400">
|
||||
Joined Date
|
||||
</p>
|
||||
</th>
|
||||
<th class="px-5 py-3 text-left sm:px-6">
|
||||
<p class="font-medium text-gray-500 text-theme-xs dark:text-gray-400">
|
||||
Status
|
||||
</p>
|
||||
</th>
|
||||
<th class="px-5 py-3 text-left sm:px-6">
|
||||
<p class="font-medium text-gray-500 text-theme-xs dark:text-gray-400">
|
||||
Actions
|
||||
</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100 dark:divide-gray-800">
|
||||
@foreach ($users as $user)
|
||||
<tr class="hover:bg-gray-50 dark:hover:bg-white/[0.02]">
|
||||
<td class="px-5 py-4 sm:px-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 overflow-hidden rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center text-gray-500">
|
||||
@if($user->avatar)
|
||||
<img src="{{ asset('storage/' . $user->avatar) }}" alt="{{ $user->name }}" class="w-full h-full object-cover">
|
||||
@else
|
||||
<span class="text-xs font-bold">{{ substr($user->first_name ?? $user->name, 0, 2) }}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<span class="block font-medium text-gray-800 text-theme-sm dark:text-white/90">
|
||||
{{ $user->name ?? $user->first_name . ' ' . $user->last_name }}
|
||||
</span>
|
||||
<span class="block text-gray-500 text-theme-xs dark:text-gray-400">
|
||||
{{ $user->email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-4 sm:px-6">
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {{ $user->isAdmin() ? 'bg-brand-50 text-brand-700 dark:bg-brand-500/15 dark:text-brand-500' : 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300' }}">
|
||||
{{ $user->role ? ucfirst($user->role->name) : 'User' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-5 py-4 sm:px-6">
|
||||
<p class="text-gray-500 text-theme-sm dark:text-gray-400">
|
||||
{{ $user->created_at->format('M d, Y') }}
|
||||
<span class="block text-theme-xs text-gray-400">{{ $user->created_at->diffForHumans() }}</span>
|
||||
</p>
|
||||
</td>
|
||||
<td class="px-5 py-4 sm:px-6">
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium w-fit {{ $user->status === 'active' ? 'bg-green-50 text-green-700 dark:bg-green-500/15 dark:text-green-500' : 'bg-red-50 text-red-700 dark:bg-red-500/15 dark:text-red-500' }}">
|
||||
{{ ucfirst($user->status) }}
|
||||
</span>
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium w-fit {{ $user->hasVerifiedEmail() ? 'bg-blue-50 text-blue-700 dark:bg-blue-500/15 dark:text-blue-500' : 'bg-yellow-50 text-yellow-700 dark:bg-yellow-500/15 dark:text-yellow-500' }}">
|
||||
{{ $user->hasVerifiedEmail() ? 'Verified' : 'Unverified' }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-4 sm:px-6">
|
||||
<div class="flex items-center space-x-2">
|
||||
@if($user->id !== auth()->id())
|
||||
<form action="{{ route('admin.users.toggle-status', $user->id) }}" method="POST" class="inline-block">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<button type="submit" class="text-gray-500 hover:text-{{ $user->status === 'active' ? 'red' : 'green' }}-500 dark:text-gray-400 dark:hover:text-{{ $user->status === 'active' ? 'red' : 'green' }}-500" title="{{ $user->status === 'active' ? 'Suspend' : 'Activate' }} User">
|
||||
@if($user->status === 'active')
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"></path></svg>
|
||||
@else
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
@endif
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<button @click="openEditEmailModal('{{ $user->id }}', '{{ $user->email }}')" class="text-gray-500 hover:text-brand-500 dark:text-gray-400 dark:hover:text-brand-500" title="Edit Email">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg>
|
||||
</button>
|
||||
@endif
|
||||
|
||||
@if(!$user->hasVerifiedEmail())
|
||||
<form action="{{ route('admin.users.send-verification', $user->id) }}" method="POST" class="inline-block" onsubmit="return confirm('Send verification email to {{ $user->email }}?');">
|
||||
@csrf
|
||||
<button type="submit" class="text-gray-500 hover:text-brand-500 dark:text-gray-400 dark:hover:text-brand-500" title="Send Verification Email">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg>
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('admin.users.send-reset-link', $user->id) }}" method="POST" class="inline-block" onsubmit="return confirm('Send password reset link to {{ $user->email }}?');">
|
||||
@csrf
|
||||
<button type="submit" class="text-gray-500 hover:text-brand-500 dark:text-gray-400 dark:hover:text-brand-500" title="Send Password Reset Link">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11.536 11 9 13.536 7.464 12 4.929 14.536V17h2.472l4.243-4.243a6 6 0 018.828-5.743zM16.5 13.5V18h6v-4.5h-6z"></path></svg>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@if($user->id !== auth()->id())
|
||||
<form action="{{ route('admin.users.destroy', $user->id) }}" method="POST" class="inline-block" onsubmit="return confirm('Are you sure you want to delete this user? This action cannot be undone.');">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="text-gray-500 hover:text-red-500 dark:text-gray-400 dark:hover:text-red-500" title="Delete User">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg>
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
@if($users->hasPages())
|
||||
<div class="border-t border-gray-200 px-5 py-4 dark:border-gray-800">
|
||||
{{ $users->links() }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Edit Email Modal -->
|
||||
<div x-show="showEditEmailModal" class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-xs"
|
||||
x-transition.opacity style="display: none;">
|
||||
<div @click.outside="showEditEmailModal = false"
|
||||
class="w-full max-w-lg rounded-2xl bg-white p-6 shadow-xl dark:bg-gray-900 mx-4"
|
||||
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">
|
||||
|
||||
<h3 class="mb-4 text-lg font-semibold text-gray-800 dark:text-white/90">Edit User Email</h3>
|
||||
|
||||
<form :action="editEmailUrl" method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
|
||||
<div class="mb-5">
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Email Address
|
||||
</label>
|
||||
<input type="email" name="email" x-model="selectedUserEmail" x-ref="emailInput" required
|
||||
class="w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 text-sm text-gray-800 placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-white/[0.03] dark:text-white/90">
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-3">
|
||||
<button type="button" @click="showEditEmailModal = false"
|
||||
class="rounded-lg border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-white/[0.03]">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="rounded-lg bg-brand-500 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-brand-600 focus:outline-hidden focus:ring-2 focus:ring-brand-500/50">
|
||||
Update Email
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
97
resources/views/pages/auth/forgot-password.blade.php
Normal file
97
resources/views/pages/auth/forgot-password.blade.php
Normal file
@@ -0,0 +1,97 @@
|
||||
@extends('layouts.fullscreen-layout')
|
||||
|
||||
@section('content')
|
||||
<div class="relative z-1 bg-white p-6 sm:p-0 dark:bg-gray-900">
|
||||
<div class="relative flex h-screen w-full flex-col justify-center sm:p-0 lg:flex-row dark:bg-gray-900">
|
||||
<!-- Form -->
|
||||
<div class="flex w-full flex-1 flex-col lg:w-1/2">
|
||||
<div class="mx-auto w-full max-w-md pt-10">
|
||||
<a href="{{ route('home') }}"
|
||||
class="inline-flex items-center text-sm text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300">
|
||||
<svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
||||
viewBox="0 0 20 20" fill="none">
|
||||
<path d="M12.7083 5L7.5 10.2083L12.7083 15.4167" stroke="" stroke-width="1.5"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
Back to Home
|
||||
</a>
|
||||
</div>
|
||||
<div class="mx-auto flex w-full max-w-md flex-1 flex-col justify-center">
|
||||
<div>
|
||||
<div class="mb-5 sm:mb-8">
|
||||
<h1 class="text-title-sm sm:text-title-md mb-2 font-semibold text-gray-800 dark:text-white/90">
|
||||
Forgot Password
|
||||
</h1>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Enter your email address below. We'll look for your account and send you a password reset email.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if (session('status'))
|
||||
<div class="mb-4 rounded-lg bg-success-50 px-4 py-3 text-sm text-success-600 dark:bg-success-500/10 dark:text-success-500" role="alert">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('password.email') }}" method="POST">
|
||||
@csrf
|
||||
<div class="space-y-5">
|
||||
<!-- Email -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Email<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<input type="email" name="email" value="{{ old('email') }}"
|
||||
placeholder="Enter your email" required
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
@error('email')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Button -->
|
||||
<div>
|
||||
<button type="submit"
|
||||
class="bg-brand-500 shadow-theme-xs hover:bg-brand-600 flex w-full items-center justify-center rounded-lg px-4 py-3 text-sm font-medium text-white transition">
|
||||
Send Reset Link
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="mt-5 text-center">
|
||||
<a href="{{ route('signin') }}" class="text-brand-500 hover:text-brand-600 dark:text-brand-400 text-sm">
|
||||
Back to Login
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-brand-950 relative hidden h-full w-full items-center lg:grid lg:w-1/2 dark:bg-white/5">
|
||||
<div class="z-1 flex items-center justify-center">
|
||||
<x-common.common-grid-shape />
|
||||
<div class="flex max-w-xs flex-col items-center">
|
||||
<a href="{{ route('home') }}" class="mb-4 block">
|
||||
<img src="{{ asset('images/logo/auth-logo.svg') }}" alt="Logo" />
|
||||
</a>
|
||||
<p class="text-center text-gray-400 dark:text-white/60">
|
||||
Free and Open-Source Tailwind CSS Admin Dashboard Template
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toggler -->
|
||||
<div class="fixed right-6 bottom-6 z-50">
|
||||
<button
|
||||
class="bg-brand-500 hover:bg-brand-600 inline-flex size-14 items-center justify-center rounded-full text-white transition-colors"
|
||||
@click.prevent="$store.theme.toggle()">
|
||||
<!-- Sun Icon -->
|
||||
<svg class="hidden fill-current dark:block" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.99998 1.5415C10.4142 1.5415 10.75 1.87729 10.75 2.2915V3.5415C10.75 3.95572 10.4142 4.2915 9.99998 4.2915C9.58577 4.2915 9.24998 3.95572 9.24998 3.5415V2.2915C9.24998 1.87729 9.58577 1.5415 9.99998 1.5415ZM10.0009 6.79327C8.22978 6.79327 6.79402 8.22904 6.79402 10.0001C6.79402 11.7712 8.22978 13.207 10.0009 13.207C11.772 13.207 13.2078 11.7712 13.2078 10.0001C13.2078 8.22904 11.772 6.79327 10.0009 6.79327ZM5.29402 10.0001C5.29402 7.40061 7.40135 5.29327 10.0009 5.29327C12.6004 5.29327 14.7078 7.40061 14.7078 10.0001C14.7078 12.5997 12.6004 14.707 10.0009 14.707C7.40135 14.707 5.29402 12.5997 5.29402 10.0001ZM15.9813 5.08035C16.2742 4.78746 16.2742 4.31258 15.9813 4.01969C15.6884 3.7268 15.2135 3.7268 14.9207 4.01969L14.0368 4.90357C13.7439 5.19647 13.7439 5.67134 14.0368 5.96423C14.3297 6.25713 14.8045 6.25713 15.0974 5.96423L15.9813 5.08035ZM18.4577 10.0001C18.4577 10.4143 18.1219 10.7501 17.7077 10.7501H16.4577C16.0435 10.7501 15.7077 10.4143 15.7077 10.0001C15.7077 9.58592 16.0435 9.25013 16.4577 9.25013H17.7077C18.1219 9.25013 18.4577 9.58592 18.4577 10.0001ZM14.9207 15.9806C15.2135 16.2735 15.6884 16.2735 15.9813 15.9806C16.2742 15.6877 16.2742 15.2128 15.9813 14.9199L15.0974 14.036C14.8045 13.7431 14.3297 13.7431 14.0368 14.036C13.7439 14.3289 13.7439 14.8038 14.0368 15.0967L14.9207 15.9806ZM9.99998 15.7088C10.4142 15.7088 10.75 16.0445 10.75 16.4588V17.7088C10.75 18.123 10.4142 18.4588 9.99998 18.4588C9.58577 18.4588 9.24998 18.123 9.24998 17.7088V16.4588C9.24998 16.0445 9.58577 15.7088 9.99998 15.7088ZM5.96356 15.0972C6.25646 14.8043 6.25646 14.3295 5.96356 14.0366C5.67067 13.7437 5.1958 13.7437 4.9029 14.0366L4.01902 14.9204C3.72613 15.2133 3.72613 15.6882 4.01902 15.9811C4.31191 16.274 4.78679 16.274 5.07968 15.9811L5.96356 15.0972ZM4.29224 10.0001C4.29224 10.4143 3.95645 10.7501 3.54224 10.7501H2.29224C1.87802 10.7501 1.54224 10.4143 1.54224 10.0001C1.54224 9.58592 1.87802 9.25013 2.29224 9.25013H3.54224C3.95645 9.25013 4.29224 9.58592 4.29224 10.0001ZM4.9029 5.9637C5.1958 6.25659 5.67067 6.25659 5.96356 5.9637C6.25646 5.6708 6.25646 5.19593 5.96356 4.90303L5.07968 4.01915C4.78679 3.72626 4.31191 3.72626 4.01902 4.01915C3.72613 4.31204 3.72613 4.78692 4.01902 5.07981L4.9029 5.9637Z" fill="" /> </svg>
|
||||
<!-- Moon Icon -->
|
||||
<svg class="fill-current dark:hidden" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17.4547 11.97L18.1799 12.1611C18.265 11.8383 18.1265 11.4982 17.8401 11.3266C17.5538 11.1551 17.1885 11.1934 16.944 11.4207L17.4547 11.97ZM8.0306 2.5459L8.57989 3.05657C8.80718 2.81209 8.84554 2.44682 8.67398 2.16046C8.50243 1.8741 8.16227 1.73559 7.83948 1.82066L8.0306 2.5459ZM12.9154 13.0035C9.64678 13.0035 6.99707 10.3538 6.99707 7.08524H5.49707C5.49707 11.1823 8.81835 14.5035 12.9154 14.5035V13.0035ZM16.944 11.4207C15.8869 12.4035 14.4721 13.0035 12.9154 13.0035V14.5035C14.8657 14.5035 16.6418 13.7499 17.9654 12.5193L16.944 11.4207ZM16.7295 11.7789C15.9437 14.7607 13.2277 16.9586 10.0003 16.9586V18.4586C13.9257 18.4586 17.2249 15.7853 18.1799 12.1611L16.7295 11.7789ZM10.0003 16.9586C6.15734 16.9586 3.04199 13.8433 3.04199 10.0003H1.54199C1.54199 14.6717 5.32892 18.4586 10.0003 18.4586V16.9586ZM3.04199 10.0003C3.04199 6.77289 5.23988 4.05695 8.22173 3.27114L7.83948 1.82066C4.21532 2.77574 1.54199 6.07486 1.54199 10.0003H3.04199ZM6.99707 7.08524C6.99707 5.52854 7.5971 4.11366 8.57989 3.05657L7.48132 2.03522C6.25073 3.35885 5.49707 5.13487 5.49707 7.08524H6.99707Z" fill="" /> </svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
129
resources/views/pages/auth/reset-password.blade.php
Normal file
129
resources/views/pages/auth/reset-password.blade.php
Normal file
@@ -0,0 +1,129 @@
|
||||
@extends('layouts.fullscreen-layout')
|
||||
|
||||
@section('content')
|
||||
<div class="relative z-1 bg-white p-6 sm:p-0 dark:bg-gray-900">
|
||||
<div class="relative flex h-screen w-full flex-col justify-center sm:p-0 lg:flex-row dark:bg-gray-900">
|
||||
<!-- Form -->
|
||||
<div class="flex w-full flex-1 flex-col lg:w-1/2">
|
||||
<div class="mx-auto w-full max-w-md pt-10">
|
||||
<a href="{{ route('home') }}"
|
||||
class="inline-flex items-center text-sm text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300">
|
||||
<svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
||||
viewBox="0 0 20 20" fill="none">
|
||||
<path d="M12.7083 5L7.5 10.2083L12.7083 15.4167" stroke="" stroke-width="1.5"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
Back to Home
|
||||
</a>
|
||||
</div>
|
||||
<div class="mx-auto flex w-full max-w-md flex-1 flex-col justify-center">
|
||||
<div>
|
||||
<div class="mb-5 sm:mb-8">
|
||||
<h1 class="text-title-sm sm:text-title-md mb-2 font-semibold text-gray-800 dark:text-white/90">
|
||||
Reset Password
|
||||
</h1>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Enter your new password details below.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('password.update') }}" method="POST">
|
||||
@csrf
|
||||
<input type="hidden" name="token" value="{{ $token }}">
|
||||
|
||||
<div class="space-y-5">
|
||||
<!-- Email -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Email<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<input type="email" name="email" value="{{ $email ?? old('email') }}"
|
||||
placeholder="Your email" required readonly
|
||||
class="cursor-not-allowed bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:placeholder:text-white/30" />
|
||||
@error('email')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
New Password<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<div x-data="{ showPassword: false }" class="relative">
|
||||
<input :type="showPassword ? 'text' : 'password'" name="password" required
|
||||
placeholder="Enter new password"
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent py-2.5 pr-11 pl-4 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
<span @click="showPassword = !showPassword"
|
||||
class="absolute top-1/2 right-4 z-30 -translate-y-1/2 cursor-pointer text-gray-500 dark:text-gray-400">
|
||||
<svg x-show="!showPassword" class="fill-current" width="20" height="20"
|
||||
viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M10.0002 13.8619C7.23361 13.8619 4.86803 12.1372 3.92328 9.70241C4.86804 7.26761 7.23361 5.54297 10.0002 5.54297C12.7667 5.54297 15.1323 7.26762 16.0771 9.70243C15.1323 12.1372 12.7667 13.8619 10.0002 13.8619ZM10.0002 4.04297C6.48191 4.04297 3.49489 6.30917 2.4155 9.4593C2.3615 9.61687 2.3615 9.78794 2.41549 9.94552C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C13.5184 15.3619 16.5055 13.0957 17.5849 9.94555C17.6389 9.78797 17.6389 9.6169 17.5849 9.45932C16.5055 6.30919 13.5184 4.04297 10.0002 4.04297ZM9.99151 7.84413C8.96527 7.84413 8.13333 8.67606 8.13333 9.70231C8.13333 10.7286 8.96527 11.5605 9.99151 11.5605H10.0064C11.0326 11.5605 11.8646 10.7286 11.8646 9.70231C11.8646 8.67606 11.0326 7.84413 10.0064 7.84413H9.99151Z"
|
||||
fill="#98A2B3" />
|
||||
</svg>
|
||||
<svg x-show="showPassword" class="fill-current" width="20" height="20"
|
||||
viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M4.63803 3.57709C4.34513 3.2842 3.87026 3.2842 3.57737 3.57709C3.28447 3.86999 3.28447 4.34486 3.57737 4.63775L4.85323 5.91362C3.74609 6.84199 2.89363 8.06395 2.4155 9.45936C2.3615 9.61694 2.3615 9.78801 2.41549 9.94558C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C11.255 15.3619 12.4422 15.0737 13.4994 14.5598L15.3625 16.4229C15.6554 16.7158 16.1302 16.7158 16.4231 16.4229C16.716 16.13 16.716 15.6551 16.4231 15.3622L4.63803 3.57709ZM12.3608 13.4212L10.4475 11.5079C10.3061 11.5423 10.1584 11.5606 10.0064 11.5606H9.99151C8.96527 11.5606 8.13333 10.7286 8.13333 9.70237C8.13333 9.5461 8.15262 9.39434 8.18895 9.24933L5.91885 6.97923C5.03505 7.69015 4.34057 8.62704 3.92328 9.70247C4.86803 12.1373 7.23361 13.8619 10.0002 13.8619C10.8326 13.8619 11.6287 13.7058 12.3608 13.4212ZM16.0771 9.70249C15.7843 10.4569 15.3552 11.1432 14.8199 11.7311L15.8813 12.7925C16.6329 11.9813 17.2187 11.0143 17.5849 9.94561C17.6389 9.78803 17.6389 9.61696 17.5849 9.45938C16.5055 6.30925 13.5184 4.04303 10.0002 4.04303C9.13525 4.04303 8.30244 4.17999 7.52218 4.43338L8.75139 5.66259C9.1556 5.58413 9.57311 5.54303 10.0002 5.54303C12.7667 5.54303 15.1323 7.26768 16.0771 9.70249Z"
|
||||
fill="#98A2B3" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
@error('password')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Confirm Password
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input type="password" name="password_confirmation" required
|
||||
placeholder="Confirm new password"
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Button -->
|
||||
<div>
|
||||
<button type="submit"
|
||||
class="bg-brand-500 shadow-theme-xs hover:bg-brand-600 flex w-full items-center justify-center rounded-lg px-4 py-3 text-sm font-medium text-white transition">
|
||||
Reset Password
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-brand-950 relative hidden h-full w-full items-center lg:grid lg:w-1/2 dark:bg-white/5">
|
||||
<div class="z-1 flex items-center justify-center">
|
||||
<x-common.common-grid-shape />
|
||||
<div class="flex max-w-xs flex-col items-center">
|
||||
<a href="{{ route('home') }}" class="mb-4 block">
|
||||
<img src="{{ asset('images/logo/auth-logo.svg') }}" alt="Logo" />
|
||||
</a>
|
||||
<p class="text-center text-gray-400 dark:text-white/60">
|
||||
Free and Open-Source Tailwind CSS Admin Dashboard Template
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toggler -->
|
||||
<div class="fixed right-6 bottom-6 z-50">
|
||||
<button
|
||||
class="bg-brand-500 hover:bg-brand-600 inline-flex size-14 items-center justify-center rounded-full text-white transition-colors"
|
||||
@click.prevent="$store.theme.toggle()">
|
||||
<!-- Sun Icon -->
|
||||
<svg class="hidden fill-current dark:block" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.99998 1.5415C10.4142 1.5415 10.75 1.87729 10.75 2.2915V3.5415C10.75 3.95572 10.4142 4.2915 9.99998 4.2915C9.58577 4.2915 9.24998 3.95572 9.24998 3.5415V2.2915C9.24998 1.87729 9.58577 1.5415 9.99998 1.5415ZM10.0009 6.79327C8.22978 6.79327 6.79402 8.22904 6.79402 10.0001C6.79402 11.7712 8.22978 13.207 10.0009 13.207C11.772 13.207 13.2078 11.7712 13.2078 10.0001C13.2078 8.22904 11.772 6.79327 10.0009 6.79327ZM5.29402 10.0001C5.29402 7.40061 7.40135 5.29327 10.0009 5.29327C12.6004 5.29327 14.7078 7.40061 14.7078 10.0001C14.7078 12.5997 12.6004 14.707 10.0009 14.707C7.40135 14.707 5.29402 12.5997 5.29402 10.0001ZM15.9813 5.08035C16.2742 4.78746 16.2742 4.31258 15.9813 4.01969C15.6884 3.7268 15.2135 3.7268 14.9207 4.01969L14.0368 4.90357C13.7439 5.19647 13.7439 5.67134 14.0368 5.96423C14.3297 6.25713 14.8045 6.25713 15.0974 5.96423L15.9813 5.08035ZM18.4577 10.0001C18.4577 10.4143 18.1219 10.7501 17.7077 10.7501H16.4577C16.0435 10.7501 15.7077 10.4143 15.7077 10.0001C15.7077 9.58592 16.0435 9.25013 16.4577 9.25013H17.7077C18.1219 9.25013 18.4577 9.58592 18.4577 10.0001ZM14.9207 15.9806C15.2135 16.2735 15.6884 16.2735 15.9813 15.9806C16.2742 15.6877 16.2742 15.2128 15.9813 14.9199L15.0974 14.036C14.8045 13.7431 14.3297 13.7431 14.0368 14.036C13.7439 14.3289 13.7439 14.8038 14.0368 15.0967L14.9207 15.9806ZM9.99998 15.7088C10.4142 15.7088 10.75 16.0445 10.75 16.4588V17.7088C10.75 18.123 10.4142 18.4588 9.99998 18.4588C9.58577 18.4588 9.24998 18.123 9.24998 17.7088V16.4588C9.24998 16.0445 9.58577 15.7088 9.99998 15.7088ZM5.96356 15.0972C6.25646 14.8043 6.25646 14.3295 5.96356 14.0366C5.67067 13.7437 5.1958 13.7437 4.9029 14.0366L4.01902 14.9204C3.72613 15.2133 3.72613 15.6882 4.01902 15.9811C4.31191 16.274 4.78679 16.274 5.07968 15.9811L5.96356 15.0972ZM4.29224 10.0001C4.29224 10.4143 3.95645 10.7501 3.54224 10.7501H2.29224C1.87802 10.7501 1.54224 10.4143 1.54224 10.0001C1.54224 9.58592 1.87802 9.25013 2.29224 9.25013H3.54224C3.95645 9.25013 4.29224 9.58592 4.29224 10.0001ZM4.9029 5.9637C5.1958 6.25659 5.67067 6.25659 5.96356 5.9637C6.25646 5.6708 6.25646 5.19593 5.96356 4.90303L5.07968 4.01915C4.78679 3.72626 4.31191 3.72626 4.01902 4.01915C3.72613 4.31204 3.72613 4.78692 4.01902 5.07981L4.9029 5.9637Z" fill="" /> </svg>
|
||||
<!-- Moon Icon -->
|
||||
<svg class="fill-current dark:hidden" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17.4547 11.97L18.1799 12.1611C18.265 11.8383 18.1265 11.4982 17.8401 11.3266C17.5538 11.1551 17.1885 11.1934 16.944 11.4207L17.4547 11.97ZM8.0306 2.5459L8.57989 3.05657C8.80718 2.81209 8.84554 2.44682 8.67398 2.16046C8.50243 1.8741 8.16227 1.73559 7.83948 1.82066L8.0306 2.5459ZM12.9154 13.0035C9.64678 13.0035 6.99707 10.3538 6.99707 7.08524H5.49707C5.49707 11.1823 8.81835 14.5035 12.9154 14.5035V13.0035ZM16.944 11.4207C15.8869 12.4035 14.4721 13.0035 12.9154 13.0035V14.5035C14.8657 14.5035 16.6418 13.7499 17.9654 12.5193L16.944 11.4207ZM16.7295 11.7789C15.9437 14.7607 13.2277 16.9586 10.0003 16.9586V18.4586C13.9257 18.4586 17.2249 15.7853 18.1799 12.1611L16.7295 11.7789ZM10.0003 16.9586C6.15734 16.9586 3.04199 13.8433 3.04199 10.0003H1.54199C1.54199 14.6717 5.32892 18.4586 10.0003 18.4586V16.9586ZM3.04199 10.0003C3.04199 6.77289 5.23988 4.05695 8.22173 3.27114L7.83948 1.82066C4.21532 2.77574 1.54199 6.07486 1.54199 10.0003H3.04199ZM6.99707 7.08524C6.99707 5.52854 7.5971 4.11366 8.57989 3.05657L7.48132 2.03522C6.25073 3.35885 5.49707 5.13487 5.49707 7.08524H6.99707Z" fill="" /> </svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
142
resources/views/pages/auth/setup-password.blade.php
Normal file
142
resources/views/pages/auth/setup-password.blade.php
Normal file
@@ -0,0 +1,142 @@
|
||||
@extends('layouts.fullscreen-layout')
|
||||
|
||||
@section('content')
|
||||
<div class="relative z-1 bg-white p-6 sm:p-0 dark:bg-gray-900">
|
||||
<div class="relative flex h-screen w-full flex-col justify-center sm:p-0 lg:flex-row dark:bg-gray-900">
|
||||
<!-- Form -->
|
||||
<div class="flex w-full flex-1 flex-col lg:w-1/2">
|
||||
<div class="mx-auto flex w-full max-w-md flex-1 flex-col justify-center">
|
||||
<div>
|
||||
<div class="mb-5 sm:mb-8">
|
||||
<h1 class="text-title-sm sm:text-title-md mb-2 font-semibold text-gray-800 dark:text-white/90">
|
||||
Complete Your Registration
|
||||
</h1>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Set a password to secure your account and enable email login.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- User Info Preview -->
|
||||
<div class="mb-6 rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="h-16 w-16 overflow-hidden rounded-full border border-gray-200 dark:border-gray-800">
|
||||
<img src="{{ session('social_signup_avatar') ?? asset('images/user/owner.jpg') }}" alt="avatar" class="h-full w-full object-cover" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-800 dark:text-white/90">{{ session('social_signup_name') }}</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ session('social_signup_email') }}</p>
|
||||
<span class="mt-1 inline-flex items-center rounded-full bg-blue-50 px-2 py-0.5 text-xs font-medium text-blue-700 dark:bg-blue-900/10 dark:text-blue-400">
|
||||
via {{ ucfirst(session('social_signup_provider', 'social')) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="mb-4 rounded-lg bg-error-50 p-4 text-sm text-error-500">
|
||||
<ul class="list-disc list-inside">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('setup-password') }}" method="POST">
|
||||
@csrf
|
||||
<div class="space-y-5">
|
||||
<!-- Name fields removed as they are provided by social account -->
|
||||
|
||||
<!-- Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Password<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<div x-data="{ showPassword: false }" class="relative">
|
||||
<input :type="showPassword ? 'text' : 'password'" name="password" required
|
||||
placeholder="Enter your password (min. 8 characters)"
|
||||
class="h-11 w-full rounded-lg border border-gray-300 bg-transparent py-2.5 pr-11 pl-4 text-sm text-gray-800 placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
<span @click="showPassword = !showPassword"
|
||||
class="absolute top-1/2 right-4 z-30 -translate-y-1/2 cursor-pointer text-gray-500 dark:text-gray-400">
|
||||
<svg x-show="!showPassword" class="fill-current" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0002 13.8619C7.23361 13.8619 4.86803 12.1372 3.92328 9.70241C4.86804 7.26761 7.23361 5.54297 10.0002 5.54297C12.7667 5.54297 15.1323 7.26762 16.0771 9.70243C15.1323 12.1372 12.7667 13.8619 10.0002 13.8619ZM10.0002 4.04297C6.48191 4.04297 3.49489 6.30917 2.4155 9.4593C2.3615 9.61687 2.3615 9.78794 2.41549 9.94552C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C13.5184 15.3619 16.5055 13.0957 17.5849 9.94555C17.6389 9.78797 17.6389 9.6169 17.5849 9.45932C16.5055 6.30919 13.5184 4.04297 10.0002 4.04297ZM9.99151 7.84413C8.96527 7.84413 8.13333 8.67606 8.13333 9.70231C8.13333 10.7286 8.96527 11.5605 9.99151 11.5605H10.0064C11.0326 11.5605 11.8646 10.7286 11.8646 9.70231C11.8646 8.67606 11.0326 7.84413 10.0064 7.84413H9.99151Z" fill="#98A2B3" />
|
||||
</svg>
|
||||
<svg x-show="showPassword" class="fill-current" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.63803 3.57709C4.34513 3.2842 3.87026 3.2842 3.57737 3.57709C3.28447 3.86999 3.28447 4.34486 3.57737 4.63775L4.85323 5.91362C3.74609 6.84199 2.89363 8.06395 2.4155 9.45936C2.3615 9.61694 2.3615 9.78801 2.41549 9.94558C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C11.255 15.3619 12.4422 15.0737 13.4994 14.5598L15.3625 16.4229C15.6554 16.7158 16.1302 16.7158 16.4231 16.4229C16.716 16.13 16.716 15.6551 16.4231 15.3622L4.63803 3.57709ZM12.3608 13.4212L10.4475 11.5079C10.3061 11.5423 10.1584 11.5606 10.0064 11.5606H9.99151C8.96527 11.5606 8.13333 10.7286 8.13333 9.70237C8.13333 9.5461 8.15262 9.39434 8.18895 9.24933L5.91885 6.97923C5.03505 7.69015 4.34057 8.62704 3.92328 9.70247C4.86803 12.1373 7.23361 13.8619 10.0002 13.8619C10.8326 13.8619 11.6287 13.7058 12.3608 13.4212ZM16.0771 9.70249C15.7843 10.4569 15.3552 11.1432 14.8199 11.7311L15.8813 12.7925C16.6329 11.9813 17.2187 11.0143 17.5849 9.94561C17.6389 9.78803 17.6389 9.61696 17.5849 9.45938C16.5055 6.30925 13.5184 4.04303 10.0002 4.04303C9.13525 4.04303 8.30244 4.17999 7.52218 4.43338L8.75139 5.66259C9.1556 5.58413 9.57311 5.54303 10.0002 5.54303C12.7667 5.54303 15.1323 7.26768 16.0771 9.70249Z" fill="#98A2B3" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Confirm Password<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<div x-data="{ showPassword: false }" class="relative">
|
||||
<input :type="showPassword ? 'text' : 'password'" name="password_confirmation" required
|
||||
placeholder="Confirm your password"
|
||||
class="h-11 w-full rounded-lg border border-gray-300 bg-transparent py-2.5 pr-11 pl-4 text-sm text-gray-800 placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
<span @click="showPassword = !showPassword"
|
||||
class="absolute top-1/2 right-4 z-30 -translate-y-1/2 cursor-pointer text-gray-500 dark:text-gray-400">
|
||||
<svg x-show="!showPassword" class="fill-current" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0002 13.8619C7.23361 13.8619 4.86803 12.1372 3.92328 9.70241C4.86804 7.26761 7.23361 5.54297 10.0002 5.54297C12.7667 5.54297 15.1323 7.26762 16.0771 9.70243C15.1323 12.1372 12.7667 13.8619 10.0002 13.8619ZM10.0002 4.04297C6.48191 4.04297 3.49489 6.30917 2.4155 9.4593C2.3615 9.61687 2.3615 9.78794 2.41549 9.94552C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C13.5184 15.3619 16.5055 13.0957 17.5849 9.94555C17.6389 9.78797 17.6389 9.6169 17.5849 9.45932C16.5055 6.30919 13.5184 4.04297 10.0002 4.04297ZM9.99151 7.84413C8.96527 7.84413 8.13333 8.67606 8.13333 9.70231C8.13333 10.7286 8.96527 11.5605 9.99151 11.5605H10.0064C11.0326 11.5605 11.8646 10.7286 11.8646 9.70231C11.8646 8.67606 11.0326 7.84413 10.0064 7.84413H9.99151Z" fill="#98A2B3" />
|
||||
</svg>
|
||||
<svg x-show="showPassword" class="fill-current" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.63803 3.57709C4.34513 3.2842 3.87026 3.2842 3.57737 3.57709C3.28447 3.86999 3.28447 4.34486 3.57737 4.63775L4.85323 5.91362C3.74609 6.84199 2.89363 8.06395 2.4155 9.45936C2.3615 9.61694 2.3615 9.78801 2.41549 9.94558C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C11.255 15.3619 12.4422 15.0737 13.4994 14.5598L15.3625 16.4229C15.6554 16.7158 16.1302 16.7158 16.4231 16.4229C16.716 16.13 16.716 15.6551 16.4231 15.3622L4.63803 3.57709ZM12.3608 13.4212L10.4475 11.5079C10.3061 11.5423 10.1584 11.5606 10.0064 11.5606H9.99151C8.96527 11.5606 8.13333 10.7286 8.13333 9.70237C8.13333 9.5461 8.15262 9.39434 8.18895 9.24933L5.91885 6.97923C5.03505 7.69015 4.34057 8.62704 3.92328 9.70247C4.86803 12.1373 7.23361 13.8619 10.0002 13.8619C10.8326 13.8619 11.6287 13.7058 12.3608 13.4212ZM16.0771 9.70249C15.7843 10.4569 15.3552 11.1432 14.8199 11.7311L15.8813 12.7925C16.6329 11.9813 17.2187 11.0143 17.5849 9.94561C17.6389 9.78803 17.6389 9.61696 17.5849 9.45938C16.5055 6.30925 13.5184 4.04303 10.0002 4.04303C9.13525 4.04303 8.30244 4.17999 7.52218 4.43338L8.75139 5.66259C9.1556 5.58413 9.57311 5.54303 10.0002 5.54303C12.7667 5.54303 15.1323 7.26768 16.0771 9.70249Z" fill="#98A2B3" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info Box -->
|
||||
<div class="rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-500/30 dark:bg-blue-500/10">
|
||||
<p class="text-xs text-blue-700 dark:text-blue-400">
|
||||
<strong>Why set a password?</strong><br>
|
||||
This allows you to sign in with your email and password in the future, even if you don't want to use {{ ucfirst(session('social_signup_provider', 'social')) }} login.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Button -->
|
||||
<div>
|
||||
<button type="submit"
|
||||
class="bg-brand-500 shadow-theme-xs hover:bg-brand-600 flex w-full items-center justify-center rounded-lg px-4 py-3 text-sm font-medium text-white transition">
|
||||
Complete Registration
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-brand-950 relative hidden h-full w-full items-center lg:grid lg:w-1/2 dark:bg-white/5">
|
||||
<div class="z-1 flex items-center justify-center">
|
||||
<x-common.common-grid-shape />
|
||||
<div class="flex max-w-xs flex-col items-center">
|
||||
<a href="{{ route('home') }}" class="mb-4 block">
|
||||
<img src="./images/logo/auth-logo.svg" alt="Logo" />
|
||||
</a>
|
||||
<p class="text-center text-gray-400 dark:text-white/60">
|
||||
One more step to complete your registration
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Theme Toggler -->
|
||||
<div class="fixed right-6 bottom-6 z-50">
|
||||
<button
|
||||
class="bg-brand-500 hover:bg-brand-600 inline-flex size-14 items-center justify-center rounded-full text-white transition-colors"
|
||||
@click.prevent="$store.theme.toggle()">
|
||||
<svg class="hidden fill-current dark:block" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99998 1.5415C10.4142 1.5415 10.75 1.87729 10.75 2.2915V3.5415C10.75 3.95572 10.4142 4.2915 9.99998 4.2915C9.58577 4.2915 9.24998 3.95572 9.24998 3.5415V2.2915C9.24998 1.87729 9.58577 1.5415 9.99998 1.5415ZM10.0009 6.79327C8.22978 6.79327 6.79402 8.22904 6.79402 10.0001C6.79402 11.7712 8.22978 13.207 10.0009 13.207C11.772 13.207 13.2078 11.7712 13.2078 10.0001C13.2078 8.22904 11.772 6.79327 10.0009 6.79327ZM5.29402 10.0001C5.29402 7.40061 7.40135 5.29327 10.0009 5.29327C12.6004 5.29327 14.7078 7.40061 14.7078 10.0001C14.7078 12.5997 12.6004 14.707 10.0009 14.707C7.40135 14.707 5.29402 12.5997 5.29402 10.0001ZM15.9813 5.08035C16.2742 4.78746 16.2742 4.31258 15.9813 4.01969C15.6884 3.7268 15.2135 3.7268 14.9207 4.01969L14.0368 4.90357C13.7439 5.19647 13.7439 5.67134 14.0368 5.96423C14.3297 6.25713 14.8045 6.25713 15.0974 5.96423L15.9813 5.08035ZM18.4577 10.0001C18.4577 10.4143 18.1219 10.7501 17.7077 10.7501H16.4577C16.0435 10.7501 15.7077 10.4143 15.7077 10.0001C15.7077 9.58592 16.0435 9.25013 16.4577 9.25013H17.7077C18.1219 9.25013 18.4577 9.58592 18.4577 10.0001ZM14.9207 15.9806C15.2135 16.2735 15.6884 16.2735 15.9813 15.9806C16.2742 15.6877 16.2742 15.2128 15.9813 14.9199L15.0974 14.036C14.8045 13.7431 14.3297 13.7431 14.0368 14.036C13.7439 14.3289 13.7439 14.8038 14.0368 15.0967L14.9207 15.9806ZM9.99998 15.7088C10.4142 15.7088 10.75 16.0445 10.75 16.4588V17.7088C10.75 18.123 10.4142 18.4588 9.99998 18.4588C9.58577 18.4588 9.24998 18.123 9.24998 17.7088V16.4588C9.24998 16.0445 9.58577 15.7088 9.99998 15.7088ZM5.96356 15.0972C6.25646 14.8043 6.25646 14.3295 5.96356 14.0366C5.67067 13.7437 5.1958 13.7437 4.9029 14.0366L4.01902 14.9204C3.72613 15.2133 3.72613 15.6882 4.01902 15.9811C4.31191 16.274 4.78679 16.274 5.07968 15.9811L5.96356 15.0972ZM4.29224 10.0001C4.29224 10.4143 3.95645 10.7501 3.54224 10.7501H2.29224C1.87802 10.7501 1.54224 10.4143 1.54224 10.0001C1.54224 9.58592 1.87802 9.25013 2.29224 9.25013H3.54224C3.95645 9.25013 4.29224 9.58592 4.29224 10.0001ZM4.9029 5.9637C5.1958 6.25659 5.67067 6.25659 5.96356 5.9637C6.25646 5.6708 6.25646 5.19593 5.96356 4.90303L5.07968 4.01915C4.78679 3.72626 4.31191 3.72626 4.01902 4.01915C3.72613 4.31204 3.72613 4.78692 4.01902 5.07981L4.9029 5.9637Z" fill="" />
|
||||
</svg>
|
||||
<svg class="fill-current dark:hidden" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.4547 11.97L18.1799 12.1611C18.265 11.8383 18.1265 11.4982 17.8401 11.3266C17.5538 11.1551 17.1885 11.1934 16.944 11.4207L17.4547 11.97ZM8.0306 2.5459L8.57989 3.05657C8.80718 2.81209 8.84554 2.44682 8.67398 2.16046C8.50243 1.8741 8.16227 1.73559 7.83948 1.82066L8.0306 2.5459ZM12.9154 13.0035C9.64678 13.0035 6.99707 10.3538 6.99707 7.08524H5.49707C5.49707 11.1823 8.81835 14.5035 12.9154 14.5035V13.0035ZM16.944 11.4207C15.8869 12.4035 14.4721 13.0035 12.9154 13.0035V14.5035C14.8657 14.5035 16.6418 13.7499 17.9654 12.5193L16.944 11.4207ZM16.7295 11.7789C15.9437 14.7607 13.2277 16.9586 10.0003 16.9586V18.4586C13.9257 18.4586 17.2249 15.7853 18.1799 12.1611L16.7295 11.7789ZM10.0003 16.9586C6.15734 16.9586 3.04199 13.8433 3.04199 10.0003H1.54199C1.54199 14.6717 5.32892 18.4586 10.0003 18.4586V16.9586ZM3.04199 10.0003C3.04199 6.77289 5.23988 4.05695 8.22173 3.27114L7.83948 1.82066C4.21532 2.77574 1.54199 6.07486 1.54199 10.0003H3.04199ZM6.99707 7.08524C6.99707 5.52854 7.5971 4.11366 8.57989 3.05657L7.48132 2.03522C6.25073 3.35885 5.49707 5.13487 5.49707 7.08524H6.99707Z" fill="" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
173
resources/views/pages/auth/signin.blade.php
Normal file
173
resources/views/pages/auth/signin.blade.php
Normal file
@@ -0,0 +1,173 @@
|
||||
@extends('layouts.fullscreen-layout')
|
||||
|
||||
@section('content')
|
||||
<div class="relative z-1 bg-white p-6 sm:p-0 dark:bg-gray-900">
|
||||
<div class="relative flex h-screen w-full flex-col justify-center sm:p-0 lg:flex-row dark:bg-gray-900">
|
||||
<!-- Form -->
|
||||
<div class="flex w-full flex-1 flex-col lg:w-1/2">
|
||||
<div class="mx-auto w-full max-w-md pt-10">
|
||||
<a href="{{ route('dashboard') }}"
|
||||
class="inline-flex items-center text-sm text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300">
|
||||
<svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M12.7083 5L7.5 10.2083L12.7083 15.4167" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
Back to dashboard
|
||||
</a>
|
||||
</div>
|
||||
<div class="mx-auto flex w-full max-w-md flex-1 flex-col justify-center">
|
||||
<div>
|
||||
<div class="mb-5 sm:mb-8">
|
||||
<h1 class="text-title-sm sm:text-title-md mb-2 font-semibold text-gray-800 dark:text-white/90">
|
||||
Sign In
|
||||
</h1>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Enter your email and password to sign in!
|
||||
</p>
|
||||
</div>
|
||||
<!-- Session Error handled globally -->
|
||||
<div>
|
||||
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-5">
|
||||
<button onclick="window.location.href = '{{ route('auth.social', ['provider' => 'google', 'context' => 'signin']) }}'"
|
||||
class="inline-flex items-center justify-center gap-3 rounded-lg bg-gray-100 px-7 py-3 text-sm font-normal text-gray-700 transition-colors hover:bg-gray-200 hover:text-gray-800 dark:bg-white/5 dark:text-white/90 dark:hover:bg-white/10">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M18.7511 10.1944C18.7511 9.47495 18.6915 8.94995 18.5626 8.40552H10.1797V11.6527H15.1003C15.0011 12.4597 14.4654 13.675 13.2749 14.4916L13.2582 14.6003L15.9087 16.6126L16.0924 16.6305C17.7788 15.1041 18.7511 12.8583 18.7511 10.1944Z"
|
||||
fill="#4285F4" />
|
||||
<path
|
||||
d="M10.1788 18.75C12.5895 18.75 14.6133 17.9722 16.0915 16.6305L13.274 14.4916C12.5201 15.0068 11.5081 15.3666 10.1788 15.3666C7.81773 15.3666 5.81379 13.8402 5.09944 11.7305L4.99473 11.7392L2.23868 13.8295L2.20264 13.9277C3.67087 16.786 6.68674 18.75 10.1788 18.75Z"
|
||||
fill="#34A853" />
|
||||
<path
|
||||
d="M5.10014 11.7305C4.91165 11.186 4.80257 10.6027 4.80257 9.99992C4.80257 9.3971 4.91165 8.81379 5.09022 8.26935L5.08523 8.1534L2.29464 6.02954L2.20333 6.0721C1.5982 7.25823 1.25098 8.5902 1.25098 9.99992C1.25098 11.4096 1.5982 12.7415 2.20333 13.9277L5.10014 11.7305Z"
|
||||
fill="#FBBC05" />
|
||||
<path
|
||||
d="M10.1789 4.63331C11.8554 4.63331 12.9864 5.34303 13.6312 5.93612L16.1511 3.525C14.6035 2.11528 12.5895 1.25 10.1789 1.25C6.68676 1.25 3.67088 3.21387 2.20264 6.07218L5.08953 8.26943C5.81381 6.15972 7.81776 4.63331 10.1789 4.63331Z"
|
||||
fill="#EB4335" />
|
||||
</svg>
|
||||
Sign in with Google
|
||||
</button>
|
||||
<button onclick="window.location.href = '{{ route('auth.social', ['provider' => 'github', 'context' => 'signin']) }}'"
|
||||
class="inline-flex items-center justify-center gap-3 rounded-lg bg-gray-100 px-7 py-3 text-sm font-normal text-gray-700 transition-colors hover:bg-gray-200 hover:text-gray-800 dark:bg-white/5 dark:text-white/90 dark:hover:bg-white/10">
|
||||
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||
|
||||
Sign in with GitHub
|
||||
</button>
|
||||
</div>
|
||||
<div class="relative py-3 sm:py-5">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-200 dark:border-gray-800"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center text-sm">
|
||||
<span class="bg-white p-2 text-gray-400 sm:px-5 sm:py-2 dark:bg-gray-900">Or</span>
|
||||
</div>
|
||||
</div>
|
||||
<form action="{{ route('signin') }}" method="POST">
|
||||
@csrf
|
||||
<div class="space-y-5">
|
||||
<!-- Email -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Email<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<input type="email" id="email" name="email" value="{{ old('email') }}" placeholder="info@gmail.com"
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
@error('email')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
<!-- Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Password<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<div x-data="{ showPassword: false }" class="relative">
|
||||
<input :type="showPassword ? 'text' : 'password'"
|
||||
name="password"
|
||||
placeholder="Enter your password"
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent py-2.5 pr-11 pl-4 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
<span @click="showPassword = !showPassword"
|
||||
class="absolute top-1/2 right-4 z-30 -translate-y-1/2 cursor-pointer text-gray-500 dark:text-gray-400">
|
||||
<svg x-show="!showPassword" class="fill-current" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0002 13.8619C7.23361 13.8619 4.86803 12.1372 3.92328 9.70241C4.86804 7.26761 7.23361 5.54297 10.0002 5.54297C12.7667 5.54297 15.1323 7.26762 16.0771 9.70243C15.1323 12.1372 12.7667 13.8619 10.0002 13.8619ZM10.0002 4.04297C6.48191 4.04297 3.49489 6.30917 2.4155 9.4593C2.3615 9.61687 2.3615 9.78794 2.41549 9.94552C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C13.5184 15.3619 16.5055 13.0957 17.5849 9.94555C17.6389 9.78797 17.6389 9.6169 17.5849 9.45932C16.5055 6.30919 13.5184 4.04297 10.0002 4.04297ZM9.99151 7.84413C8.96527 7.84413 8.13333 8.67606 8.13333 9.70231C8.13333 10.7286 8.96527 11.5605 9.99151 11.5605H10.0064C11.0326 11.5605 11.8646 10.7286 11.8646 9.70231C11.8646 8.67606 11.0326 7.84413 10.0064 7.84413H9.99151Z" fill="#98A2B3" />
|
||||
</svg>
|
||||
<svg x-show="showPassword" class="fill-current" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M4.63803 3.57709C4.34513 3.2842 3.87026 3.2842 3.57737 3.57709C3.28447 3.86999 3.28447 4.34486 3.57737 4.63775L4.85323 5.91362C3.74609 6.84199 2.89363 8.06395 2.4155 9.45936C2.3615 9.61694 2.3615 9.78801 2.41549 9.94558C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C11.255 15.3619 12.4422 15.0737 13.4994 14.5598L15.3625 16.4229C15.6554 16.7158 16.1302 16.7158 16.4231 16.4229C16.716 16.13 16.716 15.6551 16.4231 15.3622L4.63803 3.57709ZM12.3608 13.4212L10.4475 11.5079C10.3061 11.5423 10.1584 11.5606 10.0064 11.5606H9.99151C8.96527 11.5606 8.13333 10.7286 8.13333 9.70237C8.13333 9.5461 8.15262 9.39434 8.18895 9.24933L5.91885 6.97923C5.03505 7.69015 4.34057 8.62704 3.92328 9.70247C4.86803 12.1373 7.23361 13.8619 10.0002 13.8619C10.8326 13.8619 11.6287 13.7058 12.3608 13.4212ZM16.0771 9.70249C15.7843 10.4569 15.3552 11.1432 14.8199 11.7311L15.8813 12.7925C16.6329 11.9813 17.2187 11.0143 17.5849 9.94561C17.6389 9.78803 17.6389 9.61696 17.5849 9.45938C16.5055 6.30925 13.5184 4.04303 10.0002 4.04303C9.13525 4.04303 8.30244 4.17999 7.52218 4.43338L8.75139 5.66259C9.1556 5.58413 9.57311 5.54303 10.0002 5.54303C12.7667 5.54303 15.1323 7.26768 16.0771 9.70249Z"
|
||||
fill="#98A2B3" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Checkbox -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div x-data="{ checkboxToggle: false }">
|
||||
<label for="checkboxLabelOne"
|
||||
class="flex cursor-pointer items-center text-sm font-normal text-gray-700 select-none dark:text-gray-400">
|
||||
<div class="relative">
|
||||
<input type="checkbox" id="checkboxLabelOne" name="remember" class="sr-only" @change="checkboxToggle = !checkboxToggle" />
|
||||
<div :class="checkboxToggle ? 'border-brand-500 bg-brand-500' :
|
||||
'bg-transparent border-gray-300 dark:border-gray-700'"
|
||||
class="mr-3 flex h-5 w-5 items-center justify-center rounded-md border-[1.25px]">
|
||||
<span :class="checkboxToggle ? '' : 'opacity-0'">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.6666 3.5L5.24992 9.91667L2.33325 7" stroke="white" stroke-width="1.94437" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
Keep me logged in
|
||||
</label>
|
||||
</div>
|
||||
<a href="{{ route('password.request') }}" class="text-brand-500 hover:text-brand-600 dark:text-brand-400 text-sm">
|
||||
Forgot password?
|
||||
</a>
|
||||
</div>
|
||||
<!-- Button -->
|
||||
<div>
|
||||
<button type="submit"
|
||||
class="bg-brand-500 shadow-theme-xs hover:bg-brand-600 flex w-full items-center justify-center rounded-lg px-4 py-3 text-sm font-medium text-white transition">
|
||||
Sign In
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-5">
|
||||
<p class="text-center text-sm font-normal text-gray-700 sm:text-start dark:text-gray-400">
|
||||
Don't have an account?
|
||||
<a href="{{ route('signup') }}" class="text-brand-500 hover:text-brand-600 dark:text-brand-400">Sign Up</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-brand-950 relative hidden h-full w-full items-center lg:grid lg:w-1/2 dark:bg-white/5">
|
||||
<div class="z-1 flex items-center justify-center">
|
||||
<!-- ===== Common Grid Shape Start ===== -->
|
||||
<x-common.common-grid-shape/>
|
||||
<div class="flex max-w-xs flex-col items-center">
|
||||
<a href="{{ route('home') }}" class="mb-4 block">
|
||||
<img src="./images/logo/auth-logo.svg" alt="Logo" />
|
||||
</a>
|
||||
<p class="text-center text-gray-400 dark:text-white/60">
|
||||
Free and Open-Source Tailwind CSS Admin Dashboard Template
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toggler -->
|
||||
<div class="fixed right-6 bottom-6 z-50">
|
||||
<button
|
||||
class="bg-brand-500 hover:bg-brand-600 inline-flex size-14 items-center justify-center rounded-full text-white transition-colors"
|
||||
@click.prevent="$store.theme.toggle()">
|
||||
<svg class="hidden fill-current dark:block" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.99998 1.5415C10.4142 1.5415 10.75 1.87729 10.75 2.2915V3.5415C10.75 3.95572 10.4142 4.2915 9.99998 4.2915C9.58577 4.2915 9.24998 3.95572 9.24998 3.5415V2.2915C9.24998 1.87729 9.58577 1.5415 9.99998 1.5415ZM10.0009 6.79327C8.22978 6.79327 6.79402 8.22904 6.79402 10.0001C6.79402 11.7712 8.22978 13.207 10.0009 13.207C11.772 13.207 13.2078 11.7712 13.2078 10.0001C13.2078 8.22904 11.772 6.79327 10.0009 6.79327ZM5.29402 10.0001C5.29402 7.40061 7.40135 5.29327 10.0009 5.29327C12.6004 5.29327 14.7078 7.40061 14.7078 10.0001C14.7078 12.5997 12.6004 14.707 10.0009 14.707C7.40135 14.707 5.29402 12.5997 5.29402 10.0001ZM15.9813 5.08035C16.2742 4.78746 16.2742 4.31258 15.9813 4.01969C15.6884 3.7268 15.2135 3.7268 14.9207 4.01969L14.0368 4.90357C13.7439 5.19647 13.7439 5.67134 14.0368 5.96423C14.3297 6.25713 14.8045 6.25713 15.0974 5.96423L15.9813 5.08035ZM18.4577 10.0001C18.4577 10.4143 18.1219 10.7501 17.7077 10.7501H16.4577C16.0435 10.7501 15.7077 10.4143 15.7077 10.0001C15.7077 9.58592 16.0435 9.25013 16.4577 9.25013H17.7077C18.1219 9.25013 18.4577 9.58592 18.4577 10.0001ZM14.9207 15.9806C15.2135 16.2735 15.6884 16.2735 15.9813 15.9806C16.2742 15.6877 16.2742 15.2128 15.9813 14.9199L15.0974 14.036C14.8045 13.7431 14.3297 13.7431 14.0368 14.036C13.7439 14.3289 13.7439 14.8038 14.0368 15.0967L14.9207 15.9806ZM9.99998 15.7088C10.4142 15.7088 10.75 16.0445 10.75 16.4588V17.7088C10.75 18.123 10.4142 18.4588 9.99998 18.4588C9.58577 18.4588 9.24998 18.123 9.24998 17.7088V16.4588C9.24998 16.0445 9.58577 15.7088 9.99998 15.7088ZM5.96356 15.0972C6.25646 14.8043 6.25646 14.3295 5.96356 14.0366C5.67067 13.7437 5.1958 13.7437 4.9029 14.0366L4.01902 14.9204C3.72613 15.2133 3.72613 15.6882 4.01902 15.9811C4.31191 16.274 4.78679 16.274 5.07968 15.9811L5.96356 15.0972ZM4.29224 10.0001C4.29224 10.4143 3.95645 10.7501 3.54224 10.7501H2.29224C1.87802 10.7501 1.54224 10.4143 1.54224 10.0001C1.54224 9.58592 1.87802 9.25013 2.29224 9.25013H3.54224C3.95645 9.25013 4.29224 9.58592 4.29224 10.0001ZM4.9029 5.9637C5.1958 6.25659 5.67067 6.25659 5.96356 5.9637C6.25646 5.6708 6.25646 5.19593 5.96356 4.90303L5.07968 4.01915C4.78679 3.72626 4.31191 3.72626 4.01902 4.01915C3.72613 4.31204 3.72613 4.78692 4.01902 5.07981L4.9029 5.9637Z" fill="" />
|
||||
</svg>
|
||||
<svg class="fill-current dark:hidden" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.4547 11.97L18.1799 12.1611C18.265 11.8383 18.1265 11.4982 17.8401 11.3266C17.5538 11.1551 17.1885 11.1934 16.944 11.4207L17.4547 11.97ZM8.0306 2.5459L8.57989 3.05657C8.80718 2.81209 8.84554 2.44682 8.67398 2.16046C8.50243 1.8741 8.16227 1.73559 7.83948 1.82066L8.0306 2.5459ZM12.9154 13.0035C9.64678 13.0035 6.99707 10.3538 6.99707 7.08524H5.49707C5.49707 11.1823 8.81835 14.5035 12.9154 14.5035V13.0035ZM16.944 11.4207C15.8869 12.4035 14.4721 13.0035 12.9154 13.0035V14.5035C14.8657 14.5035 16.6418 13.7499 17.9654 12.5193L16.944 11.4207ZM16.7295 11.7789C15.9437 14.7607 13.2277 16.9586 10.0003 16.9586V18.4586C13.9257 18.4586 17.2249 15.7853 18.1799 12.1611L16.7295 11.7789ZM10.0003 16.9586C6.15734 16.9586 3.04199 13.8433 3.04199 10.0003H1.54199C1.54199 14.6717 5.32892 18.4586 10.0003 18.4586V16.9586ZM3.04199 10.0003C3.04199 6.77289 5.23988 4.05695 8.22173 3.27114L7.83948 1.82066C4.21532 2.77574 1.54199 6.07486 1.54199 10.0003H3.04199ZM6.99707 7.08524C6.99707 5.52854 7.5971 4.11366 8.57989 3.05657L7.48132 2.03522C6.25073 3.35885 5.49707 5.13487 5.49707 7.08524H6.99707Z" fill="" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
193
resources/views/pages/auth/signup.blade.php
Normal file
193
resources/views/pages/auth/signup.blade.php
Normal file
@@ -0,0 +1,193 @@
|
||||
@extends('layouts.fullscreen-layout')
|
||||
|
||||
@section('content')
|
||||
<div class="relative z-1 bg-white p-6 sm:p-0 dark:bg-gray-900">
|
||||
<div class="flex h-screen w-full flex-col justify-center sm:p-0 lg:flex-row dark:bg-gray-900">
|
||||
<!-- Form -->
|
||||
<div class="flex w-full flex-1 flex-col lg:w-1/2">
|
||||
<div class="mx-auto w-full max-w-md pt-5 sm:py-10">
|
||||
<a href="{{ route('home') }}"
|
||||
class="inline-flex items-center text-sm text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300">
|
||||
<svg class="stroke-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M12.7083 5L7.5 10.2083L12.7083 15.4167" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
Back to dashboard
|
||||
</a>
|
||||
</div>
|
||||
<div class="mx-auto flex w-full max-w-md flex-1 flex-col justify-center">
|
||||
<div class="mb-5 sm:mb-8">
|
||||
<h1 class="text-title-sm sm:text-title-md mb-2 font-semibold text-gray-800 dark:text-white/90">
|
||||
Sign Up
|
||||
</h1>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Enter your email and password to sign up!
|
||||
</p>
|
||||
</div>
|
||||
<!-- Session Error handled globally -->
|
||||
<div>
|
||||
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-5">
|
||||
<button onclick="window.location.href = '{{ route('auth.social', ['provider' => 'google', 'context' => 'signup']) }}'"
|
||||
class="inline-flex items-center justify-center gap-3 rounded-lg bg-gray-100 px-7 py-3 text-sm font-normal text-gray-700 transition-colors hover:bg-gray-200 hover:text-gray-800 dark:bg-white/5 dark:text-white/90 dark:hover:bg-white/10">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.7511 10.1944C18.7511 9.47495 18.6915 8.94995 18.5626 8.40552H10.1797V11.6527H15.1003C15.0011 12.4597 14.4654 13.675 13.2749 14.4916L13.2582 14.6003L15.9087 16.6126L16.0924 16.6305C17.7788 15.1041 18.7511 12.8583 18.7511 10.1944Z" fill="#4285F4" />
|
||||
<path d="M10.1788 18.75C12.5895 18.75 14.6133 17.9722 16.0915 16.6305L13.274 14.4916C12.5201 15.0068 11.5081 15.3666 10.1788 15.3666C7.81773 15.3666 5.81379 13.8402 5.09944 11.7305L4.99473 11.7392L2.23868 13.8295L2.20264 13.9277C3.67087 16.786 6.68674 18.75 10.1788 18.75Z" fill="#34A853" />
|
||||
<path d="M5.10014 11.7305C4.91165 11.186 4.80257 10.6027 4.80257 9.99992C4.80257 9.3971 4.91165 8.81379 5.09022 8.26935L5.08523 8.1534L2.29464 6.02954L2.20333 6.0721C1.5982 7.25823 1.25098 8.5902 1.25098 9.99992C1.25098 11.4096 1.5982 12.7415 2.20333 13.9277L5.10014 11.7305Z" fill="#FBBC05" />
|
||||
<path d="M10.1789 4.63331C11.8554 4.63331 12.9864 5.34303 13.6312 5.93612L16.1511 3.525C14.6035 2.11528 12.5895 1.25 10.1789 1.25C6.68676 1.25 3.67088 3.21387 2.20264 6.07218L5.08953 8.26943C5.81381 6.15972 7.81776 4.63331 10.1789 4.63331Z" fill="#EB4335" />
|
||||
</svg>
|
||||
Sign up with Google
|
||||
</button>
|
||||
<button onclick="window.location.href = '{{ route('auth.social', ['provider' => 'github', 'context' => 'signup']) }}'"
|
||||
class="inline-flex items-center justify-center gap-3 rounded-lg bg-gray-100 px-7 py-3 text-sm font-normal text-gray-700 transition-colors hover:bg-gray-200 hover:text-gray-800 dark:bg-white/5 dark:text-white/90 dark:hover:bg-white/10">
|
||||
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||
|
||||
Sign up with GitHub
|
||||
</button>
|
||||
</div>
|
||||
<div class="relative py-3 sm:py-5">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-200 dark:border-gray-800"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center text-sm">
|
||||
<span class="bg-white p-2 text-gray-400 sm:px-5 sm:py-2 dark:bg-gray-900">Or</span>
|
||||
</div>
|
||||
</div>
|
||||
<form action="{{ route('signup') }}" method="POST">
|
||||
@csrf
|
||||
<div class="space-y-5">
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
<!-- First Name -->
|
||||
<div class="sm:col-span-1">
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
First Name<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<input type="text" id="fname" name="fname" value="{{ old('fname') }}"
|
||||
placeholder="Enter your first name"
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
@error('fname')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
<!-- Last Name -->
|
||||
<div class="sm:col-span-1">
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Last Name <span class="text-gray-400 font-normal">(Optional)</span>
|
||||
</label>
|
||||
<input type="text" id="lname" name="lname" value="{{ old('lname') }}"
|
||||
placeholder="Enter your last name"
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
@error('lname')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<!-- Email -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Email<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<input type="email" id="email" name="email" value="{{ old('email') }}" placeholder="Enter your email"
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2.5 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
@error('email')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
<!-- Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Password<span class="text-error-500">*</span>
|
||||
</label>
|
||||
<div x-data="{ showPassword: false }" class="relative">
|
||||
<input :type="showPassword ? 'text' : 'password'" name="password" placeholder="Enter your password"
|
||||
class="dark:bg-dark-900 shadow-theme-xs focus:border-brand-300 focus:ring-brand-500/10 dark:focus:border-brand-800 h-11 w-full rounded-lg border border-gray-300 bg-transparent py-2.5 pr-11 pl-4 text-sm text-gray-800 placeholder:text-gray-400 focus:ring-3 focus:outline-hidden dark:border-gray-700 dark:bg-gray-900 dark:text-white/90 dark:placeholder:text-white/30" />
|
||||
@error('password')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
<span @click="showPassword = !showPassword"
|
||||
class="absolute top-1/2 right-4 z-30 -translate-y-1/2 cursor-pointer text-gray-500 dark:text-gray-400">
|
||||
<svg x-show="!showPassword" class="fill-current" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0002 13.8619C7.23361 13.8619 4.86803 12.1372 3.92328 9.70241C4.86804 7.26761 7.23361 5.54297 10.0002 5.54297C12.7667 5.54297 15.1323 7.26762 16.0771 9.70243C15.1323 12.1372 12.7667 13.8619 10.0002 13.8619ZM10.0002 4.04297C6.48191 4.04297 3.49489 6.30917 2.4155 9.4593C2.3615 9.61687 2.3615 9.78794 2.41549 9.94552C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C13.5184 15.3619 16.5055 13.0957 17.5849 9.94555C17.6389 9.78797 17.6389 9.6169 17.5849 9.45932C16.5055 6.30919 13.5184 4.04297 10.0002 4.04297ZM9.99151 7.84413C8.96527 7.84413 8.13333 8.67606 8.13333 9.70231C8.13333 10.7286 8.96527 11.5605 9.99151 11.5605H10.0064C11.0326 11.5605 11.8646 10.7286 11.8646 9.70231C11.8646 8.67606 11.0326 7.84413 10.0064 7.84413H9.99151Z" fill="#98A2B3" />
|
||||
</svg>
|
||||
<svg x-show="showPassword" class="fill-current" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.63803 3.57709C4.34513 3.2842 3.87026 3.2842 3.57737 3.57709C3.28447 3.86999 3.28447 4.34486 3.57737 4.63775L4.85323 5.91362C3.74609 6.84199 2.89363 8.06395 2.4155 9.45936C2.3615 9.61694 2.3615 9.78801 2.41549 9.94558C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C11.255 15.3619 12.4422 15.0737 13.4994 14.5598L15.3625 16.4229C15.6554 16.7158 16.1302 16.7158 16.4231 16.4229C16.716 16.13 16.716 15.6551 16.4231 15.3622L4.63803 3.57709ZM12.3608 13.4212L10.4475 11.5079C10.3061 11.5423 10.1584 11.5606 10.0064 11.5606H9.99151C8.96527 11.5606 8.13333 10.7286 8.13333 9.70237C8.13333 9.5461 8.15262 9.39434 8.18895 9.24933L5.91885 6.97923C5.03505 7.69015 4.34057 8.62704 3.92328 9.70247C4.86803 12.1373 7.23361 13.8619 10.0002 13.8619C10.8326 13.8619 11.6287 13.7058 12.3608 13.4212ZM16.0771 9.70249C15.7843 10.4569 15.3552 11.1432 14.8199 11.7311L15.8813 12.7925C16.6329 11.9813 17.2187 11.0143 17.5849 9.94561C17.6389 9.78803 17.6389 9.61696 17.5849 9.45938C16.5055 6.30925 13.5184 4.04303 10.0002 4.04303C9.13525 4.04303 8.30244 4.17999 7.52218 4.43338L8.75139 5.66259C9.1556 5.58413 9.57311 5.54303 10.0002 5.54303C12.7667 5.54303 15.1323 7.26768 16.0771 9.70249Z" fill="#98A2B3" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Checkbox -->
|
||||
<div>
|
||||
<div x-data="{ checkboxToggle: false }">
|
||||
<label for="checkboxLabelOne"
|
||||
class="flex cursor-pointer items-start text-sm font-normal text-gray-700 select-none dark:text-gray-400">
|
||||
<div class="relative">
|
||||
<input type="checkbox" id="checkboxLabelOne" name="terms" class="sr-only" required @change="checkboxToggle = !checkboxToggle" />
|
||||
<div :class="checkboxToggle ? 'border-brand-500 bg-brand-500' :
|
||||
'bg-transparent border-gray-300 dark:border-gray-700'"
|
||||
class="mr-3 flex h-5 w-5 items-center justify-center rounded-md border-[1.25px]">
|
||||
<span :class="checkboxToggle ? '' : 'opacity-0'">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.6666 3.5L5.24992 9.91667L2.33325 7" stroke="white" stroke-width="1.94437" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="inline-block font-normal text-gray-500 dark:text-gray-400">
|
||||
By creating an account means you agree to the
|
||||
<span class="text-gray-800 dark:text-white/90">
|
||||
Terms and Conditions,
|
||||
</span>
|
||||
and our
|
||||
<span class="text-gray-800 dark:text-white">
|
||||
Privacy Policy
|
||||
</span>
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Button -->
|
||||
<div>
|
||||
<button type="submit"
|
||||
class="bg-brand-500 shadow-theme-xs hover:bg-brand-600 flex w-full items-center justify-center rounded-lg px-4 py-3 text-sm font-medium text-white transition">
|
||||
Sign Up
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-5">
|
||||
<p class="text-center text-sm font-normal text-gray-700 sm:text-start dark:text-gray-400">
|
||||
Already have an account?
|
||||
<a href="{{ route('signin') }}" class="text-brand-500 hover:text-brand-600 dark:text-brand-400">Sign In</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-brand-950 relative hidden h-full w-full items-center lg:grid lg:w-1/2 dark:bg-white/5">
|
||||
<div class="z-1 flex items-center justify-center">
|
||||
<!-- ===== Common Grid Shape Start ===== -->
|
||||
<x-common.common-grid-shape />
|
||||
<div class="flex max-w-xs flex-col items-center">
|
||||
<a href="{{ route('home') }}" class="mb-4 block">
|
||||
<img src="./images/logo/auth-logo.svg" alt="Logo" />
|
||||
</a>
|
||||
<p class="text-center text-gray-400 dark:text-white/60">
|
||||
Free and Open-Source Tailwind CSS Admin Dashboard Template
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toggler -->
|
||||
<div class="fixed right-6 bottom-6 z-50">
|
||||
<button
|
||||
class="bg-brand-500 hover:bg-brand-600 inline-flex size-14 items-center justify-center rounded-full text-white transition-colors"
|
||||
@click.prevent="$store.theme.toggle()">
|
||||
<svg class="hidden fill-current dark:block" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99998 1.5415C10.4142 1.5415 10.75 1.87729 10.75 2.2915V3.5415C10.75 3.95572 10.4142 4.2915 9.99998 4.2915C9.58577 4.2915 9.24998 3.95572 9.24998 3.5415V2.2915C9.24998 1.87729 9.58577 1.5415 9.99998 1.5415ZM10.0009 6.79327C8.22978 6.79327 6.79402 8.22904 6.79402 10.0001C6.79402 11.7712 8.22978 13.207 10.0009 13.207C11.772 13.207 13.2078 11.7712 13.2078 10.0001C13.2078 8.22904 11.772 6.79327 10.0009 6.79327ZM5.29402 10.0001C5.29402 7.40061 7.40135 5.29327 10.0009 5.29327C12.6004 5.29327 14.7078 7.40061 14.7078 10.0001C14.7078 12.5997 12.6004 14.707 10.0009 14.707C7.40135 14.707 5.29402 12.5997 5.29402 10.0001ZM15.9813 5.08035C16.2742 4.78746 16.2742 4.31258 15.9813 4.01969C15.6884 3.7268 15.2135 3.7268 14.9207 4.01969L14.0368 4.90357C13.7439 5.19647 13.7439 5.67134 14.0368 5.96423C14.3297 6.25713 14.8045 6.25713 15.0974 5.96423L15.9813 5.08035ZM18.4577 10.0001C18.4577 10.4143 18.1219 10.7501 17.7077 10.7501H16.4577C16.0435 10.7501 15.7077 10.4143 15.7077 10.0001C15.7077 9.58592 16.0435 9.25013 16.4577 9.25013H17.7077C18.1219 9.25013 18.4577 9.58592 18.4577 10.0001ZM14.9207 15.9806C15.2135 16.2735 15.6884 16.2735 15.9813 15.9806C16.2742 15.6877 16.2742 15.2128 15.9813 14.9199L15.0974 14.036C14.8045 13.7431 14.3297 13.7431 14.0368 14.036C13.7439 14.3289 13.7439 14.8038 14.0368 15.0967L14.9207 15.9806ZM9.99998 15.7088C10.4142 15.7088 10.75 16.0445 10.75 16.4588V17.7088C10.75 18.123 10.4142 18.4588 9.99998 18.4588C9.58577 18.4588 9.24998 18.123 9.24998 17.7088V16.4588C9.24998 16.0445 9.58577 15.7088 9.99998 15.7088ZM5.96356 15.0972C6.25646 14.8043 6.25646 14.3295 5.96356 14.0366C5.67067 13.7437 5.1958 13.7437 4.9029 14.0366L4.01902 14.9204C3.72613 15.2133 3.72613 15.6882 4.01902 15.9811C4.31191 16.274 4.78679 16.274 5.07968 15.9811L5.96356 15.0972ZM4.29224 10.0001C4.29224 10.4143 3.95645 10.7501 3.54224 10.7501H2.29224C1.87802 10.7501 1.54224 10.4143 1.54224 10.0001C1.54224 9.58592 1.87802 9.25013 2.29224 9.25013H3.54224C3.95645 9.25013 4.29224 9.58592 4.29224 10.0001ZM4.9029 5.9637C5.1958 6.25659 5.67067 6.25659 5.96356 5.9637C6.25646 5.6708 6.25646 5.19593 5.96356 4.90303L5.07968 4.01915C4.78679 3.72626 4.31191 3.72626 4.01902 4.01915C3.72613 4.31204 3.72613 4.78692 4.01902 5.07981L4.9029 5.9637Z" fill="" />
|
||||
</svg>
|
||||
<svg class="fill-current dark:hidden" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.4547 11.97L18.1799 12.1611C18.265 11.8383 18.1265 11.4982 17.8401 11.3266C17.5538 11.1551 17.1885 11.1934 16.944 11.4207L17.4547 11.97ZM8.0306 2.5459L8.57989 3.05657C8.80718 2.81209 8.84554 2.44682 8.67398 2.16046C8.50243 1.8741 8.16227 1.73559 7.83948 1.82066L8.0306 2.5459ZM12.9154 13.0035C9.64678 13.0035 6.99707 10.3538 6.99707 7.08524H5.49707C5.49707 11.1823 8.81835 14.5035 12.9154 14.5035V13.0035ZM16.944 11.4207C15.8869 12.4035 14.4721 13.0035 12.9154 13.0035V14.5035C14.8657 14.5035 16.6418 13.7499 17.9654 12.5193L16.944 11.4207ZM16.7295 11.7789C15.9437 14.7607 13.2277 16.9586 10.0003 16.9586V18.4586C13.9257 18.4586 17.2249 15.7853 18.1799 12.1611L16.7295 11.7789ZM10.0003 16.9586C6.15734 16.9586 3.04199 13.8433 3.04199 10.0003H1.54199C1.54199 14.6717 5.32892 18.4586 10.0003 18.4586V16.9586ZM3.04199 10.0003C3.04199 6.77289 5.23988 4.05695 8.22173 3.27114L7.83948 1.82066C4.21532 2.77574 1.54199 6.07486 1.54199 10.0003H3.04199ZM6.99707 7.08524C6.99707 5.52854 7.5971 4.11366 8.57989 3.05657L7.48132 2.03522C6.25073 3.35885 5.49707 5.13487 5.49707 7.08524H6.99707Z" fill="" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
66
resources/views/pages/auth/verify-email.blade.php
Normal file
66
resources/views/pages/auth/verify-email.blade.php
Normal file
@@ -0,0 +1,66 @@
|
||||
@extends('layouts.fullscreen-layout')
|
||||
|
||||
@section('content')
|
||||
<div class="relative z-1 bg-white p-6 sm:p-0 dark:bg-gray-900">
|
||||
<div class="relative flex h-screen w-full flex-col justify-center sm:p-0 lg:flex-row dark:bg-gray-900">
|
||||
<div class="flex w-full flex-1 flex-col lg:w-1/2">
|
||||
<div class="w-full h-full flex items-center justify-center p-4 sm:p-12.5 xl:p-17.5 text-center">
|
||||
<div class="max-w-md w-full">
|
||||
<h2 class="mb-9 text-2xl font-bold text-black dark:text-white sm:text-title-xl2">
|
||||
Verify Your Email
|
||||
</h2>
|
||||
|
||||
<div class="mb-6">
|
||||
<span class="inline-block p-4 rounded-full bg-brand-50 text-brand-500 dark:bg-brand-500/10 mb-4">
|
||||
<svg width="60" height="60" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22 6C22 4.9 21.1 4 20 4H4C2.9 4 2 4.9 2 6V18C2 19.1 2.9 20 4 20H20C21.1 20 22 19.1 22 18V6ZM20 6L12 11L4 6H20ZM20 18H4V8L12 13L20 8V18Z" fill="currentColor"/>
|
||||
</svg>
|
||||
</span>
|
||||
<p class="text-gray-700 dark:text-gray-400">
|
||||
Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you?
|
||||
</p>
|
||||
<p class="mt-4 text-sm text-gray-500 dark:text-gray-400">
|
||||
If you didn't receive the email, we will gladly send you another.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if (session('success'))
|
||||
<div class="mb-4 text-sm font-medium text-green-600 dark:text-green-400">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('verification.send') }}">
|
||||
@csrf
|
||||
<button type="submit"
|
||||
class="w-full cursor-pointer rounded-lg border border-brand-500 bg-brand-500 p-4 text-white transition hover:bg-opacity-90 hover:bg-brand-600">
|
||||
Resend Verification Email
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form action="{{ route('logout') }}" method="POST" class="mt-4">
|
||||
@csrf
|
||||
<button type="submit" class="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 underline">
|
||||
Log Out
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-brand-950 relative hidden h-full w-full items-center lg:grid lg:w-1/2 dark:bg-white/5">
|
||||
<div class="z-1 flex items-center justify-center">
|
||||
<x-common.common-grid-shape/>
|
||||
<div class="flex max-w-xs flex-col items-center">
|
||||
<a href="/" class="mb-4 block">
|
||||
<img src="{{ asset('images/logo/auth-logo.svg') }}" alt="Logo" />
|
||||
</a>
|
||||
<p class="text-center text-gray-400 dark:text-white/60">
|
||||
Secure Certificate Management System
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
17
resources/views/pages/blank.blade.php
Normal file
17
resources/views/pages/blank.blade.php
Normal file
@@ -0,0 +1,17 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="Blank Page" />
|
||||
<div class="min-h-screen rounded-2xl border border-gray-200 bg-white px-5 py-7 dark:border-gray-800 dark:bg-white/[0.03] xl:px-10 xl:py-12">
|
||||
<div class="mx-auto w-full max-w-[630px] text-center">
|
||||
<h3 class="mb-4 font-semibold text-gray-800 text-theme-xl dark:text-white/90 sm:text-2xl">
|
||||
Card Title Here
|
||||
</h3>
|
||||
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 sm:text-base">
|
||||
Start putting content on grids or panels, you can also use different combinations of
|
||||
grids.Please check out the dashboard and other pages
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
6
resources/views/pages/calender.blade.php
Normal file
6
resources/views/pages/calender.blade.php
Normal file
@@ -0,0 +1,6 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="Calender" />
|
||||
<x-calender-area />
|
||||
@endsection
|
||||
160
resources/views/pages/certificate/create.blade.php
Normal file
160
resources/views/pages/certificate/create.blade.php
Normal file
@@ -0,0 +1,160 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="Generate SSL Certificate" />
|
||||
|
||||
<div class="max-w-3xl mx-auto mb-6">
|
||||
@if(session('error'))
|
||||
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400 border border-red-100 dark:border-red-900" role="alert">
|
||||
<span class="font-medium">Error!</span> {{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="max-w-3xl mx-auto" x-data="{
|
||||
common_name: '',
|
||||
config_mode: 'default',
|
||||
san: '',
|
||||
isValid() {
|
||||
return this.common_name.length > 3 && this.common_name.includes('.');
|
||||
}
|
||||
}">
|
||||
<x-common.component-card>
|
||||
<x-slot:header>
|
||||
<div class="mb-2">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">Generate SSL Certificate</h3>
|
||||
<p class="mt-1 text-sm text-gray-500 text-balance">Create a new self-signed certificate using your Local CA. This will be signed by your private root authority.</p>
|
||||
</div>
|
||||
</x-slot:header>
|
||||
|
||||
<form action="{{ route('certificate.generate') }}" method="POST" class="space-y-8"
|
||||
x-data="{
|
||||
common_name: '',
|
||||
config_mode: 'default',
|
||||
key_bits: '2048',
|
||||
san: '',
|
||||
isValid() {
|
||||
return this.common_name.length > 3 && this.common_name.includes('.');
|
||||
}
|
||||
}">
|
||||
@csrf
|
||||
|
||||
<!-- Configuration Mode -->
|
||||
<div>
|
||||
<label class="block mb-3 text-sm font-medium text-gray-700 dark:text-gray-300">Configuration Mode</label>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<label class="relative flex p-4 cursor-pointer rounded-xl border transition-all"
|
||||
:class="config_mode === 'default' ? 'border-brand-500 ring-1 ring-brand-500 bg-brand-50/50 dark:bg-brand-900/10 dark:border-brand-400' : 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'">
|
||||
<input type="radio" name="config_mode" value="default" x-model="config_mode" class="sr-only">
|
||||
<div class="flex items-start">
|
||||
<div class="flex items-center justify-center flex-shrink-0 w-5 h-5 mt-0.5 border rounded-full transition-colors"
|
||||
:class="config_mode === 'default' ? 'border-brand-500 bg-brand-500' : 'border-gray-300 dark:border-gray-600'">
|
||||
<div class="w-2 h-2 bg-white rounded-full" x-show="config_mode === 'default'"></div>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">Default Presets</span>
|
||||
<span class="block mt-0.5 text-xs text-gray-500 dark:text-gray-400">Use system defaults for Organization, Locality, and Country settings.</span>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="relative flex p-4 cursor-pointer rounded-xl border transition-all"
|
||||
:class="config_mode === 'manual' ? 'border-brand-500 ring-1 ring-brand-500 bg-brand-50/50 dark:bg-brand-900/10 dark:border-brand-400' : 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'">
|
||||
<input type="radio" name="config_mode" value="manual" x-model="config_mode" class="sr-only">
|
||||
<div class="flex items-start">
|
||||
<div class="flex items-center justify-center flex-shrink-0 w-5 h-5 mt-0.5 border rounded-full transition-colors"
|
||||
:class="config_mode === 'manual' ? 'border-brand-500 bg-brand-500' : 'border-gray-300 dark:border-gray-600'">
|
||||
<div class="w-2 h-2 bg-white rounded-full" x-show="config_mode === 'manual'"></div>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">Manual Configuration</span>
|
||||
<span class="block mt-0.5 text-xs text-gray-500 dark:text-gray-400">Customise all Distinguised Name (DN) attributes manually.</span>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Primary Details -->
|
||||
<div class="grid grid-cols-1 gap-6">
|
||||
<div>
|
||||
<label class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">Common Name (Domain) <span class="text-error-500">*</span></label>
|
||||
<input type="text" name="common_name" x-model="common_name" placeholder="e.g. example.com or e.g. 127.0.0.1" required
|
||||
class="w-full px-4 py-2.5 text-sm border border-gray-200 rounded-lg focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white transition-colors"
|
||||
:class="common_name && !isValid() ? 'border-error-500 focus:ring-error-500/20 focus:border-error-500' : ''">
|
||||
<p x-show="common_name && !isValid()" class="mt-1.5 text-xs text-error-500 animate-pulse">Please enter a valid domain name containing at least one dot.</p>
|
||||
<p class="mt-1.5 text-xs text-gray-500">The primary Fully Qualified Domain Name (FQDN) or IP Address to be secured.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">Subject Alternative Names (SAN)</label>
|
||||
<input type="text" name="san" x-model="san" placeholder="e.g. api.local, 192.168.1.50"
|
||||
class="w-full px-4 py-2.5 text-sm border border-gray-200 rounded-lg focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white transition-colors">
|
||||
<p class="mt-1.5 text-xs text-gray-500">Optional comma-separated list of additional domains or IPs.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manual Mode Fields -->
|
||||
<div x-show="config_mode === 'manual'" 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"
|
||||
class="p-5 border border-gray-100 rounded-xl bg-gray-50 dark:bg-gray-800/50 dark:border-gray-700/50">
|
||||
|
||||
<h4 class="mb-4 text-xs font-semibold tracking-wider text-gray-500 uppercase font-lexend">Distinguished Name Attributes</h4>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div>
|
||||
<label class="block mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-300">Organization (O)</label>
|
||||
<input type="text" name="organization" value="{{ $defaults['organizationName'] ?? '' }}"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:ring-brand-500 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-300">Country (C)</label>
|
||||
<input type="text" name="country" value="{{ $defaults['countryName'] ?? 'ID' }}" maxlength="2"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:ring-brand-500 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-300">State / Province (ST)</label>
|
||||
<input type="text" name="state" value="{{ $defaults['stateOrProvinceName'] ?? '' }}"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:ring-brand-500 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-300">Locality (L)</label>
|
||||
<input type="text" name="locality" value="{{ $defaults['localityName'] ?? '' }}"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:ring-brand-500 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Key Size -->
|
||||
<div>
|
||||
<label class="block mb-3 text-sm font-medium text-gray-700 dark:text-gray-300">Private Key Size</label>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<label class="cursor-pointer">
|
||||
<input type="radio" name="key_bits" value="2048" x-model="key_bits" class="peer sr-only">
|
||||
<div class="px-4 py-2 text-sm font-medium text-gray-600 bg-white border border-gray-200 rounded-lg peer-checked:bg-brand-50 peer-checked:text-brand-700 peer-checked:border-brand-500 hover:bg-gray-50 transition-all dark:bg-gray-800 dark:border-gray-700 dark:text-gray-300 dark:peer-checked:bg-brand-900/30 dark:peer-checked:text-brand-300 dark:peer-checked:border-brand-500">
|
||||
2048 Bit (Standard)
|
||||
</div>
|
||||
</label>
|
||||
<label class="cursor-pointer">
|
||||
<input type="radio" name="key_bits" value="4096" x-model="key_bits" class="peer sr-only">
|
||||
<div class="px-4 py-2 text-sm font-medium text-gray-600 bg-white border border-gray-200 rounded-lg peer-checked:bg-brand-50 peer-checked:text-brand-700 peer-checked:border-brand-500 hover:bg-gray-50 transition-all dark:bg-gray-800 dark:border-gray-700 dark:text-gray-300 dark:peer-checked:bg-brand-900/30 dark:peer-checked:text-brand-300 dark:peer-checked:border-brand-500">
|
||||
4096 Bit (High Security)
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex items-center justify-end pt-6 space-x-3 border-t border-gray-100 dark:border-gray-800">
|
||||
<a href="{{ route('certificate.index') }}" class="px-5 py-2.5 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-700 transition shadow-sm">
|
||||
Cancel
|
||||
</a>
|
||||
<button type="submit" :disabled="!isValid()"
|
||||
class="px-6 py-2.5 text-sm font-semibold text-white transition rounded-lg bg-brand-500 hover:bg-brand-600 shadow-theme-xs disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
Generate Certificate
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
@endsection
|
||||
210
resources/views/pages/certificate/index.blade.php
Normal file
210
resources/views/pages/certificate/index.blade.php
Normal file
@@ -0,0 +1,210 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div x-data="{ createOpen: {{ $errors->any() ? 'true' : 'false' }} }">
|
||||
<div class="flex flex-col gap-4 mb-6 sm:flex-row sm:items-end sm:justify-between">
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-white/90">
|
||||
Certificate Management
|
||||
</h2>
|
||||
<nav class="mt-1">
|
||||
<ol class="flex items-center gap-1.5 text-sm text-gray-500 dark:text-gray-400">
|
||||
<li>
|
||||
<a href="{{ route('dashboard') }}" class="inline-flex items-center gap-1.5 hover:text-brand-500 transition">
|
||||
Home
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<svg class="stroke-current opacity-60" width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.75 2.5L6.25 5L3.75 7.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</li>
|
||||
<li class="font-medium text-gray-800 dark:text-white/90">Certificate Management</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div>
|
||||
@if($caReady)
|
||||
<button @click="createOpen = true" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white transition rounded-lg bg-brand-500 hover:bg-brand-600 shadow-theme-xs">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path></svg>
|
||||
Generate New SSL
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(!$caReady)
|
||||
<div class="p-6 mb-6 border border-yellow-200 rounded-xl bg-yellow-50 dark:bg-yellow-900/10 dark:border-yellow-900/30">
|
||||
<div class="flex items-start">
|
||||
<div class="p-3 bg-yellow-100 rounded-lg dark:bg-yellow-900/30">
|
||||
<svg class="w-6 h-6 text-yellow-600 dark:text-yellow-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<h4 class="text-lg font-bold text-yellow-800 dark:text-yellow-200">Setup Required</h4>
|
||||
<p class="mt-1 text-sm text-yellow-700 dark:text-yellow-300">Root CA and Intermediate CA have not been initialized in the database yet.</p>
|
||||
|
||||
@if(Auth::user()->isAdmin())
|
||||
<form action="{{ route('admin.setup-ca') }}" method="POST" class="mt-4">
|
||||
@csrf
|
||||
<button type="submit" class="inline-flex items-center px-6 py-2.5 text-sm font-semibold text-white transition rounded-lg bg-yellow-600 hover:bg-yellow-700 shadow-theme-xs">
|
||||
Run CA Setup Now
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<div class="mt-4 p-3 bg-yellow-200/50 rounded text-sm text-yellow-800 dark:bg-yellow-900/50 dark:text-yellow-200">
|
||||
<strong>Action Required:</strong> Please contact your administrator to initialize the Root CA.
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="space-y-6" x-data="{
|
||||
search: '{{ $search }}',
|
||||
perPage: '{{ $perPage }}',
|
||||
loading: false,
|
||||
updateTable(url = null) {
|
||||
this.loading = true;
|
||||
let baseUrl = url || '{{ route('certificate.index') }}';
|
||||
let finalUrl = new URL(baseUrl);
|
||||
|
||||
if (!url) {
|
||||
finalUrl.searchParams.set('search', this.search);
|
||||
finalUrl.searchParams.set('per_page', this.perPage);
|
||||
}
|
||||
|
||||
fetch(finalUrl, {
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(html => {
|
||||
let container = document.getElementById('certificate-table-container');
|
||||
container.innerHTML = html;
|
||||
this.loading = false;
|
||||
if (typeof Alpine !== 'undefined') {
|
||||
Alpine.initTree(container);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error fetching content:', err);
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
// View Modal Logic
|
||||
viewOpen: false,
|
||||
viewTitle: '',
|
||||
viewContent: '',
|
||||
viewUrl: '',
|
||||
loading: false,
|
||||
copied: false,
|
||||
|
||||
openViewModal(url, title) {
|
||||
this.viewUrl = url;
|
||||
this.viewTitle = title;
|
||||
this.viewContent = '';
|
||||
this.viewOpen = true;
|
||||
this.loading = true;
|
||||
this.copied = false;
|
||||
|
||||
fetch(url)
|
||||
.then(res => res.text())
|
||||
.then(text => {
|
||||
this.viewContent = text;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error fetching content:', err);
|
||||
this.viewContent = 'Failed to load content.';
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
copyToClipboard() {
|
||||
navigator.clipboard.writeText(this.viewContent).then(() => {
|
||||
this.copied = true;
|
||||
setTimeout(() => this.copied = false, 2000);
|
||||
});
|
||||
}
|
||||
}">
|
||||
<x-common.component-card>
|
||||
<x-slot:header>
|
||||
<h3 class="flex items-center text-base font-medium text-gray-800 dark:text-white/90">
|
||||
<svg class="w-5 h-5 mr-2.5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"></path></svg>
|
||||
SSL Certificates List
|
||||
</h3>
|
||||
</x-slot:header>
|
||||
<!-- DataTables Header Utility -->
|
||||
<div class="flex flex-col gap-4 mb-6 md:flex-row md:items-center md:justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-sm text-gray-500">Show</span>
|
||||
<select x-model="perPage" class="px-3 py-1.5 text-sm border border-gray-200 rounded-lg dark:bg-gray-800 dark:border-gray-700 dark:text-white focus:ring-brand-500">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
<span class="text-sm text-gray-500">entries</span>
|
||||
</div>
|
||||
|
||||
<div class="relative w-full md:w-64">
|
||||
<input type="text" x-model="search" placeholder="Search certificates..."
|
||||
class="w-full pl-10 pr-4 py-2 text-sm border border-gray-200 rounded-lg dark:bg-gray-800 dark:border-gray-700 dark:text-white focus:ring-brand-500 focus:border-brand-500">
|
||||
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
|
||||
<svg x-show="!loading" class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
|
||||
<svg x-show="loading" class="w-4 h-4 text-brand-500 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="certificate-table-container" class="relative">
|
||||
@include('pages.certificate.partials.table')
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
@if($caReady)
|
||||
<x-common.component-card>
|
||||
<x-slot:header>
|
||||
<h3 class="flex items-center text-base font-medium text-gray-800 dark:text-white/90">
|
||||
<svg class="w-5 h-5 mr-2.5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path></svg>
|
||||
Download Root CA Certificates
|
||||
</h3>
|
||||
</x-slot:header>
|
||||
<p class="text-sm text-gray-500 mb-6">These are the authority certificates used to sign your SSLs. Install them on your machine/browser to trust your generated certificates.</p>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<a href="{{ route('certificate.download-ca', 'root') }}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-brand-700 bg-brand-50 rounded-lg hover:bg-brand-100 transition dark:bg-brand-900/20 dark:text-brand-300">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
|
||||
Root CA (.crt)
|
||||
</a>
|
||||
<a href="{{ route('certificate.download-ca', 'int_2048') }}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 rounded-lg hover:bg-gray-200 transition dark:bg-gray-700 dark:text-gray-300">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
|
||||
Int-2048 CA (.crt)
|
||||
</a>
|
||||
<a href="{{ route('certificate.download-ca', 'int_4096') }}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 rounded-lg hover:bg-gray-200 transition dark:bg-gray-700 dark:text-gray-300">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
|
||||
Int-4096 CA (.crt)
|
||||
</a>
|
||||
<a href="{{ route('certificate.download-ca-bundle') }}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-success-700 bg-success-50 rounded-lg hover:bg-success-100 transition dark:bg-success-900/20 dark:text-success-300">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg>
|
||||
CA Bundle (Windows)
|
||||
</a>
|
||||
<a href="{{ route('certificate.download-ca-android') }}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-warning-700 bg-warning-50 rounded-lg hover:bg-warning-100 transition dark:bg-warning-900/20 dark:text-warning-300">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"></path></svg>
|
||||
CA Android (.der)
|
||||
</a>
|
||||
</div>
|
||||
<div class="mt-4 pt-4 border-t border-gray-100 dark:border-gray-700">
|
||||
<a href="{{ route('certificate.download-installer') }}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white transition rounded-lg bg-brand-500 hover:bg-brand-600 shadow-theme-xs">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
|
||||
Download Windows One-Click Installer (.bat)
|
||||
</a>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
@endif
|
||||
|
||||
@include('pages.certificate.partials.view-modal')
|
||||
</div>
|
||||
|
||||
@include('pages.certificate.partials.create-modal')
|
||||
@endsection
|
||||
@@ -0,0 +1,137 @@
|
||||
<x-ui.modal x-model="createOpen" containerClass="max-w-3xl" style="z-index: 100009;">
|
||||
<div class="p-6 sm:p-10">
|
||||
<div class="mb-6 pr-10">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">Generate SSL Certificate</h3>
|
||||
<p class="mt-1 text-sm text-gray-500 text-balance">Create a new self-signed certificate using your Local CA. This will be signed by your private root authority.</p>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('certificate.generate') }}" method="POST" class="space-y-8"
|
||||
x-data="{
|
||||
common_name: '{{ old('common_name') }}',
|
||||
config_mode: '{{ old('config_mode', 'default') }}',
|
||||
key_bits: '2048',
|
||||
san: '{{ old('san') }}',
|
||||
isValid() {
|
||||
return this.common_name.length > 3 && this.common_name.includes('.');
|
||||
}
|
||||
}">
|
||||
@csrf
|
||||
|
||||
<!-- Configuration Mode -->
|
||||
<div>
|
||||
<label class="block mb-3 text-sm font-medium text-gray-700 dark:text-gray-300">Configuration Mode</label>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<label class="relative flex p-4 cursor-pointer rounded-xl border transition-all"
|
||||
:class="config_mode === 'default' ? 'border-brand-500 ring-1 ring-brand-500 bg-brand-50/50 dark:bg-brand-900/10 dark:border-brand-400' : 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'">
|
||||
<input type="radio" name="config_mode" value="default" x-model="config_mode" class="sr-only">
|
||||
<div class="flex items-start">
|
||||
<div class="flex items-center justify-center flex-shrink-0 w-5 h-5 mt-0.5 border rounded-full transition-colors"
|
||||
:class="config_mode === 'default' ? 'border-brand-500 bg-brand-500' : 'border-gray-300 dark:border-gray-600'">
|
||||
<div class="w-2 h-2 bg-white rounded-full" x-show="config_mode === 'default'"></div>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">Default Presets</span>
|
||||
<span class="block mt-0.5 text-xs text-gray-500 dark:text-gray-400">Use system defaults for Organization, Locality, and Country settings.</span>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="relative flex p-4 cursor-pointer rounded-xl border transition-all"
|
||||
:class="config_mode === 'manual' ? 'border-brand-500 ring-1 ring-brand-500 bg-brand-50/50 dark:bg-brand-900/10 dark:border-brand-400' : 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'">
|
||||
<input type="radio" name="config_mode" value="manual" x-model="config_mode" class="sr-only">
|
||||
<div class="flex items-start">
|
||||
<div class="flex items-center justify-center flex-shrink-0 w-5 h-5 mt-0.5 border rounded-full transition-colors"
|
||||
:class="config_mode === 'manual' ? 'border-brand-500 bg-brand-500' : 'border-gray-300 dark:border-gray-600'">
|
||||
<div class="w-2 h-2 bg-white rounded-full" x-show="config_mode === 'manual'"></div>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">Manual Configuration</span>
|
||||
<span class="block mt-0.5 text-xs text-gray-500 dark:text-gray-400">Customise all Distinguised Name (DN) attributes manually.</span>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Primary Details -->
|
||||
<div class="grid grid-cols-1 gap-6">
|
||||
<div>
|
||||
<label class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">Common Name (Domain) <span class="text-error-500">*</span></label>
|
||||
<input type="text" name="common_name" x-model="common_name" placeholder="e.g. example.com or e.g. 127.0.0.1" required
|
||||
class="w-full px-4 py-2.5 text-sm border border-gray-200 rounded-lg focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white transition-colors"
|
||||
:class="common_name && !isValid() ? 'border-error-500 focus:ring-error-500/20 focus:border-error-500' : ''">
|
||||
<p x-show="common_name && !isValid()" class="mt-1.5 text-xs text-error-500 animate-pulse">Please enter a valid domain name containing at least one dot.</p>
|
||||
<p class="mt-1.5 text-xs text-gray-500">The primary Fully Qualified Domain Name (FQDN) or IP Address to be secured.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">Subject Alternative Names (SAN)</label>
|
||||
<input type="text" name="san" x-model="san" placeholder="e.g. api.local, 192.168.1.50"
|
||||
class="w-full px-4 py-2.5 text-sm border border-gray-200 rounded-lg focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white transition-colors">
|
||||
<p class="mt-1.5 text-xs text-gray-500">Optional comma-separated list of additional domains or IPs.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manual Mode Fields -->
|
||||
<div x-show="config_mode === 'manual'" 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"
|
||||
class="p-5 border border-gray-100 rounded-xl bg-gray-50 dark:bg-gray-800/50 dark:border-gray-700/50">
|
||||
|
||||
<h4 class="mb-4 text-xs font-semibold tracking-wider text-gray-500 uppercase font-lexend">Distinguished Name Attributes</h4>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div>
|
||||
<label class="block mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-300">Organization (O)</label>
|
||||
<input type="text" name="organization" value="{{ $defaults['organizationName'] ?? '' }}"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:ring-brand-500 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-300">Country (C)</label>
|
||||
<input type="text" name="country" value="{{ $defaults['countryName'] ?? 'ID' }}" maxlength="2"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:ring-brand-500 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-300">State / Province (ST)</label>
|
||||
<input type="text" name="state" value="{{ $defaults['stateOrProvinceName'] ?? '' }}"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:ring-brand-500 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-300">Locality (L)</label>
|
||||
<input type="text" name="locality" value="{{ $defaults['localityName'] ?? '' }}"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:ring-brand-500 focus:border-brand-500 dark:bg-gray-800 dark:border-gray-700 dark:text-white">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Key Size -->
|
||||
<div>
|
||||
<label class="block mb-3 text-sm font-medium text-gray-700 dark:text-gray-300">Private Key Size</label>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<label class="cursor-pointer">
|
||||
<input type="radio" name="key_bits" value="2048" x-model="key_bits" class="peer sr-only">
|
||||
<div class="px-4 py-2 text-sm font-medium text-gray-600 bg-white border border-gray-200 rounded-lg peer-checked:bg-brand-50 peer-checked:text-brand-700 peer-checked:border-brand-500 hover:bg-gray-50 transition-all dark:bg-gray-800 dark:border-gray-700 dark:text-gray-300 dark:peer-checked:bg-brand-900/30 dark:peer-checked:text-brand-300 dark:peer-checked:border-brand-500">
|
||||
2048 Bit (Standard)
|
||||
</div>
|
||||
</label>
|
||||
<label class="cursor-pointer">
|
||||
<input type="radio" name="key_bits" value="4096" x-model="key_bits" class="peer sr-only">
|
||||
<div class="px-4 py-2 text-sm font-medium text-gray-600 bg-white border border-gray-200 rounded-lg peer-checked:bg-brand-50 peer-checked:text-brand-700 peer-checked:border-brand-500 hover:bg-gray-50 transition-all dark:bg-gray-800 dark:border-gray-700 dark:text-gray-300 dark:peer-checked:bg-brand-900/30 dark:peer-checked:text-brand-300 dark:peer-checked:border-brand-500">
|
||||
4096 Bit (High Security)
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex items-center justify-end gap-3 pt-4 sm:pt-6 border-t border-gray-100 dark:border-gray-800">
|
||||
<button type="button" @click="createOpen = false" class="px-5 py-2.5 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-700 transition shadow-sm">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" :disabled="!isValid()"
|
||||
class="px-6 py-2.5 text-sm font-semibold text-white transition rounded-lg bg-brand-500 hover:bg-brand-600 shadow-theme-xs disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
Generate Certificate
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</x-ui.modal>
|
||||
172
resources/views/pages/certificate/partials/table.blade.php
Normal file
172
resources/views/pages/certificate/partials/table.blade.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<div class="max-w-full overflow-x-auto"
|
||||
x-data="{ anyOpen: false }"
|
||||
:class="anyOpen ? 'pb-32' : 'pb-4'">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<th class="px-5 py-4 text-xs font-bold text-gray-500 uppercase tracking-wider">No</th>
|
||||
<th class="px-5 py-4 text-xs font-bold text-gray-500 uppercase tracking-wider">Common Name (CN)</th>
|
||||
<th class="px-5 py-4 text-xs font-bold text-gray-500 uppercase tracking-wider">Serial Number</th>
|
||||
<th class="px-5 py-4 text-xs font-bold text-gray-500 uppercase tracking-wider hidden lg:table-cell">Alt Names (SAN)</th>
|
||||
<th class="px-5 py-4 text-xs font-bold text-gray-500 uppercase tracking-wider text-center">Status</th>
|
||||
<th class="px-5 py-4 text-xs font-bold text-gray-500 uppercase tracking-wider text-center hidden xl:table-cell">Validity Period</th>
|
||||
<th class="px-5 py-4 text-xs font-bold text-gray-500 uppercase tracking-wider text-center">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100 dark:divide-gray-800">
|
||||
@forelse ($certificates as $cert)
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/50 transition-colors">
|
||||
<td class="px-5 py-4 text-sm text-gray-500">
|
||||
{{ ($certificates->currentPage() - 1) * $certificates->perPage() + $loop->iteration }}
|
||||
</td>
|
||||
<td class="px-5 py-4">
|
||||
<div class="text-sm font-semibold text-gray-800 dark:text-white/90">{{ $cert->common_name }}</div>
|
||||
<div class="text-xs text-gray-400">{{ $cert->organization }}</div>
|
||||
</td>
|
||||
<td class="px-5 py-4 text-xs font-mono text-gray-500 dark:text-gray-400 hidden sm:table-cell">
|
||||
{{ $cert->serial_number ?: '-' }}
|
||||
</td>
|
||||
<td class="px-5 py-4 hidden lg:table-cell">
|
||||
<div class="max-w-xs truncate text-xs text-gray-500 dark:text-gray-400 font-mono" title="{{ $cert->san }}">
|
||||
{{ $cert->san ?: '-' }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-4 text-center">
|
||||
@php
|
||||
$isValid = $cert->valid_to && \Carbon\Carbon::parse($cert->valid_to)->isFuture();
|
||||
$statusClass = $isValid ? 'bg-success-50 text-success-700 dark:bg-success-900/30 dark:text-success-300' : 'bg-error-50 text-error-700 dark:bg-error-900/30 dark:text-error-300';
|
||||
$statusText = $isValid ? 'Valid' : 'Expired';
|
||||
if(!$cert->valid_to) {
|
||||
$statusClass = 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400';
|
||||
$statusText = 'Unknown';
|
||||
}
|
||||
@endphp
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 text-xs font-medium rounded-full {{ $statusClass }}">
|
||||
{{ $statusText }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-5 py-4 text-xs text-gray-500 dark:text-gray-400 text-center whitespace-nowrap hidden xl:table-cell">
|
||||
@if($cert->valid_from && $cert->valid_to)
|
||||
<div>{{ \Carbon\Carbon::parse($cert->valid_from)->format('Y-m-d') }}</div>
|
||||
<div class="text-gray-400">to</div>
|
||||
<div>{{ \Carbon\Carbon::parse($cert->valid_to)->format('Y-m-d') }}</div>
|
||||
@else
|
||||
<span class="text-gray-400">-</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-5 py-4">
|
||||
<div class="flex items-center justify-center gap-1.5">
|
||||
<!-- View Dropdown -->
|
||||
<div x-data="{ open: false }" class="relative" @click.away="open = false; anyOpen = false">
|
||||
<button @click="open = !open; anyOpen = open"
|
||||
class="inline-flex items-center px-2.5 py-1.5 text-xs font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 transition-all active:scale-90 shadow-sm"
|
||||
title="View Details">
|
||||
<svg class="w-3.5 h-3.5 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path></svg>
|
||||
<span class="hidden xl:inline">View</span>
|
||||
</button>
|
||||
<div x-show="open"
|
||||
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"
|
||||
class="absolute left-0 mt-2 w-32 rounded-xl shadow-2xl bg-white dark:bg-gray-800 ring-1 ring-black/5 z-[110] overflow-hidden border border-gray-100 dark:border-gray-700">
|
||||
<button @click.prevent="openViewModal('{{ route('certificate.view', [$cert->uuid, 'cert']) }}', 'Certificate Content'); open = false" class="w-full flex items-center px-4 py-2 text-xs text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition">
|
||||
<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
|
||||
Cert
|
||||
</button>
|
||||
<button @click.prevent="openViewModal('{{ route('certificate.view', [$cert->uuid, 'key']) }}', 'Private Key Content'); open = false" class="w-full flex items-center px-4 py-2 text-xs text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition">
|
||||
<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"></path></svg>
|
||||
Key
|
||||
</button>
|
||||
<button @click.prevent="openViewModal('{{ route('certificate.view', [$cert->uuid, 'csr']) }}', 'CSR Content'); open = false" class="w-full flex items-center px-4 py-2 text-xs text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition">
|
||||
<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"></path></svg>
|
||||
CSR
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Download Dropdown -->
|
||||
<div x-data="{ open: false }" class="relative" @click.away="open = false; anyOpen = false">
|
||||
<button @click="open = !open; anyOpen = open"
|
||||
class="inline-flex items-center px-2.5 py-1.5 text-xs font-medium text-white bg-brand-500 rounded-lg hover:bg-brand-600 transition-all active:scale-90 shadow-md"
|
||||
title="Download Files">
|
||||
<svg class="w-3.5 h-3.5 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a2 2 0 002 2h12a2 2 0 002-2v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
|
||||
<span class="hidden xl:inline">Download</span>
|
||||
</button>
|
||||
<div x-show="open"
|
||||
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"
|
||||
class="absolute left-0 mt-2 w-36 rounded-xl shadow-2xl bg-white dark:bg-gray-800 ring-1 ring-black/5 z-[110] overflow-hidden border border-gray-100 dark:border-gray-700">
|
||||
<a href="{{ route('certificate.download-zip', $cert->uuid) }}" class="flex items-center px-4 py-2 text-xs text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition">
|
||||
<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path></svg>
|
||||
ZIP Bundle
|
||||
</a>
|
||||
<a href="{{ route('certificate.download-p12', $cert->uuid) }}" class="flex items-center px-4 py-2 text-xs text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition">
|
||||
<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path></svg>
|
||||
.p12 File
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Others Dropdown -->
|
||||
<div x-data="{ open: false }" class="relative" @click.away="open = false; anyOpen = false">
|
||||
<button @click="open = !open; anyOpen = open"
|
||||
class="inline-flex items-center px-2.5 py-1.5 text-xs font-medium text-gray-600 bg-gray-100 rounded-lg hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600 transition-all active:scale-90 shadow-sm"
|
||||
title="Other Actions">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z"></path></svg>
|
||||
</button>
|
||||
<div x-show="open"
|
||||
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"
|
||||
class="absolute right-0 mt-2 w-32 rounded-xl shadow-2xl bg-white dark:bg-gray-800 ring-1 ring-black/5 z-[110] overflow-hidden border border-gray-100 dark:border-gray-700">
|
||||
<form action="{{ route('certificate.regenerate', $cert->uuid) }}" method="POST" onsubmit="return confirm('Regenerate this certificate? This will replace the current certificate and key.')">
|
||||
@csrf
|
||||
<button type="submit" class="w-full flex items-center px-4 py-2 text-xs text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition">
|
||||
<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>
|
||||
Regen
|
||||
</button>
|
||||
</form>
|
||||
<form action="{{ route('certificate.delete', $cert->uuid) }}" method="POST" onsubmit="return confirm('Truly delete this certificate?')">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="w-full flex items-center px-4 py-2 text-xs text-error-600 hover:bg-error-50 dark:hover:bg-error-900/20 transition">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg>
|
||||
Delete
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="px-5 py-12 text-center">
|
||||
<div class="flex flex-col items-center">
|
||||
<svg class="w-12 h-12 text-gray-200 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
|
||||
<p class="text-sm text-gray-500 italic">No certificates found matching your criteria.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
|
||||
{{-- Filler rows to maintain professional layout height --}}
|
||||
@php
|
||||
$currentCount = $certificates->count();
|
||||
$fillCount = 5 - ($currentCount ?: 1);
|
||||
@endphp
|
||||
@for($i = 0; $i < $fillCount; $i++)
|
||||
<tr class="border-transparent pointer-events-none select-none">
|
||||
<td class="px-5 py-4" colspan="7"> </td>
|
||||
</tr>
|
||||
@endfor
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if ($certificates->hasPages())
|
||||
<div class="px-5 py-4 border-t border-gray-100 dark:border-gray-800 ajax-pagination">
|
||||
{{ $certificates->links() }}
|
||||
</div>
|
||||
@endif
|
||||
@@ -0,0 +1,42 @@
|
||||
<x-ui.modal x-model="viewOpen" containerClass="w-full max-w-[95vw] sm:w-auto sm:min-w-[500px] sm:max-w-3xl" style="z-index: 100010;">
|
||||
<div class="flex flex-col h-[80vh] sm:h-auto sm:max-h-[85vh]">
|
||||
<!-- Header -->
|
||||
<div class="px-6 py-5 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between bg-white dark:bg-gray-900 sticky top-0 z-10 gap-8">
|
||||
<div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white" x-text="viewTitle">Certificate Content</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">View and copy the raw content below.</p>
|
||||
</div>
|
||||
<!-- Actions -->
|
||||
<div class="flex items-center gap-2">
|
||||
<a :href="viewUrl" target="_blank"
|
||||
class="inline-flex items-center px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-700 dark:hover:bg-gray-700 transition">
|
||||
<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg>
|
||||
Raw View
|
||||
</a>
|
||||
<button @click="copyToClipboard()"
|
||||
class="inline-flex items-center px-4 py-2 text-sm font-medium text-white transition rounded-lg bg-brand-500 hover:bg-brand-600 shadow-theme-xs">
|
||||
<svg x-show="!copied" class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"></path></svg>
|
||||
<svg x-show="copied" class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
||||
<span x-text="copied ? 'Copied!' : 'Copy Content'"></span>
|
||||
</button>
|
||||
<button @click="viewOpen = false" class="ml-2 text-gray-400 hover:text-gray-500 dark:hover:text-gray-300 transition-colors">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="flex-1 overflow-hidden relative bg-gray-50 dark:bg-gray-950">
|
||||
<!-- Loading State -->
|
||||
<div x-show="loading" class="absolute inset-0 flex items-center justify-center bg-white/50 dark:bg-gray-900/50 backdrop-blur-sm z-20">
|
||||
<svg class="w-8 h-8 text-brand-500 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>
|
||||
</div>
|
||||
|
||||
<!-- Editor-like View -->
|
||||
<div class="h-full overflow-auto custom-scrollbar p-0">
|
||||
<pre class="p-6 text-sm font-mono leading-relaxed text-gray-800 dark:text-gray-200 whitespace-pre-wrap break-all select-all font-fira-code" x-text="viewContent"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-ui.modal>
|
||||
22
resources/views/pages/chart/bar-chart.blade.php
Normal file
22
resources/views/pages/chart/bar-chart.blade.php
Normal file
@@ -0,0 +1,22 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="Bar chart" />
|
||||
<div class="space-y-6">
|
||||
<x-common.component-card title="Bar chart 1">
|
||||
<!-- ====== Bar Chart One Start -->
|
||||
<div class="custom-scrollbar max-w-full overflow-x-auto">
|
||||
<div id="chartOne" class="min-w-[1000px]"></div>
|
||||
</div>
|
||||
<!-- ====== Bar Chart One End -->
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Bar chart 2">
|
||||
<!-- ====== Bar Chart Two Start -->
|
||||
<div class="custom-scrollbar max-w-full overflow-x-auto">
|
||||
<div id="chartSix" class="min-w-[1000px]"></div>
|
||||
</div>
|
||||
<!-- ====== Bar Chart Two End -->
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
@endsection
|
||||
30
resources/views/pages/chart/line-chart.blade.php
Normal file
30
resources/views/pages/chart/line-chart.blade.php
Normal file
@@ -0,0 +1,30 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="Line chart" />
|
||||
<div class="space-y-6">
|
||||
<x-common.component-card title="Line chart 1">
|
||||
<!-- ====== Line Chart One Start -->
|
||||
<div class="custom-scrollbar max-w-full overflow-x-auto">
|
||||
<div id="chartThree" class="min-w-[1000px]"></div>
|
||||
</div>
|
||||
<!-- ====== Line Chart One End -->
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Line chart 2">
|
||||
<!-- ====== Line Chart Two Start -->
|
||||
<div class="custom-scrollbar max-w-full overflow-x-auto">
|
||||
<div id="chartEight" class="min-w-[1000px]"></div>
|
||||
</div>
|
||||
<!-- ====== Line Chart Two End -->
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Line chart 3">
|
||||
<!-- ====== Line Chart Three Start -->
|
||||
<div class="custom-scrollbar max-w-full overflow-x-auto">
|
||||
<div id="chartThirteen" class="min-w-[1000px]"></div>
|
||||
</div>
|
||||
<!-- ====== Line Chart Three End -->
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
@endsection
|
||||
209
resources/views/pages/dashboard.blade.php
Normal file
209
resources/views/pages/dashboard.blade.php
Normal file
@@ -0,0 +1,209 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="space-y-6" x-data="{
|
||||
loading: false,
|
||||
latency: '---',
|
||||
async refreshDashboard() {
|
||||
this.loading = true;
|
||||
window.location.reload();
|
||||
},
|
||||
async measureLatency() {
|
||||
const start = performance.now();
|
||||
try {
|
||||
await fetch(window.location.origin + '/ping', { method: 'HEAD', cache: 'no-cache' });
|
||||
const end = performance.now();
|
||||
this.latency = Math.round(end - start) + 'ms';
|
||||
} catch (e) {
|
||||
this.latency = 'Offline';
|
||||
}
|
||||
}
|
||||
}" x-init="measureLatency(); setInterval(() => measureLatency(), 5000)">
|
||||
<!-- Top Header -->
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Dashboard Oversight</h1>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Total control over your security infrastructure and API integrations.</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button @click="refreshDashboard()"
|
||||
class="p-2 text-gray-500 hover:text-brand-500 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 transition-all hover:shadow-sm"
|
||||
title="Refresh Data">
|
||||
<svg :class="loading ? 'animate-spin' : ''" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
</button>
|
||||
<a href="{{ route('api-keys.index') }}" class="px-4 py-2 bg-brand-500 hover:bg-brand-600 text-white text-sm font-medium rounded-lg transition-all shadow-lg shadow-brand-500/20">
|
||||
Manage Keys
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Metric Cards -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- Card 1: Total Certificates -->
|
||||
<div class="bg-white dark:bg-gray-800 p-6 rounded-2xl border border-gray-200 dark:border-gray-700 shadow-sm relative overflow-hidden group">
|
||||
<div class="absolute top-0 right-0 p-4 opacity-10 group-hover:scale-110 transition-transform">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-brand-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-medium text-gray-500 dark:text-gray-400">Total Certificates</span>
|
||||
<span class="text-3xl font-bold text-gray-900 dark:text-white mt-1">{{ $totalCertificates }}</span>
|
||||
<span class="text-xs text-green-500 flex items-center gap-1 mt-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M12.395 6.227a.75.75 0 011.082.022l3.992 4.497a.75.75 0 01-1.104 1.012l-3.469-3.908-4.496 3.992a.75.75 0 01-1.012-1.104l5.007-4.511z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
{{ $activeCertificates }} Active Now
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 2: API Keys -->
|
||||
<div class="bg-white dark:bg-gray-800 p-6 rounded-2xl border border-gray-200 dark:border-gray-700 shadow-sm relative overflow-hidden group">
|
||||
<div class="absolute top-0 right-0 p-4 opacity-10 group-hover:scale-110 transition-transform">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11.536 11 9 13.536 7.464 12 4.929 14.536V17h2.472l4.243-4.243a6 6 0 018.828-5.743zM16.5 13.5V18h6v-4.5h-6z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-medium text-gray-500 dark:text-gray-400">Manageable API Keys</span>
|
||||
<span class="text-3xl font-bold text-gray-900 dark:text-white mt-1">{{ $totalApiKeys }}</span>
|
||||
<span class="text-xs text-blue-500 flex items-center gap-1 mt-2">
|
||||
Latest usage: {{ $recentApiActivity->first()->last_used_at?->diffForHumans() ?? 'None' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 3: Expiring Soon -->
|
||||
<div class="bg-white dark:bg-gray-800 p-6 rounded-2xl border border-gray-200 dark:border-gray-700 shadow-sm relative overflow-hidden group">
|
||||
<div class="absolute top-0 right-0 p-4 opacity-10 group-hover:scale-110 transition-transform">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-orange-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-medium text-gray-500 dark:text-gray-400">Expiring Soon</span>
|
||||
<span class="text-3xl font-bold text-gray-900 dark:text-white mt-1">{{ $expiringSoonCount }}</span>
|
||||
<span class="text-xs text-orange-500 flex items-center gap-1 mt-2">
|
||||
Action required within 14 days
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 4: System Health -->
|
||||
<div class="bg-white dark:bg-gray-800 p-6 rounded-2xl border border-gray-200 dark:border-gray-700 shadow-sm relative overflow-hidden group">
|
||||
<div class="absolute top-0 right-0 p-4 opacity-10 group-hover:scale-110 transition-transform">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-medium text-gray-500 dark:text-gray-400">Node Status</span>
|
||||
<span class="text-3xl font-bold mt-1" :class="latency === 'Offline' ? 'text-red-500' : 'text-green-500'" x-text="latency === 'Offline' ? 'Offline' : 'Operational'">Operational</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400 flex items-center gap-1 mt-2">
|
||||
Latency: <span x-text="latency"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
||||
<!-- Analytics Chart -->
|
||||
<div class="lg:col-span-8 bg-white dark:bg-gray-800 rounded-2xl border border-gray-200 dark:border-gray-700 p-6 flex flex-col">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h3 class="font-bold text-gray-900 dark:text-white">Certificate Issuance Trends</h3>
|
||||
<span class="text-xs font-medium text-gray-400">Last 6 Months</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 flex items-end justify-between gap-2 min-h-[200px] px-2">
|
||||
@foreach($issuanceData as $index => $count)
|
||||
<div class="flex-1 flex flex-col items-center gap-2 group">
|
||||
<div class="relative w-full flex items-end justify-center">
|
||||
@php
|
||||
$max = max($issuanceData) ?: 1;
|
||||
$percentage = ($count / $max) * 100;
|
||||
@endphp
|
||||
<div class="w-full max-w-[40px] bg-brand-500/20 dark:bg-brand-500/10 rounded-t-lg group-hover:bg-brand-500/30 transition-all cursor-pointer relative"
|
||||
style="height: {{ max($percentage, 5) }}%;">
|
||||
<div class="absolute -top-8 left-1/2 -translate-x-1/2 bg-gray-900 dark:bg-gray-700 text-white text-[10px] py-1 px-2 rounded opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
{{ $count }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-[10px] font-bold text-gray-400 uppercase">{{ $months[$index] }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent API Activity -->
|
||||
<div class="lg:col-span-4 bg-white dark:bg-gray-800 rounded-2xl border border-gray-200 dark:border-gray-700 p-6">
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-6">Recent API Activity</h3>
|
||||
<div class="space-y-4">
|
||||
@forelse($recentApiActivity as $activity)
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 dark:bg-gray-900/50 rounded-xl border border-gray-100 dark:border-gray-700">
|
||||
<div class="p-2 bg-blue-100 dark:bg-blue-900/30 rounded-lg text-blue-600 dark:text-blue-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11.536 11 9 13.536 7.464 12 4.929 14.536V17h2.472l4.243-4.243a6 6 0 018.828-5.743zM16.5 13.5V18h6v-4.5h-6z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-semibold text-gray-900 dark:text-white truncate">{{ $activity->name }}</p>
|
||||
<p class="text-[10px] text-gray-500 dark:text-gray-400 mt-0.5">Used {{ $activity->last_used_at->diffForHumans() }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="text-center py-6">
|
||||
<p class="text-sm text-gray-400">No recent activity detected.</p>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Latest Certificates -->
|
||||
<div class="lg:col-span-12 bg-white dark:bg-gray-800 rounded-2xl border border-gray-200 dark:border-gray-700 overflow-hidden">
|
||||
<div class="p-6 border-b border-gray-100 dark:border-gray-700 flex items-center justify-between">
|
||||
<h3 class="font-bold text-gray-900 dark:text-white">Recently Issued Certificates</h3>
|
||||
<a href="#" class="text-xs font-bold text-brand-500 hover:text-brand-600 uppercase tracking-wider">View All</a>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-left">
|
||||
<thead>
|
||||
<tr class="text-[10px] font-bold text-gray-400 uppercase tracking-widest bg-gray-50 dark:bg-gray-900/50">
|
||||
<th class="px-6 py-4">Common Name</th>
|
||||
<th class="px-6 py-4">Organization</th>
|
||||
<th class="px-6 py-4">Issued At</th>
|
||||
<th class="px-6 py-4">Expires</th>
|
||||
<th class="px-6 py-4 text-right">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
||||
@forelse($recentCertificates as $cert)
|
||||
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/30 transition-colors">
|
||||
<td class="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">{{ $cert->common_name }}</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $cert->organization }}</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $cert->created_at->format('M d, Y') }}</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $cert->valid_to->format('M d, Y') }}</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
@if($cert->valid_to > now())
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-[10px] font-bold bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-500 uppercase">Valid</span>
|
||||
@else
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-[10px] font-bold bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-500 uppercase">Expired</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="px-6 py-8 text-center text-sm text-gray-500 dark:text-gray-400">No certificates found.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
33
resources/views/pages/errors/error-404.blade.php
Normal file
33
resources/views/pages/errors/error-404.blade.php
Normal file
@@ -0,0 +1,33 @@
|
||||
@extends('layouts.fullscreen-layout')
|
||||
|
||||
@section('content')
|
||||
@php
|
||||
$currentYear = date('Y');
|
||||
@endphp
|
||||
<div class="relative flex flex-col items-center justify-center min-h-screen p-6 overflow-hidden z-1">
|
||||
{{-- common grid shape --}}
|
||||
<x-common.common-grid-shape />
|
||||
<!-- Centered Content -->
|
||||
<div class="mx-auto w-full max-w-[242px] text-center sm:max-w-[472px]">
|
||||
<h1 class="mb-8 font-bold text-gray-800 text-title-md dark:text-white/90 xl:text-title-2xl">
|
||||
ERROR
|
||||
</h1>
|
||||
|
||||
<img src="/images/error/404.svg" alt="404" class="dark:hidden" />
|
||||
<img src="/images/error/404-dark.svg" alt="404" class="hidden dark:block" />
|
||||
|
||||
<p class="mt-10 mb-6 text-base text-gray-700 dark:text-gray-400 sm:text-lg">
|
||||
We can't seem to find the page you are looking for!
|
||||
</p>
|
||||
|
||||
<a href="/"
|
||||
class="inline-flex items-center justify-center rounded-lg border border-gray-300 bg-white px-5 py-3.5 text-sm font-medium text-gray-700 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">
|
||||
Back to Home Page
|
||||
</a>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<p class="absolute text-sm text-center text-gray-500 -translate-x-1/2 bottom-6 left-1/2 dark:text-gray-400">
|
||||
© {{ $currentYear }} - {{ config('app.name') }}
|
||||
</p>
|
||||
</div>
|
||||
@endsection
|
||||
21
resources/views/pages/form/form-elements.blade.php
Normal file
21
resources/views/pages/form/form-elements.blade.php
Normal file
@@ -0,0 +1,21 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="From Elements" />
|
||||
<div class="grid grid-cols-1 gap-6 xl:grid-cols-2">
|
||||
<div class="space-y-6">
|
||||
<x-form.form-elements.default-inputs />
|
||||
<x-form.form-elements.select-inputs />
|
||||
<x-form.form-elements.text-area-inputs />
|
||||
<x-form.form-elements.input-states />
|
||||
</div>
|
||||
<div class="space-y-6">
|
||||
<x-form.form-elements.input-group />
|
||||
<x-form.form-elements.file-input-example />
|
||||
<x-form.form-elements.checkbox-component />
|
||||
<x-form.form-elements.radio-buttons />
|
||||
<x-form.form-elements.toggle-switch />
|
||||
<x-form.form-elements.dropzone />
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
11
resources/views/pages/profile.blade.php
Normal file
11
resources/views/pages/profile.blade.php
Normal file
@@ -0,0 +1,11 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="User Profile" />
|
||||
<div class="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] lg:p-6">
|
||||
<h3 class="mb-5 text-lg font-semibold text-gray-800 dark:text-white/90 lg:mb-7">Profile</h3>
|
||||
<x-profile.profile-card :user="$user" />
|
||||
<x-profile.personal-info-card :user="$user" />
|
||||
<x-profile.address-card :user="$user" />
|
||||
</div>
|
||||
@endsection
|
||||
517
resources/views/pages/settings.blade.php
Normal file
517
resources/views/pages/settings.blade.php
Normal file
@@ -0,0 +1,517 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="mx-auto max-w-(--breakpoint-2xl) p-4 md:p-6" x-data="{
|
||||
showProfileModal: false,
|
||||
showAvatarModal: false,
|
||||
showPasswordModal: false,
|
||||
showSocialModal: false,
|
||||
showDeleteModal: false,
|
||||
socialProvider: '',
|
||||
socialProviderName: '',
|
||||
socialAction: 'connect',
|
||||
socialForm: null,
|
||||
socialConnectUrl: '',
|
||||
deleteConfirmation: '',
|
||||
activeSection: '#profile',
|
||||
mobileNavOpen: false,
|
||||
init() {
|
||||
// Smooth scrolling behavior and active section tracking
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
this.activeSection = '#' + entry.target.id;
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.3 });
|
||||
|
||||
['profile', 'security', 'social', 'access', 'danger'].forEach(id => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) observer.observe(el);
|
||||
});
|
||||
|
||||
// Check initial hash
|
||||
if (window.location.hash) {
|
||||
this.activeSection = window.location.hash;
|
||||
}
|
||||
},
|
||||
submitPasswordForm() {
|
||||
this.$refs.passwordForm.submit();
|
||||
},
|
||||
confirmSocialDisconnect(providerName, providerSlug, form) {
|
||||
this.socialProviderName = providerName;
|
||||
this.socialProvider = providerSlug;
|
||||
this.socialAction = 'disconnect';
|
||||
this.socialForm = form;
|
||||
this.showSocialModal = true;
|
||||
},
|
||||
confirmSocialConnect(providerName, url) {
|
||||
// Direct redirect without modal for connect
|
||||
window.location.href = url;
|
||||
},
|
||||
submitSocialForm() {
|
||||
if (this.socialAction === 'connect') {
|
||||
window.location.href = this.socialConnectUrl;
|
||||
} else {
|
||||
this.socialForm.submit();
|
||||
}
|
||||
},
|
||||
saveProfile() {
|
||||
this.$refs.profileForm.submit();
|
||||
}
|
||||
}">
|
||||
<style>
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
[id] {
|
||||
scroll-margin-top: 100px;
|
||||
}
|
||||
@media (max-width: 1023px) {
|
||||
[id] {
|
||||
scroll-margin-top: 140px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Breadcrumb -->
|
||||
<div class="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<h2 class="text-2xl font-semibold text-gray-800 dark:text-white/90">
|
||||
Account Settings
|
||||
</h2>
|
||||
|
||||
<nav>
|
||||
<ol class="flex items-center gap-2">
|
||||
<li>
|
||||
<a class="font-medium text-gray-500 hover:text-brand-500 dark:text-gray-400 dark:hover:text-brand-500"
|
||||
href="{{ route('dashboard') }}">
|
||||
Dashboard /
|
||||
</a>
|
||||
</li>
|
||||
<li class="font-medium text-brand-500">Settings</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
||||
<!-- Sidebar-like navigation for settings -->
|
||||
<div class="lg:col-span-1">
|
||||
<div class="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900 sticky top-24 z-10">
|
||||
<div class="p-4 sm:p-6">
|
||||
<!-- Mobile Header -->
|
||||
<div class="lg:hidden flex items-center justify-between mb-2">
|
||||
<span class="text-[10px] font-bold uppercase tracking-widest text-gray-400 dark:text-gray-500">Settings Section</span>
|
||||
<button @click="mobileNavOpen = !mobileNavOpen" class="flex items-center gap-1.5 text-xs font-semibold text-brand-500 hover:text-brand-600 transition-colors">
|
||||
<span x-text="mobileNavOpen ? 'Collapse Menu' : 'Change Section'"></span>
|
||||
<svg class="transition-transform duration-200" :class="mobileNavOpen ? 'rotate-180' : ''" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul class="flex flex-col gap-1 transition-all duration-300">
|
||||
<!-- Profile Information -->
|
||||
<li x-show="activeSection === '#profile' || mobileNavOpen || window.innerWidth >= 1024"
|
||||
x-collapse.duration.300ms>
|
||||
<a href="#profile"
|
||||
@click="if(window.innerWidth < 1024) mobileNavOpen = false"
|
||||
class="flex items-center gap-3 rounded-lg px-4 py-3 text-sm font-medium transition-all duration-200"
|
||||
:class="activeSection === '#profile'
|
||||
? 'bg-brand-50 text-brand-500 dark:bg-brand-500/10 dark:text-brand-500 shadow-sm'
|
||||
: 'text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-white/90'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
|
||||
Profile Information
|
||||
<template x-if="activeSection === '#profile' && !mobileNavOpen && window.innerWidth < 1024">
|
||||
<div class="ml-auto animate-pulse h-1.5 w-1.5 rounded-full bg-brand-500"></div>
|
||||
</template>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Security & Password -->
|
||||
<li x-show="activeSection === '#security' || mobileNavOpen || window.innerWidth >= 1024"
|
||||
x-collapse.duration.300ms>
|
||||
<a href="#security"
|
||||
@click="if(window.innerWidth < 1024) mobileNavOpen = false"
|
||||
class="flex items-center gap-3 rounded-lg px-4 py-3 text-sm font-medium transition-all duration-200"
|
||||
:class="activeSection === '#security'
|
||||
? 'bg-brand-50 text-brand-500 dark:bg-brand-500/10 dark:text-brand-500 shadow-sm'
|
||||
: 'text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-white/90'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
|
||||
Security & Password
|
||||
<template x-if="activeSection === '#security' && !mobileNavOpen && window.innerWidth < 1024">
|
||||
<div class="ml-auto animate-pulse h-1.5 w-1.5 rounded-full bg-brand-500"></div>
|
||||
</template>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Connected Accounts -->
|
||||
<li x-show="activeSection === '#social' || mobileNavOpen || window.innerWidth >= 1024"
|
||||
x-collapse.duration.300ms>
|
||||
<a href="#social"
|
||||
@click="if(window.innerWidth < 1024) mobileNavOpen = false"
|
||||
class="flex items-center gap-3 rounded-lg px-4 py-3 text-sm font-medium transition-all duration-200"
|
||||
:class="activeSection === '#social'
|
||||
? 'bg-brand-50 text-brand-500 dark:bg-brand-500/10 dark:text-brand-500 shadow-sm'
|
||||
: 'text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-white/[0.03] dark:hover:text-white/90'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><polyline points="17 11 19 13 23 9"></polyline></svg>
|
||||
Connected Accounts
|
||||
<template x-if="activeSection === '#social' && !mobileNavOpen && window.innerWidth < 1024">
|
||||
<div class="ml-auto animate-pulse h-1.5 w-1.5 rounded-full bg-brand-500"></div>
|
||||
</template>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Account Access -->
|
||||
<li x-show="activeSection === '#access' || mobileNavOpen || window.innerWidth >= 1024"
|
||||
x-collapse.duration.300ms>
|
||||
<a href="#access"
|
||||
@click="if(window.innerWidth < 1024) mobileNavOpen = false"
|
||||
class="flex items-center gap-3 rounded-lg px-4 py-3 text-sm font-medium transition-all duration-200"
|
||||
:class="activeSection === '#access'
|
||||
? 'bg-brand-50 text-brand-500 dark:bg-brand-500/10 dark:text-brand-500 shadow-sm'
|
||||
: 'text-gray-700 hover:bg-gray-100 dark:text-white/90 dark:hover:bg-white/[0.03]'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
|
||||
Account Access
|
||||
<template x-if="activeSection === '#access' && !mobileNavOpen && window.innerWidth < 1024">
|
||||
<div class="ml-auto animate-pulse h-1.5 w-1.5 rounded-full bg-brand-500"></div>
|
||||
</template>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<div class="my-2 h-px bg-gray-100 dark:bg-gray-800" x-show="mobileNavOpen || window.innerWidth >= 1024"></div>
|
||||
|
||||
<!-- Danger Zone -->
|
||||
<li x-show="activeSection === '#danger' || mobileNavOpen || window.innerWidth >= 1024"
|
||||
x-collapse.duration.300ms>
|
||||
<a href="#danger"
|
||||
@click="if(window.innerWidth < 1024) mobileNavOpen = false"
|
||||
class="flex items-center gap-3 rounded-lg px-4 py-3 text-sm font-medium transition-all duration-200"
|
||||
:class="activeSection === '#danger'
|
||||
? 'bg-error-50 text-error-600 dark:bg-error-500/10 dark:text-error-400 shadow-sm'
|
||||
: 'text-error-500 hover:bg-error-50 dark:hover:bg-error-500/10'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
|
||||
Danger Zone
|
||||
<template x-if="activeSection === '#danger' && !mobileNavOpen && window.innerWidth < 1024">
|
||||
<div class="ml-auto animate-pulse h-1.5 w-1.5 rounded-full bg-error-500"></div>
|
||||
</template>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Area -->
|
||||
<div class="lg:col-span-2 space-y-6">
|
||||
<!-- Status Messages -->
|
||||
<!-- Status Messages handled globally -->
|
||||
|
||||
<!-- Profile Information Card -->
|
||||
<div id="profile" class="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900">
|
||||
<div class="border-b border-gray-200 p-4 sm:px-6 dark:border-gray-800 flex items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
Profile Information
|
||||
</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Update your personal details and avatar.
|
||||
</p>
|
||||
</div>
|
||||
<button @click="showProfileModal = true" class="text-sm font-medium text-brand-500 hover:text-brand-600">
|
||||
Edit Profile
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="p-4 sm:p-6 relative">
|
||||
<div class="flex flex-col sm:flex-row gap-6">
|
||||
<!-- Avatar Section -->
|
||||
<div class="flex flex-col items-center gap-3">
|
||||
<div class="group relative h-24 w-24 overflow-hidden rounded-full border border-gray-200 dark:border-gray-800">
|
||||
<img src="{{ $user->avatar ? asset('storage/' . $user->avatar) : asset('images/user/owner.jpg') }}" alt="user" class="h-full w-full object-cover" />
|
||||
<button @click="showAvatarModal = true" class="absolute inset-0 flex items-center justify-center bg-black/40 opacity-0 transition-opacity group-hover:opacity-100">
|
||||
<svg class="text-white" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.0911 2.78206C14.2125 1.90338 12.7878 1.90338 11.9092 2.78206L4.57524 10.116C4.26682 10.4244 4.0547 10.8158 3.96468 11.2426L3.31231 14.3352C3.25997 14.5833 3.33653 14.841 3.51583 15.0203C3.69512 15.1996 3.95286 15.2761 4.20096 15.2238L7.29355 14.5714C7.72031 14.4814 8.11172 14.2693 8.42013 13.9609L15.7541 6.62695C16.6327 5.74827 16.6327 4.32365 15.7541 3.44497L15.0911 2.78206ZM12.9698 3.84272C13.2627 3.54982 13.7376 3.54982 14.0305 3.84272L14.6934 4.50563C14.9863 4.79852 14.9863 5.2734 14.6934 5.56629L14.044 6.21573L12.3204 4.49215L12.9698 3.84272ZM11.2597 5.55281L5.6359 11.1766C5.53309 11.2794 5.46238 11.4099 5.43238 11.5522L5.01758 13.5185L6.98394 13.1037C7.1262 13.0737 7.25666 13.003 7.35947 12.9002L12.9833 7.27639L11.2597 5.55281Z" fill="currentColor" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<button @click="showAvatarModal = true" class="text-xs font-medium text-gray-500 hover:text-brand-500">Change Photo</button>
|
||||
</div>
|
||||
|
||||
<!-- Info Grid -->
|
||||
<div class="grid grow grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-6">
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">Full Name</p>
|
||||
<p class="text-sm font-medium text-gray-800 dark:text-white/90">{{ $user->name }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">Email Address</p>
|
||||
<p class="text-sm font-medium text-gray-800 dark:text-white/90">
|
||||
{{ $user->email }}
|
||||
@if($user->hasVerifiedEmail())
|
||||
<span class="inline-flex items-center ml-2 px-2 py-0.5 rounded text-xs font-medium bg-green-50 text-green-700 dark:bg-green-500/15 dark:text-green-500">
|
||||
Verified
|
||||
</span>
|
||||
@else
|
||||
<span class="inline-flex items-center ml-2 px-2 py-0.5 rounded text-xs font-medium bg-red-50 text-red-700 dark:bg-red-500/15 dark:text-red-500">
|
||||
Unverified
|
||||
</span>
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">Phone Number</p>
|
||||
<p class="text-sm font-medium text-gray-800 dark:text-white/90">{{ $user->phone ?? 'Not set' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">Bio</p>
|
||||
<p class="text-sm line-clamp-1 font-medium text-gray-800 dark:text-white/90">{{ $user->bio ?? 'Not set' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Change Password Card -->
|
||||
<div id="security" class="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900">
|
||||
<div class="border-b border-gray-200 p-4 sm:px-6 dark:border-gray-800">
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
Change Password
|
||||
</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Update your password to keep your account secure.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-4 sm:p-6">
|
||||
<form x-ref="passwordForm" action="{{ route('settings.password') }}" method="POST" class="space-y-5" @submit.prevent="showPasswordModal = true">
|
||||
@csrf
|
||||
<!-- Old Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Current Password
|
||||
</label>
|
||||
<div x-data="{ show: false }" class="relative">
|
||||
<input :type="show ? 'text' : 'password'" name="current_password" required
|
||||
class="h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2 text-sm text-gray-800 placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-white/[0.03] dark:text-white/90">
|
||||
<button type="button" @click="show = !show" class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
||||
<svg x-show="!show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
||||
<svg x-show="show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>
|
||||
</button>
|
||||
</div>
|
||||
@error('current_password')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- New Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
New Password
|
||||
</label>
|
||||
<div x-data="{ show: false }" class="relative">
|
||||
<input :type="show ? 'text' : 'password'" name="password" required
|
||||
class="h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2 text-sm text-gray-800 placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-white/[0.03] dark:text-white/90">
|
||||
<button type="button" @click="show = !show" class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
||||
<svg x-show="!show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
||||
<svg x-show="show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>
|
||||
</button>
|
||||
</div>
|
||||
@error('password')
|
||||
<p class="mt-1 text-xs text-error-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div>
|
||||
<label class="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400">
|
||||
Confirm New Password
|
||||
</label>
|
||||
<div x-data="{ show: false }" class="relative">
|
||||
<input :type="show ? 'text' : 'password'" name="password_confirmation" required
|
||||
class="h-11 w-full rounded-lg border border-gray-300 bg-transparent px-4 py-2 text-sm text-gray-800 placeholder:text-gray-400 focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-white/[0.03] dark:text-white/90">
|
||||
<button type="button" @click="show = !show" class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
||||
<svg x-show="!show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
||||
<svg x-show="show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end pt-3">
|
||||
<button type="submit"
|
||||
class="rounded-lg bg-brand-500 px-6 py-2.5 text-sm font-medium text-white transition-colors hover:bg-brand-600 focus:outline-hidden focus:ring-2 focus:ring-brand-500/50">
|
||||
Update Password
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Connected Accounts Card -->
|
||||
<div id="social" class="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900">
|
||||
<div class="border-b border-gray-200 p-4 sm:px-6 dark:border-gray-800">
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
Connected Accounts
|
||||
</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Manage your linked social accounts.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-4 sm:p-6 space-y-6">
|
||||
<!-- Google -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex h-11 w-11 items-center justify-center rounded-full border border-gray-200 dark:border-gray-800">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18.7511 10.1944C18.7511 9.47495 18.6915 8.94995 18.5626 8.40552H10.1797V11.6527H15.1003C15.0011 12.4597 14.4654 13.675 13.2749 14.4916L13.2582 14.6003L15.9087 16.6126L16.0924 16.6305C17.7788 15.1041 18.7511 12.8583 18.7511 10.1944Z" fill="#4285F4" /><path d="M10.1788 18.75C12.5895 18.75 14.6133 17.9722 16.0915 16.6305L13.274 14.4916C12.5201 15.0068 11.5081 15.3666 10.1788 15.3666C7.81773 15.3666 5.81379 13.8402 5.09944 11.7305L4.99473 11.7392L2.23868 13.8295L2.20264 13.9277C3.67087 16.786 6.68674 18.75 10.1788 18.75Z" fill="#34A853" /><path d="M5.10014 11.7305C4.91165 11.186 4.80257 10.6027 4.80257 9.99992C4.80257 9.3971 4.91165 8.81379 5.09022 8.26935L5.08523 8.1534L2.29464 6.02954L2.20333 6.0721C1.5982 7.25823 1.25098 8.5902 1.25098 9.99992C1.25098 11.4096 1.5982 12.7415 2.20333 13.9277L5.10014 11.7305Z" fill="#FBBC05" /><path d="M10.1789 4.63331C11.8554 4.63331 12.9864 5.34303 13.6312 5.93612L16.1511 3.525C14.6035 2.11528 12.5895 1.25 10.1789 1.25C6.68676 1.25 3.67088 3.21387 2.20264 6.07218L5.08953 8.26943C5.81381 6.15972 7.81776 4.63331 10.1789 4.63331Z" fill="#EB4335" /></svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-sm font-medium text-gray-800 dark:text-white/90">Google</h4>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ $user->google_id ? 'Connected' : 'Not connected' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@if ($user->google_id)
|
||||
<form action="{{ route('settings.social.disconnect', 'google') }}" method="POST" x-ref="disconnectGoogleForm">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="button" @click="confirmSocialDisconnect('Google', 'google', $refs.disconnectGoogleForm)" class="text-sm font-medium text-error-500 hover:text-error-600">
|
||||
Disconnect
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<a href="{{ route('auth.social', ['provider' => 'google', 'context' => 'connect']) }}" class="text-sm font-medium text-brand-500 hover:text-brand-600">
|
||||
Connect
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- GitHub -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex h-11 w-11 items-center justify-center rounded-full border border-gray-200 dark:border-gray-800 text-gray-700 dark:text-white/90">
|
||||
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-sm font-medium text-gray-800 dark:text-white/90">GitHub</h4>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ $user->github_id ? 'Connected' : 'Not connected' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@if ($user->github_id)
|
||||
<form action="{{ route('settings.social.disconnect', 'github') }}" method="POST" x-ref="disconnectGitHubForm">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="button" @click="confirmSocialDisconnect('GitHub', 'github', $refs.disconnectGitHubForm)" class="text-sm font-medium text-error-500 hover:text-error-600">
|
||||
Disconnect
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<a href="{{ route('auth.social', ['provider' => 'github', 'context' => 'connect']) }}" class="text-sm font-medium text-brand-500 hover:text-brand-600">
|
||||
Connect
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Account Access Card -->
|
||||
<div id="access" class="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900">
|
||||
<div class="border-b border-gray-200 p-4 sm:px-6 dark:border-gray-800">
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
Account Access
|
||||
</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Recent login activity on your account (Max 10 records, last 1 month).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-4 sm:p-6">
|
||||
@forelse($user->loginHistories as $history)
|
||||
<div class="flex items-center justify-between py-3 border-b border-gray-100 dark:border-gray-800 last:border-0">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 dark:bg-white/[0.03] text-gray-700 dark:text-white/90">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
@if($history->provider === 'google')
|
||||
<path d="M18.7511 10.1944C18.7511 9.47495 18.6915 8.94995 18.5626 8.40552H10.1797V11.6527H15.1003C15.0011 12.4597 14.4654 13.675 13.2749 14.4916L13.2582 14.6003L15.9087 16.6126L16.0924 16.6305C17.7788 15.1041 18.7511 12.8583 18.7511 10.1944Z" fill="#4285F4" /><path d="M10.1788 18.75C12.5895 18.75 14.6133 17.9722 16.0915 16.6305L13.274 14.4916C12.5201 15.0068 11.5081 15.3666 10.1788 15.3666C7.81773 15.3666 5.81379 13.8402 5.09944 11.7305L4.99473 11.7392L2.23868 13.8295L2.20264 13.9277C3.67087 16.786 6.68674 18.75 10.1788 18.75Z" fill="#34A853" /><path d="M5.10014 11.7305C4.91165 11.186 4.80257 10.6027 4.80257 9.99992C4.80257 9.3971 4.91165 8.81379 5.09022 8.26935L5.08523 8.1534L2.29464 6.02954L2.20333 6.0721C1.5982 7.25823 1.25098 8.5902 1.25098 9.99992C1.25098 11.4096 1.5982 12.7415 2.20333 13.9277L5.10014 11.7305Z" fill="#FBBC05" /><path d="M10.1789 4.63331C11.8554 4.63331 12.9864 5.34303 13.6312 5.93612L16.1511 3.525C14.6035 2.11528 12.5895 1.25 10.1789 1.25C6.68676 1.25 3.67088 3.21387 2.20264 6.07218L5.08953 8.26943C5.81381 6.15972 7.81776 4.63331 10.1789 4.63331Z" fill="#EB4335" />
|
||||
@elseif($history->provider === 'github')
|
||||
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||
@else
|
||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h4M10 17l5-5-5-5M13.8 12H3"></path>
|
||||
@endif
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<p class="text-sm font-medium text-gray-800 dark:text-white/90">
|
||||
{{ $history->login_at->format('d M Y, H:i') }}
|
||||
</p>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
({{ $history->login_at->diffForHumans() }})
|
||||
</span>
|
||||
</div>
|
||||
@if($history->ip_address)
|
||||
<div class="mt-1 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400">
|
||||
<span class="font-mono bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 rounded text-gray-600 dark:text-gray-300">
|
||||
{{ $history->ip_address }}
|
||||
</span>
|
||||
@if($history->user_agent)
|
||||
<span class="truncate max-w-[200px]" title="{{ $history->user_agent }}">
|
||||
Login on {{ Str::limit($history->user_agent, 40) }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize
|
||||
{{ $history->provider === 'google' ? 'bg-blue-50 text-blue-700 dark:bg-blue-900/20 dark:text-blue-300' :
|
||||
($history->provider === 'github' ? 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300' :
|
||||
'bg-brand-50 text-brand-700 dark:bg-brand-900/20 dark:text-brand-300') }}">
|
||||
{{ ucfirst($history->provider) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-sm text-gray-500 italic py-4 text-center">No login history recorded yet.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Danger Zone Card -->
|
||||
<div id="danger" class="rounded-2xl border border-error-200 bg-white dark:border-error-500/30 dark:bg-gray-900">
|
||||
<div class="border-b border-error-100 p-4 sm:px-6 dark:border-error-500/20">
|
||||
<h3 class="text-lg font-semibold text-error-600 dark:text-error-400">
|
||||
Danger Zone
|
||||
</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Irreversible actions for your account.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-4 sm:p-6">
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h4 class="text-sm font-medium text-gray-800 dark:text-white/90">Delete Account</h4>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
Once you delete your account, there is no going back. Please be certain.
|
||||
</p>
|
||||
</div>
|
||||
<button @click="showDeleteModal = true" class="rounded-lg bg-error-500 px-6 py-2.5 text-sm font-medium text-white transition-colors hover:bg-error-600 focus:outline-hidden focus:ring-2 focus:ring-error-500/50">
|
||||
Delete Account
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modals -->
|
||||
|
||||
<!-- Refactored Modals -->
|
||||
<x-profile.edit-modal :user="$user" show="showProfileModal" />
|
||||
<x-profile.avatar-modal :user="$user" show="showAvatarModal" />
|
||||
<x-settings.password-modal show="showPasswordModal" />
|
||||
<x-settings.social-modal show="showSocialModal" socialProvider="socialProviderName" submitAction="submitSocialForm()" />
|
||||
<x-settings.delete-account-modal show="showDeleteModal" deleteConfirmation="deleteConfirmation" />
|
||||
</div>
|
||||
@endsection
|
||||
59
resources/views/pages/suspended.blade.php
Normal file
59
resources/views/pages/suspended.blade.php
Normal file
@@ -0,0 +1,59 @@
|
||||
@extends('layouts.fullscreen-layout')
|
||||
|
||||
@section('content')
|
||||
<div class="relative z-1 bg-white p-6 sm:p-0 dark:bg-gray-900">
|
||||
<div class="relative flex h-screen w-full flex-col justify-center sm:p-0 lg:flex-row dark:bg-gray-900">
|
||||
<div class="flex w-full flex-1 flex-col lg:w-1/2">
|
||||
<div class="w-full h-full flex items-center justify-center p-4 sm:p-12.5 xl:p-17.5 text-center">
|
||||
<div class="max-w-md w-full">
|
||||
<h2 class="mb-9 text-2xl font-bold text-black dark:text-white sm:text-title-xl2">
|
||||
Account Suspended
|
||||
</h2>
|
||||
|
||||
<div class="mb-4">
|
||||
<span class="inline-block p-4 rounded-full bg-red-50 text-red-500 dark:bg-red-500/10 mb-4">
|
||||
<svg width="60" height="60" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 8V13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.9945 16H12.0035" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
<p class="text-lg font-medium text-black dark:text-white">
|
||||
Your account has been suspended by the administrator.
|
||||
</p>
|
||||
<p class="mt-2 text-gray-500 dark:text-gray-400">
|
||||
You cannot access the dashboard or perform any actions.
|
||||
</p>
|
||||
<p class="mt-4 text-gray-500 dark:text-gray-400">
|
||||
If you believe this is a mistake, please contact support.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('logout') }}" method="POST" class="mt-8">
|
||||
@csrf
|
||||
<button type="submit"
|
||||
class="w-full cursor-pointer rounded-lg border border-brand-500 bg-brand-500 p-4 text-white transition hover:bg-opacity-90 hover:bg-brand-600">
|
||||
Sign Out
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-brand-950 relative hidden h-full w-full items-center lg:grid lg:w-1/2 dark:bg-white/5">
|
||||
<div class="z-1 flex items-center justify-center">
|
||||
<!-- ===== Common Grid Shape Start ===== -->
|
||||
<x-common.common-grid-shape/>
|
||||
<div class="flex max-w-xs flex-col items-center">
|
||||
<a href="/" class="mb-4 block">
|
||||
<img src="{{ asset('images/logo/auth-logo.svg') }}" alt="Logo" />
|
||||
</a>
|
||||
<p class="text-center text-gray-400 dark:text-white/60">
|
||||
Secure Certificate Management System
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
22
resources/views/pages/tables/basic-tables.blade.php
Normal file
22
resources/views/pages/tables/basic-tables.blade.php
Normal file
@@ -0,0 +1,22 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="From Elements" />
|
||||
<div class="space-y-6">
|
||||
<x-common.component-card title="Basic Table 1">
|
||||
<x-tables.basic-tables.basic-tables-one />
|
||||
</x-common.component-card>
|
||||
<x-common.component-card title="Basic Table 2">
|
||||
<x-tables.basic-tables.basic-tables-two />
|
||||
</x-common.component-card>
|
||||
<x-common.component-card title="Basic Table 3">
|
||||
<x-tables.basic-tables.basic-tables-three />
|
||||
</x-common.component-card>
|
||||
<x-common.component-card title="Basic Table 4">
|
||||
<x-tables.basic-tables.basic-tables-four />
|
||||
</x-common.component-card>
|
||||
<x-common.component-card title="Basic Table 5">
|
||||
<x-tables.basic-tables.basic-tables-five />
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
@endsection
|
||||
174
resources/views/pages/ui-elements/alerts.blade.php
Normal file
174
resources/views/pages/ui-elements/alerts.blade.php
Normal file
@@ -0,0 +1,174 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="Alerts" />
|
||||
|
||||
<div class="space-y-5 sm:space-y-6">
|
||||
{{-- Success Alert --}}
|
||||
<x-common.component-card title="Success Alert">
|
||||
<div class="space-y-4">
|
||||
<x-ui.alert
|
||||
variant="success"
|
||||
title="Success Message"
|
||||
message="Be cautious when performing this action."
|
||||
:showLink="true"
|
||||
linkHref="/"
|
||||
linkText="Learn more"
|
||||
/>
|
||||
|
||||
<x-ui.alert
|
||||
variant="success"
|
||||
title="Success Message"
|
||||
message="Be cautious when performing this action."
|
||||
:showLink="false"
|
||||
/>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Warning Alert --}}
|
||||
<x-common.component-card title="Warning Alert">
|
||||
<div class="space-y-4">
|
||||
<x-ui.alert
|
||||
variant="warning"
|
||||
title="Warning Message"
|
||||
message="Be cautious when performing this action."
|
||||
:showLink="true"
|
||||
linkHref="/"
|
||||
linkText="Learn more"
|
||||
/>
|
||||
|
||||
<x-ui.alert
|
||||
variant="warning"
|
||||
title="Warning Message"
|
||||
message="Be cautious when performing this action."
|
||||
:showLink="false"
|
||||
/>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Error Alert --}}
|
||||
<x-common.component-card title="Error Alert">
|
||||
<div class="space-y-4">
|
||||
<x-ui.alert
|
||||
variant="error"
|
||||
title="Error Message"
|
||||
message="Be cautious when performing this action."
|
||||
:showLink="true"
|
||||
linkHref="/"
|
||||
linkText="Learn more"
|
||||
/>
|
||||
|
||||
<x-ui.alert
|
||||
variant="error"
|
||||
title="Error Message"
|
||||
message="Be cautious when performing this action."
|
||||
:showLink="false"
|
||||
/>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Info Alert --}}
|
||||
<x-common.component-card title="Info Alert">
|
||||
<div class="space-y-4">
|
||||
<x-ui.alert
|
||||
variant="info"
|
||||
title="Info Message"
|
||||
message="Be cautious when performing this action."
|
||||
:showLink="true"
|
||||
linkHref="/"
|
||||
linkText="Learn more"
|
||||
/>
|
||||
|
||||
<x-ui.alert
|
||||
variant="info"
|
||||
title="Info Message"
|
||||
message="Be cautious when performing this action."
|
||||
:showLink="false"
|
||||
/>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Additional Examples --}}
|
||||
<x-common.component-card title="Alert Variations">
|
||||
<div class="space-y-4">
|
||||
{{-- With Slot Content --}}
|
||||
<x-ui.alert variant="success" title="Custom Content Alert">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
This alert uses <strong class="text-gray-900 dark:text-white">custom slot content</strong>
|
||||
instead of the message prop.
|
||||
</p>
|
||||
<ul class="mt-2 text-sm text-gray-500 dark:text-gray-400 list-disc list-inside">
|
||||
<li>You can add any HTML content</li>
|
||||
<li>Including lists and formatting</li>
|
||||
<li>Perfect for complex messages</li>
|
||||
</ul>
|
||||
</x-alert>
|
||||
|
||||
{{-- Minimal Alert --}}
|
||||
<x-ui.alert
|
||||
variant="info"
|
||||
title="Quick Info"
|
||||
message="Sometimes you just need a simple message."
|
||||
/>
|
||||
|
||||
{{-- Alert with Long Message --}}
|
||||
<x-ui.alert
|
||||
variant="warning"
|
||||
title="Important Notice"
|
||||
message="This is a longer message that provides more detailed information about the warning. You should read this carefully before proceeding with your action."
|
||||
:showLink="true"
|
||||
linkHref="/docs"
|
||||
linkText="View documentation"
|
||||
/>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Interactive Demo --}}
|
||||
<x-common.component-card title="Real-World Examples">
|
||||
<div class="space-y-4">
|
||||
{{-- Payment Success --}}
|
||||
<x-ui.alert variant="success" title="Payment Successful">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mb-2">
|
||||
Your payment of <strong class="text-gray-900 dark:text-white">$99.00</strong> has been processed successfully.
|
||||
</p>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
<p><strong>Order ID:</strong> #TAILADMIN-0014</p>
|
||||
<p><strong>Transaction ID:</strong> TXN-1234567890</p>
|
||||
</div>
|
||||
<a href="/orders" class="inline-block mt-3 text-sm font-medium text-green-600 dark:text-green-400 underline hover:text-green-700">
|
||||
View Order Details
|
||||
</a>
|
||||
</x-alert>
|
||||
|
||||
{{-- Account Warning --}}
|
||||
<x-ui.alert
|
||||
variant="warning"
|
||||
title="Your trial is ending soon"
|
||||
message="Your 14-day trial will expire in 3 days. Upgrade now to continue using all features."
|
||||
:showLink="true"
|
||||
linkHref="/billing"
|
||||
linkText="Upgrade now"
|
||||
/>
|
||||
|
||||
{{-- Validation Error --}}
|
||||
<x-ui.alert variant="error" title="Form Validation Failed">
|
||||
<ul class="text-sm text-gray-500 dark:text-gray-400 list-disc list-inside space-y-1">
|
||||
<li>Email field is required</li>
|
||||
<li>Password must be at least 8 characters</li>
|
||||
<li>Please accept the terms and conditions</li>
|
||||
</ul>
|
||||
</x-alert>
|
||||
|
||||
{{-- System Info --}}
|
||||
<x-ui.alert
|
||||
variant="info"
|
||||
title="Scheduled Maintenance"
|
||||
message="Our system will undergo maintenance on November 15, 2025 from 2:00 AM to 4:00 AM EST. Some features may be unavailable during this time."
|
||||
:showLink="true"
|
||||
linkHref="/status"
|
||||
linkText="Check status page"
|
||||
/>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
@endsection
|
||||
63
resources/views/pages/ui-elements/avatars.blade.php
Normal file
63
resources/views/pages/ui-elements/avatars.blade.php
Normal file
@@ -0,0 +1,63 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="Avatars" />
|
||||
|
||||
@php
|
||||
$avatarSrc = asset('images/user/user-01.jpg');
|
||||
$sizes = ['xsmall', 'small', 'medium', 'large', 'xlarge', 'xxlarge'];
|
||||
@endphp
|
||||
|
||||
<div class="space-y-5 sm:space-y-6">
|
||||
{{-- Default Avatar --}}
|
||||
<x-common.component-card title="Default Avatar">
|
||||
<div class="flex flex-col items-center justify-center gap-5 sm:flex-row">
|
||||
@foreach($sizes as $size)
|
||||
<x-ui.avatar
|
||||
:src="$avatarSrc"
|
||||
:size="$size"
|
||||
/>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Avatar with Online Indicator --}}
|
||||
<x-common.component-card title="Avatar with online indicator">
|
||||
<div class="flex flex-col items-center justify-center gap-5 sm:flex-row">
|
||||
@foreach($sizes as $size)
|
||||
<x-ui.avatar
|
||||
:src="$avatarSrc"
|
||||
:size="$size"
|
||||
status="online"
|
||||
/>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Avatar with Offline Indicator --}}
|
||||
<x-common.component-card title="Avatar with Offline indicator">
|
||||
<div class="flex flex-col items-center justify-center gap-5 sm:flex-row">
|
||||
@foreach($sizes as $size)
|
||||
<x-ui.avatar
|
||||
:src="$avatarSrc"
|
||||
:size="$size"
|
||||
status="offline"
|
||||
/>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Avatar with Busy Indicator --}}
|
||||
<x-common.component-card title="Avatar with busy indicator">
|
||||
<div class="flex flex-col items-center justify-center gap-5 sm:flex-row">
|
||||
@foreach($sizes as $size)
|
||||
<x-ui.avatar
|
||||
:src="$avatarSrc"
|
||||
:size="$size"
|
||||
status="busy"
|
||||
/>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
@endsection
|
||||
76
resources/views/pages/ui-elements/badges.blade.php
Normal file
76
resources/views/pages/ui-elements/badges.blade.php
Normal file
@@ -0,0 +1,76 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<x-common.page-breadcrumb pageTitle="Badges" />
|
||||
|
||||
@php
|
||||
use Illuminate\Support\HtmlString;
|
||||
$colors = ['primary', 'success', 'error', 'warning', 'info', 'light', 'dark'];
|
||||
|
||||
$plusIcon = new HtmlString('<svg class="fill-current" width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.25012 3C5.25012 2.58579 5.58591 2.25 6.00012 2.25C6.41433 2.25 6.75012 2.58579 6.75012 3V5.25012L9.00034 5.25012C9.41455 5.25012 9.75034 5.58591 9.75034 6.00012C9.75034 6.41433 9.41455 6.75012 9.00034 6.75012H6.75012V9.00034C6.75012 9.41455 6.41433 9.75034 6.00012 9.75034C5.58591 9.75034 5.25012 9.41455 5.25012 9.00034L5.25012 6.75012H3C2.58579 6.75012 2.25 6.41433 2.25 6.00012C2.25 5.58591 2.58579 5.25012 3 5.25012H5.25012V3Z" fill=""></path>
|
||||
</svg>');
|
||||
@endphp
|
||||
|
||||
<div class="space-y-5 sm:space-y-6">
|
||||
<x-common.component-card title="With Light Background">
|
||||
<div class="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
@foreach ($colors as $color)
|
||||
<x-ui.badge :color="$color">
|
||||
{{ $color }}
|
||||
</x-ui.badge>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="With Solid Background">
|
||||
<div class="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
@foreach ($colors as $color)
|
||||
<x-ui.badge :color="$color" variant="solid">
|
||||
{{ $color }}
|
||||
</x-ui.badge>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Light Background with Left Icon">
|
||||
<div class="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
@foreach ($colors as $color)
|
||||
<x-ui.badge :color="$color" :startIcon="$plusIcon">
|
||||
{{ $color }}
|
||||
</x-ui.badge>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Solid Background with Left Icon">
|
||||
<div class="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
@foreach ($colors as $color)
|
||||
<x-ui.badge :color="$color" variant="solid" :startIcon="$plusIcon">
|
||||
{{ $color }}
|
||||
</x-ui.badge>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Light Background with Right Icon">
|
||||
<div class="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
@foreach ($colors as $color)
|
||||
<x-ui.badge :color="$color" :endIcon="$plusIcon">
|
||||
{{ $color }}
|
||||
</x-ui.badge>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Solid Background with Right Icon">
|
||||
<div class="flex flex-wrap gap-4 sm:items-center sm:justify-center">
|
||||
@foreach ($colors as $color)
|
||||
<x-ui.badge :color="$color" variant="solid" :endIcon="$plusIcon">
|
||||
{{ $color }}
|
||||
</x-ui.badge>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
@endsection
|
||||
77
resources/views/pages/ui-elements/buttons.blade.php
Normal file
77
resources/views/pages/ui-elements/buttons.blade.php
Normal file
@@ -0,0 +1,77 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@php
|
||||
use Illuminate\Support\HtmlString;
|
||||
|
||||
// Page title
|
||||
$currentPageTitle = 'Buttons';
|
||||
|
||||
// Define BoxIcon once as an HtmlString (so it won’t get escaped)
|
||||
$BoxIcon = new HtmlString('
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M9.77692 3.24224C9.91768 3.17186 10.0834 3.17186 10.2241 3.24224L15.3713 5.81573L10.3359 8.33331C10.1248 8.43888 9.87626 8.43888 9.66512 8.33331L4.6298 5.81573L9.77692 3.24224ZM3.70264 7.0292V13.4124C3.70264 13.6018 3.80964 13.775 3.97903 13.8597L9.25016 16.4952L9.25016 9.7837C9.16327 9.75296 9.07782 9.71671 8.99432 9.67496L3.70264 7.0292ZM10.7502 16.4955V9.78396C10.8373 9.75316 10.923 9.71683 11.0067 9.67496L16.2984 7.0292V13.4124C16.2984 13.6018 16.1914 13.775 16.022 13.8597L10.7502 16.4955ZM9.41463 17.4831L9.10612 18.1002C9.66916 18.3817 10.3319 18.3817 10.8949 18.1002L16.6928 15.2013C17.3704 14.8625 17.7984 14.17 17.7984 13.4124V6.58831C17.7984 5.83076 17.3704 5.13823 16.6928 4.79945L10.8949 1.90059C10.3319 1.61908 9.66916 1.61907 9.10612 1.90059L9.44152 2.57141L9.10612 1.90059L3.30823 4.79945C2.63065 5.13823 2.20264 5.83076 2.20264 6.58831V13.4124C2.20264 14.17 2.63065 14.8625 3.30823 15.2013L9.10612 18.1002L9.41463 17.4831Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
');
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
{{-- Page Breadcrumb --}}
|
||||
<x-common.page-breadcrumb :pageTitle="$currentPageTitle" />
|
||||
|
||||
<div class="space-y-5 sm:space-y-6">
|
||||
|
||||
{{-- Primary Buttons --}}
|
||||
<x-common.component-card title="Primary Button">
|
||||
<div class="flex items-center gap-5">
|
||||
<x-ui.button size="sm" variant="primary">Button Text</x-ui.button>
|
||||
<x-ui.button size="md" variant="primary">Button Text</x-ui.button>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Primary Button with Left Icon --}}
|
||||
<x-common.component-card title="Primary Button with Left Icon">
|
||||
<div class="flex items-center gap-5">
|
||||
<x-ui.button size="sm" variant="primary" :startIcon="$BoxIcon">Button Text</x-ui.button>
|
||||
<x-ui.button size="md" variant="primary" :startIcon="$BoxIcon">Button Text</x-ui.button>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Primary Button with Right Icon --}}
|
||||
<x-common.component-card title="Primary Button with Right Icon">
|
||||
<div class="flex items-center gap-5">
|
||||
<x-ui.button size="sm" variant="primary" :endIcon="$BoxIcon">Button Text</x-ui.button>
|
||||
<x-ui.button size="md" variant="primary" :endIcon="$BoxIcon">Button Text</x-ui.button>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Outline Buttons --}}
|
||||
<x-common.component-card title="Outline Button">
|
||||
<div class="flex items-center gap-5">
|
||||
<x-ui.button size="sm" variant="outline">Button Text</x-ui.button>
|
||||
<x-ui.button size="md" variant="outline">Button Text</x-ui.button>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Outline Button with Left Icon --}}
|
||||
<x-common.component-card title="Outline Button with Left Icon">
|
||||
<div class="flex items-center gap-5">
|
||||
<x-ui.button size="sm" variant="outline" :startIcon="$BoxIcon">Button Text</x-ui.button>
|
||||
<x-ui.button size="md" variant="outline" :startIcon="$BoxIcon">Button Text</x-ui.button>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
{{-- Outline Button with Right Icon --}}
|
||||
<x-common.component-card title="Outline Button with Right Icon">
|
||||
<div class="flex items-center gap-5">
|
||||
<x-ui.button size="sm" variant="outline" :endIcon="$BoxIcon">Button Text</x-ui.button>
|
||||
<x-ui.button size="md" variant="outline" :endIcon="$BoxIcon">Button Text</x-ui.button>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
62
resources/views/pages/ui-elements/images.blade.php
Normal file
62
resources/views/pages/ui-elements/images.blade.php
Normal file
@@ -0,0 +1,62 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@php
|
||||
$images = [
|
||||
[
|
||||
'src' => asset('images/grid-image/image-04.png'),
|
||||
'alt' => 'Grid image 1',
|
||||
],
|
||||
[
|
||||
'src' => asset('images/grid-image/image-05.png'),
|
||||
'alt' => 'Grid image 2',
|
||||
],
|
||||
[
|
||||
'src' => asset('images/grid-image/image-06.png'),
|
||||
'alt' => 'Grid image 3',
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
{{-- Page Breadcrumb --}}
|
||||
<x-common.page-breadcrumb pageTitle="Images" />
|
||||
|
||||
<div class="space-y-5 sm:space-y-6">
|
||||
|
||||
<x-common.component-card title="Responsive Image">
|
||||
<div class="relative">
|
||||
<div id="pane" class="overflow-hidden">
|
||||
<img src="{{ asset('images/grid-image/image-01.png') }}" alt="Cover"
|
||||
class="w-full border border-gray-200 rounded-xl dark:border-gray-800" />
|
||||
</div>
|
||||
<div id="ghostpane" class="absolute top-0 left-0 duration-300 ease-in-out"></div>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Image in 2 Grid">
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
<div>
|
||||
<img src="{{ asset('images/grid-image/image-02.png') }}" alt="grid"
|
||||
class="w-full border border-gray-200 rounded-xl dark:border-gray-800" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<img src="{{ asset('images/grid-image/image-03.png') }}" alt="grid"
|
||||
class="w-full border border-gray-200 rounded-xl dark:border-gray-800" />
|
||||
</div>
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Image in 3 Grid">
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-3">
|
||||
@foreach ($images as $image)
|
||||
<div>
|
||||
<img src="{{ $image['src'] }}" alt="{{ $image['alt'] }}"
|
||||
class="w-full border border-gray-200 rounded-xl dark:border-gray-800" />
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-common.component-card>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
30
resources/views/pages/ui-elements/videos.blade.php
Normal file
30
resources/views/pages/ui-elements/videos.blade.php
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
{{-- Page Breadcrumb --}}
|
||||
<x-common.page-breadcrumb pageTitle="Videos" />
|
||||
|
||||
<div class="grid grid-cols-1 gap-5 sm:gap-6 xl:grid-cols-2">
|
||||
|
||||
<div class="space-y-5 sm:space-y-6">
|
||||
<x-common.component-card title="Video Ratio 16:9">
|
||||
<x-ui.youtube-embed videoId="dQw4w9WgXcQ" />
|
||||
</x-common.component-card>
|
||||
|
||||
<x-common.component-card title="Video Ratio 4:3">
|
||||
<x-ui.youtube-embed videoId="dQw4w9WgXcQ" aspectRatio="4:3" />
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
|
||||
<div class="space-y-5 sm:space-y-6">
|
||||
<x-common.component-card title="Video Ratio 21:9">
|
||||
<x-ui.youtube-embed videoId="dQw4w9WgXcQ" aspectRatio="21:9" />
|
||||
</x-common.component-card>
|
||||
<x-common.component-card title="Video Ratio 1:1">
|
||||
<x-ui.youtube-embed videoId="dQw4w9WgXcQ" aspectRatio="1:1" />
|
||||
</x-common.component-card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user