feature: login and my page

This commit is contained in:
antv
2026-07-02 15:42:47 +07:00
parent c993f848cb
commit 89790539b7
41 changed files with 1062 additions and 769 deletions
+31 -86
View File
@@ -12,93 +12,12 @@
<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>
<aside class="sidebar" aria-label="Main navigation">
<div class="flex flex-col h-full justify-between">
<div class="flex-1 flex flex-col min-h-0 overflow-hidden">
<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>
<!-- Collapse / Expand button (desktop) -->
<button id="sidebar-toggle" class="hidden lg:inline-flex p-2 focus:outline-none focus:ring-2 focus:ring-white" aria-label="Collapse sidebar" aria-controls="sidebar" aria-expanded="true">
<x-icon name="icn-chevron-left" class="w-5 h-5" />
</button>
<!-- Mobile hamburger button -->
<button id="sidebar-hamburger" class="lg:hidden p-2 focus:outline-none focus:ring-2 focus:ring-white" aria-label="Open navigation" aria-controls="sidebar" aria-expanded="false">
<x-icon name="icn-menu" class="w-5 h-5" />
</button>
</div>
<!-- Sidebar Component -->
<x-sidebar />
<nav class="p-4 space-y-1 overflow-y-auto flex-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 class="shrink-0">
<div class="px-6 py-4 border-t border-border-light text-center">
<span class="text-text-muted text-[10px]">&copy; 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>
<main class="main-content flex-1 flex flex-col h-full bg-[#f8faff] 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'))
@@ -175,6 +94,32 @@
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>