Your descriptive commit message
This commit is contained in:
@@ -1,357 +1,366 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @if(in_array(app()->getLocale(), config('app.rtl_locales'))) dir="rtl" @endif>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
|
||||
<title>
|
||||
@if(theme('seo_title'))
|
||||
{{ theme('seo_title') }}
|
||||
@isset($title)
|
||||
- {{ $title }}
|
||||
@endisset
|
||||
@else
|
||||
{{ config('app.name', 'Paymenter') }}
|
||||
@isset($title)
|
||||
- {{ $title }}
|
||||
@endisset
|
||||
@endif
|
||||
</title>
|
||||
|
||||
@if(theme('seo_description'))
|
||||
<meta name="description" content="{{ theme('seo_description') }}">
|
||||
<meta property="og:description" content="{{ theme('seo_description') }}">
|
||||
@endif
|
||||
|
||||
@if(theme('seo_keywords'))
|
||||
<meta name="keywords" content="{{ theme('seo_keywords') }}">
|
||||
@endif
|
||||
|
||||
@if(theme('seo_author'))
|
||||
<meta name="author" content="{{ theme('seo_author') }}">
|
||||
@endif
|
||||
|
||||
@vite(['themes/' . config('settings.theme') . '/js/app.js', 'themes/' . config('settings.theme') . '/css/app.css'], config('settings.theme'))
|
||||
@include('layouts.colors')
|
||||
|
||||
@if (config('settings.logo'))
|
||||
<link rel="icon" href="{{ Storage::url(config('settings.logo')) }}" type="image/png">
|
||||
@endif
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
@isset($title)
|
||||
<meta content="{{ theme('seo_title') ? theme('seo_title') . ' - ' . $title : config('app.name', 'Paymenter') . ' - ' . $title }}" property="og:title">
|
||||
<meta content="{{ theme('seo_title') ? theme('seo_title') . ' - ' . $title : config('app.name', 'Paymenter') . ' - ' . $title }}" name="title">
|
||||
@else
|
||||
<meta content="{{ theme('seo_title') ?: config('app.name', 'Paymenter') }}" property="og:title">
|
||||
<meta content="{{ theme('seo_title') ?: config('app.name', 'Paymenter') }}" name="title">
|
||||
@endisset
|
||||
|
||||
@isset($description)
|
||||
<meta content="{{ $description }}" property="og:description">
|
||||
<meta content="{{ $description }}" name="description">
|
||||
@endisset
|
||||
|
||||
<!-- Open Graph Image -->
|
||||
@if(theme('og_image'))
|
||||
<meta content="{{ theme('og_image') }}" property="og:image">
|
||||
<meta content="{{ theme('og_image') }}" name="image">
|
||||
<meta content="{{ theme('og_image') }}" property="twitter:image">
|
||||
@elseif(isset($image))
|
||||
<meta content="{{ $image }}" property="og:image">
|
||||
<meta content="{{ $image }}" name="image">
|
||||
<meta content="{{ $image }}" property="twitter:image">
|
||||
@endif
|
||||
|
||||
<!-- Additional Open Graph Tags -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{ url()->current() }}">
|
||||
<meta property="og:site_name" content="{{ config('app.name', 'Paymenter') }}">
|
||||
|
||||
<!-- Twitter Card Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{ theme('seo_title') ?: config('app.name', 'Paymenter') }}{{ isset($title) ? ' - ' . $title : '' }}">
|
||||
@if(theme('seo_description'))
|
||||
<meta name="twitter:description" content="{{ theme('seo_description') }}">
|
||||
@endif
|
||||
|
||||
<meta name="theme-color" content="{{ theme('primary') }}">
|
||||
<meta name="locale" content="{{ app()->getLocale() }}">
|
||||
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||
|
||||
{!! hook('head') !!}
|
||||
|
||||
<!-- Custom CSS from theme settings -->
|
||||
@if(theme('custom_css'))
|
||||
<style>
|
||||
{!! theme('custom_css') !!}
|
||||
</style>
|
||||
@endif
|
||||
|
||||
<!-- Custom HTML Head Section -->
|
||||
@if(theme('custom_head_html'))
|
||||
{!! theme('custom_head_html') !!}
|
||||
@endif
|
||||
|
||||
<style>
|
||||
/* Critical animations that should load immediately */
|
||||
.animate-pulse-optimized {
|
||||
animation: pulse-optimized 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-optimized {
|
||||
0%, 100% { opacity: 0.1; transform: scale(1); }
|
||||
50% { opacity: 0.25; transform: scale(1.05); }
|
||||
}
|
||||
|
||||
.low-performance * {
|
||||
animation-duration: 0.1s !important;
|
||||
transition-duration: 0.1s !important;
|
||||
}
|
||||
|
||||
.low-performance .animate-pulse-optimized {
|
||||
animation: none !important;
|
||||
opacity: 0.1 !important;
|
||||
}
|
||||
|
||||
.reveal-on-scroll {
|
||||
transform: translateY(20px);
|
||||
opacity: 0;
|
||||
transition: transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94),
|
||||
opacity 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
|
||||
.reveal-on-scroll.revealed {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn-loading {
|
||||
position: relative;
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
.btn-loading::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid currentColor;
|
||||
border-radius: 50%;
|
||||
border-top-color: transparent;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: translate(-50%, -50%) rotate(360deg); }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.mobile-optimized * {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.mobile-optimized button,
|
||||
.mobile-optimized a {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
}
|
||||
|
||||
/* Background Image Styles */
|
||||
.background-image-layer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -2;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.background-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.background-image-layer {
|
||||
background-attachment: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Integration Styles */
|
||||
.custom-chat-widget {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.custom-notification-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9998;
|
||||
padding: 10px;
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
text-align: center;
|
||||
transform: translateY(-100%);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.custom-notification-bar.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="w-full bg-background text-base min-h-screen flex flex-col antialiased"
|
||||
x-cloak
|
||||
x-data="{darkMode: $persist(window.matchMedia('(prefers-color-scheme: dark)').matches)}"
|
||||
:class="{'dark': darkMode}">
|
||||
|
||||
{!! hook('body') !!}
|
||||
|
||||
<!-- Custom HTML Body Top -->
|
||||
@if(theme('custom_body_top_html'))
|
||||
{!! theme('custom_body_top_html') !!}
|
||||
@endif
|
||||
|
||||
@if(theme('background_image_url'))
|
||||
<div class="background-image-layer"
|
||||
style="background-image: url('{{ theme('background_image_url') }}');
|
||||
opacity: {{ theme('background_image_opacity', 30) / 100 }};
|
||||
filter: blur({{ theme('background_image_blur', 5) }}px);">
|
||||
</div>
|
||||
|
||||
<div class="background-overlay"
|
||||
style="opacity: {{ theme('background_overlay_opacity', 70) / 100 }};">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<x-navigation />
|
||||
|
||||
@if(!theme('background_image_url'))
|
||||
<div class="fixed inset-0 overflow-hidden pointer-events-none z-0">
|
||||
<div class="absolute top-[50%] left-[50%] w-[300px] h-[300px] sm:w-[400px] sm:h-[400px] bg-primary rounded-full mix-blend-normal sm:mix-blend-screen filter blur-[40px] sm:blur-[120px] opacity-15 animate-pulse-optimized transform -translate-x-1/2 -translate-y-1/2"></div>
|
||||
|
||||
<div class="hidden sm:block absolute top-[30%] right-[30%] w-32 h-32 sm:w-48 sm:h-48 bg-primary rounded-full mix-blend-screen filter blur-[80px] sm:blur-[120px] opacity-10 animate-pulse-optimized"
|
||||
style="animation-delay: -1s;"></div>
|
||||
|
||||
<div class="hidden md:block absolute bottom-[15%] right-[15%] w-40 h-40 sm:w-60 sm:h-60 bg-primary rounded-full mix-blend-screen filter blur-[70px] sm:blur-[100px] opacity-15 animate-pulse-optimized"
|
||||
style="animation-delay: -2s;"></div>
|
||||
|
||||
<div class="hidden sm:block absolute top-[25%] left-[25%] w-[150px] h-[150px] sm:w-[200px] sm:h-[200px] bg-primary rounded-full mix-blend-screen filter blur-[60px] sm:blur-[90px] opacity-10 animate-pulse-optimized"
|
||||
style="animation-delay: -3s;"></div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="relative z-10 w-full flex flex-grow">
|
||||
@if (isset($sidebar) && $sidebar)
|
||||
<x-navigation.sidebar :title="$title ?? ''" />
|
||||
@endif
|
||||
|
||||
<div class="{{ (isset($sidebar) && $sidebar) ? 'md:ml-64 rtl:ml-0 rtl:md:mr-64' : '' }} flex min-w-0 flex-col flex-grow overflow-y-auto overflow-x-hidden">
|
||||
|
||||
<main class="container mt-24 mx-auto min-w-0 max-w-full px-4 sm:px-6 md:px-16 lg:px-16 relative z-10 overflow-x-auto">
|
||||
{{ $slot }}
|
||||
</main>
|
||||
|
||||
<x-notification />
|
||||
|
||||
{{-- Same width and horizontal padding as <main> so footer aligns with page containers --}}
|
||||
<div class="container relative z-0 mx-auto mb-3 min-w-0 max-w-full px-4 py-4 sm:px-6 md:px-16 lg:px-16">
|
||||
<x-navigation.footer />
|
||||
</div>
|
||||
</div>
|
||||
<x-impersonating />
|
||||
</div>
|
||||
|
||||
{!! hook('footer') !!}
|
||||
|
||||
<!-- Custom JavaScript from theme settings -->
|
||||
@if(theme('custom_js'))
|
||||
<script>
|
||||
{!! theme('custom_js') !!}
|
||||
</script>
|
||||
@endif
|
||||
|
||||
<!-- Custom HTML Body Bottom -->
|
||||
@if(theme('custom_body_bottom_html'))
|
||||
{!! theme('custom_body_bottom_html') !!}
|
||||
@endif
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
||||
const isLowEnd = connection && (connection.saveData || connection.effectiveType === 'slow-2g' || connection.effectiveType === '2g');
|
||||
const isSlowDevice = navigator.hardwareConcurrency && navigator.hardwareConcurrency <= 2;
|
||||
|
||||
if (isLowEnd || isSlowDevice) {
|
||||
document.body.classList.add('low-performance');
|
||||
}
|
||||
|
||||
if ('IntersectionObserver' in window) {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('revealed');
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.1,
|
||||
rootMargin: '50px'
|
||||
});
|
||||
|
||||
document.querySelectorAll('.reveal-on-scroll').forEach(el => {
|
||||
observer.observe(el);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
// Skip Livewire/Alpine handled buttons - they manage their own loading states
|
||||
if (e.target.hasAttribute('wire:click') ||
|
||||
e.target.hasAttribute('wire:submit') ||
|
||||
e.target.hasAttribute('x-on:click') ||
|
||||
e.target.hasAttribute('@click') ||
|
||||
e.target.closest('[wire\\:submit]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.matches('button[type="submit"], .btn-submit')) {
|
||||
e.target.classList.add('btn-loading');
|
||||
|
||||
setTimeout(() => {
|
||||
e.target.classList.remove('btn-loading');
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth <= 768) {
|
||||
document.body.classList.add('mobile-optimized');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @if(in_array(app()->getLocale(), config('app.rtl_locales'))) dir="rtl" @endif>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
|
||||
<title>
|
||||
@if(theme('seo_title'))
|
||||
{{ theme('seo_title') }}
|
||||
@isset($title)
|
||||
- {{ $title }}
|
||||
@endisset
|
||||
@else
|
||||
{{ config('app.name', 'Paymenter') }}
|
||||
@isset($title)
|
||||
- {{ $title }}
|
||||
@endisset
|
||||
@endif
|
||||
</title>
|
||||
|
||||
@if(theme('seo_description'))
|
||||
<meta name="description" content="{{ theme('seo_description') }}">
|
||||
<meta property="og:description" content="{{ theme('seo_description') }}">
|
||||
@endif
|
||||
|
||||
@if(theme('seo_keywords'))
|
||||
<meta name="keywords" content="{{ theme('seo_keywords') }}">
|
||||
@endif
|
||||
|
||||
@if(theme('seo_author'))
|
||||
<meta name="author" content="{{ theme('seo_author') }}">
|
||||
@endif
|
||||
|
||||
@vite(['themes/' . config('settings.theme') . '/js/app.js', 'themes/' . config('settings.theme') . '/css/app.css'], config('settings.theme'))
|
||||
@include('layouts.colors')
|
||||
|
||||
@if (config('settings.logo'))
|
||||
<link rel="icon" href="{{ Storage::url(config('settings.logo')) }}" type="image/png">
|
||||
@endif
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
@isset($title)
|
||||
<meta content="{{ theme('seo_title') ? theme('seo_title') . ' - ' . $title : config('app.name', 'Paymenter') . ' - ' . $title }}" property="og:title">
|
||||
<meta content="{{ theme('seo_title') ? theme('seo_title') . ' - ' . $title : config('app.name', 'Paymenter') . ' - ' . $title }}" name="title">
|
||||
@else
|
||||
<meta content="{{ theme('seo_title') ?: config('app.name', 'Paymenter') }}" property="og:title">
|
||||
<meta content="{{ theme('seo_title') ?: config('app.name', 'Paymenter') }}" name="title">
|
||||
@endisset
|
||||
|
||||
@isset($description)
|
||||
<meta content="{{ $description }}" property="og:description">
|
||||
<meta content="{{ $description }}" name="description">
|
||||
@endisset
|
||||
|
||||
<!-- Open Graph Image -->
|
||||
@if(theme('og_image'))
|
||||
<meta content="{{ theme('og_image') }}" property="og:image">
|
||||
<meta content="{{ theme('og_image') }}" name="image">
|
||||
<meta content="{{ theme('og_image') }}" property="twitter:image">
|
||||
@elseif(isset($image))
|
||||
<meta content="{{ $image }}" property="og:image">
|
||||
<meta content="{{ $image }}" name="image">
|
||||
<meta content="{{ $image }}" property="twitter:image">
|
||||
@endif
|
||||
|
||||
<!-- Additional Open Graph Tags -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{ url()->current() }}">
|
||||
<meta property="og:site_name" content="{{ config('app.name', 'Paymenter') }}">
|
||||
|
||||
<!-- Twitter Card Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{ theme('seo_title') ?: config('app.name', 'Paymenter') }}{{ isset($title) ? ' - ' . $title : '' }}">
|
||||
@if(theme('seo_description'))
|
||||
<meta name="twitter:description" content="{{ theme('seo_description') }}">
|
||||
@endif
|
||||
|
||||
<meta name="theme-color" content="{{ theme('primary') }}">
|
||||
<meta name="locale" content="{{ app()->getLocale() }}">
|
||||
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||
|
||||
{!! hook('head') !!}
|
||||
|
||||
<!-- Custom CSS from theme settings -->
|
||||
@if(theme('custom_css'))
|
||||
<style>
|
||||
{!! theme('custom_css') !!}
|
||||
</style>
|
||||
@endif
|
||||
|
||||
<!-- Custom HTML Head Section -->
|
||||
@if(theme('custom_head_html'))
|
||||
{!! theme('custom_head_html') !!}
|
||||
@endif
|
||||
|
||||
<style>
|
||||
/* Critical animations that should load immediately */
|
||||
.animate-pulse-optimized {
|
||||
animation: pulse-optimized 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-optimized {
|
||||
0%, 100% { opacity: 0.1; transform: scale(1); }
|
||||
50% { opacity: 0.25; transform: scale(1.05); }
|
||||
}
|
||||
|
||||
.low-performance * {
|
||||
animation-duration: 0.1s !important;
|
||||
transition-duration: 0.1s !important;
|
||||
}
|
||||
|
||||
.low-performance .animate-pulse-optimized {
|
||||
animation: none !important;
|
||||
opacity: 0.1 !important;
|
||||
}
|
||||
|
||||
.reveal-on-scroll {
|
||||
transform: translateY(20px);
|
||||
opacity: 0;
|
||||
transition: transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94),
|
||||
opacity 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
|
||||
.reveal-on-scroll.revealed {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn-loading {
|
||||
position: relative;
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
.btn-loading::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid currentColor;
|
||||
border-radius: 50%;
|
||||
border-top-color: transparent;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: translate(-50%, -50%) rotate(360deg); }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.mobile-optimized * {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.mobile-optimized button,
|
||||
.mobile-optimized a {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
}
|
||||
|
||||
/* Background Image Styles */
|
||||
.background-image-layer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -2;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.background-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.background-image-layer {
|
||||
background-attachment: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Integration Styles */
|
||||
.custom-chat-widget {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.custom-notification-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9998;
|
||||
padding: 10px;
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
text-align: center;
|
||||
transform: translateY(-100%);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.custom-notification-bar.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="w-full bg-background text-base min-h-screen flex flex-col antialiased {{ theme('background_image_url') ? '' : 'grid-bg noise-overlay' }}"
|
||||
x-cloak
|
||||
x-data="{darkMode: $persist(window.matchMedia('(prefers-color-scheme: dark)').matches), scrolled: false}"
|
||||
x-init="window.addEventListener('scroll', () => scrolled = window.scrollY > 20, { passive: true })"
|
||||
:class="{'dark': darkMode, 'is-scrolled': scrolled}">
|
||||
|
||||
{!! hook('body') !!}
|
||||
|
||||
<!-- Custom HTML Body Top -->
|
||||
@if(theme('custom_body_top_html'))
|
||||
{!! theme('custom_body_top_html') !!}
|
||||
@endif
|
||||
|
||||
@if(theme('background_image_url'))
|
||||
<div class="background-image-layer"
|
||||
style="background-image: url('{{ theme('background_image_url') }}');
|
||||
opacity: {{ theme('background_image_opacity', 30) / 100 }};
|
||||
filter: blur({{ theme('background_image_blur', 5) }}px);">
|
||||
</div>
|
||||
|
||||
<div class="background-overlay"
|
||||
style="opacity: {{ theme('background_overlay_opacity', 70) / 100 }};">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<x-navigation />
|
||||
|
||||
@if(!theme('background_image_url'))
|
||||
{{-- Subtle ambient gradient accents (Volt-inspired). Kept minimal so
|
||||
content readability stays crisp on both desktop and mobile. --}}
|
||||
<div class="fixed inset-0 overflow-hidden pointer-events-none z-0" aria-hidden="true">
|
||||
<div class="absolute top-[-10%] left-[-10%] w-[420px] h-[420px] bg-primary rounded-full filter blur-[110px] opacity-[0.10] sm:opacity-[0.14] animate-pulse-optimized"></div>
|
||||
|
||||
<div class="hidden md:block absolute bottom-[-15%] right-[-10%] w-[480px] h-[480px] bg-secondary rounded-full filter blur-[120px] opacity-[0.10] animate-pulse-optimized"
|
||||
style="animation-delay: -2s;"></div>
|
||||
|
||||
<div class="hidden lg:block absolute top-[30%] right-[20%] w-[260px] h-[260px] bg-primary rounded-full filter blur-[90px] opacity-[0.06] animate-pulse-optimized"
|
||||
style="animation-delay: -4s;"></div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="relative z-10 w-full flex flex-grow">
|
||||
@if (isset($sidebar) && $sidebar)
|
||||
<x-navigation.sidebar :title="$title ?? ''" />
|
||||
@endif
|
||||
|
||||
<div class="{{ (isset($sidebar) && $sidebar) ? 'md:ml-64 rtl:ml-0 rtl:md:mr-64' : '' }} flex min-w-0 flex-col flex-grow overflow-y-auto overflow-x-hidden">
|
||||
|
||||
<main class="w-full mt-24 mx-auto min-w-0 max-w-full px-4 sm:px-6 md:px-16 lg:px-16 relative z-10 transition-opacity duration-150"
|
||||
x-data="{ navigating: false }"
|
||||
x-init="
|
||||
document.addEventListener('livewire:navigate', () => { navigating = true });
|
||||
document.addEventListener('livewire:navigated', () => { $nextTick(() => { navigating = false }) });
|
||||
"
|
||||
:class="{ 'opacity-60': navigating }">
|
||||
{{ $slot }}
|
||||
</main>
|
||||
|
||||
<x-notification />
|
||||
|
||||
{{-- Same width and horizontal padding as <main> so footer aligns with page containers --}}
|
||||
<div class="w-full relative z-0 mx-auto mb-3 min-w-0 max-w-full px-4 py-4 sm:px-6 md:px-16 lg:px-16">
|
||||
<x-navigation.footer />
|
||||
</div>
|
||||
</div>
|
||||
<x-impersonating />
|
||||
</div>
|
||||
|
||||
{{-- Global command palette (Cmd/Ctrl+K) --}}
|
||||
<x-command-palette />
|
||||
|
||||
{!! hook('footer') !!}
|
||||
|
||||
<!-- Custom JavaScript from theme settings -->
|
||||
@if(theme('custom_js'))
|
||||
<script>
|
||||
{!! theme('custom_js') !!}
|
||||
</script>
|
||||
@endif
|
||||
|
||||
<!-- Custom HTML Body Bottom -->
|
||||
@if(theme('custom_body_bottom_html'))
|
||||
{!! theme('custom_body_bottom_html') !!}
|
||||
@endif
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
||||
const isLowEnd = connection && (connection.saveData || connection.effectiveType === 'slow-2g' || connection.effectiveType === '2g');
|
||||
const isSlowDevice = navigator.hardwareConcurrency && navigator.hardwareConcurrency <= 2;
|
||||
|
||||
if (isLowEnd || isSlowDevice) {
|
||||
document.body.classList.add('low-performance');
|
||||
}
|
||||
|
||||
if ('IntersectionObserver' in window) {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('revealed');
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.1,
|
||||
rootMargin: '50px'
|
||||
});
|
||||
|
||||
document.querySelectorAll('.reveal-on-scroll').forEach(el => {
|
||||
observer.observe(el);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
// Skip Livewire/Alpine handled buttons - they manage their own loading states
|
||||
if (e.target.hasAttribute('wire:click') ||
|
||||
e.target.hasAttribute('wire:submit') ||
|
||||
e.target.hasAttribute('x-on:click') ||
|
||||
e.target.hasAttribute('@click') ||
|
||||
e.target.closest('[wire\\:submit]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.matches('button[type="submit"], .btn-submit')) {
|
||||
e.target.classList.add('btn-loading');
|
||||
|
||||
setTimeout(() => {
|
||||
e.target.classList.remove('btn-loading');
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
|
||||
if (window.innerWidth <= 768) {
|
||||
document.body.classList.add('mobile-optimized');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,44 +1,97 @@
|
||||
<style>
|
||||
:root {
|
||||
/* Branding Colors (Light) */
|
||||
--color-primary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('primary', '229 100% 64%'))) }};
|
||||
--color-secondary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('secondary', '237 33% 60%'))) }};
|
||||
|
||||
/* Neutral Colors - Borders, Accents... (Light) */
|
||||
--color-neutral: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('neutral', '220 25% 85%'))) }};
|
||||
|
||||
/* Text Colors (Light) */
|
||||
--color-base: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('base', '0 0% 0%'))) }};
|
||||
--color-muted: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('muted', '220 28% 25%'))) }};
|
||||
--color-inverted: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('inverted', '100 100% 100%'))) }};
|
||||
|
||||
/* State Colors */
|
||||
--color-success: 142 71% 45%;
|
||||
--color-error: 0 75% 60%;
|
||||
--color-warning: 25 95% 53%;
|
||||
--color-inactive: 0 0% 63%;
|
||||
--color-info: 210 100% 60%;
|
||||
|
||||
/* Background Colors (Light) */
|
||||
--color-background: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('background', '100 100% 100%'))) }};
|
||||
--color-background-secondary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('background-secondary', '0 0% 97%'))) }};
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* Branding Colors (Dark) */
|
||||
--color-primary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-primary', '229 100% 64%'))) }};
|
||||
--color-secondary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-secondary', '237 33% 60%'))) }};
|
||||
|
||||
/* Neutral Colors - Borders, Accents... (Dark) */
|
||||
--color-neutral: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-neutral', '220 25% 29%'))) }};
|
||||
|
||||
/* Text Colors (Dark) */
|
||||
--color-base: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-base', '100 100% 100%'))) }};
|
||||
--color-muted: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-muted', '220 28% 25%'))) }};
|
||||
--color-inverted: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-inverted', '220 14% 60%'))) }};
|
||||
|
||||
/* Background Colors (Dark) */
|
||||
--color-background: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-background', '221 39% 11%'))) }};
|
||||
--color-background-secondary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-background-secondary', '217 33% 16%'))) }};
|
||||
}
|
||||
<style>
|
||||
/*
|
||||
* Palette: "Pure Neutral Black + Neon" dark-first aesthetic.
|
||||
* Dark mode is the canonical design; light mode is a retuned fallback.
|
||||
* Admin-configured theme() values still take precedence over these defaults.
|
||||
*/
|
||||
:root {
|
||||
/* Branding Colors (Light) — electric violet + neon cyan */
|
||||
--color-primary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('primary', '265 85% 55%'))) }};
|
||||
--color-secondary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('secondary', '190 85% 42%'))) }};
|
||||
|
||||
/* Neutral Colors - Borders, Accents... (Light) */
|
||||
--color-neutral: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('neutral', '220 13% 88%'))) }};
|
||||
|
||||
/* Text Colors (Light) */
|
||||
--color-base: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('base', '240 10% 10%'))) }};
|
||||
--color-muted: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('muted', '240 5% 45%'))) }};
|
||||
--color-inverted: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('inverted', '0 0% 100%'))) }};
|
||||
|
||||
/* State Colors */
|
||||
--color-success: 152 76% 45%;
|
||||
--color-error: 350 85% 55%;
|
||||
--color-warning: 38 95% 55%;
|
||||
--color-inactive: 220 9% 64%;
|
||||
--color-info: 210 90% 55%;
|
||||
|
||||
/* Background Colors (Light) — cooler, higher contrast */
|
||||
--color-background: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('background', '220 20% 97%'))) }};
|
||||
--color-background-secondary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('background-secondary', '0 0% 100%'))) }};
|
||||
--color-background-tertiary: 220 16% 93%;
|
||||
|
||||
/* Glass-morphism tokens (Light) */
|
||||
--color-glass: 0 0% 100% / 0.6;
|
||||
--color-glass-border: 220 13% 88% / 0.6;
|
||||
|
||||
/* Neon glow accents (Light) */
|
||||
--color-primary-glow: 265 85% 55% / 0.35;
|
||||
--color-secondary-glow: 190 85% 42% / 0.35;
|
||||
|
||||
/* Text hierarchy (Light) */
|
||||
--color-base-muted: 240 6% 35%;
|
||||
--color-base-subtle: 240 5% 55%;
|
||||
|
||||
/* Elevation shadow tokens (Light) */
|
||||
--shadow-elevated: 0 4px 16px -2px hsl(240 20% 20% / 0.08), 0 2px 4px -1px hsl(240 20% 20% / 0.04);
|
||||
--shadow-floating: 0 12px 40px -8px hsl(240 20% 20% / 0.18), 0 4px 12px -2px hsl(240 20% 20% / 0.06);
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* Branding Colors (Dark) — electric violet + neon cyan */
|
||||
--color-primary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-primary', '265 90% 66%'))) }};
|
||||
--color-secondary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-secondary', '190 95% 55%'))) }};
|
||||
|
||||
/* Neutral Colors - Borders, Accents... (Dark) — subtle slate */
|
||||
--color-neutral: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-neutral', '240 5% 18%'))) }};
|
||||
|
||||
/* Text Colors (Dark) */
|
||||
--color-base: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-base', '0 0% 98%'))) }};
|
||||
--color-muted: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-muted', '240 5% 65%'))) }};
|
||||
--color-inverted: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-inverted', '0 0% 4%'))) }};
|
||||
|
||||
/* State Colors (Dark) — brighter for contrast */
|
||||
--color-success: 152 76% 55%;
|
||||
--color-error: 350 90% 65%;
|
||||
--color-warning: 38 95% 62%;
|
||||
--color-inactive: 240 5% 45%;
|
||||
--color-info: 210 90% 65%;
|
||||
|
||||
/* Background Colors (Dark) — near-black OLED surfaces */
|
||||
--color-background: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-background', '0 0% 4%'))) }};
|
||||
--color-background-secondary: {{ str_replace(',', '', preg_replace('/^hsl\((.+)\)$/', '$1', theme('dark-background-secondary', '240 6% 8%'))) }};
|
||||
--color-background-tertiary: 240 7% 12%;
|
||||
|
||||
/* Glass-morphism tokens (Dark) */
|
||||
--color-glass: 240 6% 10% / 0.55;
|
||||
--color-glass-border: 240 5% 25% / 0.5;
|
||||
|
||||
/* Neon glow accents (Dark) */
|
||||
--color-primary-glow: 265 90% 66% / 0.45;
|
||||
--color-secondary-glow: 190 95% 55% / 0.45;
|
||||
|
||||
/* Text hierarchy (Dark) */
|
||||
--color-base-muted: 240 5% 75%;
|
||||
--color-base-subtle: 240 5% 55%;
|
||||
|
||||
/* Elevation shadow tokens (Dark) — neon-tinted */
|
||||
--shadow-elevated: 0 4px 16px -2px hsl(0 0% 0% / 0.6), 0 0 0 1px hsl(240 5% 25% / 0.3);
|
||||
--shadow-floating: 0 12px 40px -8px hsl(0 0% 0% / 0.7), 0 0 32px -8px hsl(265 90% 66% / 0.15), 0 0 0 1px hsl(240 5% 25% / 0.4);
|
||||
}
|
||||
|
||||
/* Global easing tokens — used across transitions for a unified motion feel.
|
||||
Defined on :root so both light & dark inherit. */
|
||||
:root {
|
||||
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
--ease-out-soft: cubic-bezier(0.22, 0.61, 0.36, 1);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user