Files
thankcard-system/resources/views/layouts/app.blade.php
T
2026-07-03 16:54:43 +07:00

127 lines
4.9 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">
<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 h-full 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', openSidebar);
closeBtn.addEventListener('click', closeSidebar);
overlay.addEventListener('click', closeSidebar);
}
});
</script>
@stack('scripts')
</body>
</html>