139 lines
5.5 KiB
PHP
139 lines
5.5 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="vi">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
<title>GMO-Z.com RUNSYSTEM - @yield('title', 'Dashboard')</title>
|
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
|
@stack('styles')
|
|
</head>
|
|
<body class="bg-bg-main text-text-dark font-sans antialiased" data-sidebar="expanded">
|
|
<script>
|
|
if (localStorage.getItem('sidebar-collapsed') === 'true' && window.innerWidth >= 1024) {
|
|
document.body.classList.add('sidebar-collapsed');
|
|
}
|
|
</script>
|
|
<div class="app-layout">
|
|
<!-- Mobile overlay (click outside to close) -->
|
|
<div id="sidebar-overlay" class="fixed inset-0 bg-black/30 hidden" aria-hidden="true"></div>
|
|
<!-- Sidebar Component -->
|
|
<x-sidebar />
|
|
|
|
<main class="main-content flex-1 flex flex-col min-h-screen bg-[#FAFBFF] overflow-hidden relative w-full lg:w-auto">
|
|
<!-- Header Component -->
|
|
<x-header />
|
|
|
|
<div class="flex-1 overflow-y-auto p-6 space-y-6">
|
|
@if(session('success'))
|
|
<div class="bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded relative">
|
|
<span class="block sm:inline">{{ session('success') }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
@if(session('error'))
|
|
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded relative">
|
|
<span class="block sm:inline">{{ session('error') }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
@yield('content')
|
|
</div>
|
|
</main>
|
|
</div>
|
|
@yield('modals')
|
|
@stack('modals')
|
|
<script>
|
|
window.openModal = function(id) {
|
|
const modal = document.getElementById(id);
|
|
if (!modal) return;
|
|
|
|
// 1. Prevent body scroll
|
|
document.body.style.overflow = 'hidden';
|
|
|
|
// 2. Setup initial display state
|
|
modal.classList.remove('hidden');
|
|
modal.classList.add('flex');
|
|
|
|
// 3. Trigger animations
|
|
requestAnimationFrame(() => {
|
|
modal.classList.remove('opacity-0');
|
|
modal.classList.add('opacity-100');
|
|
const panel = modal.querySelector('.modal-panel');
|
|
if (panel) {
|
|
panel.classList.remove('scale-95', 'translate-y-4');
|
|
panel.classList.add('scale-100', 'translate-y-0');
|
|
}
|
|
});
|
|
|
|
// 4. ESC to close and Trap focus
|
|
modal.setAttribute('tabindex', '-1');
|
|
modal.focus();
|
|
|
|
const escHandler = function(e) {
|
|
if (e.key === 'Escape') {
|
|
closeModal(id);
|
|
modal.removeEventListener('keydown', escHandler);
|
|
}
|
|
};
|
|
modal.addEventListener('keydown', escHandler);
|
|
};
|
|
|
|
window.closeModal = function(id) {
|
|
const modal = document.getElementById(id);
|
|
if (!modal) return;
|
|
|
|
// 1. Trigger exit animations
|
|
modal.classList.remove('opacity-100');
|
|
modal.classList.add('opacity-0');
|
|
const panel = modal.querySelector('.modal-panel');
|
|
if (panel) {
|
|
panel.classList.remove('scale-100', 'translate-y-0');
|
|
panel.classList.add('scale-95', 'translate-y-4');
|
|
}
|
|
|
|
// 2. Wait for transition then hide
|
|
setTimeout(() => {
|
|
modal.classList.add('hidden');
|
|
modal.classList.remove('flex');
|
|
document.body.style.overflow = '';
|
|
}, 300); // 300ms matches Tailwind duration-300
|
|
};
|
|
|
|
// Mobile Sidebar Toggle Logic
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const hamburger = document.getElementById('sidebar-hamburger');
|
|
const closeBtn = document.getElementById('sidebar-close');
|
|
const overlay = document.getElementById('sidebar-overlay');
|
|
const sidebar = document.querySelector('.sidebar');
|
|
|
|
if (hamburger && sidebar && overlay && closeBtn) {
|
|
function openSidebar() {
|
|
sidebar.classList.remove('-translate-x-full');
|
|
overlay.classList.remove('hidden');
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
|
|
function closeSidebar() {
|
|
sidebar.classList.add('-translate-x-full');
|
|
overlay.classList.add('hidden');
|
|
document.body.style.overflow = '';
|
|
}
|
|
|
|
hamburger.addEventListener('click', function () {
|
|
if (window.innerWidth >= 1024) {
|
|
const isCollapsed = document.body.classList.toggle('sidebar-collapsed');
|
|
localStorage.setItem('sidebar-collapsed', isCollapsed ? 'true' : 'false');
|
|
} else {
|
|
openSidebar();
|
|
}
|
|
});
|
|
closeBtn.addEventListener('click', closeSidebar);
|
|
overlay.addEventListener('click', closeSidebar);
|
|
}
|
|
});
|
|
</script>
|
|
@stack('scripts')
|
|
</body>
|
|
</html>
|