feat: add resources and view components
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,268 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>biiproject - Login</title>
|
||||
<link rel="icon" type="image/png"
|
||||
href="{{ asset($app_favicon) }}?v={{ file_exists(public_path($app_favicon ?? '')) ? filemtime(public_path($app_favicon ?? '')) : time() }}">
|
||||
|
||||
{{-- Font --}}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&family=Outfit:wght@600&display=swap"
|
||||
rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" rel="stylesheet">
|
||||
@stack('styles')
|
||||
<link href="{{ asset('assets/css/app.css') }}" rel="stylesheet">
|
||||
<script defer src="{{ asset('assets/js/app.js') }}"></script>
|
||||
<style>
|
||||
:root {
|
||||
--adminuiux-content-font: "Open Sans", sans-serif;
|
||||
--adminuiux-title-font: "Outfit", sans-serif;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.pageloader {
|
||||
background: #262e38 !important;
|
||||
backdrop-filter: blur(0.5px);
|
||||
}
|
||||
|
||||
/* Modern Pill Design System */
|
||||
.swal2-popup.modern-pill-popup {
|
||||
border-radius: 30px !important;
|
||||
font-family: 'Outfit', sans-serif !important;
|
||||
padding: 2rem !important;
|
||||
}
|
||||
|
||||
.swal2-title {
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.swal2-html-container {
|
||||
font-size: 0.95rem !important;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.btn-pill-primary {
|
||||
background-color: #1e1e1e !important;
|
||||
color: white !important;
|
||||
border-radius: 50px !important;
|
||||
padding: 10px 30px !important;
|
||||
font-weight: 600 !important;
|
||||
border: none !important;
|
||||
margin: 0 5px !important;
|
||||
}
|
||||
|
||||
.btn-pill-danger {
|
||||
background-color: #dc3545 !important;
|
||||
color: white !important;
|
||||
border-radius: 50px !important;
|
||||
padding: 10px 30px !important;
|
||||
font-weight: 600 !important;
|
||||
border: none !important;
|
||||
margin: 0 5px !important;
|
||||
}
|
||||
|
||||
.btn-pill-cancel {
|
||||
background-color: white !important;
|
||||
color: #1e1e1e !important;
|
||||
border: 2px solid #1e1e1e !important;
|
||||
border-radius: 50px !important;
|
||||
padding: 8px 28px !important;
|
||||
font-weight: 600 !important;
|
||||
margin: 0 5px !important;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
--bs-btn-color: #fff !important;
|
||||
--bs-btn-bg: #1e1e1e !important;
|
||||
--bs-btn-border-color: #1e1e1e !important;
|
||||
--bs-btn-hover-color: #fff !important;
|
||||
--bs-btn-hover-bg: #000 !important;
|
||||
--bs-btn-hover-border-color: #000 !important;
|
||||
--bs-btn-focus-shadow-rgb: 30, 30, 30 !important;
|
||||
--bs-btn-active-color: #fff !important;
|
||||
--bs-btn-active-bg: #000 !important;
|
||||
--bs-btn-active-border-color: #000 !important;
|
||||
--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125) !important;
|
||||
--bs-btn-disabled-color: #fff !important;
|
||||
--bs-btn-disabled-bg: #1e1e1e !important;
|
||||
--bs-btn-disabled-border-color: #1e1e1e !important;
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: #1e1e1e !important;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
background-color: #1e1e1e !important;
|
||||
}
|
||||
|
||||
.border-primary {
|
||||
border-color: #1e1e1e !important;
|
||||
}
|
||||
|
||||
.btn-outline-primary {
|
||||
--bs-btn-color: #1e1e1e !important;
|
||||
--bs-btn-border-color: #1e1e1e !important;
|
||||
--bs-btn-hover-color: #fff !important;
|
||||
--bs-btn-hover-bg: #1e1e1e !important;
|
||||
--bs-btn-hover-border-color: #1e1e1e !important;
|
||||
--bs-btn-focus-shadow-rgb: 30, 30, 30 !important;
|
||||
--bs-btn-active-color: #fff !important;
|
||||
--bs-btn-active-bg: #1e1e1e !important;
|
||||
--bs-btn-active-border-color: #1e1e1e !important;
|
||||
}
|
||||
|
||||
/* Standardized Modern Pill Buttons */
|
||||
.btn-pill-standard-primary {
|
||||
background-color: #ffffff !important;
|
||||
color: #212529 !important;
|
||||
border: 1px solid #212529 !important;
|
||||
border-radius: 50rem !important;
|
||||
padding: 8px 24px !important;
|
||||
font-weight: 500 !important;
|
||||
font-family: var(--adminuiux-title-font) !important;
|
||||
min-width: 110px !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.btn-pill-standard-primary:hover {
|
||||
background-color: #f8f9fa !important;
|
||||
border-color: #000000 !important;
|
||||
}
|
||||
|
||||
/* Global Zoom */
|
||||
/* html {
|
||||
zoom: 0.8;
|
||||
} */
|
||||
|
||||
/* Global 100% Fade-In Policy - Without Exception */
|
||||
.adminuiux-wrap,
|
||||
.card,
|
||||
.adminuiux-content,
|
||||
.login-box {
|
||||
animation: fadeIn 0.6s ease-out both !important;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body
|
||||
class="main-bg main-bg-opac roundedui adminuiux-header-boxed adminuiux-header-transparent adminuiux-sidebar-fill-white adminuiux-sidebar-boxed theme-black bg-gradient-1 scrollup"
|
||||
data-theme="theme-black">
|
||||
{{-- page loader --}}
|
||||
<div class="pageloader">
|
||||
<div class="container h-100">
|
||||
<div class="row justify-content-center align-items-center text-center h-100">
|
||||
<div class="col-12 mb-auto pt-4"></div>
|
||||
<div class="col-auto">
|
||||
<div class="loader5 mb-2 mx-auto"></div>
|
||||
</div>
|
||||
<div class="col-12 mt-auto pb-4">
|
||||
<p class="text-secondary">Please wait for awesome things...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="adminuiux-wrap z-index-0 position-relative bg-theme-1 ">
|
||||
<figure class="position-absolute top-0 start-0 w-100 h-100 coverimg z-index-0">
|
||||
<img style="-webkit-filter: invert(1);filter: invert(1);"
|
||||
src="{{ asset('assets/img/background-image/bg1.png') }}" alt="">
|
||||
</figure>
|
||||
<main class="adminuiux-content z-index-1 position-relative animate__animated animate__fadeIn">
|
||||
<div class="container-fluid">
|
||||
<div class="row align-items-center justify-content-center mt-auto z-index-1 height-dynamic"
|
||||
style="--h-dynamic: calc(100vh - 60px)">
|
||||
<div class="col login-box {{ $attributes->get('maxWidthClass', 'maxwidth-400') }} text-dark pb-ios">
|
||||
|
||||
{{ $slot }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@stack('modals')
|
||||
|
||||
{{-- page js --}}
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||
<script src="{{ asset('assets/js/mobileux/mobileux-auth.js') }}"></script>
|
||||
<script src="{{ asset('assets/js/password-toggle.js') }}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Global Modern Pill Mixin for Guest Layout
|
||||
window.StandardSwal = Swal.mixin({
|
||||
customClass: {
|
||||
popup: 'modern-pill-popup',
|
||||
confirmButton: 'btn-pill-primary',
|
||||
cancelButton: 'btn-pill-cancel'
|
||||
},
|
||||
buttonsStyling: false,
|
||||
confirmButtonText: 'OK',
|
||||
cancelButtonText: 'Cancel',
|
||||
showClass: { popup: 'animate__animated animate__fadeIn animate__faster' },
|
||||
hideClass: { popup: 'animate__animated animate__fadeOutDown animate__faster' }
|
||||
});
|
||||
</script>
|
||||
@if (session('success'))
|
||||
<script>
|
||||
StandardSwal.fire({
|
||||
icon: 'success',
|
||||
title: 'Success!',
|
||||
text: "{{ session('success') }}",
|
||||
timer: 2500,
|
||||
showConfirmButton: false,
|
||||
timerProgressBar: true
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
@if (session('info'))
|
||||
<script>
|
||||
StandardSwal.fire({
|
||||
icon: 'info',
|
||||
title: 'Information',
|
||||
text: "{{ session('info') }}",
|
||||
timer: 3000,
|
||||
showConfirmButton: false,
|
||||
timerProgressBar: true
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
@if (session('error'))
|
||||
<script>
|
||||
StandardSwal.fire({
|
||||
icon: 'error',
|
||||
title: 'System Notice',
|
||||
text: "{{ session('error') }}",
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
@stack('scripts')
|
||||
|
||||
{{-- Cookie Consent Banner --}}
|
||||
@include('layouts.partials.cookie-banner')
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,384 @@
|
||||
<div class="adminuiux-wrap">
|
||||
{{-- Standard sidebar --}}
|
||||
<div class="adminuiux-sidebar shadow-sm">
|
||||
<div class="adminuiux-sidebar-inner">
|
||||
<ul class="nav flex-column menu-active-line mt-3">
|
||||
|
||||
{{-- INSTANCE MODE --}}
|
||||
<li id="sidebar-mode-container"
|
||||
class="nav-item px-3 mb-2 mt-2 {{ ($instance_mode ?? 'Production') === 'Production' ? 'd-none' : '' }}">
|
||||
@php
|
||||
$modeClass = match ($instance_mode ?? 'Production') {
|
||||
'Demo' => 'bg-info text-dark',
|
||||
'Trial' => 'bg-warning text-dark',
|
||||
default => 'bg-success text-white'
|
||||
};
|
||||
@endphp
|
||||
<div id="sidebar-mode-badge"
|
||||
class="badge {{ $modeClass }} w-100 py-2 rounded-pill fw-bold shadow-sm d-flex align-items-center justify-content-center"
|
||||
style="letter-spacing: 0.5px;">
|
||||
<i class="bi bi-circle-fill me-2" style="font-size: 0.5rem; opacity: 0.8;"></i>
|
||||
<span id="sidebar-mode-text">{{ strtoupper($instance_mode ?? 'Production') }}</span>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
{{-- GROUP: OVERVIEW --}}
|
||||
<li class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-3"
|
||||
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('OVERVIEW') }}</li>
|
||||
|
||||
{{-- DASHBOARD --}}
|
||||
@can('view dashboard')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('dashboard') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('dashboard') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-cpu me-2"></i>
|
||||
<span class="menu-name">Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
{{-- NOTIFICATION CENTER --}}
|
||||
@php
|
||||
$isNotificationEnabled = get_setting('feature_notification_center', true);
|
||||
$canManageSettings = Auth::user()?->can('manage global settings');
|
||||
$canViewNotifications = Auth::user()?->can('view notification center');
|
||||
|
||||
// Show if feature is on OR if user is an admin (who can see it even if disabled)
|
||||
$showNotificationMenu = ($isNotificationEnabled && $canViewNotifications) || $canManageSettings;
|
||||
@endphp
|
||||
|
||||
@if($showNotificationMenu)
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('notification-center.index') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('notification-center*') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-bell me-2"></i>
|
||||
<span class="menu-name">Notification</span>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
{{-- GROUP: ACCESS --}}
|
||||
@canany(['view user directory', 'view access rights', 'view active sessions'])
|
||||
<li class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-4"
|
||||
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('ACCESS') }}</li>
|
||||
|
||||
@php
|
||||
$isUserSecurityActive = request()->routeIs('users*') || request()->routeIs('roles*') || request()->routeIs('session-manager*');
|
||||
@endphp
|
||||
<li class="nav-item">
|
||||
<button type="button"
|
||||
id="btn-user-security-toggle"
|
||||
class="nav-link d-flex align-items-center w-100 border-0 bg-transparent text-start"
|
||||
data-sidebar-toggle="userSecuritySubmenu"
|
||||
aria-expanded="{{ $isUserSecurityActive ? 'true' : 'false' }}">
|
||||
<i class="menu-icon bi bi-person-lock me-2"></i>
|
||||
<span class="menu-name">User & Security</span>
|
||||
<i class="bi bi-chevron-down ms-auto x-small" id="chevron-user-security"></i>
|
||||
</button>
|
||||
<ul class="nav flex-column ps-4 mb-2" id="userSecuritySubmenu"
|
||||
style="{{ $isUserSecurityActive ? '' : 'display:none;' }}overflow:hidden;transition:all 0.2s ease;">
|
||||
@can('view user directory')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('users') }}"
|
||||
class="nav-link py-1 {{ request()->routeIs('users*') ? 'active' : '' }}">
|
||||
<i class="bi bi-circle me-2 small" style="font-size: 0.5rem;"></i>
|
||||
<span class="menu-name small">User Directory</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@can('view access rights')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('roles') }}"
|
||||
class="nav-link py-1 {{ request()->routeIs('roles*') || request()->routeIs('permissions*') ? 'active' : '' }}">
|
||||
<i class="bi bi-circle me-2 small" style="font-size: 0.5rem;"></i>
|
||||
<span class="menu-name small">Access Rights</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@can('view active sessions')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('session-manager') }}"
|
||||
class="nav-link py-1 {{ request()->routeIs('session-manager*') ? 'active' : '' }}">
|
||||
<i class="bi bi-circle me-2 small" style="font-size: 0.5rem;"></i>
|
||||
<span class="menu-name small">Active Sessions</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
</ul>
|
||||
</li>
|
||||
@endcanany
|
||||
|
||||
{{-- GROUP: MONITORING --}}
|
||||
@canany(['view health and logs', 'view action history'])
|
||||
<li class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-4"
|
||||
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('MONITORING') }}</li>
|
||||
|
||||
{{-- MONITORING --}}
|
||||
@can('view health and logs')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('system-monitoring') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('system-monitoring') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-speedometer2 me-2"></i>
|
||||
<span class="menu-name">Health & Logs</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
{{-- ACTION LOGS --}}
|
||||
@can('view action history')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('action-logs') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('action-logs*') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-journal-text me-2"></i>
|
||||
<span class="menu-name">Action History</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
@endcanany
|
||||
|
||||
{{-- GROUP: CONFIGURATION --}}
|
||||
@canany(['view backup and storage', 'view maintenance mode', 'view global settings', 'view mobile settings'])
|
||||
<li class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-4"
|
||||
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('CONFIGURATION') }}</li>
|
||||
|
||||
@can('view backup and storage')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('backup-restore.index') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('backup-restore.*') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-database-check me-2"></i>
|
||||
<span class="menu-name">Backup & Storage</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@can('view maintenance mode')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('maintenance-mode') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('maintenance-mode') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-exclamation-octagon me-2"></i>
|
||||
<span class="menu-name">Maintenance</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@can('view global settings')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('system-config') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('system-config') && !request()->has('anchor') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-sliders me-2"></i>
|
||||
<span class="menu-name">Global Settings</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
|
||||
|
||||
@can('view mobile settings')
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('mobile-settings.index') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('mobile-settings*') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-phone-vibrate me-2"></i>
|
||||
<span class="menu-name">Mobile Settings</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
@endcanany
|
||||
|
||||
{{-- GROUP: DEVELOPER --}}
|
||||
@canany(['view pulse', 'view telescope', 'view api docs'])
|
||||
@php
|
||||
$pulseEnabled = (bool) get_setting('engine_pulse_enabled', true);
|
||||
$telescopeEnabled = (bool) get_setting('engine_telescope_enabled', true);
|
||||
$swaggerEnabled = (bool) get_setting('engine_swagger_enabled', true);
|
||||
$horizonEnabled = (bool) get_setting('engine_horizon_enabled', true);
|
||||
$aiDiagEnabled = Auth::user()?->can('view ai self-healing')
|
||||
? (bool) get_setting('ai_healing_enabled', false)
|
||||
: false;
|
||||
$showDevGroup = $pulseEnabled || $telescopeEnabled || $swaggerEnabled || $horizonEnabled || $aiDiagEnabled;
|
||||
@endphp
|
||||
|
||||
<li id="sidebar-dev-group"
|
||||
class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-4 {{ !$showDevGroup ? 'd-none' : '' }}"
|
||||
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('DEVELOPER') }}</li>
|
||||
|
||||
{{-- 0. AI DIAGNOSTICS --}}
|
||||
@can('view ai self-healing')
|
||||
<li id="menu-ai-diagnostics" class="nav-item {{ !$aiDiagEnabled ? 'd-none' : '' }}"
|
||||
x-data="{ pending: 0 }" x-init="
|
||||
const _fetchAiStats = () => fetch('{{ route('ai-self-healing.stats') }}').then(r=>r.json()).then(d=>{ pending = d.pending||0; }).catch(()=>{});
|
||||
_fetchAiStats();
|
||||
setInterval(_fetchAiStats, 30000);
|
||||
">
|
||||
<a href="{{ route('ai-self-healing.index') }}"
|
||||
class="nav-link d-flex align-items-center {{ request()->routeIs('ai-self-healing.*') ? 'active' : '' }}">
|
||||
<i class="menu-icon bi bi-robot me-2 text-danger"></i>
|
||||
<span class="menu-name">AI Diagnostics</span>
|
||||
<span x-show="pending > 0" x-text="pending > 9 ? '9+' : pending"
|
||||
class="badge bg-warning text-dark ms-auto rounded-pill"
|
||||
style="font-size:.6rem;min-width:18px;padding:2px 5px;" x-cloak></span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
{{-- 1. HORIZON QUEUE MONITOR --}}
|
||||
@can('manage global settings')
|
||||
<li id="menu-horizon" class="nav-item {{ !$horizonEnabled ? 'd-none' : '' }}">
|
||||
<a href="/horizon" target="_blank" class="nav-link d-flex align-items-center">
|
||||
<i class="menu-icon bi bi-speedometer2 me-2 text-primary"></i>
|
||||
<span class="menu-name">Horizon</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
{{-- 2. PULSE MONITORING --}}
|
||||
@can('view pulse')
|
||||
<li id="menu-pulse" class="nav-item {{ !$pulseEnabled ? 'd-none' : '' }}">
|
||||
<a href="/pulse" target="_blank" class="nav-link d-flex align-items-center">
|
||||
<i class="menu-icon bi bi-activity me-2 text-info"></i>
|
||||
<span class="menu-name">Pulse</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
{{-- 3. TELESCOPE DEBUGGER --}}
|
||||
@can('view telescope')
|
||||
<li id="menu-telescope" class="nav-item {{ !$telescopeEnabled ? 'd-none' : '' }}">
|
||||
<a href="/telescope" target="_blank" class="nav-link d-flex align-items-center">
|
||||
<i class="menu-icon bi bi-bug me-2 text-warning"></i>
|
||||
<span class="menu-name">Telescope</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
{{-- 4. API DOCUMENTATION --}}
|
||||
@can('view api docs')
|
||||
<li id="menu-swagger" class="nav-item {{ !$swaggerEnabled ? 'd-none' : '' }}">
|
||||
<a href="/api/documentation" target="_blank" class="nav-link d-flex align-items-center">
|
||||
<i class="menu-icon bi bi-code-square me-2 text-success"></i>
|
||||
<span class="menu-name">API Doc</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
@endcanany
|
||||
|
||||
<hr class="mx-3 opacity-10">
|
||||
|
||||
{{-- LOGOUT --}}
|
||||
<li class="nav-item">
|
||||
<a href="javascript:void(0)" class="nav-link d-flex align-items-center text-danger"
|
||||
onclick="confirmLogout();">
|
||||
<i class="menu-icon bi bi-box-arrow-right me-2"></i>
|
||||
<span class="menu-name">Logout Session</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
|
||||
@csrf
|
||||
</form>
|
||||
|
||||
<script>
|
||||
function confirmLogout() {
|
||||
StandardSwal.fire({
|
||||
title: 'Confirm Logout',
|
||||
text: 'Are you sure you want to log out from your session?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
customClass: {
|
||||
confirmButton: 'btn-pill-danger',
|
||||
cancelButton: 'btn-pill-cancel'
|
||||
},
|
||||
confirmButtonText: 'Yes, Logout',
|
||||
cancelButtonText: 'Cancel',
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
document.getElementById('logout-form').submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
<div class=" mt-auto "></div>
|
||||
|
||||
<div class="container mt-3 mt-lg-4" id="main-content" style="margin-top: 0rem !important;">
|
||||
<div class="row gx-3 align-items-center ms-4">
|
||||
<div class="col mb-3 mb-lg-4">
|
||||
<div class="row gx-2 align-items-center">
|
||||
<div class="col-auto col-md-auto text-center">
|
||||
<a href="{{ route('profile.edit') }}" class="style-none position-relative d-block">
|
||||
<figure class="avatar avatar-50 rounded coverimg align-middle">
|
||||
<img src="{{ asset('assets/img/profile.png') }}" alt="">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h5 class="fw-medium mb-0">Hello,</h5>
|
||||
<h3><span class="text-theme-1">{{ Auth::user()->name ?? 'User' }}</span></h3>
|
||||
</div>
|
||||
<div class="col-auto text-end mb-3 mb-lg-4">
|
||||
<a href="mobileux-wallet-sendmoney.html" class="style-none">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{-- adminuiux-wrap closed in app.blade.php after <main> so that .adminuiux-content sits inside the wrap --}}
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function initSidebarSubmenus() {
|
||||
var buttons = document.querySelectorAll('[data-sidebar-toggle]');
|
||||
buttons.forEach(function (btn) {
|
||||
// Remove any existing listeners to prevent duplicates
|
||||
var newBtn = btn.cloneNode(true);
|
||||
btn.parentNode.replaceChild(newBtn, btn);
|
||||
|
||||
newBtn.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
var targetId = this.getAttribute('data-sidebar-toggle');
|
||||
var submenu = document.getElementById(targetId);
|
||||
var chevron = this.querySelector('.bi-chevron-down');
|
||||
|
||||
if (!submenu) return;
|
||||
|
||||
var isOpen = submenu.style.display !== 'none';
|
||||
|
||||
if (isOpen) {
|
||||
submenu.style.display = 'none';
|
||||
this.setAttribute('aria-expanded', 'false');
|
||||
if (chevron) chevron.style.transform = 'rotate(0deg)';
|
||||
} else {
|
||||
submenu.style.display = 'block';
|
||||
this.setAttribute('aria-expanded', 'true');
|
||||
if (chevron) chevron.style.transform = 'rotate(180deg)';
|
||||
}
|
||||
});
|
||||
|
||||
// Set initial chevron state based on current aria-expanded
|
||||
var chevron = newBtn.querySelector('.bi-chevron-down');
|
||||
if (chevron) {
|
||||
var expanded = newBtn.getAttribute('aria-expanded') === 'true';
|
||||
chevron.style.transform = expanded ? 'rotate(180deg)' : 'rotate(0deg)';
|
||||
chevron.style.transition = 'transform 0.2s ease';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initSidebarSubmenus);
|
||||
} else {
|
||||
initSidebarSubmenus();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,101 @@
|
||||
@if(get_setting('feature_cookie_banner', true))
|
||||
<div id="cookie_consent_banner" class="cookie-banner-wrapper d-none animate__animated animate__fadeIn">
|
||||
<div class="cookie-banner-card card adminuiux-card p-4 shadow-lg border-0">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-12 col-md-auto mb-3 mb-md-0">
|
||||
<div class="avatar avatar-50 rounded-circle bg-warning-subtle text-warning">
|
||||
<i class="bi bi-cookie fs-3"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md">
|
||||
<h6 class="fw-bold mb-1">{{ __('We use cookies') }}</h6>
|
||||
<p class="small text-muted mb-0">
|
||||
{{ __('We use cookies to enhance your experience and analyze our traffic. By clicking "Accept", you consent to our use of cookies as described in our') }}
|
||||
<a href="{{ route('legal.show', 'privacy') }}" class="text-primary fw-bold text-decoration-none">{{ __('Privacy Policy') }}</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-12 col-md-auto mt-3 mt-md-0">
|
||||
<div class="btn-group gap-2">
|
||||
<button type="button" onclick="acceptCookies()" class="btn btn-pill-primary px-4">{{ __('Accept') }}</button>
|
||||
<button type="button" onclick="dismissCookieBanner()" class="btn btn-pill-cancel px-3">{{ __('Dismiss') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.cookie-banner-wrapper {
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
left: 40px;
|
||||
right: 40px;
|
||||
z-index: 9999;
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cookie-banner-card {
|
||||
border-radius: 30px !important;
|
||||
background: rgba(255, 255, 255, 0.8) !important;
|
||||
backdrop-filter: blur(25px) saturate(180%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4) !important;
|
||||
box-shadow: 0 40px 80px rgba(0,0,0,0.12) !important;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.cookie-banner-wrapper {
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
.cookie-banner-card {
|
||||
border-radius: 25px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function getCookie(name) {
|
||||
let nameEQ = name + "=";
|
||||
let ca = document.cookie.split(';');
|
||||
for(let i=0;i < ca.length;i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function setCookie(name,value,days) {
|
||||
let expires = "";
|
||||
if (days) {
|
||||
let date = new Date();
|
||||
date.setTime(date.getTime() + (days*24*60*60*1000));
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/; SameSite=Lax";
|
||||
}
|
||||
|
||||
function acceptCookies() {
|
||||
setCookie('cookie_consent', 'accepted', 365);
|
||||
dismissCookieBanner();
|
||||
}
|
||||
|
||||
function dismissCookieBanner() {
|
||||
const banner = document.getElementById('cookie_consent_banner');
|
||||
if (banner) {
|
||||
banner.classList.remove('animate__fadeIn');
|
||||
banner.classList.add('animate__fadeOutDown');
|
||||
setTimeout(() => banner.classList.add('d-none'), 500);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
if (!getCookie('cookie_consent')) {
|
||||
setTimeout(() => {
|
||||
const banner = document.getElementById('cookie_consent_banner');
|
||||
if (banner) banner.classList.remove('d-none');
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
Reference in New Issue
Block a user