312 lines
23 KiB
PHP
312 lines
23 KiB
PHP
@php
|
|
$user = auth()->user();
|
|
$isAdmin = $user && method_exists($user, 'isAdmin') ? $user->isAdmin() : false;
|
|
try {
|
|
$branding = \App\Models\AppSetting::branding();
|
|
} catch (\Throwable $e) {
|
|
$branding = \App\Models\AppSetting::brandingDefaults();
|
|
}
|
|
|
|
$masterDataOpen = request()->routeIs('academic-years.*')
|
|
|| request()->routeIs('departments.*')
|
|
|| request()->routeIs('classes.*')
|
|
|| request()->routeIs('document-types.*');
|
|
|
|
$kesiswaanOpen = request()->routeIs('students.*')
|
|
|| request()->routeIs('student-exits.*')
|
|
|| request()->routeIs('student-transfers.*')
|
|
|| request()->routeIs('graduated-students.*')
|
|
|| request()->routeIs('student-promotions.*')
|
|
|| request()->routeIs('student-achievements.*')
|
|
|| request()->routeIs('student-self-service.*');
|
|
|
|
$settingsOpen = request()->routeIs('settings.*');
|
|
@endphp
|
|
|
|
<div x-data="{ sidebarOpen: false, masterDataOpen: @js($masterDataOpen), kesiswaanOpen: @js($kesiswaanOpen), settingsOpen: @js($settingsOpen), profileMenuOpen: false }" class="min-h-screen bg-slate-50">
|
|
<div
|
|
x-show="sidebarOpen"
|
|
x-transition.opacity
|
|
class="fixed inset-0 z-40 bg-slate-900/50 lg:hidden"
|
|
@click="sidebarOpen = false"
|
|
></div>
|
|
|
|
<aside
|
|
:class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'"
|
|
class="fixed left-0 top-0 z-50 flex h-screen w-72 flex-col border-r border-slate-200 bg-white transition-transform duration-300 lg:translate-x-0"
|
|
>
|
|
<div class="flex h-20 items-center justify-between border-b border-slate-200 px-6">
|
|
<a href="{{ route('dashboard') }}" class="flex items-center gap-3">
|
|
<div class="flex h-12 w-12 items-center justify-center overflow-hidden rounded-2xl bg-indigo-600 text-base font-bold text-white shadow-lg shadow-indigo-200">
|
|
@if (!empty($branding['app_logo']))
|
|
<img src="{{ asset('storage/' . $branding['app_logo']) }}" alt="{{ $branding['app_name'] }}" class="h-full w-full object-contain bg-white p-2">
|
|
@else
|
|
{{ $branding['app_short_name'] ?? 'DK' }}
|
|
@endif
|
|
</div>
|
|
<div>
|
|
<div class="text-sm font-semibold text-slate-900">{{ $branding['app_name'] ?? 'Database Kesiswaan' }}</div>
|
|
<div class="text-xs text-slate-500">Admin Dashboard</div>
|
|
</div>
|
|
</a>
|
|
|
|
<button @click="sidebarOpen = false" class="rounded-lg p-2 text-slate-500 hover:bg-slate-100 lg:hidden">
|
|
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="flex-1 overflow-y-auto px-4 py-6">
|
|
<div class="mb-6 px-3">
|
|
<p class="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-400">Menu Utama</p>
|
|
</div>
|
|
|
|
<nav class="space-y-2">
|
|
<a href="{{ route('dashboard') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('dashboard') ? 'bg-indigo-50 text-indigo-700' : 'text-slate-600 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<span class="inline-flex h-9 w-9 items-center justify-center rounded-lg {{ request()->routeIs('dashboard') ? 'bg-indigo-100 text-indigo-700 shadow-sm shadow-indigo-100' : 'bg-slate-100 text-indigo-500 group-hover:text-indigo-600' }}">
|
|
<i class="fa-solid fa-house text-base"></i>
|
|
</span>
|
|
<span>Dashboard</span>
|
|
</a>
|
|
|
|
@if ($isAdmin)
|
|
<div class="space-y-2">
|
|
<button
|
|
type="button"
|
|
@click="masterDataOpen = !masterDataOpen"
|
|
class="flex w-full items-center justify-between rounded-xl px-4 py-3 text-sm font-medium transition {{ $masterDataOpen ? 'bg-indigo-50 text-indigo-700' : 'text-slate-600 hover:bg-slate-100 hover:text-slate-900' }}"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span class="inline-flex h-9 w-9 items-center justify-center rounded-lg {{ $masterDataOpen ? 'bg-cyan-100 text-cyan-700 shadow-sm shadow-cyan-100' : 'bg-slate-100 text-cyan-500' }}">
|
|
<i class="fa-solid fa-database text-base"></i>
|
|
</span>
|
|
<span>Master Data</span>
|
|
</div>
|
|
<svg class="h-4 w-4 transition-transform" :class="masterDataOpen ? 'rotate-180' : ''" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8" d="m6 9 6 6 6-6" />
|
|
</svg>
|
|
</button>
|
|
|
|
<div x-show="masterDataOpen" x-collapse class="space-y-1 pl-4">
|
|
<a href="{{ route('academic-years.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('academic-years.*') ? 'bg-cyan-50 text-cyan-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-calendar-days text-sm {{ request()->routeIs('academic-years.*') ? 'text-cyan-600' : 'text-cyan-500 group-hover:text-cyan-600' }}"></i>
|
|
<span>Tahun Angkatan</span>
|
|
</a>
|
|
<a href="{{ route('departments.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('departments.*') ? 'bg-cyan-50 text-cyan-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-building-columns text-sm {{ request()->routeIs('departments.*') ? 'text-cyan-600' : 'text-cyan-500 group-hover:text-cyan-600' }}"></i>
|
|
<span>Program Keahlian</span>
|
|
</a>
|
|
<a href="{{ route('classes.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('classes.*') ? 'bg-cyan-50 text-cyan-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-chalkboard text-sm {{ request()->routeIs('classes.*') ? 'text-cyan-600' : 'text-cyan-500 group-hover:text-cyan-600' }}"></i>
|
|
<span>Kelas</span>
|
|
</a>
|
|
<a href="{{ route('document-types.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('document-types.*') ? 'bg-cyan-50 text-cyan-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-folder-tree text-sm {{ request()->routeIs('document-types.*') ? 'text-cyan-600' : 'text-cyan-500 group-hover:text-cyan-600' }}"></i>
|
|
<span>Jenis Dokumen</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="space-y-2">
|
|
<button
|
|
type="button"
|
|
@click="kesiswaanOpen = !kesiswaanOpen"
|
|
class="flex w-full items-center justify-between rounded-xl px-4 py-3 text-sm font-medium transition {{ $kesiswaanOpen ? 'bg-indigo-50 text-indigo-700' : 'text-slate-600 hover:bg-slate-100 hover:text-slate-900' }}"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span class="inline-flex h-9 w-9 items-center justify-center rounded-lg {{ $kesiswaanOpen ? 'bg-emerald-100 text-emerald-700 shadow-sm shadow-emerald-100' : 'bg-slate-100 text-emerald-500' }}">
|
|
<i class="fa-solid fa-user-graduate text-base"></i>
|
|
</span>
|
|
<span>Kesiswaan</span>
|
|
</div>
|
|
<svg class="h-4 w-4 transition-transform" :class="kesiswaanOpen ? 'rotate-180' : ''" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8" d="m6 9 6 6 6-6" />
|
|
</svg>
|
|
</button>
|
|
|
|
<div x-show="kesiswaanOpen" x-collapse class="space-y-1 pl-4">
|
|
<a href="{{ route('students.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('students.index') || request()->routeIs('students.create') || request()->routeIs('students.edit') || request()->routeIs('students.show') || request()->routeIs('students.import.*') ? 'bg-emerald-50 text-emerald-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-users text-sm {{ request()->routeIs('students.index') || request()->routeIs('students.create') || request()->routeIs('students.edit') || request()->routeIs('students.show') || request()->routeIs('students.import.*') ? 'text-emerald-600' : 'text-emerald-500 group-hover:text-emerald-600' }}"></i>
|
|
<span>Data Siswa</span>
|
|
</a>
|
|
<a href="{{ route('student-exits.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('student-exits.*') ? 'bg-amber-50 text-amber-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-right-from-bracket text-sm {{ request()->routeIs('student-exits.*') ? 'text-amber-600' : 'text-amber-500 group-hover:text-amber-600' }}"></i>
|
|
<span>Data Siswa Keluar</span>
|
|
</a>
|
|
<a href="{{ route('student-transfers.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('student-transfers.*') ? 'bg-blue-50 text-blue-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-right-left text-sm {{ request()->routeIs('student-transfers.*') ? 'text-blue-600' : 'text-blue-500 group-hover:text-blue-600' }}"></i>
|
|
<span>Data Siswa Mutasi</span>
|
|
</a>
|
|
<a href="{{ route('student-achievements.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('student-achievements.*') ? 'bg-yellow-50 text-yellow-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-trophy text-sm {{ request()->routeIs('student-achievements.*') ? 'text-yellow-600' : 'text-yellow-500 group-hover:text-yellow-600' }}"></i>
|
|
<span>Data Siswa Berprestasi</span>
|
|
</a>
|
|
<a href="{{ route('student-promotions.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('student-promotions.*') ? 'bg-lime-50 text-lime-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-arrow-trend-up text-sm {{ request()->routeIs('student-promotions.*') ? 'text-lime-600' : 'text-lime-500 group-hover:text-lime-600' }}"></i>
|
|
<span>Kenaikan Kelas</span>
|
|
</a>
|
|
<a href="{{ route('student-self-service.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('student-self-service.*') ? 'bg-fuchsia-50 text-fuchsia-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-id-card-clip text-sm {{ request()->routeIs('student-self-service.*') ? 'text-fuchsia-600' : 'text-fuchsia-500 group-hover:text-fuchsia-600' }}"></i>
|
|
<span>Self Servis Siswa</span>
|
|
</a>
|
|
<a href="{{ route('graduated-students.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('graduated-students.*') ? 'bg-sky-50 text-sky-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-user-check text-sm {{ request()->routeIs('graduated-students.*') ? 'text-sky-600' : 'text-sky-500 group-hover:text-sky-600' }}"></i>
|
|
<span>Data Siswa Lulus</span>
|
|
</a>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
@if ($isAdmin)
|
|
<div class="space-y-2">
|
|
<button
|
|
type="button"
|
|
@click="settingsOpen = !settingsOpen"
|
|
class="flex w-full items-center justify-between rounded-xl px-4 py-3 text-sm font-medium transition {{ $settingsOpen ? 'bg-indigo-50 text-indigo-700' : 'text-slate-600 hover:bg-slate-100 hover:text-slate-900' }}"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span class="inline-flex h-9 w-9 items-center justify-center rounded-lg {{ $settingsOpen ? 'bg-violet-100 text-violet-700 shadow-sm shadow-violet-100' : 'bg-slate-100 text-violet-500' }}">
|
|
<i class="fa-solid fa-gear text-base"></i>
|
|
</span>
|
|
<span>Pengaturan</span>
|
|
</div>
|
|
<svg class="h-4 w-4 transition-transform" :class="settingsOpen ? 'rotate-180' : ''" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8" d="m6 9 6 6 6-6" />
|
|
</svg>
|
|
</button>
|
|
|
|
<div x-show="settingsOpen" x-collapse class="space-y-1 pl-4">
|
|
<a href="{{ route('settings.users.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('settings.users.*') ? 'bg-violet-50 text-violet-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-user-shield text-sm {{ request()->routeIs('settings.users.*') ? 'text-violet-600' : 'text-violet-500 group-hover:text-violet-600' }}"></i>
|
|
<span>Manajemen Pengguna</span>
|
|
</a>
|
|
<a href="{{ route('settings.branding.index') }}"
|
|
class="group flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('settings.branding.*') ? 'bg-pink-50 text-pink-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-palette text-sm {{ request()->routeIs('settings.branding.*') ? 'text-pink-600' : 'text-pink-500 group-hover:text-pink-600' }}"></i>
|
|
<span>Branding Aplikasi</span>
|
|
</a>
|
|
<a href="{{ route('settings.sync-tokens.index') }}"
|
|
class="flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('settings.sync-tokens.*') ? 'bg-emerald-50 text-emerald-700' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-900' }}">
|
|
<i class="fa-solid fa-rotate text-sm"></i>
|
|
<span>Sinkron Database</span>
|
|
</a>
|
|
<a href="{{ route('settings.reset-data.index') }}"
|
|
class="flex items-center gap-3 rounded-xl px-4 py-3 text-sm font-medium transition {{ request()->routeIs('settings.reset-data.*') ? 'bg-rose-50 text-rose-700' : 'text-slate-500 hover:bg-rose-50 hover:text-rose-700' }}">
|
|
<i class="fa-solid fa-trash-can text-sm"></i>
|
|
<span>Kosongkan Data</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="mt-auto border-t border-slate-200 px-4 py-3">
|
|
<div class="text-center">
|
|
<span class="text-[10px] font-semibold uppercase tracking-[0.22em] text-slate-400">Developed by</span>
|
|
<a href="https://noctkj.net" target="_blank" rel="noopener noreferrer" class="mt-1 block text-sm font-semibold tracking-[0.04em] text-slate-700 transition hover:text-indigo-600">
|
|
noctkj.net
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<div class="lg:pl-72">
|
|
<header class="sticky top-0 z-30 border-b border-slate-200 bg-white/80 backdrop-blur-xl">
|
|
<div class="flex h-20 items-center justify-between px-4 sm:px-6 lg:px-8">
|
|
<div class="flex items-center gap-3">
|
|
<button @click="sidebarOpen = true" class="inline-flex h-11 w-11 items-center justify-center rounded-xl border border-slate-200 bg-white text-slate-500 shadow-sm lg:hidden">
|
|
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8" d="M4 6h16M4 12h16M4 18h16" />
|
|
</svg>
|
|
</button>
|
|
|
|
<div>
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-slate-400">Panel Admin</p>
|
|
<h1 class="text-lg font-semibold text-slate-900">{{ $branding['app_name'] ?? 'Database Kesiswaan' }}</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3">
|
|
<div class="relative" @click.away="profileMenuOpen = false">
|
|
@php
|
|
$currentUser = auth()->user();
|
|
$currentUserName = data_get($currentUser, 'name', 'User');
|
|
$currentUserEmail = data_get($currentUser, 'email', '-');
|
|
$currentUserInitial = strtoupper(substr((string) $currentUserName, 0, 1)) ?: 'U';
|
|
@endphp
|
|
|
|
<button
|
|
type="button"
|
|
@click="profileMenuOpen = !profileMenuOpen"
|
|
class="flex items-center gap-3 rounded-2xl border border-slate-200 bg-white px-3 py-2 shadow-sm transition hover:border-indigo-200 hover:bg-slate-50"
|
|
>
|
|
<div class="hidden text-right md:block">
|
|
<div class="text-sm font-semibold text-slate-800">{{ $currentUserName }}</div>
|
|
<div class="text-xs text-slate-500">{{ $isAdmin ? 'Administrator' : 'Staff' }}</div>
|
|
</div>
|
|
|
|
<div class="flex h-11 w-11 items-center justify-center rounded-full bg-indigo-100 text-sm font-bold text-indigo-700">
|
|
{{ $currentUserInitial }}
|
|
</div>
|
|
|
|
<svg class="hidden h-4 w-4 text-slate-400 transition-transform md:block" :class="profileMenuOpen ? 'rotate-180' : ''" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8" d="m6 9 6 6 6-6" />
|
|
</svg>
|
|
</button>
|
|
|
|
<div
|
|
x-show="profileMenuOpen"
|
|
x-transition.origin.top.right
|
|
class="absolute right-0 z-50 mt-3 w-60 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-xl shadow-slate-200/70"
|
|
>
|
|
<div class="border-b border-slate-100 px-4 py-4">
|
|
<div class="text-sm font-semibold text-slate-800">{{ $currentUserName }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">{{ $currentUserEmail }}</div>
|
|
</div>
|
|
<div class="p-2">
|
|
<a href="{{ route('profile.edit') }}" class="flex items-center gap-3 rounded-xl px-3 py-3 text-sm font-medium text-slate-700 transition hover:bg-slate-50 hover:text-indigo-700">
|
|
<i class="fa-solid fa-id-badge text-sm"></i>
|
|
<span>Profil Administrator</span>
|
|
</a>
|
|
<form method="POST" action="{{ route('logout') }}">
|
|
@csrf
|
|
<button type="submit" class="flex w-full items-center gap-3 rounded-xl px-3 py-3 text-sm font-medium text-rose-600 transition hover:bg-rose-50">
|
|
<i class="fa-solid fa-right-from-bracket text-sm"></i>
|
|
<span>Logout</span>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="px-4 py-6 sm:px-6 lg:px-8">
|
|
@isset($header)
|
|
<div class="mb-6 rounded-2xl border border-slate-200 bg-white px-6 py-5 shadow-sm">
|
|
{{ $header }}
|
|
</div>
|
|
@endisset
|
|
|
|
{{ $slot }}
|
|
</main>
|
|
</div>
|
|
</div>
|