271 lines
8.8 KiB
PHP
271 lines
8.8 KiB
PHP
@extends('admin.layouts.app')
|
|
|
|
@section('title', 'Dashboard Admin')
|
|
|
|
@push('styles')
|
|
<style>
|
|
/* ── PAGE ── */
|
|
.dash-header { margin-bottom: 28px; }
|
|
.dash-title { font-size: 22px; font-weight: 800; color: #0f1f3d; margin-bottom: 2px; }
|
|
.dash-sub { font-size: 13px; color: #94a3b8; }
|
|
|
|
/* ── STAT CARDS ── */
|
|
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; margin-bottom: 28px; }
|
|
|
|
.stat-card {
|
|
border-radius: 20px;
|
|
padding: 24px 22px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
cursor: default;
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
animation: fadeUp 0.4s ease both;
|
|
}
|
|
|
|
.stat-card:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(0,0,0,0.12); }
|
|
|
|
.stat-card:nth-child(1) { background: linear-gradient(135deg, #fff7e6, #ffe4b2); animation-delay: 0s; }
|
|
.stat-card:nth-child(2) { background: linear-gradient(135deg, #e8fff3, #b8f5d4); animation-delay: 0.07s; }
|
|
.stat-card:nth-child(3) { background: linear-gradient(135deg, #eef4ff, #c5d9ff); animation-delay: 0.14s; }
|
|
.stat-card:nth-child(4) { background: linear-gradient(135deg, #ffeef4, #ffc5db); animation-delay: 0.21s; }
|
|
|
|
.stat-card::after {
|
|
content: '';
|
|
position: absolute;
|
|
width: 120px; height: 120px;
|
|
border-radius: 50%;
|
|
opacity: 0.15;
|
|
right: -30px; bottom: -30px;
|
|
}
|
|
|
|
.stat-card:nth-child(1)::after { background: #f97316; }
|
|
.stat-card:nth-child(2)::after { background: #22c55e; }
|
|
.stat-card:nth-child(3)::after { background: #2b8ef3; }
|
|
.stat-card:nth-child(4)::after { background: #ec4899; }
|
|
|
|
.stat-label { font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; margin-bottom: 10px; }
|
|
.stat-card:nth-child(1) .stat-label { color: #c2651a; }
|
|
.stat-card:nth-child(2) .stat-label { color: #15803d; }
|
|
.stat-card:nth-child(3) .stat-label { color: #1d5fb8; }
|
|
.stat-card:nth-child(4) .stat-label { color: #be185d; }
|
|
|
|
.stat-num { font-size: 42px; font-weight: 800; line-height: 1; color: #0f1f3d; }
|
|
|
|
.stat-icon {
|
|
position: absolute; top: 20px; right: 20px;
|
|
width: 42px; height: 42px; border-radius: 12px;
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 20px;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.stat-card:nth-child(1) .stat-icon { background: rgba(249,115,22,0.15); }
|
|
.stat-card:nth-child(2) .stat-icon { background: rgba(34,197,94,0.15); }
|
|
.stat-card:nth-child(3) .stat-icon { background: rgba(43,142,243,0.15); }
|
|
.stat-card:nth-child(4) .stat-icon { background: rgba(236,72,153,0.15); }
|
|
|
|
/* ── BOTTOM ROW ── */
|
|
.dash-bottom { display: grid; grid-template-columns: 1fr 340px; gap: 20px; }
|
|
|
|
/* Card container */
|
|
.dash-card {
|
|
background: white;
|
|
border-radius: 20px;
|
|
border: 1.5px solid #e8f0fb;
|
|
padding: 24px;
|
|
box-shadow: 0 4px 20px rgba(43,142,243,0.06);
|
|
animation: fadeUp 0.4s ease 0.28s both;
|
|
}
|
|
|
|
.card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
|
|
.card-title { font-size: 15px; font-weight: 700; color: #0f1f3d; }
|
|
.card-badge { font-size: 11px; font-weight: 700; background: #e8f4ff; color: #2b8ef3; padding: 3px 10px; border-radius: 99px; }
|
|
|
|
/* Chart */
|
|
.chart-wrap { position: relative; height: 240px; }
|
|
|
|
/* Challenge list */
|
|
.challenge-item {
|
|
background: #f8faff;
|
|
border-radius: 14px;
|
|
padding: 14px 16px;
|
|
margin-bottom: 10px;
|
|
border-left: 4px solid #2b8ef3;
|
|
transition: all 0.2s;
|
|
cursor: default;
|
|
}
|
|
|
|
.challenge-item:nth-child(2) { border-left-color: #22c55e; }
|
|
.challenge-item:nth-child(3) { border-left-color: #f97316; }
|
|
|
|
.challenge-item:hover { background: #eef4ff; transform: translateX(3px); }
|
|
|
|
.ch-kelas { font-size: 12px; font-weight: 700; color: #2b8ef3; margin-bottom: 3px; }
|
|
.challenge-item:nth-child(2) .ch-kelas { color: #16a34a; }
|
|
.challenge-item:nth-child(3) .ch-kelas { color: #ea580c; }
|
|
|
|
.ch-judul { font-size: 13px; font-weight: 600; color: #0f1f3d; margin-bottom: 3px; }
|
|
.ch-meta { font-size: 11px; color: #94a3b8; }
|
|
|
|
.btn-add-challenge {
|
|
display: flex; align-items: center; justify-content: center; gap: 6px;
|
|
width: 100%; padding: 11px;
|
|
background: white; border: 2px dashed #dbeeff;
|
|
border-radius: 12px; color: #2b8ef3; font-size: 13px; font-weight: 700;
|
|
text-decoration: none; margin-top: 4px;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.btn-add-challenge:hover { background: #e8f4ff; border-color: #2b8ef3; color: #2b8ef3; }
|
|
|
|
@keyframes fadeUp {
|
|
from { opacity: 0; transform: translateY(16px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
@media (max-width: 1100px) {
|
|
.stat-grid { grid-template-columns: repeat(2, 1fr); }
|
|
.dash-bottom { grid-template-columns: 1fr; }
|
|
}
|
|
</style>
|
|
@endpush
|
|
|
|
@section('content')
|
|
|
|
@php
|
|
use Carbon\Carbon;
|
|
$greeting = Carbon::now()->hour < 12 ? 'Selamat Pagi' : (Carbon::now()->hour < 17 ? 'Selamat Siang' : 'Selamat Malam');
|
|
@endphp
|
|
|
|
<div class="dash-header">
|
|
<div class="dash-title">{{ $greeting }}, {{ Auth::guard('admin')->user()->username ?? 'Admin' }} 👋</div>
|
|
<div class="dash-sub">{{ Carbon::now()->isoFormat('dddd, D MMMM Y') }}</div>
|
|
</div>
|
|
|
|
{{-- STAT CARDS --}}
|
|
<div class="stat-grid">
|
|
<div class="stat-card">
|
|
<div class="stat-icon">👨🏫</div>
|
|
<div class="stat-label">Total Guru</div>
|
|
<div class="stat-num">{{ $totalGuru }}</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-icon">🏫</div>
|
|
<div class="stat-label">Total Kelas</div>
|
|
<div class="stat-num">{{ $totalKelas }}</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-icon">👨🎓</div>
|
|
<div class="stat-label">Total Siswa</div>
|
|
<div class="stat-num">{{ $totalSiswa }}</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-icon">📚</div>
|
|
<div class="stat-label">Total Mapel</div>
|
|
<div class="stat-num">{{ $totalMapel }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- BOTTOM: Chart + Challenge --}}
|
|
<div class="dash-bottom">
|
|
|
|
{{-- Bar Chart --}}
|
|
<div class="dash-card">
|
|
<div class="card-head">
|
|
<div class="card-title">Total Siswa Berdasarkan Kelas</div>
|
|
<span class="card-badge">{{ $chartData->count() }} Kelas</span>
|
|
</div>
|
|
<div class="chart-wrap">
|
|
<canvas id="kelasChart"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Challenge Terbaru --}}
|
|
<div class="dash-card">
|
|
<div class="card-head">
|
|
<div class="card-title">Challenge Terbaru</div>
|
|
<a href="{{ route('admin.challenge.index') }}" class="card-badge" style="text-decoration:none">Lihat Semua →</a>
|
|
</div>
|
|
|
|
@forelse($latestChallenges as $ch)
|
|
<div class="challenge-item">
|
|
<div class="ch-kelas">
|
|
{{ $ch->kelas->pluck('nama_kelas')->join(', ') ?: 'Semua Kelas' }}
|
|
</div>
|
|
<div class="ch-judul">{{ $ch->judul_challenge }}</div>
|
|
<div class="ch-meta">
|
|
{{ $ch->soal->count() }} Soal
|
|
@if($ch->tenggat_waktu)
|
|
· Tenggat: {{ \Carbon\Carbon::parse($ch->tenggat_waktu)->isoFormat('D MMM Y') }}
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div style="text-align:center;padding:24px;color:#94a3b8;font-size:13px;">
|
|
Belum ada challenge dibuat.
|
|
</div>
|
|
@endforelse
|
|
|
|
<a href="{{ route('admin.challenge.create') }}" class="btn-add-challenge">
|
|
+ Tambahkan Challenge Baru
|
|
</a>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@endsection
|
|
|
|
@push('scripts')
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
|
<script>
|
|
const labels = @json($chartData->pluck('nama_kelas'));
|
|
const values = @json($chartData->pluck('siswa_count'));
|
|
|
|
const colors = [
|
|
'rgba(43,142,243,0.8)',
|
|
'rgba(34,197,94,0.8)',
|
|
'rgba(249,115,22,0.8)',
|
|
'rgba(168,85,247,0.8)',
|
|
'rgba(236,72,153,0.8)',
|
|
'rgba(234,179,8,0.8)',
|
|
];
|
|
|
|
const ctx = document.getElementById('kelasChart').getContext('2d');
|
|
new Chart(ctx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: 'Jumlah Siswa',
|
|
data: values,
|
|
backgroundColor: labels.map((_, i) => colors[i % colors.length]),
|
|
borderRadius: 10,
|
|
borderSkipped: false,
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: { display: false },
|
|
tooltip: {
|
|
callbacks: {
|
|
label: ctx => ` ${ctx.parsed.y} siswa`
|
|
}
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
grid: { color: '#f1f5f9' },
|
|
ticks: { font: { family: 'Poppins', size: 11 }, color: '#94a3b8' }
|
|
},
|
|
x: {
|
|
grid: { display: false },
|
|
ticks: { font: { family: 'Poppins', size: 11 }, color: '#64748b' }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
@endpush |