feat: dukung status PKL/Magang (pkl) dari e-jurnal — validasi sync + pkl; rekap mingguan/bulanan kolom P; export Excel kolom P; warna selaras e-jurnal (S=amber, P=violet)
This commit is contained in:
@@ -144,8 +144,9 @@
|
||||
$color = match($status) {
|
||||
'hadir' => 'text-emerald-600 bg-emerald-50',
|
||||
'alpha' => 'text-red-600 bg-red-50',
|
||||
'sakit' => 'text-purple-600 bg-purple-50',
|
||||
'sakit' => 'text-amber-600 bg-amber-50',
|
||||
'izin' => 'text-blue-600 bg-blue-50',
|
||||
'pkl' => 'text-violet-600 bg-violet-50',
|
||||
'terlambat' => 'text-yellow-600 bg-yellow-50',
|
||||
default => 'text-gray-300',
|
||||
};
|
||||
@@ -154,6 +155,7 @@
|
||||
'alpha' => 'A',
|
||||
'sakit' => 'S',
|
||||
'izin' => 'I',
|
||||
'pkl' => 'P',
|
||||
'terlambat' => 'T',
|
||||
default => '-',
|
||||
};
|
||||
@@ -172,7 +174,8 @@
|
||||
<div class="px-5 py-3 border-t border-gray-100 bg-gray-50/50 text-xs text-gray-400 text-center flex items-center justify-center gap-4">
|
||||
<span><span class="inline-block w-7 h-7 rounded-lg bg-emerald-50 text-emerald-600 text-center text-xs font-bold">H</span> Hadir</span>
|
||||
<span><span class="inline-block w-7 h-7 rounded-lg bg-red-50 text-red-600 text-center text-xs font-bold">A</span> Alpha</span>
|
||||
<span><span class="inline-block w-7 h-7 rounded-lg bg-purple-50 text-purple-600 text-center text-xs font-bold">S</span> Sakit</span>
|
||||
<span><span class="inline-block w-7 h-7 rounded-lg bg-amber-50 text-amber-600 text-center text-xs font-bold">S</span> Sakit</span>
|
||||
<span><span class="inline-block w-7 h-7 rounded-lg bg-violet-50 text-violet-600 text-center text-xs font-bold">P</span> PKL</span>
|
||||
<span><span class="inline-block w-7 h-7 rounded-lg bg-blue-50 text-blue-600 text-center text-xs font-bold">I</span> Izin</span>
|
||||
<span><span class="inline-block w-7 h-7 rounded-lg bg-yellow-50 text-yellow-600 text-center text-xs font-bold">T</span> Terlambat</span>
|
||||
</div>
|
||||
@@ -226,7 +229,7 @@
|
||||
<span class="text-[10px] text-gray-400 font-normal">{{ \Carbon\Carbon::parse($row['date'])->format('d/m') }}</span>
|
||||
</th>
|
||||
@endforeach
|
||||
<th colspan="4" class="px-3 py-2 text-center text-xs font-semibold text-gray-800 uppercase tracking-wider border-b border-slate-200 border-l-2 border-gray-400 bg-gray-100/80">
|
||||
<th colspan="5" class="px-3 py-2 text-center text-xs font-semibold text-gray-800 uppercase tracking-wider border-b border-slate-200 border-l-2 border-gray-400 bg-gray-100/80">
|
||||
TOTAL<br>
|
||||
<span class="text-[10px] text-gray-500 font-normal">Hari</span>
|
||||
</th>
|
||||
@@ -237,14 +240,16 @@
|
||||
$sep = !$loop->last ? 'border-r-2 border-gray-300' : '';
|
||||
@endphp
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-emerald-600 uppercase tracking-wider">H</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-purple-600 uppercase tracking-wider">S</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-amber-600 uppercase tracking-wider">S</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-blue-600 uppercase tracking-wider">I</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-red-600 uppercase tracking-wider {{ $sep }}">A</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-red-600 uppercase tracking-wider">A</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-violet-600 uppercase tracking-wider {{ $sep }}">P</th>
|
||||
@endforeach
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-emerald-700 uppercase tracking-wider bg-gray-100/80 border-l-2 border-gray-400">H</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-purple-700 uppercase tracking-wider bg-gray-100/80">S</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-amber-700 uppercase tracking-wider bg-gray-100/80">S</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-blue-700 uppercase tracking-wider bg-gray-100/80">I</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-red-700 uppercase tracking-wider bg-gray-100/80">A</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-violet-700 uppercase tracking-wider bg-gray-100/80">P</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-50">
|
||||
@@ -260,24 +265,27 @@
|
||||
@endphp
|
||||
@if($s)
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-emerald-600">{{ $s['hadir'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-purple-600">{{ $s['sakit'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-amber-600">{{ $s['sakit'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-blue-600">{{ $s['izin'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $s['alpha'] > 0 ? 'text-red-600' : 'text-gray-400' }} {{ $sep }}">{{ $s['alpha'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $s['alpha'] > 0 ? 'text-red-600' : 'text-gray-400' }}">{{ $s['alpha'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $s['pkl'] > 0 ? 'text-violet-600' : 'text-gray-400' }} {{ $sep }}">{{ $s['pkl'] }}</td>
|
||||
@else
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300">—</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300">—</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300">—</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300">—</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300 {{ $sep }}">—</td>
|
||||
@endif
|
||||
@endforeach
|
||||
{{-- TOTAL --}}
|
||||
@php
|
||||
$t = $totals[$student->id] ?? ['hadir' => 0, 'sakit' => 0, 'izin' => 0, 'alpha' => 0];
|
||||
$t = $totals[$student->id] ?? ['hadir' => 0, 'sakit' => 0, 'izin' => 0, 'alpha' => 0, 'pkl' => 0];
|
||||
@endphp
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-emerald-700 bg-gray-50 border-l-2 border-gray-300">{{ $t['hadir'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-purple-700 bg-gray-50">{{ $t['sakit'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-amber-700 bg-gray-50">{{ $t['sakit'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-blue-700 bg-gray-50">{{ $t['izin'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $t['alpha'] > 0 ? 'text-red-700' : 'text-gray-400' }} bg-gray-50">{{ $t['alpha'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $t['pkl'] > 0 ? 'text-violet-700' : 'text-gray-400' }} bg-gray-50">{{ $t['pkl'] }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@@ -285,7 +293,8 @@
|
||||
</div>
|
||||
<div class="px-5 py-3 border-t border-gray-100 bg-gray-50/50 text-xs text-gray-400 text-center flex items-center justify-center gap-4">
|
||||
<span class="text-emerald-600 font-bold">H</span> Hadir
|
||||
<span class="text-purple-600 font-bold">S</span> Sakit
|
||||
<span class="text-amber-600 font-bold">S</span> Sakit
|
||||
<span class="text-violet-600 font-bold">P</span> PKL
|
||||
<span class="text-blue-600 font-bold">I</span> Izin
|
||||
<span class="text-red-600 font-bold">A</span> Alpha
|
||||
</div>
|
||||
@@ -339,7 +348,7 @@
|
||||
<span class="text-[10px] text-gray-400 font-normal">{{ \Carbon\Carbon::parse($row['start'])->format('d/m') }}-{{ \Carbon\Carbon::parse($row['end'])->format('d/m') }}</span>
|
||||
</th>
|
||||
@endforeach
|
||||
<th colspan="4" class="px-3 py-2 text-center text-xs font-semibold text-gray-800 uppercase tracking-wider border-b border-slate-200 border-l-2 border-gray-400 bg-gray-100/80">
|
||||
<th colspan="5" class="px-3 py-2 text-center text-xs font-semibold text-gray-800 uppercase tracking-wider border-b border-slate-200 border-l-2 border-gray-400 bg-gray-100/80">
|
||||
TOTAL<br>
|
||||
<span class="text-[10px] text-gray-500 font-normal">Hari</span>
|
||||
</th>
|
||||
@@ -350,14 +359,16 @@
|
||||
$sep = !$loop->last ? 'border-r-2 border-gray-300' : '';
|
||||
@endphp
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-emerald-600 uppercase tracking-wider">H</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-purple-600 uppercase tracking-wider">S</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-amber-600 uppercase tracking-wider">S</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-blue-600 uppercase tracking-wider">I</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-red-600 uppercase tracking-wider {{ $sep }}">A</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-red-600 uppercase tracking-wider">A</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-violet-600 uppercase tracking-wider {{ $sep }}">P</th>
|
||||
@endforeach
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-emerald-700 uppercase tracking-wider bg-gray-100/80 border-l-2 border-gray-400">H</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-purple-700 uppercase tracking-wider bg-gray-100/80">S</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-amber-700 uppercase tracking-wider bg-gray-100/80">S</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-blue-700 uppercase tracking-wider bg-gray-100/80">I</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-red-700 uppercase tracking-wider bg-gray-100/80">A</th>
|
||||
<th class="px-2 py-1.5 text-center text-[10px] font-bold text-violet-700 uppercase tracking-wider bg-gray-100/80">P</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-50">
|
||||
@@ -373,24 +384,27 @@
|
||||
@endphp
|
||||
@if($s)
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-emerald-600">{{ $s['hadir'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-purple-600">{{ $s['sakit'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-amber-600">{{ $s['sakit'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-blue-600">{{ $s['izin'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $s['alpha'] > 0 ? 'text-red-600' : 'text-gray-400' }} {{ $sep }}">{{ $s['alpha'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $s['alpha'] > 0 ? 'text-red-600' : 'text-gray-400' }}">{{ $s['alpha'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $s['pkl'] > 0 ? 'text-violet-600' : 'text-gray-400' }} {{ $sep }}">{{ $s['pkl'] }}</td>
|
||||
@else
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300">—</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300">—</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300">—</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300">—</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs text-gray-300 {{ $sep }}">—</td>
|
||||
@endif
|
||||
@endforeach
|
||||
{{-- TOTAL --}}
|
||||
@php
|
||||
$t = $totals[$student->id] ?? ['hadir' => 0, 'sakit' => 0, 'izin' => 0, 'alpha' => 0];
|
||||
$t = $totals[$student->id] ?? ['hadir' => 0, 'sakit' => 0, 'izin' => 0, 'alpha' => 0, 'pkl' => 0];
|
||||
@endphp
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-emerald-700 bg-gray-50 border-l-2 border-gray-300">{{ $t['hadir'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-purple-700 bg-gray-50">{{ $t['sakit'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-amber-700 bg-gray-50">{{ $t['sakit'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold text-blue-700 bg-gray-50">{{ $t['izin'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $t['alpha'] > 0 ? 'text-red-700' : 'text-gray-400' }} bg-gray-50">{{ $t['alpha'] }}</td>
|
||||
<td class="px-2 py-2.5 text-center text-xs font-bold {{ $t['pkl'] > 0 ? 'text-violet-700' : 'text-gray-400' }} bg-gray-50">{{ $t['pkl'] }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@@ -398,7 +412,8 @@
|
||||
</div>
|
||||
<div class="px-5 py-3 border-t border-gray-100 bg-gray-50/50 text-xs text-gray-400 text-center flex items-center justify-center gap-4">
|
||||
<span class="text-emerald-600 font-bold">H</span> Hadir
|
||||
<span class="text-purple-600 font-bold">S</span> Sakit
|
||||
<span class="text-amber-600 font-bold">S</span> Sakit
|
||||
<span class="text-violet-600 font-bold">P</span> PKL
|
||||
<span class="text-blue-600 font-bold">I</span> Izin
|
||||
<span class="text-red-600 font-bold">A</span> Alpha
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
@include('errors._error', [
|
||||
@include('errors.layout', [
|
||||
'code' => '403',
|
||||
'title' => 'Akses Ditolak',
|
||||
'message' => 'Anda tidak memiliki izin untuk mengakses halaman ini. Jika menurut Anda ini keliru, silakan hubungi administrator.',
|
||||
'icon' => 'fa-lock',
|
||||
'iconFrom' => '#ef4444', 'iconTo' => '#dc2626', 'iconShadow' => 'rgba(239, 68, 68, 0.35)',
|
||||
'codeFrom' => '#f87171', 'codeTo' => '#dc2626',
|
||||
'ctaFrom' => '#ef4444', 'ctaTo' => '#dc2626', 'ctaShadow' => 'rgba(239, 68, 68, 0.35)',
|
||||
'showContact' => true,
|
||||
'message' => 'Kamu tidak memiliki izin untuk membuka halaman ini. Jika menurutmu ini sebuah kesalahan, silakan hubungi administrator.',
|
||||
'image' => 'error-403.png',
|
||||
])
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
@include('errors._error', [
|
||||
@include('errors.layout', [
|
||||
'code' => '404',
|
||||
'title' => 'Halaman Tidak Ditemukan',
|
||||
'message' => 'Halaman yang Anda cari mungkin telah dipindah, dihapus, atau alamatnya salah. Coba periksa kembali atau kembali ke beranda.',
|
||||
'icon' => 'fa-map',
|
||||
'iconFrom' => '#f59e0b', 'iconTo' => '#f97316', 'iconShadow' => 'rgba(245, 158, 11, 0.35)',
|
||||
'codeFrom' => '#fbbf24', 'codeTo' => '#f97316',
|
||||
'ctaFrom' => '#f59e0b', 'ctaTo' => '#f97316', 'ctaShadow' => 'rgba(249, 115, 22, 0.35)',
|
||||
'message' => 'Halaman yang kamu cari sepertinya telah dipindahkan, dihapus, atau alamatnya salah. Coba periksa kembali alamatnya ya.',
|
||||
'image' => 'error-404.png',
|
||||
])
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
@include('errors._error', [
|
||||
@include('errors.layout', [
|
||||
'code' => '419',
|
||||
'title' => 'Sesi Berakhir',
|
||||
'message' => 'Sesi Anda telah berakhir atau tidak valid. Silakan muat ulang halaman dan coba lagi.',
|
||||
'icon' => 'fa-hourglass-half',
|
||||
'iconFrom' => '#f59e0b', 'iconTo' => '#d97706', 'iconShadow' => 'rgba(245, 158, 11, 0.35)',
|
||||
'codeFrom' => '#fbbf24', 'codeTo' => '#d97706',
|
||||
'ctaFrom' => '#f59e0b', 'ctaTo' => '#d97706', 'ctaShadow' => 'rgba(245, 158, 11, 0.35)',
|
||||
'message' => 'Sesi login kamu sudah kedaluwarsa. Muat ulang halaman ini lalu masuk kembali untuk melanjutkan aktivitas.',
|
||||
'image' => 'error-419.png',
|
||||
])
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
@include('errors.layout', [
|
||||
'code' => '429',
|
||||
'title' => 'Terlalu Banyak Permintaan',
|
||||
'message' => 'Kamu mengirim terlalu banyak permintaan dalam waktu singkat. Tunggu beberapa saat, lalu coba lagi.',
|
||||
'image' => 'error-429.png',
|
||||
])
|
||||
@@ -1,10 +1,6 @@
|
||||
@include('errors._error', [
|
||||
@include('errors.layout', [
|
||||
'code' => '500',
|
||||
'title' => 'Terjadi Kesalahan',
|
||||
'message' => 'Maaf, terjadi kendala pada server kami. Silakan muat ulang halaman atau coba lagi beberapa saat. Jika terus berlanjut, hubungi administrator.',
|
||||
'icon' => 'fa-triangle-exclamation',
|
||||
'iconFrom' => '#8b5cf6', 'iconTo' => '#7c3aed', 'iconShadow' => 'rgba(139, 92, 246, 0.35)',
|
||||
'codeFrom' => '#a78bfa', 'codeTo' => '#7c3aed',
|
||||
'ctaFrom' => '#8b5cf6', 'ctaTo' => '#7c3aed', 'ctaShadow' => 'rgba(139, 92, 246, 0.35)',
|
||||
'showContact' => true,
|
||||
'title' => 'Terjadi Kesalahan Server',
|
||||
'message' => 'Ups, terjadi kendala di server kami. Tim kami sudah mendapat laporan dan akan segera memperbaikinya. Coba lagi dalam beberapa saat.',
|
||||
'image' => 'error-500.png',
|
||||
])
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
@include('errors._error', [
|
||||
@include('errors.layout', [
|
||||
'code' => '503',
|
||||
'title' => 'Sedang Pemeliharaan',
|
||||
'message' => 'Sistem sedang dalam pemeliharaan. Silakan kembali beberapa saat lagi. Terima kasih atas kesabaran Anda.',
|
||||
'icon' => 'fa-screwdriver-wrench',
|
||||
'iconFrom' => '#0ea5e9', 'iconTo' => '#0284c7', 'iconShadow' => 'rgba(14, 165, 233, 0.35)',
|
||||
'codeFrom' => '#38bdf8', 'codeTo' => '#0284c7',
|
||||
'ctaFrom' => '#0ea5e9', 'ctaTo' => '#0284c7', 'ctaShadow' => 'rgba(14, 165, 233, 0.35)',
|
||||
'showBack' => false,
|
||||
'title' => 'Sedang Dalam Perbaikan',
|
||||
'message' => 'Sistem sedang dalam perawatan sebentar. Tenang, data ketertiban dan poin kamu tetap aman. Silakan kembali beberapa saat lagi.',
|
||||
'image' => 'error-503.png',
|
||||
])
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
{{-- Template halaman error premium v2 (standalone, CSS murni — tanpa CDN) --}}
|
||||
@php
|
||||
$appName = \App\Models\Setting::getValue('app_name', 'Aplikasi Ketertiban');
|
||||
$schoolName = \App\Models\Setting::getValue('school_name', 'SMKN 1 Wonorejo');
|
||||
@endphp
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>{{ $code }} - {{ $title }} | {{ $appName }}</title>
|
||||
<link rel="stylesheet" href="/vendor/font-awesome/css/all.min.css">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
html, body { height: 100%; }
|
||||
body {
|
||||
min-height: 100vh; display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px; position: relative; overflow: hidden;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
|
||||
background:
|
||||
radial-gradient(1200px 600px at 80% -10%, {{ $ctaFrom }}22, transparent 60%),
|
||||
radial-gradient(900px 500px at -10% 110%, {{ $ctaTo }}1f, transparent 60%),
|
||||
linear-gradient(135deg, #f8fafc 0%, #eef4ff 50%, #f4f8ff 100%);
|
||||
}
|
||||
{{-- Pola grid halus --}}
|
||||
.bg-grid {
|
||||
position: absolute; inset: 0; pointer-events: none; opacity: .5;
|
||||
background-image:
|
||||
linear-gradient(rgba(100,116,139,.06) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(100,116,139,.06) 1px, transparent 1px);
|
||||
background-size: 44px 44px;
|
||||
mask-image: radial-gradient(ellipse at center, #000 30%, transparent 75%);
|
||||
-webkit-mask-image: radial-gradient(ellipse at center, #000 30%, transparent 75%);
|
||||
}
|
||||
{{-- Orb mengambang --}}
|
||||
.orb { position: absolute; border-radius: 9999px; filter: blur(70px); pointer-events: none; animation: drift 14s ease-in-out infinite; }
|
||||
.orb-1 { width: 420px; height: 420px; top: -120px; right: -100px; background: {{ $ctaFrom }}38; }
|
||||
.orb-2 { width: 480px; height: 480px; bottom: -160px; left: -120px; background: {{ $ctaTo }}33; animation-delay: -5s; }
|
||||
.orb-3 { width: 220px; height: 220px; top: 40%; left: 55%; background: {{ $codeFrom }}26; animation-delay: -9s; }
|
||||
@keyframes drift {
|
||||
0%, 100% { transform: translate(0, 0) scale(1); }
|
||||
50% { transform: translate(30px, -30px) scale(1.08); }
|
||||
}
|
||||
{{-- Titik dekoratif --}}
|
||||
.dots {
|
||||
position: absolute; inset: 0; pointer-events: none; opacity: .35;
|
||||
background-image: radial-gradient(rgba(148,163,184,.35) 1.2px, transparent 1.2px);
|
||||
background-size: 26px 26px;
|
||||
mask-image: radial-gradient(ellipse at 50% 40%, #000 10%, transparent 70%);
|
||||
-webkit-mask-image: radial-gradient(ellipse at 50% 40%, #000 10%, transparent 70%);
|
||||
}
|
||||
|
||||
{{-- Kartu glass + border gradien berputar --}}
|
||||
.card {
|
||||
position: relative; z-index: 10; width: 100%; max-width: 500px;
|
||||
background: rgba(255,255,255,.72); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
|
||||
border-radius: 30px; padding: 44px 36px; text-align: center;
|
||||
box-shadow: 0 30px 70px -20px rgba(15,23,42,.25), 0 0 0 1px rgba(255,255,255,.6) inset;
|
||||
animation: fadeUp .55s cubic-bezier(.22,.9,.3,1.2) both;
|
||||
}
|
||||
.card::before {
|
||||
content: ""; position: absolute; inset: -2px; border-radius: 32px; z-index: -1;
|
||||
background: conic-gradient(from var(--angle, 0deg),
|
||||
transparent 0%, {{ $ctaTo }} 12%, transparent 26%,
|
||||
transparent 50%, {{ $ctaFrom }} 62%, transparent 78%);
|
||||
animation: spin 7s linear infinite;
|
||||
}
|
||||
@property --angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
|
||||
@keyframes spin { to { --angle: 360deg; } }
|
||||
@keyframes fadeUp { from { opacity: 0; transform: translateY(22px) scale(.98); } to { opacity: 1; transform: none; } }
|
||||
|
||||
.icon-box {
|
||||
width: 92px; height: 92px; margin: 0 auto 26px; position: relative;
|
||||
border-radius: 26px; display: flex; align-items: center; justify-content: center;
|
||||
background: linear-gradient(135deg, {{ $iconFrom }}, {{ $iconTo }});
|
||||
box-shadow: 0 16px 34px {{ $iconShadow }}, 0 0 0 6px rgba(255,255,255,.7);
|
||||
animation: floaty 3.2s ease-in-out infinite;
|
||||
}
|
||||
.icon-box::after {
|
||||
content: ""; position: absolute; inset: -14px; border-radius: 34px;
|
||||
background: linear-gradient(135deg, {{ $iconFrom }}33, transparent 60%);
|
||||
filter: blur(8px); z-index: -1;
|
||||
}
|
||||
.icon-box i { font-size: 34px; color: #fff; filter: drop-shadow(0 3px 6px rgba(0,0,0,.18)); }
|
||||
@keyframes floaty { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
|
||||
|
||||
{{-- Angka besar berlapis --}}
|
||||
.code-wrap { position: relative; margin-bottom: 14px; }
|
||||
.code {
|
||||
position: relative; z-index: 2; font-size: 108px; font-weight: 900; letter-spacing: -4px; line-height: 1;
|
||||
background: linear-gradient(135deg, {{ $codeFrom }}, {{ $codeTo }});
|
||||
-webkit-background-clip: text; background-clip: text; color: transparent;
|
||||
filter: drop-shadow(0 10px 24px {{ $iconShadow }});
|
||||
}
|
||||
.code-ghost {
|
||||
position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
|
||||
font-size: 190px; font-weight: 900; letter-spacing: -6px; line-height: 1;
|
||||
color: transparent; -webkit-text-stroke: 1.5px {{ $codeFrom }}1f;
|
||||
pointer-events: none; user-select: none;
|
||||
}
|
||||
|
||||
h1 { font-size: 21px; font-weight: 800; color: #0f172a; margin-bottom: 10px; }
|
||||
.msg { font-size: 14px; color: #64748b; line-height: 1.7; margin-bottom: 34px; }
|
||||
|
||||
.actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
|
||||
.btn {
|
||||
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
|
||||
padding: 13px 22px; font-size: 14px; font-weight: 700; border-radius: 16px;
|
||||
text-decoration: none; border: 2px solid transparent; cursor: pointer;
|
||||
transition: transform .15s ease, box-shadow .15s ease, background .15s ease, border-color .15s ease;
|
||||
animation: fadeUp .55s cubic-bezier(.22,.9,.3,1.2) both;
|
||||
}
|
||||
.btn:hover { transform: translateY(-2px); }
|
||||
.btn:active { transform: translateY(0) scale(.98); }
|
||||
.btn-ghost { background: rgba(255,255,255,.9); color: #334155; border-color: #e2e8f0; animation-delay: .08s; }
|
||||
.btn-ghost:hover { background: #fff; border-color: #cbd5e1; }
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, {{ $ctaFrom }}, {{ $ctaTo }}); color: #fff;
|
||||
box-shadow: 0 12px 28px {{ $ctaShadow }};
|
||||
}
|
||||
.btn-primary:hover { filter: brightness(1.06); box-shadow: 0 16px 34px {{ $ctaShadow }}; }
|
||||
.btn-contact { background: #eff6ff; color: #2563eb; border-color: #dbeafe; animation-delay: .16s; }
|
||||
.btn-contact:hover { background: #dbeafe; }
|
||||
|
||||
.footer { text-align: center; margin-top: 26px; font-size: 12px; color: #94a3b8; animation: fadeUp .55s both .22s; }
|
||||
.footer i { margin-right: 5px; color: #cbd5e1; }
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.card { padding: 34px 22px; }
|
||||
.code { font-size: 84px; letter-spacing: -3px; }
|
||||
.code-ghost { font-size: 140px; }
|
||||
.actions { flex-direction: column; }
|
||||
.btn { width: 100%; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-grid"></div>
|
||||
<div class="orb orb-1"></div>
|
||||
<div class="orb orb-2"></div>
|
||||
<div class="orb orb-3"></div>
|
||||
<div class="dots"></div>
|
||||
|
||||
<div class="card">
|
||||
<div class="icon-box"><i class="fa-solid {{ $icon }}"></i></div>
|
||||
<div class="code-wrap">
|
||||
<div class="code-ghost">{{ $code }}</div>
|
||||
<div class="code">{{ $code }}</div>
|
||||
</div>
|
||||
<h1>{{ $title }}</h1>
|
||||
<p class="msg">{{ $message }}</p>
|
||||
|
||||
<div class="actions">
|
||||
@if($showBack ?? true)
|
||||
<button onclick="history.length > 1 ? history.back() : window.location.href='{{ url('/') }}'" class="btn btn-ghost">
|
||||
<i class="fa-solid fa-arrow-left" style="font-size:12px"></i> Kembali
|
||||
</button>
|
||||
@endif
|
||||
<a href="{{ url('/') }}" class="btn btn-primary">
|
||||
<i class="fa-solid fa-house" style="font-size:12px"></i> Ke Beranda
|
||||
</a>
|
||||
@if($showContact ?? false)
|
||||
<a href="mailto:admin@smkn1-wonorejo.sch.id" class="btn btn-contact">
|
||||
<i class="fa-solid fa-headset" style="font-size:12px"></i> Hubungi Admin
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="footer"><i class="fa-solid fa-shield-halved"></i>{{ $appName }} • {{ $schoolName }}</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,130 @@
|
||||
@php
|
||||
$appName = \App\Models\Setting::getValue('app_name', config('app.name', 'Aplikasi Ketertiban'));
|
||||
$schoolName = \App\Models\Setting::getValue('school_name', 'SMKN 1 Wonorejo');
|
||||
@endphp
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="theme-color" content="#2563eb">
|
||||
<title>{{ $code }} — {{ $appName }}</title>
|
||||
<style>
|
||||
* { margin:0; padding:0; box-sizing:border-box; }
|
||||
html, body { height:100%; }
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background:#ffffff; color:#1e293b;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
min-height:100vh; padding:32px 20px; position:relative; overflow-x:hidden;
|
||||
}
|
||||
/* dekorasi background biru sangat muda */
|
||||
body::before, body::after {
|
||||
content:''; position:fixed; border-radius:50%; z-index:0; pointer-events:none;
|
||||
}
|
||||
body::before {
|
||||
width:460px; height:460px; background:rgba(219,234,254,.55);
|
||||
top:-140px; right:-120px; filter:blur(20px);
|
||||
}
|
||||
body::after {
|
||||
width:400px; height:400px; background:rgba(204,251,241,.5);
|
||||
bottom:-130px; left:-100px; filter:blur(20px);
|
||||
}
|
||||
.page { width:100%; max-width:1040px; position:relative; z-index:1; }
|
||||
.card {
|
||||
display:grid; grid-template-columns:45fr 55fr; gap:40px; align-items:center;
|
||||
background:#fff; border-radius:28px; padding:56px 52px;
|
||||
box-shadow:0 30px 70px -20px rgba(30,58,138,.18);
|
||||
border:1px solid #eef2f7;
|
||||
}
|
||||
/* ===== Kolom kiri: teks ===== */
|
||||
.text-side { text-align:left; }
|
||||
.code {
|
||||
font-size:116px; font-weight:900; line-height:1; letter-spacing:1px;
|
||||
color:#1e3a8a; font-variant-numeric:tabular-nums;
|
||||
}
|
||||
h1 { font-size:27px; font-weight:800; color:#0f172a; margin-top:6px; }
|
||||
.divider {
|
||||
width:56px; height:5px; border-radius:99px; background:#2563eb; margin:18px 0 16px;
|
||||
}
|
||||
p.desc { font-size:15.5px; line-height:1.75; color:#334155; max-width:400px; }
|
||||
.actions { margin-top:30px; display:flex; flex-direction:column; align-items:flex-start; gap:16px; }
|
||||
.btn-primary {
|
||||
display:inline-flex; align-items:center; gap:10px; padding:14px 28px; border-radius:12px;
|
||||
background:#2563eb; color:#fff; font-size:14.5px; font-weight:700; text-decoration:none;
|
||||
box-shadow:0 10px 24px -8px rgba(37,99,235,.55); transition:.2s; border:0; cursor:pointer; font-family:inherit;
|
||||
}
|
||||
.btn-primary:hover { transform:translateY(-2px); box-shadow:0 14px 28px -8px rgba(37,99,235,.6); }
|
||||
.btn-link {
|
||||
display:inline-flex; align-items:center; gap:8px; padding:6px 2px;
|
||||
background:none; border:0; color:#1d4ed8; font-size:14px; font-weight:700; cursor:pointer;
|
||||
text-decoration:none; font-family:inherit; transition:.2s;
|
||||
}
|
||||
.btn-link:hover { opacity:.75; }
|
||||
/* ===== Kolom kanan: ilustrasi ===== */
|
||||
.art-side { display:flex; justify-content:center; align-items:center; }
|
||||
.art {
|
||||
width:100%; max-width:460px; height:auto; object-fit:contain; display:block;
|
||||
}
|
||||
/* ===== Info box footer ===== */
|
||||
.infobox {
|
||||
margin-top:22px; display:flex; align-items:center; gap:14px;
|
||||
background:#fff; border:1px solid #e2e8f0; border-radius:16px;
|
||||
padding:15px 22px; box-shadow:0 10px 30px -18px rgba(30,58,138,.25);
|
||||
}
|
||||
.ico-info {
|
||||
flex:0 0 auto; width:28px; height:28px; border-radius:50%;
|
||||
background:#dbeafe; color:#2563eb; font-weight:800; font-size:15px;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
}
|
||||
.info-text { flex:1; font-size:13.5px; color:#334155; line-height:1.6; }
|
||||
.ico-lock { flex:0 0 auto; color:#93c5fd; display:flex; }
|
||||
/* ===== Responsif ===== */
|
||||
@media (max-width:820px){
|
||||
body { padding:24px 16px; }
|
||||
.card { grid-template-columns:1fr; gap:18px; padding:30px 24px 26px; border-radius:22px; text-align:center; }
|
||||
.text-side { text-align:center; display:flex; flex-direction:column; align-items:center; }
|
||||
.actions { align-items:center; margin-top:24px; }
|
||||
.divider { margin-left:auto; margin-right:auto; }
|
||||
.code { font-size:84px; }
|
||||
h1 { font-size:22px; }
|
||||
p.desc { max-width:100%; }
|
||||
.art { max-width:280px; }
|
||||
.infobox { padding:13px 16px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="card">
|
||||
<div class="text-side">
|
||||
<div class="code">{{ $code }}</div>
|
||||
<h1>{{ $title }}</h1>
|
||||
<div class="divider"></div>
|
||||
<p class="desc">{{ $message }}</p>
|
||||
<div class="actions">
|
||||
<a class="btn-primary" href="{{ url('/') }}">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10.5 12 3l9 7.5"/><path d="M5 9.5V21h14V9.5"/></svg>
|
||||
Kembali ke Beranda
|
||||
</a>
|
||||
<button class="btn-link" type="button" onclick="history.length > 1 ? history.back() : location.href='/'">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5"/><path d="m12 19-7-7 7-7"/></svg>
|
||||
Kembali
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="art-side">
|
||||
<img class="art" src="{{ asset('errors/' . $image) }}" alt="{{ $title }}" onerror="this.onerror=null;this.src='{{ asset('errors/placeholder.svg') }}'">
|
||||
</div>
|
||||
</div>
|
||||
<div class="infobox">
|
||||
<span class="ico-info">i</span>
|
||||
<span class="info-text">Butuh bantuan? Hubungi administrator {{ $schoolName }} untuk informasi lebih lanjut.</span>
|
||||
<span class="ico-lock">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="11" width="16" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user