344 lines
13 KiB
PHP
344 lines
13 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
<title>{{ config('app.name', 'Laravel') }}</title>
|
|
<link rel="icon" type="image/png" href="{{ asset('Lambang_Kabupaten_Pasuruan.png') }}">
|
|
<link rel="preconnect" href="https://fonts.bunny.net">
|
|
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet"/>
|
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
|
<style>
|
|
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
|
|
body{font-family:'Figtree',sans-serif;background:#f1f5f9;min-height:100dvh;-webkit-font-smoothing:antialiased;}
|
|
|
|
/* ══ NAVBAR ══ */
|
|
#nb-wrap{
|
|
position:sticky;top:0;z-index:50;
|
|
padding:10px 16px 0;
|
|
transition:padding .25s;
|
|
}
|
|
#nb-wrap.scrolled{ padding-top:0; }
|
|
|
|
#nb-shell{
|
|
max-width:80rem;margin:0 auto;
|
|
background:rgba(255,255,255,.96);
|
|
backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
|
|
border:1.5px solid #e2e8f0;
|
|
border-radius:16px;
|
|
box-shadow:0 4px 24px rgba(15,23,42,.07);
|
|
padding:14px 22px;
|
|
transition:border-radius .25s,box-shadow .25s;
|
|
will-change:transform;
|
|
transform:translateZ(0);
|
|
}
|
|
#nb-wrap.scrolled #nb-shell{
|
|
border-radius:0 0 16px 16px;
|
|
border-top:none;
|
|
box-shadow:0 8px 32px rgba(15,23,42,.10);
|
|
}
|
|
|
|
.nb-row{ display:flex;align-items:center;gap:12px; }
|
|
|
|
/* ── LINKS ── */
|
|
.nb-links{ display:flex;align-items:center;gap:8px;flex:1; }
|
|
|
|
.nb-links a{
|
|
display:inline-flex;align-items:center;
|
|
padding:10px 18px;border-radius:12px;
|
|
font-size:15px;font-weight:700;
|
|
color:#475569;background:#f8fafc;
|
|
border:1.5px solid transparent;
|
|
text-decoration:none;white-space:nowrap;
|
|
letter-spacing:.01em;
|
|
transition:background .15s,color .15s,border-color .15s,box-shadow .15s,
|
|
max-width .2s ease, opacity .2s ease, padding .2s ease, margin .2s ease;
|
|
max-width:200px;
|
|
overflow:hidden;
|
|
opacity:1;
|
|
will-change:max-width, opacity;
|
|
}
|
|
.nb-links a:hover{ background:#fff;border-color:#e2e8f0;color:#1e293b; }
|
|
.nb-links a.nb-active{
|
|
background:#2563eb;color:#fff;
|
|
border-color:#2563eb;
|
|
box-shadow:0 3px 10px rgba(37,99,235,.25);
|
|
}
|
|
|
|
.nb-links.hide-inactive a:not(.nb-active){
|
|
max-width:0;opacity:0;
|
|
padding-left:0;padding-right:0;
|
|
margin:0;border-width:0;
|
|
pointer-events:none;
|
|
}
|
|
|
|
/* ── USER ── */
|
|
.nb-user{ display:flex;align-items:center;gap:10px;flex-shrink:0; }
|
|
.nb-avatar{
|
|
width:40px;height:40px;border-radius:50%;
|
|
background:linear-gradient(135deg,#3b82f6,#2563eb);
|
|
display:flex;align-items:center;justify-content:center;
|
|
color:#fff;font-size:15px;font-weight:800;
|
|
box-shadow:0 2px 8px rgba(37,99,235,.22);flex-shrink:0;
|
|
}
|
|
.nb-name{ font-size:14px;font-weight:700;color:#374151;white-space:nowrap; }
|
|
.nb-logout{
|
|
font-size:14px;font-weight:700;color:#ef4444;
|
|
background:#fff1f2;border:1.5px solid #fecdd3;
|
|
padding:8px 16px;border-radius:10px;cursor:pointer;
|
|
transition:background .15s;white-space:nowrap;
|
|
}
|
|
.nb-logout:hover{ background:#ffe4e6; }
|
|
|
|
/* ══ MOBILE ══ */
|
|
@media(max-width:768px){
|
|
#nb-wrap{ padding:8px 8px 0; }
|
|
#nb-shell{ padding:10px 12px 12px; border-radius:14px; }
|
|
.nb-row{ flex-direction:column; align-items:stretch; gap:8px; }
|
|
|
|
/* Baris user: avatar + nama + tombol keluar */
|
|
.nb-user{
|
|
justify-content:space-between;
|
|
width:100%;
|
|
background:#f8fafc;
|
|
border:1.5px solid #e2e8f0;
|
|
border-radius:12px;
|
|
padding:10px 14px;
|
|
}
|
|
.nb-user > div:first-child{ display:flex; align-items:center; gap:10px; flex:1; }
|
|
.nb-avatar{ width:38px; height:38px; font-size:16px; flex-shrink:0; }
|
|
.nb-name{
|
|
display:block !important;
|
|
font-size:15px;
|
|
font-weight:700;
|
|
color:#1e293b;
|
|
}
|
|
.nb-logout{
|
|
font-size:14px;
|
|
font-weight:700;
|
|
padding:9px 18px;
|
|
border-radius:10px;
|
|
min-height:44px;
|
|
display:flex;
|
|
align-items:center;
|
|
white-space:nowrap;
|
|
flex-shrink:0;
|
|
}
|
|
|
|
/* Nav links: scroll horizontal, semua label tampil penuh */
|
|
.nb-links{
|
|
overflow-x:auto;
|
|
-webkit-overflow-scrolling:touch;
|
|
scrollbar-width:none;
|
|
gap:6px;
|
|
padding-bottom:2px;
|
|
display:flex !important;
|
|
flex-wrap:nowrap;
|
|
}
|
|
.nb-links::-webkit-scrollbar{ display:none; }
|
|
.nb-links a{
|
|
font-size:14px !important;
|
|
font-weight:700 !important;
|
|
padding:12px 20px !important;
|
|
border-radius:10px !important;
|
|
min-height:48px !important;
|
|
display:inline-flex !important;
|
|
align-items:center !important;
|
|
white-space:nowrap !important;
|
|
/* Paksa tampil semua — override hide-inactive */
|
|
max-width:none !important;
|
|
opacity:1 !important;
|
|
border-width:1.5px !important;
|
|
pointer-events:auto !important;
|
|
overflow:visible !important;
|
|
}
|
|
/* Paksa semua link tetap terlihat di mobile */
|
|
.nb-links.hide-inactive a:not(.nb-active){
|
|
max-width:none !important;
|
|
opacity:1 !important;
|
|
padding:12px 20px !important;
|
|
margin:0 !important;
|
|
border-width:1.5px !important;
|
|
pointer-events:auto !important;
|
|
}
|
|
}
|
|
|
|
@media(max-width:400px){
|
|
.nb-links a{ font-size:13px !important; padding:11px 16px !important; min-height:44px !important; }
|
|
.nb-logout{ font-size:13px; padding:9px 14px; }
|
|
.nb-name{ font-size:14px; }
|
|
}
|
|
|
|
/* ══ LAYOUT ══ */
|
|
.page-header{ max-width:80rem;margin:14px auto 0;padding:0 16px; }
|
|
.page-header-inner{
|
|
background:#fff;border:1.5px solid #e2e8f0;border-radius:16px;
|
|
box-shadow:0 2px 12px rgba(15,23,42,.05);padding:14px 18px;
|
|
}
|
|
.page-main{
|
|
max-width:80rem;margin:14px auto 24px;padding:0 16px;
|
|
display:flex;flex-direction:column;gap:14px;
|
|
}
|
|
|
|
@media(max-width:768px){
|
|
.page-header{ padding:0 10px;margin-top:12px; }
|
|
.page-header-inner{ padding:14px 16px;border-radius:14px; }
|
|
.page-main{ padding:0 10px;margin-top:12px;margin-bottom:24px;gap:12px; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<!-- ══ NAVBAR ══ -->
|
|
<div id="nb-wrap">
|
|
<div id="nb-shell">
|
|
<div class="nb-row">
|
|
|
|
@php $role = Auth::user()->role ?? null; @endphp
|
|
|
|
<!-- USER -->
|
|
<div class="nb-user">
|
|
<div style="display:flex;align-items:center;gap:10px;">
|
|
<div class="nb-avatar">{{ strtoupper(substr(Auth::user()->name ?? 'U', 0, 1)) }}</div>
|
|
<span class="nb-name">{{ Auth::user()->name ?? '' }}</span>
|
|
</div>
|
|
<form method="POST" action="{{ route('logout') }}">
|
|
@csrf
|
|
<button type="submit" class="nb-logout">Keluar</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- LINKS -->
|
|
<nav class="nb-links" id="nb-links">
|
|
@if($role === 'admin')
|
|
<a href="{{ route('admin.dashboard') }}"
|
|
class="{{ request()->routeIs('admin.dashboard') ? 'nb-active' : '' }}">Dashboard</a>
|
|
<a href="{{ route('admin.data-warga') }}"
|
|
class="{{ request()->routeIs('admin.data-warga') ? 'nb-active' : '' }}">Data Warga</a>
|
|
<a href="{{ route('admin.data-akun') }}"
|
|
class="{{ request()->routeIs('admin.data-akun') ? 'nb-active' : '' }}">Data Akun</a>
|
|
<a href="{{ route('admin.filterisasi') }}"
|
|
class="{{ request()->routeIs('admin.filterisasi') ? 'nb-active' : '' }}">Filterisasi</a>
|
|
<a href="{{ route('admin.laporan') }}"
|
|
class="{{ request()->routeIs('admin.laporan') ? 'nb-active' : '' }}">Laporan</a>
|
|
@else
|
|
<a href="{{ route('dashboard') }}"
|
|
class="{{ request()->routeIs('dashboard') ? 'nb-active' : '' }}">Dashboard</a>
|
|
<a href="{{ route('rt.calon-penerima.create') }}"
|
|
class="{{ request()->routeIs('rt.calon-penerima.create') ? 'nb-active' : '' }}">Inputkan Warga</a>
|
|
<a href="{{ route('rt.calon-penerima.index') }}"
|
|
class="{{ request()->routeIs('rt.calon-penerima.index') ? 'nb-active' : '' }}">Riwayat</a>
|
|
<a href="{{ route('rt.laporan.index') }}"
|
|
class="{{ request()->routeIs('rt.laporan.*') ? 'nb-active' : '' }}">Laporan</a>
|
|
@endif
|
|
</nav>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- HEADER SLOT -->
|
|
@isset($header)
|
|
<div class="page-header">
|
|
<div class="page-header-inner">{{ $header }}</div>
|
|
</div>
|
|
@endisset
|
|
|
|
<!-- MAIN -->
|
|
<main class="page-main">{{ $slot }}</main>
|
|
|
|
<script>
|
|
(function(){
|
|
var wrap = document.getElementById('nb-wrap');
|
|
var links = document.getElementById('nb-links');
|
|
|
|
/* ── scrolled class: IntersectionObserver, zero reflow ── */
|
|
var sentinel = document.createElement('div');
|
|
sentinel.style.cssText = 'position:absolute;top:1px;left:0;width:1px;height:1px;pointer-events:none;';
|
|
document.body.prepend(sentinel);
|
|
new IntersectionObserver(function(e){
|
|
e[0].isIntersecting
|
|
? wrap.classList.remove('scrolled')
|
|
: wrap.classList.add('scrolled');
|
|
}, {threshold:0}).observe(sentinel);
|
|
|
|
var MOBILE_BP = 768;
|
|
|
|
var lastY = window.scrollY;
|
|
var peakY = window.scrollY;
|
|
var hidden = false;
|
|
var rafPending = null;
|
|
|
|
var DEAD_ZONE = 8;
|
|
var UP_THRESHOLD = 32;
|
|
var BOTTOM_GUARD = 12;
|
|
|
|
function isMobile(){ return window.innerWidth <= MOBILE_BP; }
|
|
|
|
function maxScroll(){
|
|
return Math.max(0, document.documentElement.scrollHeight - window.innerHeight);
|
|
}
|
|
|
|
function applyHide(val){
|
|
if(val === hidden) return;
|
|
hidden = val;
|
|
if(val) links.classList.add('hide-inactive');
|
|
else links.classList.remove('hide-inactive');
|
|
}
|
|
|
|
function tick(){
|
|
rafPending = null;
|
|
|
|
/* Mobile: selalu tampilkan semua link, jangan collapse */
|
|
if(isMobile()){
|
|
applyHide(false);
|
|
lastY = window.scrollY;
|
|
peakY = window.scrollY;
|
|
return;
|
|
}
|
|
|
|
var y = window.scrollY;
|
|
var diff = y - lastY;
|
|
|
|
if(y > peakY) peakY = y;
|
|
|
|
/* Bottom guard */
|
|
if(y >= maxScroll() - BOTTOM_GUARD){
|
|
if(y > 50) applyHide(true);
|
|
lastY = y;
|
|
return;
|
|
}
|
|
|
|
/* Dead zone */
|
|
if(Math.abs(diff) < DEAD_ZONE){
|
|
lastY = y;
|
|
return;
|
|
}
|
|
|
|
if(diff > 0 && y > 50){
|
|
applyHide(true);
|
|
} else if(diff < 0 && hidden){
|
|
if(peakY - y >= UP_THRESHOLD){
|
|
applyHide(false);
|
|
peakY = y;
|
|
}
|
|
}
|
|
|
|
lastY = y;
|
|
}
|
|
|
|
window.addEventListener('scroll', function(){
|
|
if(rafPending) return;
|
|
rafPending = requestAnimationFrame(tick);
|
|
}, {passive:true});
|
|
|
|
/* Resize: kalau user putar layar dari landscape ke portrait, reset state */
|
|
window.addEventListener('resize', function(){
|
|
if(isMobile()) applyHide(false);
|
|
}, {passive:true});
|
|
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html> |