all feature
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
<!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">
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="flex flex-col h-full justify-between">
|
||||
<div>
|
||||
<div class="h-16 flex items-center justify-between px-6 border-b border-border-light">
|
||||
<div class="flex items-center gap-2">
|
||||
<img src="{{ asset('images/logo.png') }}" alt="GMO-Z.com RUNSYSTEM" class="h-8 w-auto object-contain">
|
||||
</div>
|
||||
<button class="text-text-light hover:text-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<nav class="p-4 space-y-1">
|
||||
@if(Auth::check() && Auth::user()->role == \App\Models\User::ROLE_ADMIN)
|
||||
<!-- ADMIN SIDEBAR -->
|
||||
<a href="{{ route('admin.users.index') }}" class="sidebar-link {{ request()->routeIs('admin.users.index') ? 'sidebar-link-active' : '' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" />
|
||||
</svg>
|
||||
<span>{{ __('layout.manage_users') }}</span>
|
||||
</a>
|
||||
<a href="{{ route('admin.users.create') }}" class="sidebar-link {{ request()->routeIs('admin.users.create') ? 'sidebar-link-active' : '' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
<span>{{ __('layout.add_user') }}</span>
|
||||
</a>
|
||||
@else
|
||||
<!-- USER SIDEBAR -->
|
||||
<a href="{{ route('user.dashboard') }}" class="sidebar-link {{ request()->routeIs('user.dashboard') ? 'sidebar-link-active' : '' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
|
||||
</svg>
|
||||
<span>{{ __('layout.my_page') }}</span>
|
||||
</a>
|
||||
<a href="{{ route('user.send') }}" class="sidebar-link {{ request()->routeIs('user.send') ? 'sidebar-link-active' : '' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5" />
|
||||
</svg>
|
||||
<span>{{ __('layout.send_card') }}</span>
|
||||
</a>
|
||||
@endif
|
||||
|
||||
<a href="{{ route('user.change_password') }}" class="sidebar-link {{ request()->routeIs('user.change_password') ? 'sidebar-link-active' : '' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0V10.5m-2.812 10.5h14.625c.621 0 1.125-.504 1.125-1.125V11.25c0-.621-.504-1.125-1.125-1.125H3.75c-.621 0-1.125.504-1.125 1.125v7.875c0 .621.504 1.125 1.125 1.125z" />
|
||||
</svg>
|
||||
<span>{{ __('layout.change_password') }}</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="mx-4 my-2 p-4 rounded-lg bg-primary/5 border border-primary/10 flex flex-col items-center text-center">
|
||||
<img src="https://illustrations.popsy.co/blue/document-delivery.svg" alt="Support" class="w-24 h-24 object-contain mb-2">
|
||||
<h4 class="text-text-dark font-semibold text-xs mb-1">{{ __('layout.have_questions') }}</h4>
|
||||
<a href="#" class="btn-primary py-1.5 px-4 text-xs w-full mt-2 inline-block">{{ __('layout.feedback') }}</a>
|
||||
</div>
|
||||
|
||||
<div class="px-6 py-4 border-t border-border-light text-center">
|
||||
<span class="text-text-muted text-[10px]">© 2026 GMO-Z.com RUNSYSTEM</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="main-content">
|
||||
<header class="top-header">
|
||||
<div class="flex items-center gap-3 overflow-x-auto py-2">
|
||||
<span class="text-text-light text-xs font-bold whitespace-nowrap">Thank Card System</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4 shrink-0">
|
||||
<div class="flex items-center gap-2 border-l border-border-light pl-4">
|
||||
<div class="w-8 h-8 rounded-full bg-primary-light text-primary flex items-center justify-center font-bold text-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-primary">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-xs font-bold text-text-dark">{{ Auth::check() ? Auth::user()->mail : 'GUEST' }}</span>
|
||||
|
||||
<form method="POST" action="{{ route('logout') }}" class="ml-2">
|
||||
@csrf
|
||||
<button type="submit" class="text-xs text-red-500 font-bold hover:underline">{{ __('layout.logout') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</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
|
||||
};
|
||||
</script>
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user