feat: add resources and view components

This commit is contained in:
2026-05-21 16:05:19 +07:00
parent 28a06315b8
commit b2d60e680d
249 changed files with 37379 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+268
View File
@@ -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 &amp; 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