lil icon update
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 847 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
|
@ -0,0 +1,174 @@
|
||||||
|
@extends('siswa.layouts.app')
|
||||||
|
|
||||||
|
@section('title', 'Challenge')
|
||||||
|
|
||||||
|
@push('styles')
|
||||||
|
<style>
|
||||||
|
.page-title { font-size: 28px; font-weight: 800; margin-top: -20px; margin-bottom: 6px; }
|
||||||
|
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 24px; }
|
||||||
|
|
||||||
|
.challenge-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.challenge-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #e5e5e5;
|
||||||
|
padding: 22px;
|
||||||
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.challenge-card:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0,0,0,0.1); }
|
||||||
|
.challenge-card.sudah { border-color: #a5e6ba; background: linear-gradient(135deg, #f0fdf4, #fff); }
|
||||||
|
.challenge-card.lewat { border-color: #fecaca; background: #fffafa; opacity: 0.85; }
|
||||||
|
|
||||||
|
.card-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 99px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-aktif { background: #dcfce7; color: #16a34a; }
|
||||||
|
.badge-sudah { background: #e0f2fe; color: #0369a1; }
|
||||||
|
.badge-lewat { background: #fee2e2; color: #dc2626; }
|
||||||
|
|
||||||
|
.card-title { font-size: 16px; font-weight: 700; color: #1e293b; margin-bottom: 8px; line-height: 1.4; }
|
||||||
|
.card-desc { font-size: 13px; color: #64748b; margin-bottom: 14px; line-height: 1.6; }
|
||||||
|
|
||||||
|
.card-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
|
||||||
|
|
||||||
|
.meta-item {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 99px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #475569;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-item.exp { background: #fef9c3; color: #b45309; border-color: #fde68a; }
|
||||||
|
|
||||||
|
.btn-kerjakan {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||||
|
color: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
.btn-kerjakan:hover { opacity: 0.9; color: white; }
|
||||||
|
|
||||||
|
.btn-lihat-hasil {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
background: #e0f2fe;
|
||||||
|
color: #0369a1;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.btn-lihat-hasil:hover { background: #bae6fd; color: #0369a1; }
|
||||||
|
|
||||||
|
.btn-disabled {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
background: #f1f5f9;
|
||||||
|
color: #94a3b8;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state { text-align: center; padding: 60px 20px; color: #94a3b8; }
|
||||||
|
.alert-error { background: #fee2e2; color: #991b1b; border-radius: 12px; padding: 12px 16px; margin-bottom: 20px; font-weight: 500; font-size: 14px; }
|
||||||
|
|
||||||
|
.challenge-card::before {
|
||||||
|
content: '🏆';
|
||||||
|
position: absolute;
|
||||||
|
top: 16px; right: 16px;
|
||||||
|
font-size: 28px;
|
||||||
|
opacity: 0.12;
|
||||||
|
}
|
||||||
|
.challenge-card.sudah::before { content: '✅'; opacity: 0.2; }
|
||||||
|
.challenge-card.lewat::before { content: '⏰'; opacity: 0.15; }
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
<h3 class="page-title">🏆 Challenge</h3>
|
||||||
|
<p class="page-subtitle">Kerjakan challenge untuk mendapatkan EXP dan naik peringkat di leaderboard!</p>
|
||||||
|
|
||||||
|
@if(session('error'))
|
||||||
|
<div class="alert-error">❌ {{ session('error') }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($challenges->isEmpty())
|
||||||
|
<div class="empty-state">
|
||||||
|
<div style="font-size:56px;margin-bottom:16px">🎯</div>
|
||||||
|
<p style="font-size:16px;font-weight:600;color:#475569">Belum ada challenge untuk kelasmu.</p>
|
||||||
|
<p style="font-size:13px">Tunggu admin membuat challenge baru!</p>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="challenge-grid">
|
||||||
|
@foreach($challenges as $ch)
|
||||||
|
@php
|
||||||
|
$isLewat = \Carbon\Carbon::parse($ch->tenggat_waktu)->isPast();
|
||||||
|
$isSudah = in_array($ch->id_challenge, $sudahDikerjakan);
|
||||||
|
$cardClass = $isSudah ? 'sudah' : ($isLewat ? 'lewat' : '');
|
||||||
|
@endphp
|
||||||
|
<div class="challenge-card {{ $cardClass }}">
|
||||||
|
@if($isSudah)
|
||||||
|
<span class="card-badge badge-sudah">✅ Sudah Dikerjakan</span>
|
||||||
|
@elseif($isLewat)
|
||||||
|
<span class="card-badge badge-lewat">⏰ Tenggat Lewat</span>
|
||||||
|
@else
|
||||||
|
<span class="card-badge badge-aktif">🔥 Aktif</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="card-title">{{ $ch->judul_challenge }}</div>
|
||||||
|
@if($ch->deskripsi)
|
||||||
|
<div class="card-desc">{{ Str::limit($ch->deskripsi, 80) }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="card-meta">
|
||||||
|
<span class="meta-item">📝 {{ $ch->soal_count }} soal</span>
|
||||||
|
<span class="meta-item exp">⭐ {{ $ch->exp }} EXP</span>
|
||||||
|
<span class="meta-item">⏰ {{ \Carbon\Carbon::parse($ch->tenggat_waktu)->format('d M Y, H:i') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($isSudah)
|
||||||
|
<a href="{{ route('siswa.challenge.hasil', $ch->id_challenge) }}" class="btn-lihat-hasil">📊 Lihat Hasil</a>
|
||||||
|
@elseif($isLewat)
|
||||||
|
<span class="btn-disabled">Tenggat sudah lewat</span>
|
||||||
|
@else
|
||||||
|
<a href="{{ route('siswa.challenge.kerjakan', $ch->id_challenge) }}" class="btn-kerjakan">🚀 Kerjakan Sekarang</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 982 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 918 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 939 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
|
@ -95,25 +95,93 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MODAL */
|
/* ── MODAL SHARED ─────────────────────────────────── */
|
||||||
.modal-header-challenge {
|
|
||||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
|
||||||
color: white;
|
|
||||||
border-bottom: none;
|
|
||||||
border-radius: 16px 16px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header-challenge .btn-close { filter: brightness(0) invert(1); }
|
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Header kuning (Tambah) */
|
||||||
|
.modal-header-yellow {
|
||||||
|
background: #f9c946;
|
||||||
|
color: #1e293b;
|
||||||
|
border-bottom: none;
|
||||||
|
border-radius: 16px 16px 0 0;
|
||||||
|
padding: 18px 24px;
|
||||||
|
}
|
||||||
|
.modal-header-yellow .modal-title { font-weight: 800; font-size: 18px; }
|
||||||
|
.modal-header-yellow .btn-close { filter: none; }
|
||||||
|
|
||||||
|
/* Header ungu (Edit — tetap seperti semula) */
|
||||||
|
.modal-header-challenge {
|
||||||
|
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||||
|
color: white;
|
||||||
|
border-bottom: none;
|
||||||
|
border-radius: 16px 16px 0 0;
|
||||||
|
}
|
||||||
|
.modal-header-challenge .btn-close { filter: brightness(0) invert(1); }
|
||||||
|
|
||||||
.modal-body label { font-weight: 600; font-size: 13px; }
|
.modal-body label { font-weight: 600; font-size: 13px; }
|
||||||
|
|
||||||
/* SOAL CARD */
|
/* ── STEP INDICATOR ───────────────────────────────── */
|
||||||
|
.step-indicator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
.step-dot {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 800;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.step-dot.active { background: #f9c946; color: #1e293b; box-shadow: 0 0 0 3px rgba(249,201,70,.3); }
|
||||||
|
.step-dot.done { background: #16a34a; color: white; }
|
||||||
|
.step-dot.inactive { background: #e2e8f0; color: #94a3b8; }
|
||||||
|
.step-label {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-left: 8px;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
.step-label.active { color: #1e293b; }
|
||||||
|
.step-label.inactive { color: #94a3b8; }
|
||||||
|
.step-line {
|
||||||
|
flex: 1;
|
||||||
|
height: 2px;
|
||||||
|
background: #e2e8f0;
|
||||||
|
margin: 0 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.step-line-fill {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: #16a34a;
|
||||||
|
transform: scaleX(0);
|
||||||
|
transform-origin: left;
|
||||||
|
transition: transform 0.4s ease;
|
||||||
|
}
|
||||||
|
.step-line-fill.filled { transform: scaleX(1); }
|
||||||
|
|
||||||
|
/* ── STEP PANELS ──────────────────────────────────── */
|
||||||
|
.step-panel { display: none; }
|
||||||
|
.step-panel.active { display: block; }
|
||||||
|
|
||||||
|
/* ── SOAL CARD ────────────────────────────────────── */
|
||||||
.soal-card {
|
.soal-card {
|
||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
border: 1px solid #e2e8f0;
|
border: 1px solid #e2e8f0;
|
||||||
|
|
@ -122,7 +190,6 @@
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soal-card .soal-number {
|
.soal-card .soal-number {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10px;
|
top: -10px;
|
||||||
|
|
@ -134,7 +201,6 @@
|
||||||
padding: 2px 10px;
|
padding: 2px 10px;
|
||||||
border-radius: 99px;
|
border-radius: 99px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soal-card .btn-hapus-soal {
|
.soal-card .btn-hapus-soal {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
|
|
@ -151,7 +217,6 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soal-card .btn-hapus-soal:hover { background: #fca5a5; }
|
.soal-card .btn-hapus-soal:hover { background: #fca5a5; }
|
||||||
|
|
||||||
.opsi-grid {
|
.opsi-grid {
|
||||||
|
|
@ -160,7 +225,6 @@
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opsi-item { display: flex; flex-direction: column; gap: 4px; }
|
.opsi-item { display: flex; flex-direction: column; gap: 4px; }
|
||||||
.opsi-item label { font-size: 12px; color: #64748b; font-weight: 600; }
|
.opsi-item label { font-size: 12px; color: #64748b; font-weight: 600; }
|
||||||
.opsi-item input { border-radius: 8px; border: 1px solid #cbd5e1; padding: 6px 10px; font-size: 13px; }
|
.opsi-item input { border-radius: 8px; border: 1px solid #cbd5e1; padding: 6px 10px; font-size: 13px; }
|
||||||
|
|
@ -175,7 +239,6 @@
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border: 1px solid #e2e8f0;
|
border: 1px solid #e2e8f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jawaban-row label { font-size: 12px; color: #64748b; font-weight: 600; min-width: 90px; }
|
.jawaban-row label { font-size: 12px; color: #64748b; font-weight: 600; min-width: 90px; }
|
||||||
|
|
||||||
.btn-tambah-soal {
|
.btn-tambah-soal {
|
||||||
|
|
@ -197,7 +260,6 @@
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kelas-check-item {
|
.kelas-check-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -209,10 +271,78 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kelas-check-item:hover { background: #e6f0ff; border-color: #2b8ef3; }
|
.kelas-check-item:hover { background: #e6f0ff; border-color: #2b8ef3; }
|
||||||
.kelas-check-item input[type="checkbox"] { cursor: pointer; }
|
.kelas-check-item input[type="checkbox"] { cursor: pointer; }
|
||||||
|
|
||||||
|
.modal-dialog-fixed .modal-content {
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* form harus ikut flex agar modal-body bisa grow */
|
||||||
|
.modal-dialog-fixed form {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog-fixed .modal-header,
|
||||||
|
.modal-dialog-fixed .modal-footer {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog-fixed .modal-body {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* step-indicator tidak ikut scroll */
|
||||||
|
.modal-dialog-fixed .step-indicator {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog-fixed .step-panel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog-fixed .step-panel.active {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 1: scroll jika form terlalu panjang */
|
||||||
|
#tambah-step-1,
|
||||||
|
#edit-step-1 {
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 2: soal-scroll-area yang mengelola scroll */
|
||||||
|
#tambah-step-2,
|
||||||
|
#edit-step-2 {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.soal-scroll-area {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 6px;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
.soal-scroll-area::-webkit-scrollbar { width: 6px; }
|
||||||
|
.soal-scroll-area::-webkit-scrollbar-track { background: #f1f5f9; border-radius: 99px; }
|
||||||
|
.soal-scroll-area::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 99px; }
|
||||||
|
.soal-scroll-area::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
|
||||||
|
|
||||||
.section-divider {
|
.section-divider {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|
@ -221,6 +351,24 @@
|
||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
margin: 16px 0 12px;
|
margin: 16px 0 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── FOOTER BUTTONS ───────────────────────────────── */
|
||||||
|
.btn-green {
|
||||||
|
background: #16a34a;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 9px 22px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
.btn-green:hover { background: #15803d; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<h3 class="page-title">DAFTAR CHALLENGE</h3>
|
<h3 class="page-title">DAFTAR CHALLENGE</h3>
|
||||||
|
|
@ -230,18 +378,16 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="custom-card">
|
<div class="custom-card">
|
||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<button class="btn-primary-custom" onclick="openTambahModal()">
|
<button class="btn-primary-custom" onclick="openTambahModal()">
|
||||||
<img src="{{ asset('images/icon/main/add.png') }}" width="18"> Tambah Challenge
|
<img src="{{ asset('images/icon/main/add.png') }}" width="18" alt="Tambah"> Tambah Challenge
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<form method="GET">
|
<form method="GET">
|
||||||
<div class="search-box">
|
<div class="search-box">
|
||||||
<input type="text" name="search" placeholder="Cari challenge..."
|
<input type="text" name="search" placeholder="Cari challenge..."
|
||||||
value="{{ request('search') }}">
|
value="{{ request('search') }}">
|
||||||
<button style="border:none;background:none" type="submit">
|
<button style="border:none;background:none" type="submit">
|
||||||
<img src="{{ asset('images/icon/main/search.png') }}" width="18">
|
<img src="{{ asset('images/icon/main/search.png') }}" width="18" alt="Cari">
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
@ -288,18 +434,18 @@
|
||||||
<td>
|
<td>
|
||||||
<button onclick="openEditModal({{ $ch->id_challenge }})"
|
<button onclick="openEditModal({{ $ch->id_challenge }})"
|
||||||
style="border:none;background:none">
|
style="border:none;background:none">
|
||||||
<img src="{{ asset('images/icon/main/edit.png') }}" class="action-icon">
|
<img src="{{ asset('images/icon/main/edit.png') }}" class="action-icon" alt="Edit">
|
||||||
</button>
|
</button>
|
||||||
<a href="{{ route('admin.challenge.show', $ch->id_challenge) }}"
|
<a href="{{ route('admin.challenge.show', $ch->id_challenge) }}"
|
||||||
style="border:none;background:none;display:inline">
|
style="border:none;background:none;display:inline">
|
||||||
<img src="{{ asset('images/icon/main/search.png') }}" class="action-icon">
|
<img src="{{ asset('images/icon/main/search.png') }}" class="action-icon" alt="Detail">
|
||||||
</a>
|
</a>
|
||||||
<form action="{{ route('admin.challenge.destroy', $ch->id_challenge) }}"
|
<form action="{{ route('admin.challenge.destroy', $ch->id_challenge) }}"
|
||||||
method="POST" class="d-inline"
|
method="POST" class="d-inline"
|
||||||
onsubmit="return confirm('Yakin hapus challenge ini?')">
|
onsubmit="return confirm('Yakin hapus challenge ini?')">
|
||||||
@csrf @method('DELETE')
|
@csrf @method('DELETE')
|
||||||
<button type="submit" style="border:none;background:none">
|
<button type="submit" style="border:none;background:none">
|
||||||
<img src="{{ asset('images/icon/main/del.png') }}" class="action-icon">
|
<img src="{{ asset('images/icon/main/del.png') }}" class="action-icon" alt="Hapus">
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -317,12 +463,14 @@
|
||||||
|
|
||||||
|
|
||||||
{{-- ============================================================ --}}
|
{{-- ============================================================ --}}
|
||||||
{{-- MODAL TAMBAH --}}
|
{{-- MODAL TAMBAH (2-step) --}}
|
||||||
{{-- ============================================================ --}}
|
{{-- ============================================================ --}}
|
||||||
<div class="modal fade" id="modalTambah" tabindex="-1">
|
<div class="modal fade" id="modalTambah" tabindex="-1">
|
||||||
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
|
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-fixed">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header modal-header-challenge">
|
|
||||||
|
{{-- Header kuning --}}
|
||||||
|
<div class="modal-header modal-header-yellow">
|
||||||
<h5 class="modal-title">🏆 Tambah Challenge Baru</h5>
|
<h5 class="modal-title">🏆 Tambah Challenge Baru</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -331,67 +479,100 @@
|
||||||
@csrf
|
@csrf
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
||||||
{{-- INFO CHALLENGE --}}
|
{{-- Step Indicator --}}
|
||||||
<div class="section-divider">📋 Informasi Challenge</div>
|
<div class="step-indicator" style="flex-shrink:0">
|
||||||
|
<div class="step-dot active" id="tambah-dot-1">1</div>
|
||||||
<div class="row g-3 mb-2">
|
<span class="step-label active" id="tambah-label-1">Informasi Challenge</span>
|
||||||
<div class="col-8">
|
<div class="step-line">
|
||||||
<label>Judul Challenge <span class="text-danger">*</span></label>
|
<div class="step-line-fill" id="tambah-line-fill"></div>
|
||||||
<input type="text" name="judul_challenge" class="form-control"
|
|
||||||
placeholder="Contoh: Challenge Matematika Minggu Ini" required>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<label>Total EXP <span class="text-danger">*</span></label>
|
|
||||||
<input type="number" name="exp" class="form-control" value="100" min="0" required>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="step-dot inactive" id="tambah-dot-2">2</div>
|
||||||
|
<span class="step-label inactive" id="tambah-label-2">Daftar Soal</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
{{-- ─── STEP 1: Info Challenge ─── --}}
|
||||||
<label>Deskripsi</label>
|
<div class="step-panel active" id="tambah-step-1">
|
||||||
<textarea name="deskripsi" class="form-control" rows="2"
|
|
||||||
placeholder="Deskripsi singkat challenge (opsional)"></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-3 mb-3">
|
<div class="section-divider">📋 Informasi Challenge</div>
|
||||||
<div class="col-6">
|
<div class="row g-3 mb-2">
|
||||||
<label>Tenggat Waktu <span class="text-danger">*</span></label>
|
<div class="col-8">
|
||||||
<input type="datetime-local" name="tenggat_waktu" class="form-control" required
|
<label>Judul Challenge <span class="text-danger">*</span></label>
|
||||||
min="{{ now()->format('Y-m-d\TH:i') }}">
|
<input type="text" name="judul_challenge" id="tambah-judul" class="form-control"
|
||||||
|
placeholder="Contoh: Challenge Matematika Minggu Ini">
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<label>Total EXP <span class="text-danger">*</span></label>
|
||||||
|
<input type="number" name="exp" id="tambah-exp" class="form-control" value="100" min="0">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
|
||||||
<label>Badge Reward</label>
|
<div class="mb-3">
|
||||||
<select name="id_badge" class="form-control">
|
<label>Deskripsi</label>
|
||||||
<option value="">-- Tanpa Badge --</option>
|
<textarea name="deskripsi" class="form-control" rows="2"
|
||||||
@foreach($badges as $badge)
|
placeholder="Deskripsi singkat challenge (opsional)"></textarea>
|
||||||
<option value="{{ $badge->id_badge }}">{{ $badge->nama_badge }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- PILIH KELAS --}}
|
<div class="row g-3 mb-3">
|
||||||
<div class="section-divider">🏫 Target Kelas</div>
|
<div class="col-6">
|
||||||
<div class="kelas-checkbox-grid mb-3">
|
<label>Tenggat Waktu <span class="text-danger">*</span></label>
|
||||||
@foreach($kelas as $k)
|
<input type="datetime-local" name="tenggat_waktu" id="tambah-tenggat" class="form-control"
|
||||||
<label class="kelas-check-item">
|
min="{{ now()->format('Y-m-d\TH:i') }}">
|
||||||
<input type="checkbox" name="id_kelas[]" value="{{ $k->id_kelas }}">
|
</div>
|
||||||
<span style="font-size:13px;font-weight:600">{{ $k->tingkat }} {{ $k->nama_kelas }}</span>
|
<div class="col-6">
|
||||||
</label>
|
<label>Badge Reward</label>
|
||||||
@endforeach
|
<select name="id_badge" class="form-control">
|
||||||
</div>
|
<option value="">-- Tanpa Badge --</option>
|
||||||
|
@foreach($badges as $badge)
|
||||||
|
<option value="{{ $badge->id_badge }}">{{ $badge->nama_badge }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{-- SOAL --}}
|
<div class="section-divider">🏫 Target Kelas</div>
|
||||||
<div class="section-divider">📝 Daftar Soal</div>
|
<div class="kelas-checkbox-grid mb-1">
|
||||||
<div id="soalContainer"></div>
|
@foreach($kelas as $k)
|
||||||
<button type="button" class="btn-tambah-soal" onclick="tambahSoal('soalContainer')">
|
<label class="kelas-check-item">
|
||||||
+ Tambah Soal
|
<input type="checkbox" name="id_kelas[]" value="{{ $k->id_kelas }}">
|
||||||
|
<span style="font-size:13px;font-weight:600">{{ $k->tingkat }} {{ $k->nama_kelas }}</span>
|
||||||
|
</label>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>{{-- /step-1 --}}
|
||||||
|
|
||||||
|
{{-- ─── STEP 2: Soal ─── --}}
|
||||||
|
<div class="step-panel" id="tambah-step-2">
|
||||||
|
|
||||||
|
<div class="section-divider" style="flex-shrink:0">📝 Daftar Soal</div>
|
||||||
|
<div id="soalContainer" class="soal-scroll-area"></div>
|
||||||
|
<div style="flex-shrink:0;padding-top:8px">
|
||||||
|
<button type="button" class="btn-tambah-soal" onclick="tambahSoal('soalContainer')">
|
||||||
|
+ Tambah Soal
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>{{-- /step-2 --}}
|
||||||
|
|
||||||
|
</div>{{-- /modal-body --}}
|
||||||
|
|
||||||
|
<div class="modal-footer" style="gap:8px">
|
||||||
|
{{-- Batal (step 1) / Kembali (step 2) --}}
|
||||||
|
<button type="button" class="btn btn-secondary" id="tambah-btn-back"
|
||||||
|
data-bs-dismiss="modal">Batal</button>
|
||||||
|
|
||||||
|
{{-- Next (step 1) --}}
|
||||||
|
<button type="button" class="btn-green" id="tambah-btn-next"
|
||||||
|
onclick="tambahGoStep2()">
|
||||||
|
Berikutnya →
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{{-- Submit (step 2, hidden awalnya) --}}
|
||||||
|
<button type="submit" class="btn-green" id="tambah-btn-submit" style="display:none">
|
||||||
|
💾 Simpan Challenge
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
|
||||||
<button type="submit" class="btn btn-success">💾 Simpan Challenge</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -402,9 +583,9 @@
|
||||||
{{-- MODAL EDIT --}}
|
{{-- MODAL EDIT --}}
|
||||||
{{-- ============================================================ --}}
|
{{-- ============================================================ --}}
|
||||||
<div class="modal fade" id="modalEdit" tabindex="-1">
|
<div class="modal fade" id="modalEdit" tabindex="-1">
|
||||||
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
|
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-fixed">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header modal-header-challenge">
|
<div class="modal-header modal-header-yellow">
|
||||||
<h5 class="modal-title">✏️ Edit Challenge</h5>
|
<h5 class="modal-title">✏️ Edit Challenge</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -413,74 +594,236 @@
|
||||||
@csrf @method('PUT')
|
@csrf @method('PUT')
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
||||||
<div class="section-divider">📋 Informasi Challenge</div>
|
{{-- Step Indicator --}}
|
||||||
<div class="row g-3 mb-2">
|
<div class="step-indicator" style="flex-shrink:0">
|
||||||
<div class="col-8">
|
<div class="step-dot active" id="edit-dot-1">1</div>
|
||||||
<label>Judul Challenge <span class="text-danger">*</span></label>
|
<span class="step-label active" id="edit-label-1">Informasi Challenge</span>
|
||||||
<input type="text" name="judul_challenge" id="editJudul" class="form-control" required>
|
<div class="step-line">
|
||||||
</div>
|
<div class="step-line-fill" id="edit-line-fill"></div>
|
||||||
<div class="col-4">
|
|
||||||
<label>Total EXP <span class="text-danger">*</span></label>
|
|
||||||
<input type="number" name="exp" id="editExp" class="form-control" min="0" required>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="step-dot inactive" id="edit-dot-2">2</div>
|
||||||
|
<span class="step-label inactive" id="edit-label-2">Daftar Soal</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
{{-- ─── STEP 1: Info Challenge ─── --}}
|
||||||
<label>Deskripsi</label>
|
<div class="step-panel active" id="edit-step-1">
|
||||||
<textarea name="deskripsi" id="editDeskripsi" class="form-control" rows="2"></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-3 mb-3">
|
<div class="section-divider">📋 Informasi Challenge</div>
|
||||||
<div class="col-6">
|
<div class="row g-3 mb-2">
|
||||||
<label>Tenggat Waktu <span class="text-danger">*</span></label>
|
<div class="col-8">
|
||||||
<input type="datetime-local" name="tenggat_waktu" id="editTenggat" class="form-control" required>
|
<label>Judul Challenge <span class="text-danger">*</span></label>
|
||||||
|
<input type="text" name="judul_challenge" id="editJudul" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<label>Total EXP <span class="text-danger">*</span></label>
|
||||||
|
<input type="number" name="exp" id="editExp" class="form-control" min="0" required>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
|
||||||
<label>Badge Reward</label>
|
<div class="mb-3">
|
||||||
<select name="id_badge" id="editBadge" class="form-control">
|
<label>Deskripsi</label>
|
||||||
<option value="">-- Tanpa Badge --</option>
|
<textarea name="deskripsi" id="editDeskripsi" class="form-control" rows="2"></textarea>
|
||||||
@foreach($badges as $badge)
|
|
||||||
<option value="{{ $badge->id_badge }}">{{ $badge->nama_badge }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section-divider">🏫 Target Kelas</div>
|
<div class="row g-3 mb-3">
|
||||||
<div class="kelas-checkbox-grid mb-3" id="editKelasContainer">
|
<div class="col-6">
|
||||||
@foreach($kelas as $k)
|
<label>Tenggat Waktu <span class="text-danger">*</span></label>
|
||||||
<label class="kelas-check-item">
|
<input type="datetime-local" name="tenggat_waktu" id="editTenggat" class="form-control" required>
|
||||||
<input type="checkbox" name="id_kelas[]"
|
</div>
|
||||||
value="{{ $k->id_kelas }}" class="edit-kelas-check">
|
<div class="col-6">
|
||||||
<span style="font-size:13px;font-weight:600">{{ $k->tingkat }} {{ $k->nama_kelas }}</span>
|
<label>Badge Reward</label>
|
||||||
</label>
|
<select name="id_badge" id="editBadge" class="form-control">
|
||||||
@endforeach
|
<option value="">-- Tanpa Badge --</option>
|
||||||
</div>
|
@foreach($badges as $badge)
|
||||||
|
<option value="{{ $badge->id_badge }}">{{ $badge->nama_badge }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="section-divider">📝 Daftar Soal</div>
|
<div class="section-divider">🏫 Target Kelas</div>
|
||||||
<div id="editSoalContainer"></div>
|
<div class="kelas-checkbox-grid mb-1" id="editKelasContainer">
|
||||||
<button type="button" class="btn-tambah-soal" onclick="tambahSoal('editSoalContainer')">
|
@foreach($kelas as $k)
|
||||||
+ Tambah Soal
|
<label class="kelas-check-item">
|
||||||
|
<input type="checkbox" name="id_kelas[]"
|
||||||
|
value="{{ $k->id_kelas }}" class="edit-kelas-check">
|
||||||
|
<span style="font-size:13px;font-weight:600">{{ $k->tingkat }} {{ $k->nama_kelas }}</span>
|
||||||
|
</label>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>{{-- /edit-step-1 --}}
|
||||||
|
|
||||||
|
{{-- ─── STEP 2: Soal ─── --}}
|
||||||
|
<div class="step-panel" id="edit-step-2">
|
||||||
|
|
||||||
|
<div class="section-divider" style="flex-shrink:0">📝 Daftar Soal</div>
|
||||||
|
<div id="editSoalContainer" class="soal-scroll-area"></div>
|
||||||
|
<div style="flex-shrink:0;padding-top:8px">
|
||||||
|
<button type="button" class="btn-tambah-soal" onclick="tambahSoal('editSoalContainer')">
|
||||||
|
+ Tambah Soal
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>{{-- /edit-step-2 --}}
|
||||||
|
|
||||||
|
</div>{{-- /modal-body --}}
|
||||||
|
|
||||||
|
<div class="modal-footer" style="gap:8px">
|
||||||
|
<button type="button" class="btn btn-secondary" id="edit-btn-back"
|
||||||
|
data-bs-dismiss="modal">Batal</button>
|
||||||
|
<button type="button" class="btn-green" id="edit-btn-next"
|
||||||
|
onclick="editGoStep2()">
|
||||||
|
Berikutnya →
|
||||||
</button>
|
</button>
|
||||||
|
<button type="submit" class="btn-green" id="edit-btn-submit" style="display:none">
|
||||||
|
💾 Update Challenge
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
|
||||||
<button type="submit" class="btn btn-warning">💾 Update Challenge</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let soalCountTambah = 0;
|
let soalCountTambah = 0;
|
||||||
let soalCountEdit = 0;
|
let soalCountEdit = 0;
|
||||||
|
|
||||||
// ===== TAMBAH SOAL BARU =====
|
/* ══════════════════════════════════════════════════
|
||||||
|
STEP NAVIGATION — MODAL TAMBAH
|
||||||
|
══════════════════════════════════════════════════ */
|
||||||
|
function tambahGoStep2() {
|
||||||
|
// Validasi step 1
|
||||||
|
const judul = document.getElementById('tambah-judul').value.trim();
|
||||||
|
const tenggat = document.getElementById('tambah-tenggat').value;
|
||||||
|
if (!judul) { alert('Judul challenge wajib diisi.'); return; }
|
||||||
|
if (!tenggat) { alert('Tenggat waktu wajib diisi.'); return; }
|
||||||
|
|
||||||
|
// Transisi
|
||||||
|
document.getElementById('tambah-step-1').classList.remove('active');
|
||||||
|
document.getElementById('tambah-step-2').classList.add('active');
|
||||||
|
|
||||||
|
// Indikator
|
||||||
|
document.getElementById('tambah-dot-1').classList.replace('active', 'done');
|
||||||
|
document.getElementById('tambah-dot-1').textContent = '✓';
|
||||||
|
document.getElementById('tambah-label-1').classList.replace('active', 'inactive');
|
||||||
|
document.getElementById('tambah-dot-2').classList.replace('inactive', 'active');
|
||||||
|
document.getElementById('tambah-label-2').classList.replace('inactive', 'active');
|
||||||
|
document.getElementById('tambah-line-fill').classList.add('filled');
|
||||||
|
|
||||||
|
// Footer buttons
|
||||||
|
document.getElementById('tambah-btn-next').style.display = 'none';
|
||||||
|
document.getElementById('tambah-btn-submit').style.display = '';
|
||||||
|
const backBtn = document.getElementById('tambah-btn-back');
|
||||||
|
backBtn.removeAttribute('data-bs-dismiss');
|
||||||
|
backBtn.textContent = '← Kembali';
|
||||||
|
backBtn.onclick = tambahGoStep1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tambahGoStep1() {
|
||||||
|
document.getElementById('tambah-step-2').classList.remove('active');
|
||||||
|
document.getElementById('tambah-step-1').classList.add('active');
|
||||||
|
|
||||||
|
document.getElementById('tambah-dot-1').classList.replace('done', 'active');
|
||||||
|
document.getElementById('tambah-dot-1').textContent = '1';
|
||||||
|
document.getElementById('tambah-label-1').classList.replace('inactive', 'active');
|
||||||
|
document.getElementById('tambah-dot-2').classList.replace('active', 'inactive');
|
||||||
|
document.getElementById('tambah-label-2').classList.replace('active', 'inactive');
|
||||||
|
document.getElementById('tambah-line-fill').classList.remove('filled');
|
||||||
|
|
||||||
|
document.getElementById('tambah-btn-next').style.display = '';
|
||||||
|
document.getElementById('tambah-btn-submit').style.display = 'none';
|
||||||
|
const backBtn = document.getElementById('tambah-btn-back');
|
||||||
|
backBtn.setAttribute('data-bs-dismiss', 'modal');
|
||||||
|
backBtn.textContent = 'Batal';
|
||||||
|
backBtn.onclick = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ══════════════════════════════════════════════════
|
||||||
|
STEP NAVIGATION — MODAL EDIT
|
||||||
|
══════════════════════════════════════════════════ */
|
||||||
|
function editGoStep2() {
|
||||||
|
const judul = document.getElementById('editJudul').value.trim();
|
||||||
|
const tenggat = document.getElementById('editTenggat').value;
|
||||||
|
if (!judul) { alert('Judul challenge wajib diisi.'); return; }
|
||||||
|
if (!tenggat) { alert('Tenggat waktu wajib diisi.'); return; }
|
||||||
|
|
||||||
|
document.getElementById('edit-step-1').classList.remove('active');
|
||||||
|
document.getElementById('edit-step-2').classList.add('active');
|
||||||
|
|
||||||
|
document.getElementById('edit-dot-1').classList.replace('active', 'done');
|
||||||
|
document.getElementById('edit-dot-1').textContent = '✓';
|
||||||
|
document.getElementById('edit-label-1').classList.replace('active', 'inactive');
|
||||||
|
document.getElementById('edit-dot-2').classList.replace('inactive', 'active');
|
||||||
|
document.getElementById('edit-label-2').classList.replace('inactive', 'active');
|
||||||
|
document.getElementById('edit-line-fill').classList.add('filled');
|
||||||
|
|
||||||
|
document.getElementById('edit-btn-next').style.display = 'none';
|
||||||
|
document.getElementById('edit-btn-submit').style.display = '';
|
||||||
|
const backBtn = document.getElementById('edit-btn-back');
|
||||||
|
backBtn.removeAttribute('data-bs-dismiss');
|
||||||
|
backBtn.textContent = '← Kembali';
|
||||||
|
backBtn.onclick = editGoStep1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function editGoStep1() {
|
||||||
|
document.getElementById('edit-step-2').classList.remove('active');
|
||||||
|
document.getElementById('edit-step-1').classList.add('active');
|
||||||
|
|
||||||
|
document.getElementById('edit-dot-1').classList.replace('done', 'active');
|
||||||
|
document.getElementById('edit-dot-1').textContent = '1';
|
||||||
|
document.getElementById('edit-label-1').classList.replace('inactive', 'active');
|
||||||
|
document.getElementById('edit-dot-2').classList.replace('active', 'inactive');
|
||||||
|
document.getElementById('edit-label-2').classList.replace('active', 'inactive');
|
||||||
|
document.getElementById('edit-line-fill').classList.remove('filled');
|
||||||
|
|
||||||
|
document.getElementById('edit-btn-next').style.display = '';
|
||||||
|
document.getElementById('edit-btn-submit').style.display = 'none';
|
||||||
|
const backBtn = document.getElementById('edit-btn-back');
|
||||||
|
backBtn.setAttribute('data-bs-dismiss', 'modal');
|
||||||
|
backBtn.textContent = 'Batal';
|
||||||
|
backBtn.onclick = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ══════════════════════════════════════════════════
|
||||||
|
EXP HELPER — hitung & sebar exp_per_soal otomatis
|
||||||
|
══════════════════════════════════════════════════ */
|
||||||
|
function getExpInput(containerId) {
|
||||||
|
// Tambah → pakai #tambah-exp | Edit → pakai #editExp
|
||||||
|
return containerId === 'editSoalContainer'
|
||||||
|
? document.getElementById('editExp')
|
||||||
|
: document.getElementById('tambah-exp');
|
||||||
|
}
|
||||||
|
|
||||||
|
function recalcExp(containerId) {
|
||||||
|
const expInput = getExpInput(containerId);
|
||||||
|
const totalExp = parseInt(expInput ? expInput.value : 0) || 0;
|
||||||
|
const cards = document.querySelectorAll(`#${containerId} .soal-card`);
|
||||||
|
const jumlah = cards.length;
|
||||||
|
if (jumlah === 0) return;
|
||||||
|
|
||||||
|
// Bagi rata, sisa EXP diberikan ke soal terakhir
|
||||||
|
const base = Math.floor(totalExp / jumlah);
|
||||||
|
const remainder = totalExp - base * jumlah;
|
||||||
|
|
||||||
|
cards.forEach((card, i) => {
|
||||||
|
const hiddenInput = card.querySelector('input[name="exp_per_soal[]"]');
|
||||||
|
const displaySpan = card.querySelector('.exp-per-soal-display');
|
||||||
|
const val = base + (i === jumlah - 1 ? remainder : 0);
|
||||||
|
if (hiddenInput) hiddenInput.value = val;
|
||||||
|
if (displaySpan) displaySpan.textContent = val + ' EXP';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ══════════════════════════════════════════════════
|
||||||
|
SOAL HELPERS
|
||||||
|
══════════════════════════════════════════════════ */
|
||||||
function tambahSoal(containerId, data = null) {
|
function tambahSoal(containerId, data = null) {
|
||||||
const isEdit = containerId === 'editSoalContainer';
|
const isEdit = containerId === 'editSoalContainer';
|
||||||
const count = isEdit ? ++soalCountEdit : ++soalCountTambah;
|
const count = isEdit ? ++soalCountEdit : ++soalCountTambah;
|
||||||
const container = document.getElementById(containerId);
|
const container = document.getElementById(containerId);
|
||||||
|
|
||||||
const card = document.createElement('div');
|
const card = document.createElement('div');
|
||||||
|
|
@ -525,17 +868,24 @@ function tambahSoal(containerId, data = null) {
|
||||||
`<option value="${o}" ${data && data.jawaban_benar === o ? 'selected' : ''}>${o}</option>`
|
`<option value="${o}" ${data && data.jawaban_benar === o ? 'selected' : ''}>${o}</option>`
|
||||||
).join('')}
|
).join('')}
|
||||||
</select>
|
</select>
|
||||||
<label style="margin-left:16px">EXP per Soal</label>
|
{{-- Hidden — nilainya diisi recalcExp() --}}
|
||||||
<input type="number" name="exp_per_soal[]" class="form-control" style="width:90px"
|
<input type="hidden" name="exp_per_soal[]" value="0">
|
||||||
min="0" value="${data ? data.exp_per_soal : 10}" required>
|
<span style="margin-left:auto;background:#f0fdf4;color:#16a34a;font-size:12px;font-weight:700;
|
||||||
|
padding:4px 12px;border-radius:99px;white-space:nowrap">
|
||||||
|
⚡ <span class="exp-per-soal-display">0 EXP</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
container.appendChild(card);
|
container.appendChild(card);
|
||||||
renumberSoal(containerId);
|
renumberSoal(containerId);
|
||||||
|
recalcExp(containerId); // update semua kartu setelah soal baru ditambah
|
||||||
|
|
||||||
|
// Scroll ke soal baru
|
||||||
|
const scrollArea = container.closest('.soal-scroll-area') || container;
|
||||||
|
scrollArea.scrollTop = scrollArea.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== HAPUS SOAL =====
|
|
||||||
function hapusSoal(btn, containerId) {
|
function hapusSoal(btn, containerId) {
|
||||||
const container = document.getElementById(containerId);
|
const container = document.getElementById(containerId);
|
||||||
if (container.querySelectorAll('.soal-card').length <= 1) {
|
if (container.querySelectorAll('.soal-card').length <= 1) {
|
||||||
|
|
@ -544,56 +894,75 @@ function hapusSoal(btn, containerId) {
|
||||||
}
|
}
|
||||||
btn.closest('.soal-card').remove();
|
btn.closest('.soal-card').remove();
|
||||||
renumberSoal(containerId);
|
renumberSoal(containerId);
|
||||||
|
recalcExp(containerId); // update ulang setelah soal dihapus
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== RENUMBER SOAL =====
|
|
||||||
function renumberSoal(containerId) {
|
function renumberSoal(containerId) {
|
||||||
const cards = document.querySelectorAll(`#${containerId} .soal-card`);
|
document.querySelectorAll(`#${containerId} .soal-card`).forEach((card, i) => {
|
||||||
cards.forEach((card, i) => {
|
|
||||||
const num = card.querySelector('.soal-number');
|
const num = card.querySelector('.soal-number');
|
||||||
if (num) num.textContent = `Soal ${i + 1}`;
|
if (num) num.textContent = `Soal ${i + 1}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== BUKA MODAL TAMBAH =====
|
/* ══════════════════════════════════════════════════
|
||||||
|
OPEN MODAL TAMBAH
|
||||||
|
══════════════════════════════════════════════════ */
|
||||||
function openTambahModal() {
|
function openTambahModal() {
|
||||||
|
// Reset state
|
||||||
soalCountTambah = 0;
|
soalCountTambah = 0;
|
||||||
document.getElementById('soalContainer').innerHTML = '';
|
document.getElementById('soalContainer').innerHTML = '';
|
||||||
document.getElementById('formTambah').reset();
|
document.getElementById('formTambah').reset();
|
||||||
tambahSoal('soalContainer'); // default 1 soal
|
|
||||||
|
// Paksa step 1
|
||||||
|
tambahGoStep1();
|
||||||
|
|
||||||
|
// Default 1 soal
|
||||||
|
tambahSoal('soalContainer');
|
||||||
|
|
||||||
|
// Recalc EXP otomatis setiap kali angka EXP di step-1 berubah
|
||||||
|
const expElTambah = document.getElementById('tambah-exp');
|
||||||
|
expElTambah.oninput = () => recalcExp('soalContainer');
|
||||||
|
|
||||||
new bootstrap.Modal(document.getElementById('modalTambah')).show();
|
new bootstrap.Modal(document.getElementById('modalTambah')).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== BUKA MODAL EDIT =====
|
/* ══════════════════════════════════════════════════
|
||||||
|
OPEN MODAL EDIT
|
||||||
|
══════════════════════════════════════════════════ */
|
||||||
async function openEditModal(idChallenge) {
|
async function openEditModal(idChallenge) {
|
||||||
soalCountEdit = 0;
|
soalCountEdit = 0;
|
||||||
document.getElementById('editSoalContainer').innerHTML = '';
|
document.getElementById('editSoalContainer').innerHTML = '';
|
||||||
|
|
||||||
// Fetch data challenge via AJAX
|
// Reset ke step 1
|
||||||
|
editGoStep1();
|
||||||
|
|
||||||
const res = await fetch(`/admin/challenge/${idChallenge}/edit-data`);
|
const res = await fetch(`/admin/challenge/${idChallenge}/edit-data`);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
// Isi form
|
document.getElementById('formEdit').action = `/admin/challenge/${idChallenge}`;
|
||||||
document.getElementById('formEdit').action = `/admin/challenge/${idChallenge}`;
|
document.getElementById('editJudul').value = data.judul_challenge;
|
||||||
document.getElementById('editJudul').value = data.judul_challenge;
|
document.getElementById('editExp').value = data.exp;
|
||||||
document.getElementById('editExp').value = data.exp;
|
document.getElementById('editDeskripsi').value = data.deskripsi ?? '';
|
||||||
document.getElementById('editDeskripsi').value = data.deskripsi ?? '';
|
document.getElementById('editBadge').value = data.id_badge ?? '';
|
||||||
document.getElementById('editBadge').value = data.id_badge ?? '';
|
|
||||||
|
|
||||||
// Format datetime-local
|
const dt = new Date(data.tenggat_waktu);
|
||||||
const dt = new Date(data.tenggat_waktu);
|
const pad = n => String(n).padStart(2, '0');
|
||||||
const pad = n => String(n).padStart(2,'0');
|
|
||||||
document.getElementById('editTenggat').value =
|
document.getElementById('editTenggat').value =
|
||||||
`${dt.getFullYear()}-${pad(dt.getMonth()+1)}-${pad(dt.getDate())}T${pad(dt.getHours())}:${pad(dt.getMinutes())}`;
|
`${dt.getFullYear()}-${pad(dt.getMonth()+1)}-${pad(dt.getDate())}T${pad(dt.getHours())}:${pad(dt.getMinutes())}`;
|
||||||
|
|
||||||
// Centang kelas
|
|
||||||
document.querySelectorAll('.edit-kelas-check').forEach(cb => {
|
document.querySelectorAll('.edit-kelas-check').forEach(cb => {
|
||||||
cb.checked = data.kelas.includes(parseInt(cb.value));
|
cb.checked = data.kelas.includes(parseInt(cb.value));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Isi soal
|
|
||||||
data.soal.forEach(s => tambahSoal('editSoalContainer', s));
|
data.soal.forEach(s => tambahSoal('editSoalContainer', s));
|
||||||
|
|
||||||
|
// Recalc EXP otomatis setiap kali angka EXP di modal edit berubah
|
||||||
|
const expElEdit = document.getElementById('editExp');
|
||||||
|
expElEdit.oninput = () => recalcExp('editSoalContainer');
|
||||||
|
|
||||||
|
// Recalc sekali saat modal dibuka
|
||||||
|
recalcExp('editSoalContainer');
|
||||||
|
|
||||||
new bootstrap.Modal(document.getElementById('modalEdit')).show();
|
new bootstrap.Modal(document.getElementById('modalEdit')).show();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,6 @@
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="dash-header">
|
<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 class="dash-sub">{{ Carbon::now()->isoFormat('dddd, D MMMM Y') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@
|
||||||
--blue-dark: #1a7ae0;
|
--blue-dark: #1a7ae0;
|
||||||
--blue-light:#e8f4ff;
|
--blue-light:#e8f4ff;
|
||||||
--blue-mid: #dbeeff;
|
--blue-mid: #dbeeff;
|
||||||
--accent1: #f97316; /* orange */
|
--accent1: #f97316;
|
||||||
--accent2: #22c55e; /* green */
|
--accent2: #22c55e;
|
||||||
--accent3: #a855f7; /* purple */
|
--accent3: #a855f7;
|
||||||
--bg: #f0f6ff;
|
--bg: #f0f6ff;
|
||||||
--dark: #0f1f3d;
|
--dark: #0f1f3d;
|
||||||
}
|
}
|
||||||
|
|
@ -29,6 +29,14 @@
|
||||||
color: var(--dark);
|
color: var(--dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── ICON SIZES ── */
|
||||||
|
.icon-pill { width: 18px; height: 18px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-sm { width: 20px; height: 20px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-md { width: 28px; height: 28px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-feat { width: 32px; height: 32px; object-fit: contain; }
|
||||||
|
.icon-portal { width: 40px; height: 40px; object-fit: contain; }
|
||||||
|
.icon-footer { width: 16px; height: 16px; object-fit: contain; vertical-align: middle; margin-right: 6px; }
|
||||||
|
|
||||||
/* ── NAVBAR ── */
|
/* ── NAVBAR ── */
|
||||||
.navbar {
|
.navbar {
|
||||||
background: rgba(255,255,255,0.9);
|
background: rgba(255,255,255,0.9);
|
||||||
|
|
@ -51,7 +59,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-brand img { width: 42px; height: 42px; object-fit: contain; }
|
.navbar-brand img { width: 42px; height: 42px; object-fit: contain; }
|
||||||
|
|
||||||
.nav-link { font-weight: 600; font-size: 14px; color: #475569 !important; transition: color 0.2s; }
|
.nav-link { font-weight: 600; font-size: 14px; color: #475569 !important; transition: color 0.2s; }
|
||||||
.nav-link:hover { color: var(--blue) !important; }
|
.nav-link:hover { color: var(--blue) !important; }
|
||||||
|
|
||||||
|
|
@ -78,7 +85,6 @@
|
||||||
padding: 70px 0;
|
padding: 70px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decorative grid */
|
|
||||||
.hero::before {
|
.hero::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -90,15 +96,12 @@
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Big circle bg */
|
|
||||||
.hero-bg-circle {
|
.hero-bg-circle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 700px;
|
width: 700px; height: 700px;
|
||||||
height: 700px;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: radial-gradient(circle, rgba(43,142,243,0.12) 0%, transparent 70%);
|
background: radial-gradient(circle, rgba(43,142,243,0.12) 0%, transparent 70%);
|
||||||
right: -200px;
|
right: -200px; top: 50%;
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,10 +132,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-title .blue-text { color: var(--blue); }
|
.hero-title .blue-text { color: var(--blue); }
|
||||||
.hero-title .underline-text {
|
.hero-title .underline-text { position: relative; display: inline-block; }
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.hero-title .underline-text::after {
|
.hero-title .underline-text::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -189,12 +189,7 @@
|
||||||
}
|
}
|
||||||
.btn-hero-outline:hover { border-color: var(--blue); color: var(--blue); transform: translateY(-3px); }
|
.btn-hero-outline:hover { border-color: var(--blue); color: var(--blue); transform: translateY(-3px); }
|
||||||
|
|
||||||
/* Hero right side */
|
.hero-visual { position: relative; z-index: 2; animation: fadeUp 0.5s ease 0.15s both; }
|
||||||
.hero-visual {
|
|
||||||
position: relative;
|
|
||||||
z-index: 2;
|
|
||||||
animation: fadeUp 0.5s ease 0.15s both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero-main-card {
|
.hero-main-card {
|
||||||
background: white;
|
background: white;
|
||||||
|
|
@ -205,48 +200,25 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hmc-header {
|
.hmc-header { display: flex; align-items: center; gap: 12px; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 2px solid var(--blue-light); }
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
border-bottom: 2px solid var(--blue-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hmc-logo { width: 48px; height: 48px; border-radius: 14px; background: var(--blue-light); display: flex; align-items: center; justify-content: center; }
|
.hmc-logo { width: 48px; height: 48px; border-radius: 14px; background: var(--blue-light); display: flex; align-items: center; justify-content: center; }
|
||||||
.hmc-logo img { width: 36px; height: 36px; object-fit: contain; }
|
.hmc-logo img { width: 36px; height: 36px; object-fit: contain; }
|
||||||
.hmc-name { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 15px; }
|
.hmc-name { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 15px; }
|
||||||
.hmc-sub { font-size: 12px; color: #94a3b8; }
|
.hmc-sub { font-size: 12px; color: #94a3b8; }
|
||||||
|
|
||||||
.hmc-stat-row { display: grid; grid-template-columns: repeat(3,1fr); gap: 12px; margin-bottom: 20px; }
|
.hmc-stat-row { display: grid; grid-template-columns: repeat(3,1fr); gap: 12px; margin-bottom: 20px; }
|
||||||
.hmc-stat {
|
.hmc-stat { background: var(--blue-light); border-radius: 14px; padding: 14px 10px; text-align: center; }
|
||||||
background: var(--blue-light);
|
|
||||||
border-radius: 14px;
|
|
||||||
padding: 14px 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.hmc-stat-num { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 20px; color: var(--blue); }
|
.hmc-stat-num { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 20px; color: var(--blue); }
|
||||||
.hmc-stat-label { font-size: 10px; color: #64748b; font-weight: 600; margin-top: 2px; }
|
.hmc-stat-label { font-size: 10px; color: #64748b; font-weight: 600; margin-top: 2px; }
|
||||||
|
|
||||||
.hmc-lb { background: var(--blue-light); border-radius: 16px; padding: 16px; }
|
.hmc-lb { background: var(--blue-light); border-radius: 16px; padding: 16px; }
|
||||||
.hmc-lb-title { font-size: 12px; font-weight: 700; color: #64748b; margin-bottom: 12px; }
|
.hmc-lb-title { font-size: 12px; font-weight: 700; color: #64748b; margin-bottom: 12px; display: flex; align-items: center; gap: 6px; }
|
||||||
|
.hmc-lb-row { display: flex; align-items: center; gap: 10px; padding: 8px; border-radius: 10px; background: white; margin-bottom: 8px; }
|
||||||
|
.hmc-lb-rank { width: 24px; height: 24px; border-radius: 50%; background: var(--blue); color: white; font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center; flex-shrink: 0; overflow: hidden; }
|
||||||
|
.hmc-lb-rank img { width: 20px; height: 20px; object-fit: contain; }
|
||||||
|
.hmc-lb-name { flex: 1; font-size: 12px; font-weight: 700; display: flex; align-items: center; gap: 4px; }
|
||||||
|
.hmc-lb-exp { font-size: 12px; font-weight: 700; color: var(--blue); display: flex; align-items: center; gap: 3px; }
|
||||||
|
|
||||||
.hmc-lb-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 10px;
|
|
||||||
background: white;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hmc-lb-rank { width: 24px; height: 24px; border-radius: 50%; background: var(--blue); color: white; font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
|
||||||
.hmc-lb-name { flex: 1; font-size: 12px; font-weight: 700; }
|
|
||||||
.hmc-lb-exp { font-size: 12px; font-weight: 700; color: var(--blue); }
|
|
||||||
|
|
||||||
/* Floating badges */
|
|
||||||
.float-badge {
|
.float-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: white;
|
background: white;
|
||||||
|
|
@ -272,22 +244,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── STATS BAR ── */
|
/* ── STATS BAR ── */
|
||||||
.stats-bar {
|
.stats-bar { background: var(--blue); padding: 28px 0; }
|
||||||
background: var(--blue);
|
|
||||||
padding: 28px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stat-bar-item { text-align: center; color: white; }
|
.stat-bar-item { text-align: center; color: white; }
|
||||||
.stat-bar-num { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 32px; }
|
.stat-bar-num { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 32px; }
|
||||||
.stat-bar-label { font-size: 13px; opacity: 0.8; margin-top: 2px; }
|
.stat-bar-label { font-size: 13px; opacity: 0.8; margin-top: 2px; }
|
||||||
|
|
||||||
.stat-divider {
|
|
||||||
width: 1px;
|
|
||||||
height: 50px;
|
|
||||||
background: rgba(255,255,255,0.2);
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── FEATURES ── */
|
/* ── FEATURES ── */
|
||||||
.features-section { padding: 90px 0; }
|
.features-section { padding: 90px 0; }
|
||||||
|
|
||||||
|
|
@ -317,7 +278,6 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feat-card:hover { transform: translateY(-6px); box-shadow: 0 20px 48px rgba(43,142,243,0.12); border-color: var(--blue); }
|
.feat-card:hover { transform: translateY(-6px); box-shadow: 0 20px 48px rgba(43,142,243,0.12); border-color: var(--blue); }
|
||||||
|
|
||||||
.feat-icon {
|
.feat-icon {
|
||||||
|
|
@ -325,10 +285,8 @@
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
background: var(--blue-light);
|
background: var(--blue-light);
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
font-size: 24px;
|
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feat-icon.orange { background: #fff4ee; }
|
.feat-icon.orange { background: #fff4ee; }
|
||||||
.feat-icon.green { background: #eefaf3; }
|
.feat-icon.green { background: #eefaf3; }
|
||||||
.feat-icon.purple { background: #f5eeff; }
|
.feat-icon.purple { background: #f5eeff; }
|
||||||
|
|
@ -337,132 +295,46 @@
|
||||||
|
|
||||||
.feat-title { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 17px; color: var(--dark); margin-bottom: 10px; }
|
.feat-title { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 17px; color: var(--dark); margin-bottom: 10px; }
|
||||||
.feat-desc { font-size: 13px; color: #64748b; line-height: 1.75; }
|
.feat-desc { font-size: 13px; color: #64748b; line-height: 1.75; }
|
||||||
|
.feat-tag { display: inline-block; background: var(--blue-light); color: var(--blue); font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 99px; margin-top: 14px; }
|
||||||
.feat-tag {
|
|
||||||
display: inline-block;
|
|
||||||
background: var(--blue-light);
|
|
||||||
color: var(--blue);
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 700;
|
|
||||||
padding: 3px 10px;
|
|
||||||
border-radius: 99px;
|
|
||||||
margin-top: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── HOW ── */
|
/* ── HOW ── */
|
||||||
.how-section { padding: 90px 0; background: linear-gradient(180deg, white, var(--blue-light)); }
|
.how-section { padding: 90px 0; background: linear-gradient(180deg, white, var(--blue-light)); }
|
||||||
|
.step-wrap { display: flex; flex-direction: column; gap: 0; }
|
||||||
.step-wrap {
|
.step-item { display: flex; gap: 24px; align-items: flex-start; position: relative; }
|
||||||
display: flex;
|
.step-item:not(:last-child)::after { content: ''; position: absolute; left: 23px; top: 52px; bottom: -20px; width: 2px; background: linear-gradient(180deg, var(--blue), transparent); }
|
||||||
flex-direction: column;
|
.step-num-wrap { width: 48px; height: 48px; border-radius: 50%; background: var(--blue); color: white; font-family: 'Sora', sans-serif; font-weight: 800; font-size: 18px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; box-shadow: 0 6px 20px rgba(43,142,243,0.35); }
|
||||||
gap: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-item {
|
|
||||||
display: flex;
|
|
||||||
gap: 24px;
|
|
||||||
align-items: flex-start;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-item:not(:last-child)::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: 23px;
|
|
||||||
top: 52px;
|
|
||||||
bottom: -20px;
|
|
||||||
width: 2px;
|
|
||||||
background: linear-gradient(180deg, var(--blue), transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-num-wrap {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: var(--blue);
|
|
||||||
color: white;
|
|
||||||
font-family: 'Sora', sans-serif;
|
|
||||||
font-weight: 800;
|
|
||||||
font-size: 18px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-shrink: 0;
|
|
||||||
box-shadow: 0 6px 20px rgba(43,142,243,0.35);
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-body { padding-bottom: 36px; }
|
.step-body { padding-bottom: 36px; }
|
||||||
.step-title { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 17px; margin-bottom: 6px; }
|
.step-title { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 17px; margin-bottom: 6px; }
|
||||||
.step-desc { font-size: 13px; color: #64748b; line-height: 1.75; }
|
.step-desc { font-size: 13px; color: #64748b; line-height: 1.75; }
|
||||||
|
|
||||||
/* ── LOGIN ── */
|
/* ── LOGIN ── */
|
||||||
.login-section { padding: 90px 0; }
|
.login-section { padding: 90px 0; }
|
||||||
|
.portal-card { background: white; border-radius: 24px; padding: 40px 32px; text-align: center; border: 2px solid #e8f0fb; transition: all 0.25s; position: relative; overflow: hidden; }
|
||||||
.portal-card {
|
.portal-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 5px; }
|
||||||
background: white;
|
|
||||||
border-radius: 24px;
|
|
||||||
padding: 40px 32px;
|
|
||||||
text-align: center;
|
|
||||||
border: 2px solid #e8f0fb;
|
|
||||||
transition: all 0.25s;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portal-card::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0; left: 0; right: 0;
|
|
||||||
height: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pc-blue::before { background: var(--blue); }
|
.pc-blue::before { background: var(--blue); }
|
||||||
.pc-green::before { background: var(--accent2); }
|
.pc-green::before { background: var(--accent2); }
|
||||||
.pc-orange::before { background: var(--accent1); }
|
.pc-orange::before { background: var(--accent1); }
|
||||||
|
|
||||||
.portal-card:hover { transform: translateY(-6px); box-shadow: 0 20px 48px rgba(43,142,243,0.12); }
|
.portal-card:hover { transform: translateY(-6px); box-shadow: 0 20px 48px rgba(43,142,243,0.12); }
|
||||||
|
.portal-icon-wrap { width: 72px; height: 72px; border-radius: 20px; display: flex; align-items: center; justify-content: center; margin: 0 auto 18px; }
|
||||||
.portal-icon-wrap {
|
|
||||||
width: 72px; height: 72px;
|
|
||||||
border-radius: 20px;
|
|
||||||
display: flex; align-items: center; justify-content: center;
|
|
||||||
font-size: 32px;
|
|
||||||
margin: 0 auto 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.piw-blue { background: var(--blue-light); }
|
.piw-blue { background: var(--blue-light); }
|
||||||
.piw-green { background: #eefaf3; }
|
.piw-green { background: #eefaf3; }
|
||||||
.piw-orange { background: #fff4ee; }
|
.piw-orange { background: #fff4ee; }
|
||||||
|
|
||||||
.portal-title { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 20px; margin-bottom: 8px; }
|
.portal-title { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 20px; margin-bottom: 8px; }
|
||||||
.portal-desc { font-size: 13px; color: #64748b; line-height: 1.7; margin-bottom: 24px; }
|
.portal-desc { font-size: 13px; color: #64748b; line-height: 1.7; margin-bottom: 24px; }
|
||||||
|
.btn-portal { display: inline-block; border-radius: 12px; padding: 12px 28px; font-weight: 700; font-size: 14px; text-decoration: none; transition: all 0.2s; }
|
||||||
.btn-portal {
|
|
||||||
display: inline-block;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 12px 28px;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 14px;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bp-blue { background: var(--blue); color: white; }
|
.bp-blue { background: var(--blue); color: white; }
|
||||||
.bp-green { background: var(--accent2); color: white; }
|
.bp-green { background: var(--accent2); color: white; }
|
||||||
.bp-orange { background: var(--accent1); color: white; }
|
.bp-orange { background: var(--accent1); color: white; }
|
||||||
|
|
||||||
.btn-portal:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.15); color: white; }
|
.btn-portal:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.15); color: white; }
|
||||||
|
|
||||||
/* ── FOOTER ── */
|
/* ── FOOTER ── */
|
||||||
footer { background: var(--dark); color: white; padding: 48px 0 24px; }
|
footer { background: var(--dark); color: white; padding: 48px 0 24px; }
|
||||||
.ft-brand { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 18px; margin-bottom: 10px; }
|
.ft-brand { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 18px; margin-bottom: 10px; }
|
||||||
.ft-desc { font-size: 13px; color: #94a3b8; line-height: 1.7; max-width: 300px; }
|
.ft-desc { font-size: 13px; color: #94a3b8; line-height: 1.7; max-width: 300px; }
|
||||||
.ft-link { color: #94a3b8; font-size: 13px; text-decoration: none; display: block; margin-bottom: 8px; transition: color 0.2s; }
|
.ft-link { color: #94a3b8; font-size: 13px; text-decoration: none; display: flex; align-items: center; margin-bottom: 8px; transition: color 0.2s; }
|
||||||
.ft-link:hover { color: #60b4ff; }
|
.ft-link:hover { color: #60b4ff; }
|
||||||
.ft-heading { font-weight: 700; font-size: 14px; margin-bottom: 16px; }
|
.ft-heading { font-weight: 700; font-size: 14px; margin-bottom: 16px; }
|
||||||
.ft-copy { font-size: 12px; color: #475569; text-align: center; margin-top: 36px; padding-top: 20px; border-top: 1px solid #1e3a5f; }
|
.ft-copy { font-size: 12px; color: #475569; text-align: center; margin-top: 36px; padding-top: 20px; border-top: 1px solid #1e3a5f; }
|
||||||
|
|
||||||
.blue-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--blue); margin-right: 6px; }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -471,7 +343,7 @@
|
||||||
<nav class="navbar navbar-expand-lg">
|
<nav class="navbar navbar-expand-lg">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="#">
|
<a class="navbar-brand" href="#">
|
||||||
<img src="/images/logo/logosmk.png" alt="Logo">
|
<img src="/images/logo/logosmk.png" alt="Logo SMK">
|
||||||
<div>
|
<div>
|
||||||
<div>E-Learning RPL</div>
|
<div>E-Learning RPL</div>
|
||||||
<div style="font-size:10px;color:#94a3b8;font-weight:500;">SMKN 1 Tapen</div>
|
<div style="font-size:10px;color:#94a3b8;font-weight:500;">SMKN 1 Tapen</div>
|
||||||
|
|
@ -500,16 +372,22 @@
|
||||||
<div class="row align-items-center g-5">
|
<div class="row align-items-center g-5">
|
||||||
|
|
||||||
<div class="col-lg-6 hero-content">
|
<div class="col-lg-6 hero-content">
|
||||||
<div class="hero-pill">💻 Platform E-Learning Jurusan RPL</div>
|
<div class="hero-pill">
|
||||||
|
<img src="{{ asset('images/icon/lp/pc.png') }}" alt="Platform" class="icon-pill">
|
||||||
|
E-Learning Jurusan RPL
|
||||||
|
</div>
|
||||||
<h1 class="hero-title">
|
<h1 class="hero-title">
|
||||||
Kuasai <span class="blue-text">Coding</span>,<br>
|
Kerjakan <span class="blue-text">Tugas</span>,<br>
|
||||||
Raih <span class="underline-text">Prestasi</span>
|
Raih <span class="underline-text">Prestasi</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="hero-desc">
|
<p class="hero-desc">
|
||||||
Platform e-learning khusus jurusan Rekayasa Perangkat Lunak — akses materi coding, kerjakan tugas, ikuti challenge, dan buktikan siapa developer terbaik di kelasmu!
|
Platform e-learning khusus jurusan Rekayasa Perangkat Lunak akses materi, kerjakan tugas, ikuti challenge, dan dapatkan badge terbaik!
|
||||||
</p>
|
</p>
|
||||||
<div class="hero-actions">
|
<div class="hero-actions">
|
||||||
<a href="#masuk" class="btn-hero-main">🚀 Mulai Sekarang</a>
|
<a href="#masuk" class="btn-hero-main">
|
||||||
|
<img src="{{ asset('images/icon/lp/rocket.png') }}" alt="Mulai" class="icon-sm">
|
||||||
|
Mulai Sekarang
|
||||||
|
</a>
|
||||||
<a href="#fitur" class="btn-hero-outline">Lihat Fitur</a>
|
<a href="#fitur" class="btn-hero-outline">Lihat Fitur</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -518,15 +396,17 @@
|
||||||
<div class="hero-main-card">
|
<div class="hero-main-card">
|
||||||
|
|
||||||
<div class="float-badge fb-1">
|
<div class="float-badge fb-1">
|
||||||
⭐ <span>+150 EXP didapat!</span>
|
<img src="{{ asset('images/icon/lp/star.png') }}" alt="EXP" class="icon-sm">
|
||||||
|
<span>+150 EXP didapat!</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="float-badge fb-2">
|
<div class="float-badge fb-2">
|
||||||
🏆 <span>Naik ke #2!</span>
|
<img src="{{ asset('images/icon/lp/piala.png') }}" alt="Naik peringkat" class="icon-sm">
|
||||||
|
<span>Naik ke #2!</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hmc-header">
|
<div class="hmc-header">
|
||||||
<div class="hmc-logo">
|
<div class="hmc-logo">
|
||||||
<img src="/images/logo/logosmk.png" alt="Logo">
|
<img src="/images/logo/logosmk.png" alt="Logo SMK">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="hmc-name">Dashboard Siswa RPL</div>
|
<div class="hmc-name">Dashboard Siswa RPL</div>
|
||||||
|
|
@ -536,35 +416,52 @@
|
||||||
|
|
||||||
<div class="hmc-stat-row">
|
<div class="hmc-stat-row">
|
||||||
<div class="hmc-stat">
|
<div class="hmc-stat">
|
||||||
<div class="hmc-stat-num">24</div>
|
<div class="hmc-stat-num">7</div>
|
||||||
<div class="hmc-stat-label">Materi</div>
|
<div class="hmc-stat-label">Materi</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hmc-stat">
|
<div class="hmc-stat">
|
||||||
<div class="hmc-stat-num">8</div>
|
<div class="hmc-stat-num">4</div>
|
||||||
<div class="hmc-stat-label">Tugas</div>
|
<div class="hmc-stat-label">Tugas</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hmc-stat">
|
<div class="hmc-stat">
|
||||||
<div class="hmc-stat-num">850</div>
|
<div class="hmc-stat-num">304</div>
|
||||||
<div class="hmc-stat-label">EXP</div>
|
<div class="hmc-stat-label">EXP</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hmc-lb">
|
<div class="hmc-lb">
|
||||||
<div class="hmc-lb-title">🏅 Leaderboard Kelas</div>
|
<div class="hmc-lb-title">
|
||||||
|
<img src="{{ asset('images/icon/lp/piala.png') }}" alt="Leaderboard" class="icon-sm">
|
||||||
|
Leaderboard Kelas
|
||||||
|
</div>
|
||||||
<div class="hmc-lb-row">
|
<div class="hmc-lb-row">
|
||||||
<div class="hmc-lb-rank" style="background:#f59e0b;">🥇</div>
|
<div class="hmc-lb-rank" style="background:#f59e0b;">
|
||||||
<div class="hmc-lb-name">Andi Prasetyo</div>
|
<img src="{{ asset('images/icon/lp/medal1.png') }}" alt="Juara 1">
|
||||||
<div class="hmc-lb-exp">1.200 ⭐</div>
|
</div>
|
||||||
|
<div class="hmc-lb-name">Retasya Salsabila</div>
|
||||||
|
<div class="hmc-lb-exp">
|
||||||
|
1.200
|
||||||
|
<img src="{{ asset('images/icon/lp/star.png') }}" alt="EXP" class="icon-pill">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hmc-lb-row" style="background:#e8f4ff;">
|
<div class="hmc-lb-row" style="background:#e8f4ff;">
|
||||||
<div class="hmc-lb-rank">2</div>
|
<div class="hmc-lb-rank" style="background:var(--blue);">2</div>
|
||||||
<div class="hmc-lb-name">Kamu 👋</div>
|
<div class="hmc-lb-name">
|
||||||
<div class="hmc-lb-exp">850 ⭐</div>
|
Kamu
|
||||||
|
<img src="{{ asset('images/icon/lp/wavinghand.png') }}" alt="Hai" class="icon-pill">
|
||||||
|
</div>
|
||||||
|
<div class="hmc-lb-exp">
|
||||||
|
850
|
||||||
|
<img src="{{ asset('images/icon/lp/star.png') }}" alt="EXP" class="icon-pill">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hmc-lb-row">
|
<div class="hmc-lb-row">
|
||||||
<div class="hmc-lb-rank" style="background:#64748b;">3</div>
|
<div class="hmc-lb-rank" style="background:#64748b;">3</div>
|
||||||
<div class="hmc-lb-name">Siti Rahayu</div>
|
<div class="hmc-lb-name">Keisya Nadia</div>
|
||||||
<div class="hmc-lb-exp">720 ⭐</div>
|
<div class="hmc-lb-exp">
|
||||||
|
720
|
||||||
|
<img src="{{ asset('images/icon/lp/star.png') }}" alt="EXP" class="icon-pill">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -579,25 +476,25 @@
|
||||||
<div class="row align-items-center g-3">
|
<div class="row align-items-center g-3">
|
||||||
<div class="col-6 col-md-3">
|
<div class="col-6 col-md-3">
|
||||||
<div class="stat-bar-item">
|
<div class="stat-bar-item">
|
||||||
<div class="stat-bar-num">500+</div>
|
<div class="stat-bar-num">10+</div>
|
||||||
<div class="stat-bar-label">Materi Tersedia</div>
|
<div class="stat-bar-label">Materi Tersedia</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-md-3">
|
<div class="col-6 col-md-3">
|
||||||
<div class="stat-bar-item">
|
<div class="stat-bar-item">
|
||||||
<div class="stat-bar-num">1.200+</div>
|
<div class="stat-bar-num">100+</div>
|
||||||
<div class="stat-bar-label">Siswa Aktif</div>
|
<div class="stat-bar-label">Siswa Aktif</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-md-3">
|
<div class="col-6 col-md-3">
|
||||||
<div class="stat-bar-item">
|
<div class="stat-bar-item">
|
||||||
<div class="stat-bar-num">300+</div>
|
<div class="stat-bar-num">15+</div>
|
||||||
<div class="stat-bar-label">Challenge Selesai</div>
|
<div class="stat-bar-label">Challenge Selesai</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-md-3">
|
<div class="col-6 col-md-3">
|
||||||
<div class="stat-bar-item">
|
<div class="stat-bar-item">
|
||||||
<div class="stat-bar-num">50+</div>
|
<div class="stat-bar-num">15+</div>
|
||||||
<div class="stat-bar-label">Guru Pengajar</div>
|
<div class="stat-bar-label">Guru Pengajar</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -611,41 +508,49 @@
|
||||||
<div class="row align-items-center g-5 mb-5">
|
<div class="row align-items-center g-5 mb-5">
|
||||||
<div class="col-lg-5">
|
<div class="col-lg-5">
|
||||||
<div class="pill-label">✦ Fitur Platform</div>
|
<div class="pill-label">✦ Fitur Platform</div>
|
||||||
<h2 class="sec-title">Lengkap untuk<br>Siswa RPL yang<br>Ambisius</h2>
|
<h2 class="sec-title">Lengkap untuk<br>Siswa RPL di<br>SMKN 1 Tapen</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 offset-lg-1">
|
<div class="col-lg-6 offset-lg-1">
|
||||||
<p class="sec-desc">Dari materi pemrograman hingga gamifikasi — semua dirancang khusus untuk mendukung proses belajar di jurusan Rekayasa Perangkat Lunak.</p>
|
<p class="sec-desc">Dari materi pemrograman hingga gamifikasi semua dirancang untuk mendukung proses belajar mengajar di jurusan Rekayasa Perangkat Lunak.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<div class="feat-card">
|
<div class="feat-card">
|
||||||
<div class="feat-icon">📖</div>
|
<div class="feat-icon">
|
||||||
|
<img src="{{ asset('images/icon/lp/buku1.png') }}" alt="Materi Digital" class="icon-feat">
|
||||||
|
</div>
|
||||||
<div class="feat-title">Materi Digital</div>
|
<div class="feat-title">Materi Digital</div>
|
||||||
<p class="feat-desc">Guru RPL upload modul, siswa akses kapan saja. Materi terorganisir per mapel dan kelas — dari dasar coding sampai advanced.</p>
|
<p class="feat-desc">Guru RPL upload materi, siswa akses kapan saja. Materi terorganisir per mapel dan kelas dari dasar coding hingga advanced.</p>
|
||||||
<span class="feat-tag">Untuk Siswa & Guru</span>
|
<span class="feat-tag">Untuk Siswa & Guru</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<div class="feat-card">
|
<div class="feat-card">
|
||||||
<div class="feat-icon orange">📝</div>
|
<div class="feat-icon orange">
|
||||||
|
<img src="{{ asset('images/icon/lp/buku2.png') }}" alt="Pengumpulan Tugas" class="icon-feat">
|
||||||
|
</div>
|
||||||
<div class="feat-title">Pengumpulan Tugas</div>
|
<div class="feat-title">Pengumpulan Tugas</div>
|
||||||
<p class="feat-desc">Submit tugas coding online langsung dari browser. Tracking status real-time: belum, dikumpulkan, atau terlambat.</p>
|
<p class="feat-desc">Submit tugas langsung dari browser. Tracking status real-time: belum, dikumpulkan, atau terlambat.</p>
|
||||||
<span class="feat-tag" style="background:#fff4ee;color:#f97316;">Manajemen Tugas</span>
|
<span class="feat-tag" style="background:#fff4ee;color:#f97316;">Manajemen Tugas</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<div class="feat-card">
|
<div class="feat-card">
|
||||||
<div class="feat-icon green">🏆</div>
|
<div class="feat-icon green">
|
||||||
|
<img src="{{ asset('images/icon/lp/piala.png') }}" alt="Challenge Interaktif" class="icon-feat">
|
||||||
|
</div>
|
||||||
<div class="feat-title">Challenge Interaktif</div>
|
<div class="feat-title">Challenge Interaktif</div>
|
||||||
<p class="feat-desc">Kuis pilihan ganda seputar materi RPL dengan navigasi soal dinamis. Kerjakan sebelum tenggat dan buktikan kemampuanmu!</p>
|
<p class="feat-desc">Kuis pilihan ganda seputar materi RPL. Kerjakan sebelum tenggat dan buktikan kemampuanmu!</p>
|
||||||
<span class="feat-tag" style="background:#eefaf3;color:#22c55e;">Gamifikasi</span>
|
<span class="feat-tag" style="background:#eefaf3;color:#22c55e;">Gamifikasi</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<div class="feat-card">
|
<div class="feat-card">
|
||||||
<div class="feat-icon purple">⭐</div>
|
<div class="feat-icon purple">
|
||||||
|
<img src="{{ asset('images/icon/lp/star.png') }}" alt="Sistem EXP" class="icon-feat">
|
||||||
|
</div>
|
||||||
<div class="feat-title">Sistem EXP</div>
|
<div class="feat-title">Sistem EXP</div>
|
||||||
<p class="feat-desc">Setiap jawaban benar menghasilkan EXP. Semakin banyak belajar, semakin tinggi skormu!</p>
|
<p class="feat-desc">Setiap jawaban benar menghasilkan EXP. Semakin banyak belajar, semakin tinggi skormu!</p>
|
||||||
<span class="feat-tag" style="background:#f5eeff;color:#a855f7;">Reward System</span>
|
<span class="feat-tag" style="background:#f5eeff;color:#a855f7;">Reward System</span>
|
||||||
|
|
@ -653,18 +558,22 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<div class="feat-card">
|
<div class="feat-card">
|
||||||
<div class="feat-icon yellow">📊</div>
|
<div class="feat-icon yellow">
|
||||||
|
<img src="{{ asset('images/icon/lp/lb.png') }}" alt="Leaderboard" class="icon-feat">
|
||||||
|
</div>
|
||||||
<div class="feat-title">Leaderboard Real-time</div>
|
<div class="feat-title">Leaderboard Real-time</div>
|
||||||
<p class="feat-desc">Peringkat diperbarui otomatis setiap kali siswa menyelesaikan challenge. Siapa #1?</p>
|
<p class="feat-desc">Peringkat diperbarui otomatis setiap kali siswa menyelesaikan challenge. Siapa #1?</p>
|
||||||
<span class="feat-tag" style="background:#fffbea;color:#d97706;">Kompetisi Sehat</span>
|
<span class="feat-tag" style="background:#fffbea;color:#d97706;">Kompetisi Sehat Antar Siswa</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="col-md-6 col-lg-4">
|
||||||
<div class="feat-card">
|
<div class="feat-card">
|
||||||
<div class="feat-icon pink">🛡️</div>
|
<div class="feat-icon pink">
|
||||||
|
<img src="{{ asset('images/icon/lp/shield.png') }}" alt="Multi-Role Panel" class="icon-feat">
|
||||||
|
</div>
|
||||||
<div class="feat-title">Multi-Role Panel</div>
|
<div class="feat-title">Multi-Role Panel</div>
|
||||||
<p class="feat-desc">Dashboard terpisah untuk Siswa, Guru, dan Admin dengan hak akses yang sesuai peran.</p>
|
<p class="feat-desc">Dashboard terpisah untuk Siswa, Guru, dan Admin dengan hak akses yang sesuai peran.</p>
|
||||||
<span class="feat-tag" style="background:#fff0f6;color:#ec4899;">Keamanan</span>
|
<span class="feat-tag" style="background:#fff0f6;color:#ec4899;">Keamanan User</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -678,9 +587,8 @@
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="pill-label">✦ Cara Kerja</div>
|
<div class="pill-label">✦ Cara Kerja</div>
|
||||||
<h2 class="sec-title">Mulai dalam<br>3 Langkah<br>Mudah</h2>
|
<h2 class="sec-title">Mulai dalam<br>3 Langkah<br>Mudah</h2>
|
||||||
<p class="sec-desc" style="margin-top:14px;">Tidak perlu instalasi apapun — cukup buka browser dan login!</p>
|
<p class="sec-desc" style="margin-top:14px;">Tidak perlu instalasi apapun cukup buka browser dan login!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-lg-7 offset-lg-1">
|
<div class="col-lg-7 offset-lg-1">
|
||||||
<div class="step-wrap">
|
<div class="step-wrap">
|
||||||
<div class="step-item">
|
<div class="step-item">
|
||||||
|
|
@ -694,7 +602,7 @@
|
||||||
<div class="step-num-wrap">2</div>
|
<div class="step-num-wrap">2</div>
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
<div class="step-title">Akses Materi & Selesaikan Tugas</div>
|
<div class="step-title">Akses Materi & Selesaikan Tugas</div>
|
||||||
<p class="step-desc">Pelajari materi yang diupload guru dan kumpulkan tugas tepat waktu untuk performa terbaik.</p>
|
<p class="step-desc">Pelajari materi yang diupload guru dan kumpulkan tugas tepat waktu.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-item">
|
<div class="step-item">
|
||||||
|
|
@ -718,27 +626,32 @@
|
||||||
<h2 class="sec-title">Masuk Sesuai Peranmu</h2>
|
<h2 class="sec-title">Masuk Sesuai Peranmu</h2>
|
||||||
<p style="font-size:15px;color:#64748b;">Pilih portal yang sesuai dengan peranmu di jurusan RPL SMKN 1 Tapen.</p>
|
<p style="font-size:15px;color:#64748b;">Pilih portal yang sesuai dengan peranmu di jurusan RPL SMKN 1 Tapen.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-4 justify-content-center">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="portal-card pc-blue">
|
<div class="portal-card pc-blue">
|
||||||
<div class="portal-icon-wrap piw-blue">👨💻</div>
|
<div class="portal-icon-wrap piw-blue">
|
||||||
|
<img src="{{ asset('images/icon/lp/siswa.png') }}" alt="Siswa" class="icon-portal">
|
||||||
|
</div>
|
||||||
<div class="portal-title">Siswa RPL</div>
|
<div class="portal-title">Siswa RPL</div>
|
||||||
<p class="portal-desc">Akses materi coding, kumpulkan tugas, kerjakan challenge, dan pantau posisimu di leaderboard kelas.</p>
|
<p class="portal-desc">Akses materi coding, kumpulkan tugas, kerjakan challenge, dan lihat posisimu di leaderboard kelas.</p>
|
||||||
<a href="/siswa/login" class="btn-portal bp-blue">Masuk sebagai Siswa →</a>
|
<a href="/siswa/login" class="btn-portal bp-blue">Masuk sebagai Siswa →</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="portal-card pc-green">
|
<div class="portal-card pc-green">
|
||||||
<div class="portal-icon-wrap piw-green">👩🏫</div>
|
<div class="portal-icon-wrap piw-green">
|
||||||
|
<img src="{{ asset('images/icon/lp/guru.png') }}" alt="Guru" class="icon-portal">
|
||||||
|
</div>
|
||||||
<div class="portal-title">Guru</div>
|
<div class="portal-title">Guru</div>
|
||||||
<p class="portal-desc">Upload modul RPL, buat tugas coding, nilai pengumpulan siswa, dan pantau perkembangan kelas.</p>
|
<p class="portal-desc">Upload materi, buat tugas, nilai pengumpulan siswa, dan pantau perkembangan kelas.</p>
|
||||||
<a href="/guru/login" class="btn-portal bp-green">Masuk sebagai Guru →</a>
|
<a href="/guru/login" class="btn-portal bp-green">Masuk sebagai Guru →</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="portal-card pc-orange">
|
<div class="portal-card pc-orange">
|
||||||
<div class="portal-icon-wrap piw-orange">🛡️</div>
|
<div class="portal-icon-wrap piw-orange">
|
||||||
|
<img src="{{ asset('images/icon/lp/admin.png') }}" alt="Admin" class="icon-portal">
|
||||||
|
</div>
|
||||||
<div class="portal-title">Admin</div>
|
<div class="portal-title">Admin</div>
|
||||||
<p class="portal-desc">Kelola data jurusan RPL, buat challenge, dan pantau seluruh aktivitas di platform.</p>
|
<p class="portal-desc">Kelola data jurusan RPL, buat challenge, dan pantau seluruh aktivitas di platform.</p>
|
||||||
<a href="/admin/login" class="btn-portal bp-orange">Masuk sebagai Admin →</a>
|
<a href="/admin/login" class="btn-portal bp-orange">Masuk sebagai Admin →</a>
|
||||||
|
|
@ -754,7 +667,7 @@
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<div class="d-flex align-items-center gap-3 mb-3">
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
<img src="/images/logo/logosmk.png" alt="Logo" style="width:40px;height:40px;object-fit:contain;filter:brightness(10);">
|
<img src="/images/logo/logosmk.png" alt="Logo SMK" style="width:40px;height:40px;object-fit:contain;filter:brightness(10);">
|
||||||
<div class="ft-brand">E-Learning RPL</div>
|
<div class="ft-brand">E-Learning RPL</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="ft-desc">Platform e-learning dengan gamifikasi khusus jurusan Rekayasa Perangkat Lunak SMKN 1 Tapen.</p>
|
<p class="ft-desc">Platform e-learning dengan gamifikasi khusus jurusan Rekayasa Perangkat Lunak SMKN 1 Tapen.</p>
|
||||||
|
|
@ -767,18 +680,23 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="ft-heading">Portal</div>
|
<div class="ft-heading">Portal</div>
|
||||||
<a href="/siswa/login" class="ft-link">👩🎓 Siswa</a>
|
<a href="/siswa/login" class="ft-link">
|
||||||
<a href="/guru/login" class="ft-link">👩🏫 Guru</a>
|
<img src="{{ asset('images/icon/lp/siswa.png') }}" alt="Siswa" class="icon-footer"> Siswa
|
||||||
<a href="/admin/login" class="ft-link">🛡️ Admin</a>
|
</a>
|
||||||
|
<a href="/guru/login" class="ft-link">
|
||||||
|
<img src="{{ asset('images/icon/lp/guru.png') }}" alt="Guru" class="icon-footer"> Guru
|
||||||
|
</a>
|
||||||
|
<a href="/admin/login" class="ft-link">
|
||||||
|
<img src="{{ asset('images/icon/lp/admin.png') }}" alt="Admin" class="icon-footer"> Admin
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ft-copy">© 2025 SMKN 1 Tapen · Jurusan Rekayasa Perangkat Lunak · Platform E-Learning Gamifikasi</div>
|
<div class="ft-copy">© Retasya Salsabila · 2026 SMKN 1 Tapen · Jurusan Rekayasa Perangkat Lunak · Platform E-Learning Gamifikasi</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// Smooth scroll
|
|
||||||
document.querySelectorAll('a[href^="#"]').forEach(a => {
|
document.querySelectorAll('a[href^="#"]').forEach(a => {
|
||||||
a.addEventListener('click', e => {
|
a.addEventListener('click', e => {
|
||||||
const t = document.querySelector(a.getAttribute('href'));
|
const t = document.querySelector(a.getAttribute('href'));
|
||||||
|
|
@ -786,7 +704,6 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scroll reveal
|
|
||||||
const observer = new IntersectionObserver((entries) => {
|
const observer = new IntersectionObserver((entries) => {
|
||||||
entries.forEach(e => {
|
entries.forEach(e => {
|
||||||
if (e.isIntersecting) {
|
if (e.isIntersecting) {
|
||||||
|
|
|
||||||
|
|
@ -17,25 +17,23 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hasil-hero::before {
|
.hasil-emoji { margin-bottom: 10px; }
|
||||||
content: '🏆';
|
.hasil-emoji img { width: 64px; height: 64px; object-fit: contain; }
|
||||||
position: absolute;
|
|
||||||
font-size: 120px;
|
|
||||||
opacity: 0.08;
|
|
||||||
top: -10px; right: -10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hasil-emoji { font-size: 52px; margin-bottom: 10px; }
|
|
||||||
.hasil-title { font-size: 22px; font-weight: 800; margin-bottom: 4px; }
|
.hasil-title { font-size: 22px; font-weight: 800; margin-bottom: 4px; }
|
||||||
.hasil-subtitle { font-size: 14px; opacity: 0.85; margin-bottom: 20px; }
|
.hasil-subtitle { font-size: 14px; opacity: 0.85; margin-bottom: 20px; }
|
||||||
|
|
||||||
.hasil-exp {
|
.hasil-exp {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
background: rgba(255,255,255,0.2);
|
background: rgba(255,255,255,0.2);
|
||||||
border-radius: 99px;
|
border-radius: 99px;
|
||||||
padding: 8px 24px;
|
padding: 8px 24px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
.hasil-exp img { width: 22px; height: 22px; object-fit: contain; }
|
||||||
|
|
||||||
.stat-row { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; margin-bottom: 24px; }
|
.stat-row { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; margin-bottom: 24px; }
|
||||||
.stat-box { background: white; border-radius: 16px; border: 2px solid #e5e5e5; padding: 18px 14px; text-align: center; }
|
.stat-box { background: white; border-radius: 16px; border: 2px solid #e5e5e5; padding: 18px 14px; text-align: center; }
|
||||||
|
|
@ -43,7 +41,17 @@
|
||||||
.stat-label { font-size: 12px; color: #94a3b8; margin: 4px 0 0; font-weight: 500; }
|
.stat-label { font-size: 12px; color: #94a3b8; margin: 4px 0 0; font-weight: 500; }
|
||||||
|
|
||||||
.custom-card { background: white; border-radius: 20px; border: 2px solid #e5e5e5; padding: 24px; margin-bottom: 16px; }
|
.custom-card { background: white; border-radius: 20px; border: 2px solid #e5e5e5; padding: 24px; margin-bottom: 16px; }
|
||||||
.section-title { font-size: 16px; font-weight: 700; color: #1e293b; margin-bottom: 16px; }
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1e293b;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.section-title img { width: 20px; height: 20px; object-fit: contain; }
|
||||||
|
|
||||||
.soal-review { border: 2px solid #e2e8f0; border-radius: 14px; padding: 18px; margin-bottom: 12px; }
|
.soal-review { border: 2px solid #e2e8f0; border-radius: 14px; padding: 18px; margin-bottom: 12px; }
|
||||||
.soal-review.benar { border-color: #22c55e; background: #f0fdf4; }
|
.soal-review.benar { border-color: #22c55e; background: #f0fdf4; }
|
||||||
|
|
@ -51,9 +59,20 @@
|
||||||
|
|
||||||
.review-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
|
.review-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
|
||||||
.review-number { font-size: 12px; font-weight: 700; color: #64748b; }
|
.review-number { font-size: 12px; font-weight: 700; color: #64748b; }
|
||||||
.review-status { font-size: 12px; font-weight: 700; padding: 2px 10px; border-radius: 99px; }
|
|
||||||
|
.review-status {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 99px;
|
||||||
|
}
|
||||||
|
.review-status img { width: 13px; height: 13px; object-fit: contain; }
|
||||||
.review-status.benar { background: #dcfce7; color: #16a34a; }
|
.review-status.benar { background: #dcfce7; color: #16a34a; }
|
||||||
.review-status.salah { background: #fee2e2; color: #dc2626; }
|
.review-status.salah { background: #fee2e2; color: #dc2626; }
|
||||||
|
|
||||||
.review-pertanyaan { font-size: 14px; font-weight: 600; color: #1e293b; margin-bottom: 12px; line-height: 1.6; }
|
.review-pertanyaan { font-size: 14px; font-weight: 600; color: #1e293b; margin-bottom: 12px; line-height: 1.6; }
|
||||||
|
|
||||||
.opsi-review {
|
.opsi-review {
|
||||||
|
|
@ -66,7 +85,6 @@
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opsi-review.jawaban-benar { background: #dcfce7; font-weight: 700; color: #15803d; }
|
.opsi-review.jawaban-benar { background: #dcfce7; font-weight: 700; color: #15803d; }
|
||||||
.opsi-review.salah-dipilih { background: #fee2e2; color: #991b1b; font-weight: 700; }
|
.opsi-review.salah-dipilih { background: #fee2e2; color: #991b1b; font-weight: 700; }
|
||||||
|
|
||||||
|
|
@ -77,13 +95,25 @@
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
font-size: 11px; font-weight: 700; flex-shrink: 0;
|
font-size: 11px; font-weight: 700; flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opsi-review.jawaban-benar .opsi-circle { background: #22c55e; color: white; }
|
.opsi-review.jawaban-benar .opsi-circle { background: #22c55e; color: white; }
|
||||||
.opsi-review.salah-dipilih .opsi-circle { background: #ef4444; color: white; }
|
.opsi-review.salah-dipilih .opsi-circle { background: #ef4444; color: white; }
|
||||||
|
|
||||||
|
.opsi-tag {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 12px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.opsi-tag img { width: 13px; height: 13px; object-fit: contain; }
|
||||||
|
|
||||||
.btn-back {
|
.btn-back {
|
||||||
display: block;
|
display: flex;
|
||||||
text-align: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
@ -100,7 +130,17 @@
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
@php
|
@php
|
||||||
$emoji = $persentase >= 80 ? '🎉' : ($persentase >= 60 ? '👍' : '💪');
|
if ($persentase >= 80) {
|
||||||
|
$emojiSrc = asset('images/icon/siswac/confetti.png');
|
||||||
|
$emojiAlt = 'Selamat, hasil luar biasa!';
|
||||||
|
} elseif ($persentase >= 60) {
|
||||||
|
$emojiSrc = asset('images/icon/siswac/sip.png');
|
||||||
|
$emojiAlt = 'Bagus, terus tingkatkan!';
|
||||||
|
} else {
|
||||||
|
$emojiSrc = asset('images/icon/siswac/muscle.png');
|
||||||
|
$emojiAlt = 'Semangat, jangan menyerah!';
|
||||||
|
}
|
||||||
|
|
||||||
$pesan = $persentase >= 80
|
$pesan = $persentase >= 80
|
||||||
? 'Luar biasa! Kamu menguasai materi ini!'
|
? 'Luar biasa! Kamu menguasai materi ini!'
|
||||||
: ($persentase >= 60 ? 'Bagus! Terus tingkatkan kemampuanmu!' : 'Jangan menyerah! Terus semangat belajar!');
|
: ($persentase >= 60 ? 'Bagus! Terus tingkatkan kemampuanmu!' : 'Jangan menyerah! Terus semangat belajar!');
|
||||||
|
|
@ -109,10 +149,15 @@
|
||||||
<div class="hasil-wrapper">
|
<div class="hasil-wrapper">
|
||||||
|
|
||||||
<div class="hasil-hero">
|
<div class="hasil-hero">
|
||||||
<div class="hasil-emoji">{{ $emoji }}</div>
|
<div class="hasil-emoji">
|
||||||
|
<img src="{{ $emojiSrc }}" alt="{{ $emojiAlt }}">
|
||||||
|
</div>
|
||||||
<div class="hasil-title">{{ $challenge->judul_challenge }}</div>
|
<div class="hasil-title">{{ $challenge->judul_challenge }}</div>
|
||||||
<div class="hasil-subtitle">{{ $pesan }}</div>
|
<div class="hasil-subtitle">{{ $pesan }}</div>
|
||||||
<div class="hasil-exp">⭐ +{{ $peserta->exp }} EXP didapat!</div>
|
<div class="hasil-exp">
|
||||||
|
<img src="{{ asset('images/icon/siswac/star.png') }}" alt="Ikon bintang EXP">
|
||||||
|
+{{ $peserta->exp }} EXP didapat!
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stat-row">
|
<div class="stat-row">
|
||||||
|
|
@ -131,7 +176,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="custom-card">
|
<div class="custom-card">
|
||||||
<p class="section-title">📋 Pembahasan Jawaban</p>
|
<p class="section-title">
|
||||||
|
<img src="{{ asset('images/icon/siswac/buku1.png') }}" alt="Ikon buku">
|
||||||
|
Pembahasan Jawaban
|
||||||
|
</p>
|
||||||
|
|
||||||
@foreach($challenge->soal as $i => $soal)
|
@foreach($challenge->soal as $i => $soal)
|
||||||
@php
|
@php
|
||||||
|
|
@ -143,7 +191,11 @@
|
||||||
<div class="review-header">
|
<div class="review-header">
|
||||||
<span class="review-number">Soal {{ $i + 1 }}</span>
|
<span class="review-number">Soal {{ $i + 1 }}</span>
|
||||||
<span class="review-status {{ $isBenar ? 'benar' : 'salah' }}">
|
<span class="review-status {{ $isBenar ? 'benar' : 'salah' }}">
|
||||||
{{ $isBenar ? '✅ Benar' : '❌ Salah' }}
|
@if($isBenar)
|
||||||
|
<img src="{{ asset('images/icon/siswac/v.png') }}" alt="Centang benar"> Benar
|
||||||
|
@else
|
||||||
|
<img src="{{ asset('images/icon/siswac/x.png') }}" alt="Tanda salah"> Salah
|
||||||
|
@endif
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -160,9 +212,11 @@
|
||||||
<span class="opsi-circle">{{ $opsi }}</span>
|
<span class="opsi-circle">{{ $opsi }}</span>
|
||||||
<span>{{ $soal->$key }}</span>
|
<span>{{ $soal->$key }}</span>
|
||||||
@if($isJwbBenar)
|
@if($isJwbBenar)
|
||||||
<span style="margin-left:auto;font-size:12px">✅ Jawaban benar</span>
|
<span class="opsi-tag">
|
||||||
|
<img src="{{ asset('images/icon/siswac/v.png') }}" alt="Centang benar"> Jawaban benar
|
||||||
|
</span>
|
||||||
@elseif($isDipilih)
|
@elseif($isDipilih)
|
||||||
<span style="margin-left:auto;font-size:12px">← Jawabanmu</span>
|
<span class="opsi-tag">← Jawabanmu</span>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,16 @@
|
||||||
|
|
||||||
@push('styles')
|
@push('styles')
|
||||||
<style>
|
<style>
|
||||||
.page-title { font-size: 28px; font-weight: 800; margin-top: -20px; margin-bottom: 6px; }
|
.page-title {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1e293b;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.page-title img { width: 32px; height: 32px; object-fit: contain; }
|
||||||
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 24px; }
|
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 24px; }
|
||||||
|
|
||||||
.challenge-grid {
|
.challenge-grid {
|
||||||
|
|
@ -13,6 +22,7 @@
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hapus ::before emoji — diganti dengan badge gambar */
|
||||||
.challenge-card {
|
.challenge-card {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|
@ -22,11 +32,20 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.challenge-card:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0,0,0,0.1); }
|
.challenge-card:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0,0,0,0.1); }
|
||||||
.challenge-card.sudah { border-color: #a5e6ba; background: linear-gradient(135deg, #f0fdf4, #fff); }
|
.challenge-card.sudah { border-color: #a5e6ba; background: linear-gradient(135deg, #f0fdf4, #fff); }
|
||||||
.challenge-card.lewat { border-color: #fecaca; background: #fffafa; opacity: 0.85; }
|
.challenge-card.lewat { border-color: #fecaca; background: #fffafa; opacity: 0.85; }
|
||||||
|
|
||||||
|
/* Watermark pojok kanan atas via img absolut */
|
||||||
|
.card-watermark {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px; right: 14px;
|
||||||
|
width: 36px; height: 36px;
|
||||||
|
object-fit: contain;
|
||||||
|
opacity: 0.12;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.card-badge {
|
.card-badge {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -37,6 +56,7 @@
|
||||||
border-radius: 99px;
|
border-radius: 99px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
.card-badge img { width: 13px; height: 13px; object-fit: contain; }
|
||||||
|
|
||||||
.badge-aktif { background: #dcfce7; color: #16a34a; }
|
.badge-aktif { background: #dcfce7; color: #16a34a; }
|
||||||
.badge-sudah { background: #e0f2fe; color: #0369a1; }
|
.badge-sudah { background: #e0f2fe; color: #0369a1; }
|
||||||
|
|
@ -59,12 +79,14 @@
|
||||||
color: #475569;
|
color: #475569;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
.meta-item img { width: 14px; height: 14px; object-fit: contain; }
|
||||||
.meta-item.exp { background: #fef9c3; color: #b45309; border-color: #fde68a; }
|
.meta-item.exp { background: #fef9c3; color: #b45309; border-color: #fde68a; }
|
||||||
|
|
||||||
.btn-kerjakan {
|
.btn-kerjakan {
|
||||||
display: block;
|
display: flex;
|
||||||
text-align: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
@ -74,11 +96,14 @@
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
}
|
}
|
||||||
|
.btn-kerjakan img { width: 16px; height: 16px; object-fit: contain; }
|
||||||
.btn-kerjakan:hover { opacity: 0.9; color: white; }
|
.btn-kerjakan:hover { opacity: 0.9; color: white; }
|
||||||
|
|
||||||
.btn-lihat-hasil {
|
.btn-lihat-hasil {
|
||||||
display: block;
|
display: flex;
|
||||||
text-align: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
background: #e0f2fe;
|
background: #e0f2fe;
|
||||||
color: #0369a1;
|
color: #0369a1;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
@ -87,6 +112,7 @@
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
.btn-lihat-hasil img { width: 16px; height: 16px; object-fit: contain; }
|
||||||
.btn-lihat-hasil:hover { background: #bae6fd; color: #0369a1; }
|
.btn-lihat-hasil:hover { background: #bae6fd; color: #0369a1; }
|
||||||
|
|
||||||
.btn-disabled {
|
.btn-disabled {
|
||||||
|
|
@ -102,32 +128,42 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state { text-align: center; padding: 60px 20px; color: #94a3b8; }
|
.empty-state { text-align: center; padding: 60px 20px; color: #94a3b8; }
|
||||||
.alert-error { background: #fee2e2; color: #991b1b; border-radius: 12px; padding: 12px 16px; margin-bottom: 20px; font-weight: 500; font-size: 14px; }
|
.empty-state img { width: 56px; height: 56px; object-fit: contain; margin-bottom: 16px; }
|
||||||
|
|
||||||
.challenge-card::before {
|
.alert-error {
|
||||||
content: '🏆';
|
display: flex;
|
||||||
position: absolute;
|
align-items: center;
|
||||||
top: 16px; right: 16px;
|
gap: 8px;
|
||||||
font-size: 28px;
|
background: #fee2e2;
|
||||||
opacity: 0.12;
|
color: #991b1b;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.challenge-card.sudah::before { content: '✅'; opacity: 0.2; }
|
.alert-error img { width: 16px; height: 16px; object-fit: contain; flex-shrink: 0; }
|
||||||
.challenge-card.lewat::before { content: '⏰'; opacity: 0.15; }
|
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<h3 class="page-title">🏆 Challenge</h3>
|
<h3 class="page-title">
|
||||||
|
<img src="{{ asset('images/icon/siswac/piala.png') }}" alt="Ikon piala">
|
||||||
|
Challenge
|
||||||
|
</h3>
|
||||||
<p class="page-subtitle">Kerjakan challenge untuk mendapatkan EXP dan naik peringkat di leaderboard!</p>
|
<p class="page-subtitle">Kerjakan challenge untuk mendapatkan EXP dan naik peringkat di leaderboard!</p>
|
||||||
|
|
||||||
@if(session('error'))
|
@if(session('error'))
|
||||||
<div class="alert-error">❌ {{ session('error') }}</div>
|
<div class="alert-error">
|
||||||
|
<img src="{{ asset('images/icon/siswac/x.png') }}" alt="Error">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if($challenges->isEmpty())
|
@if($challenges->isEmpty())
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div style="font-size:56px;margin-bottom:16px">🎯</div>
|
<img src="{{ asset('images/icon/siswac/target.png') }}" alt="Belum ada challenge">
|
||||||
<p style="font-size:16px;font-weight:600;color:#475569">Belum ada challenge untuk kelasmu.</p>
|
<p style="font-size:16px;font-weight:600;color:#475569">Belum ada challenge untuk kelasmu.</p>
|
||||||
<p style="font-size:13px">Tunggu admin membuat challenge baru!</p>
|
<p style="font-size:13px">Tunggu admin membuat challenge baru!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -138,14 +174,36 @@
|
||||||
$isLewat = \Carbon\Carbon::parse($ch->tenggat_waktu)->isPast();
|
$isLewat = \Carbon\Carbon::parse($ch->tenggat_waktu)->isPast();
|
||||||
$isSudah = in_array($ch->id_challenge, $sudahDikerjakan);
|
$isSudah = in_array($ch->id_challenge, $sudahDikerjakan);
|
||||||
$cardClass = $isSudah ? 'sudah' : ($isLewat ? 'lewat' : '');
|
$cardClass = $isSudah ? 'sudah' : ($isLewat ? 'lewat' : '');
|
||||||
|
|
||||||
|
// Watermark pojok kanan atas sesuai status
|
||||||
|
if ($isSudah) {
|
||||||
|
$watermarkSrc = asset('images/icon/siswac/v.png');
|
||||||
|
$watermarkAlt = 'Sudah dikerjakan';
|
||||||
|
} elseif ($isLewat) {
|
||||||
|
$watermarkSrc = asset('images/icon/siswac/alarm.png');
|
||||||
|
$watermarkAlt = 'Tenggat lewat';
|
||||||
|
} else {
|
||||||
|
$watermarkSrc = asset('images/icon/siswac/piala.png');
|
||||||
|
$watermarkAlt = 'Challenge aktif';
|
||||||
|
}
|
||||||
@endphp
|
@endphp
|
||||||
<div class="challenge-card {{ $cardClass }}">
|
<div class="challenge-card {{ $cardClass }}">
|
||||||
|
|
||||||
|
{{-- Watermark pengganti ::before emoji --}}
|
||||||
|
<img class="card-watermark" src="{{ $watermarkSrc }}" alt="{{ $watermarkAlt }}">
|
||||||
|
|
||||||
@if($isSudah)
|
@if($isSudah)
|
||||||
<span class="card-badge badge-sudah">✅ Sudah Dikerjakan</span>
|
<span class="card-badge badge-sudah">
|
||||||
|
<img src="{{ asset('images/icon/siswac/v.png') }}" alt="Centang"> Sudah Dikerjakan
|
||||||
|
</span>
|
||||||
@elseif($isLewat)
|
@elseif($isLewat)
|
||||||
<span class="card-badge badge-lewat">⏰ Tenggat Lewat</span>
|
<span class="card-badge badge-lewat">
|
||||||
|
<img src="{{ asset('images/icon/siswac/alarm.png') }}" alt="Alarm"> Tenggat Lewat
|
||||||
|
</span>
|
||||||
@else
|
@else
|
||||||
<span class="card-badge badge-aktif">🔥 Aktif</span>
|
<span class="card-badge badge-aktif">
|
||||||
|
<img src="{{ asset('images/icon/siswac/api.png') }}" alt="Api aktif"> Aktif
|
||||||
|
</span>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="card-title">{{ $ch->judul_challenge }}</div>
|
<div class="card-title">{{ $ch->judul_challenge }}</div>
|
||||||
|
|
@ -154,18 +212,34 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="card-meta">
|
<div class="card-meta">
|
||||||
<span class="meta-item">📝 {{ $ch->soal_count }} soal</span>
|
<span class="meta-item">
|
||||||
<span class="meta-item exp">⭐ {{ $ch->exp }} EXP</span>
|
<img src="{{ asset('images/icon/siswac/buku1.png') }}" alt="Jumlah soal">
|
||||||
<span class="meta-item">⏰ {{ \Carbon\Carbon::parse($ch->tenggat_waktu)->format('d M Y, H:i') }}</span>
|
{{ $ch->soal_count }} soal
|
||||||
|
</span>
|
||||||
|
<span class="meta-item exp">
|
||||||
|
<img src="{{ asset('images/icon/siswac/star.png') }}" alt="EXP">
|
||||||
|
{{ $ch->exp }} EXP
|
||||||
|
</span>
|
||||||
|
<span class="meta-item">
|
||||||
|
<img src="{{ asset('images/icon/siswac/alarm.png') }}" alt="Tenggat waktu">
|
||||||
|
{{ \Carbon\Carbon::parse($ch->tenggat_waktu)->format('d M Y, H:i') }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($isSudah)
|
@if($isSudah)
|
||||||
<a href="{{ route('siswa.challenge.hasil', $ch->id_challenge) }}" class="btn-lihat-hasil">📊 Lihat Hasil</a>
|
<a href="{{ route('siswa.challenge.hasil', $ch->id_challenge) }}" class="btn-lihat-hasil">
|
||||||
|
<img src="{{ asset('images/icon/siswac/lb.png') }}" alt="Lihat hasil">
|
||||||
|
Lihat Hasil
|
||||||
|
</a>
|
||||||
@elseif($isLewat)
|
@elseif($isLewat)
|
||||||
<span class="btn-disabled">Tenggat sudah lewat</span>
|
<span class="btn-disabled">Tenggat sudah lewat</span>
|
||||||
@else
|
@else
|
||||||
<a href="{{ route('siswa.challenge.kerjakan', $ch->id_challenge) }}" class="btn-kerjakan">🚀 Kerjakan Sekarang</a>
|
<a href="{{ route('siswa.challenge.kerjakan', $ch->id_challenge) }}" class="btn-kerjakan">
|
||||||
|
<img src="{{ asset('images/icon/siswac/rocket.png') }}" alt="Kerjakan">
|
||||||
|
Kerjakan Sekarang
|
||||||
|
</a>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,12 @@
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: #1e293b;
|
color: #1e293b;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
.quiz-title img { width: 24px; height: 24px; object-fit: contain; }
|
||||||
|
|
||||||
.quiz-meta {
|
.quiz-meta {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
@ -34,12 +39,12 @@
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.quiz-meta span {
|
.quiz-meta span {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
.quiz-meta img { width: 14px; height: 14px; object-fit: contain; }
|
||||||
|
|
||||||
/* Progress bar */
|
/* Progress bar */
|
||||||
.progress-bar-wrap {
|
.progress-bar-wrap {
|
||||||
|
|
@ -49,14 +54,12 @@
|
||||||
margin-bottom: 28px;
|
margin-bottom: 28px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar-fill {
|
.progress-bar-fill {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(90deg, #667eea, #764ba2);
|
background: linear-gradient(90deg, #667eea, #764ba2);
|
||||||
border-radius: 99px;
|
border-radius: 99px;
|
||||||
transition: width 0.4s ease;
|
transition: width 0.4s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-label {
|
.progress-label {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
@ -72,9 +75,8 @@
|
||||||
border: 2px solid #e5e5e5;
|
border: 2px solid #e5e5e5;
|
||||||
padding: 28px;
|
padding: 28px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
display: none; /* sembunyikan semua dulu */
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soal-card.active { display: block; }
|
.soal-card.active { display: block; }
|
||||||
|
|
||||||
.soal-number {
|
.soal-number {
|
||||||
|
|
@ -113,19 +115,16 @@
|
||||||
color: #1e293b;
|
color: #1e293b;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opsi-item:hover {
|
.opsi-item:hover {
|
||||||
border-color: #667eea;
|
border-color: #667eea;
|
||||||
background: #f0eeff;
|
background: #f0eeff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opsi-item.selected {
|
.opsi-item.selected {
|
||||||
border-color: #667eea;
|
border-color: #667eea;
|
||||||
background: linear-gradient(135deg, #ede9fe, #f5f3ff);
|
background: linear-gradient(135deg, #ede9fe, #f5f3ff);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #4c1d95;
|
color: #4c1d95;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opsi-item input[type="radio"] { display: none; }
|
.opsi-item input[type="radio"] { display: none; }
|
||||||
|
|
||||||
.opsi-label-circle {
|
.opsi-label-circle {
|
||||||
|
|
@ -141,7 +140,6 @@
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
transition: all 0.18s;
|
transition: all 0.18s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opsi-item.selected .opsi-label-circle {
|
.opsi-item.selected .opsi-label-circle {
|
||||||
background: #667eea;
|
background: #667eea;
|
||||||
color: white;
|
color: white;
|
||||||
|
|
@ -156,6 +154,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-nav {
|
.btn-nav {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
padding: 11px 24px;
|
padding: 11px 24px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
border: none;
|
border: none;
|
||||||
|
|
@ -165,11 +166,9 @@
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
font-family: 'Poppins', sans-serif;
|
font-family: 'Poppins', sans-serif;
|
||||||
}
|
}
|
||||||
|
.btn-nav img { width: 16px; height: 16px; object-fit: contain; }
|
||||||
|
|
||||||
.btn-prev {
|
.btn-prev { background: #f1f5f9; color: #475569; }
|
||||||
background: #f1f5f9;
|
|
||||||
color: #475569;
|
|
||||||
}
|
|
||||||
.btn-prev:hover { background: #e2e8f0; }
|
.btn-prev:hover { background: #e2e8f0; }
|
||||||
.btn-prev:disabled { opacity: 0.4; cursor: not-allowed; }
|
.btn-prev:disabled { opacity: 0.4; cursor: not-allowed; }
|
||||||
|
|
||||||
|
|
@ -196,7 +195,6 @@
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soal-dot {
|
.soal-dot {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
@ -211,13 +209,15 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soal-dot.active { background: #667eea; color: white; }
|
.soal-dot.active { background: #667eea; color: white; }
|
||||||
.soal-dot.answered { background: #dcfce7; color: #16a34a; border: 2px solid #22c55e; }
|
.soal-dot.answered { background: #dcfce7; color: #16a34a; border: 2px solid #22c55e; }
|
||||||
.soal-dot.active.answered { background: #22c55e; color: white; }
|
.soal-dot.active.answered { background: #22c55e; color: white; }
|
||||||
|
|
||||||
/* Warning belum semua dijawab */
|
/* Warning belum semua dijawab */
|
||||||
.warning-box {
|
.warning-box {
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
background: #fff7ed;
|
background: #fff7ed;
|
||||||
border: 1px solid #fed7aa;
|
border: 1px solid #fed7aa;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
@ -226,8 +226,8 @@
|
||||||
color: #c2410c;
|
color: #c2410c;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
.warning-box img { width: 16px; height: 16px; object-fit: contain; flex-shrink: 0; }
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
|
|
@ -237,11 +237,23 @@
|
||||||
|
|
||||||
{{-- Header --}}
|
{{-- Header --}}
|
||||||
<div class="quiz-header">
|
<div class="quiz-header">
|
||||||
<div class="quiz-title">🏆 {{ $challenge->judul_challenge }}</div>
|
<div class="quiz-title">
|
||||||
|
<img src="{{ asset('images/icon/siswac/piala.png') }}" alt="Ikon piala">
|
||||||
|
{{ $challenge->judul_challenge }}
|
||||||
|
</div>
|
||||||
<div class="quiz-meta">
|
<div class="quiz-meta">
|
||||||
<span>📝 {{ $challenge->soal->count() }} Soal</span>
|
<span>
|
||||||
<span>⭐ {{ $challenge->exp }} EXP</span>
|
<img src="{{ asset('images/icon/siswac/buku1.png') }}" alt="Jumlah soal">
|
||||||
<span>⏰ Tenggat: {{ \Carbon\Carbon::parse($challenge->tenggat_waktu)->format('d M Y, H:i') }}</span>
|
{{ $challenge->soal->count() }} Soal
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<img src="{{ asset('images/icon/siswac/star.png') }}" alt="EXP">
|
||||||
|
{{ $challenge->exp }} EXP
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<img src="{{ asset('images/icon/siswac/alarm.png') }}" alt="Tenggat waktu">
|
||||||
|
Tenggat: {{ \Carbon\Carbon::parse($challenge->tenggat_waktu)->format('d M Y, H:i') }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -291,7 +303,8 @@
|
||||||
|
|
||||||
{{-- Warning --}}
|
{{-- Warning --}}
|
||||||
<div class="warning-box" id="warningBox">
|
<div class="warning-box" id="warningBox">
|
||||||
⚠️ Masih ada <span id="warningCount"></span> soal yang belum dijawab. Yakin ingin submit?
|
<img src="{{ asset('images/icon/siswac/alert.png') }}" alt="Peringatan">
|
||||||
|
Masih ada <span id="warningCount"></span> soal yang belum dijawab. Yakin ingin submit?
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Navigasi --}}
|
{{-- Navigasi --}}
|
||||||
|
|
@ -304,7 +317,8 @@
|
||||||
|
|
||||||
<button type="submit" class="btn-nav btn-submit" id="btnSubmit"
|
<button type="submit" class="btn-nav btn-submit" id="btnSubmit"
|
||||||
onclick="return konfirmasiSubmit()">
|
onclick="return konfirmasiSubmit()">
|
||||||
🎯 Selesai & Submit
|
<img src="{{ asset('images/icon/siswac/target.png') }}" alt="Submit">
|
||||||
|
Selesai & Submit
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
@ -319,11 +333,9 @@
|
||||||
let jawaban = {}; // { index: 'A'/'B'/'C'/'D' }
|
let jawaban = {}; // { index: 'A'/'B'/'C'/'D' }
|
||||||
|
|
||||||
function goToSoal(index) {
|
function goToSoal(index) {
|
||||||
// Sembunyikan soal sekarang
|
|
||||||
document.getElementById(`soal-${currentSoal}`).classList.remove('active');
|
document.getElementById(`soal-${currentSoal}`).classList.remove('active');
|
||||||
document.getElementById(`dot-${currentSoal}`).classList.remove('active');
|
document.getElementById(`dot-${currentSoal}`).classList.remove('active');
|
||||||
|
|
||||||
// Tampilkan soal target
|
|
||||||
currentSoal = index;
|
currentSoal = index;
|
||||||
document.getElementById(`soal-${currentSoal}`).classList.add('active');
|
document.getElementById(`soal-${currentSoal}`).classList.add('active');
|
||||||
|
|
||||||
|
|
@ -345,16 +357,13 @@ function prevSoal() {
|
||||||
function pilihJawaban(soalIndex, opsi, idSoal) {
|
function pilihJawaban(soalIndex, opsi, idSoal) {
|
||||||
jawaban[soalIndex] = opsi;
|
jawaban[soalIndex] = opsi;
|
||||||
|
|
||||||
// Hapus selected dari semua opsi soal ini
|
|
||||||
['A','B','C','D'].forEach(o => {
|
['A','B','C','D'].forEach(o => {
|
||||||
document.getElementById(`label-${soalIndex}-${o}`)?.classList.remove('selected');
|
document.getElementById(`label-${soalIndex}-${o}`)?.classList.remove('selected');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tandai yang dipilih
|
|
||||||
document.getElementById(`label-${soalIndex}-${opsi}`)?.classList.add('selected');
|
document.getElementById(`label-${soalIndex}-${opsi}`)?.classList.add('selected');
|
||||||
document.getElementById(`radio-${soalIndex}-${opsi}`).checked = true;
|
document.getElementById(`radio-${soalIndex}-${opsi}`).checked = true;
|
||||||
|
|
||||||
// Update dot
|
|
||||||
const dot = document.getElementById(`dot-${soalIndex}`);
|
const dot = document.getElementById(`dot-${soalIndex}`);
|
||||||
dot.classList.add('answered');
|
dot.classList.add('answered');
|
||||||
|
|
||||||
|
|
@ -370,9 +379,9 @@ function updateNav() {
|
||||||
|
|
||||||
if (currentSoal === totalSoal - 1) {
|
if (currentSoal === totalSoal - 1) {
|
||||||
btnNext.style.display = 'none';
|
btnNext.style.display = 'none';
|
||||||
btnSubmit.style.display = 'block';
|
btnSubmit.style.display = 'inline-flex';
|
||||||
} else {
|
} else {
|
||||||
btnNext.style.display = 'block';
|
btnNext.style.display = 'inline-flex';
|
||||||
btnSubmit.style.display = 'none';
|
btnSubmit.style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -392,7 +401,7 @@ function konfirmasiSubmit() {
|
||||||
|
|
||||||
if (belum > 0) {
|
if (belum > 0) {
|
||||||
document.getElementById('warningCount').textContent = belum + ' soal';
|
document.getElementById('warningCount').textContent = belum + ' soal';
|
||||||
warningBox.style.display = 'block';
|
warningBox.style.display = 'flex';
|
||||||
return confirm(`Masih ada ${belum} soal yang belum dijawab. Yakin ingin submit?`);
|
return confirm(`Masih ada ${belum} soal yang belum dijawab. Yakin ingin submit?`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,36 @@
|
||||||
|
|
||||||
.card-link:hover { text-decoration: underline; }
|
.card-link:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
/* ICONS */
|
||||||
|
.icon-sm {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
object-fit: contain;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-md {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
object-fit: contain;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-rank {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
object-fit: contain;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-mascot {
|
||||||
|
width: 300px;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
object-fit: contain;
|
||||||
|
margin-top: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
/* TUGAS */
|
/* TUGAS */
|
||||||
.tugas-date-label {
|
.tugas-date-label {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
@ -81,6 +111,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.tugas-empty {
|
.tugas-empty {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
@ -161,14 +195,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.challenge-bolt {
|
.challenge-bolt {
|
||||||
width: 40px;
|
width: 48px;
|
||||||
height: 40px;
|
height: 48px;
|
||||||
background: #fef9c3;
|
background: #fef9c3;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 20px;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,24 +272,6 @@
|
||||||
border-top-color: #fde68a;
|
border-top-color: #fde68a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mascot-img {
|
|
||||||
width: 300px; /* sesuaikan */
|
|
||||||
height: auto;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mascot-placeholder {
|
|
||||||
width: 130px;
|
|
||||||
height: 130px;
|
|
||||||
margin-top: 28px;
|
|
||||||
background: linear-gradient(135deg, #dbeafe, #e0f2fe);
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* LEADERBOARD */
|
/* LEADERBOARD */
|
||||||
.lb-item {
|
.lb-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -269,9 +284,10 @@
|
||||||
.lb-item:last-child { border-bottom: none; }
|
.lb-item:last-child { border-bottom: none; }
|
||||||
|
|
||||||
.lb-rank-icon {
|
.lb-rank-icon {
|
||||||
font-size: 22px;
|
|
||||||
width: 32px;
|
width: 32px;
|
||||||
text-align: center;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lb-avatar {
|
.lb-avatar {
|
||||||
|
|
@ -327,7 +343,7 @@
|
||||||
@foreach($items as $item)
|
@foreach($items as $item)
|
||||||
<div class="tugas-item">
|
<div class="tugas-item">
|
||||||
<span class="tugas-time">{{ $item['jam'] }}</span>
|
<span class="tugas-time">{{ $item['jam'] }}</span>
|
||||||
<span style="font-size:18px">📋</span>
|
<img src="{{ asset('images/icon/siswadb/buku.png') }}" alt="Ikon tugas" class="icon-md">
|
||||||
<div class="tugas-info">
|
<div class="tugas-info">
|
||||||
<p class="tugas-nama">{{ $item['nama'] }}</p>
|
<p class="tugas-nama">{{ $item['nama'] }}</p>
|
||||||
<p class="tugas-mapel">{{ $item['mapel'] }}</p>
|
<p class="tugas-mapel">{{ $item['mapel'] }}</p>
|
||||||
|
|
@ -335,7 +351,10 @@
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@empty
|
@empty
|
||||||
<div class="tugas-empty">🎉 Tidak ada tugas yang pending!</div>
|
<div class="tugas-empty">
|
||||||
|
<img src="{{ asset('images/icon/siswadb/confetti.png') }}" alt="Semua tugas selesai" class="icon-sm">
|
||||||
|
Tidak ada tugas yang pending!
|
||||||
|
</div>
|
||||||
@endforelse
|
@endforelse
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -370,7 +389,9 @@
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="challenge-item">
|
<div class="challenge-item">
|
||||||
<div class="challenge-bolt">⚡</div>
|
<div class="challenge-bolt">
|
||||||
|
<img src="{{ asset('images/icon/siswadb/starw.png') }}" alt="Ikon challenge mingguan" class="icon-md">
|
||||||
|
</div>
|
||||||
<div style="flex:1">
|
<div style="flex:1">
|
||||||
<p class="challenge-desc">Ayo kerjakan challenge dan dapatkan EXP tambahan!</p>
|
<p class="challenge-desc">Ayo kerjakan challenge dan dapatkan EXP tambahan!</p>
|
||||||
<div class="progress-bar-wrap">
|
<div class="progress-bar-wrap">
|
||||||
|
|
@ -393,15 +414,12 @@
|
||||||
ini, yuk lanjutkan untuk mendapatkan badge yang lebih menarik!
|
ini, yuk lanjutkan untuk mendapatkan badge yang lebih menarik!
|
||||||
@else
|
@else
|
||||||
Belum ada tugas yang diselesaikan minggu ini.
|
Belum ada tugas yang diselesaikan minggu ini.
|
||||||
Ayo mulai kerjakan tugasmu! 💪
|
Ayo mulai kerjakan tugasmu!
|
||||||
|
<img src="{{ asset('images/icon/siswadb/muscle.png') }}" alt="Semangat!" class="icon-sm">
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(file_exists(public_path('images/mascot.png')))
|
<img src="{{ asset('images/icon/mascot/mascot-hi.png') }}" alt="Maskot Belajar" class="icon-mascot">
|
||||||
<img src="{{ asset('images/mascot.png') }}" class="mascot-img" alt="Mascot">
|
|
||||||
@else
|
|
||||||
<img src="{{ asset('images/icon/mascot/main_mascott.png') }}" alt="Mascot" class="mascot-img">
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- ===== LEADERBOARD ===== --}}
|
{{-- ===== LEADERBOARD ===== --}}
|
||||||
|
|
@ -414,9 +432,12 @@
|
||||||
@forelse($leaderboard as $lb)
|
@forelse($leaderboard as $lb)
|
||||||
<div class="lb-item">
|
<div class="lb-item">
|
||||||
<span class="lb-rank-icon">
|
<span class="lb-rank-icon">
|
||||||
@if($lb['rank'] === 1) 🥇
|
@if($lb['rank'] === 1)
|
||||||
@elseif($lb['rank'] === 2) 🥈
|
<img src="{{ asset('images/icon/siswadb/1.png') }}" alt="Peringkat 1" class="icon-rank">
|
||||||
@else 🥉
|
@elseif($lb['rank'] === 2)
|
||||||
|
<img src="{{ asset('images/icon/siswadb/2.png') }}" alt="Peringkat 2" class="icon-rank">
|
||||||
|
@else
|
||||||
|
<img src="{{ asset('images/icon/siswadb/3.png') }}" alt="Peringkat 3" class="icon-rank">
|
||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
<div class="lb-avatar">{{ strtoupper(substr($lb['nama'], 0, 1)) }}</div>
|
<div class="lb-avatar">{{ strtoupper(substr($lb['nama'], 0, 1)) }}</div>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>@yield('title', 'Siswa Panel')</title>
|
<title>@yield('title', 'Dashboard Siswa')</title>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -12,18 +12,49 @@
|
||||||
body { font-family: 'Poppins', sans-serif; background-color: #f5f9ff; margin: 0; height: 100vh; overflow: hidden; }
|
body { font-family: 'Poppins', sans-serif; background-color: #f5f9ff; margin: 0; height: 100vh; overflow: hidden; }
|
||||||
.siswa-wrapper { display: flex; height: 100vh; overflow: hidden; }
|
.siswa-wrapper { display: flex; height: 100vh; overflow: hidden; }
|
||||||
|
|
||||||
|
/* GLOBAL ICONS — berlaku di semua halaman */
|
||||||
|
.icon-sm { width: 16px; height: 16px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-md { width: 24px; height: 24px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-rank { width: 28px; height: 28px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-mascot { width: 300px; max-width: 100%; height: auto; object-fit: contain; margin-top: 28px; }
|
||||||
|
|
||||||
.sidebar { width: 260px; flex-shrink: 0; background: #ffffff; border-right: 2px solid #e6f0ff; padding: 30px 20px; display: flex; flex-direction: column; transition: width 0.3s ease, padding 0.3s ease; overflow: hidden; height: 100vh; position: sticky; top: 0; }
|
.sidebar { width: 260px; flex-shrink: 0; background: #ffffff; border-right: 2px solid #e6f0ff; padding: 30px 20px; display: flex; flex-direction: column; transition: width 0.3s ease, padding 0.3s ease; overflow: hidden; height: 100vh; position: sticky; top: 0; }
|
||||||
.sidebar.collapsed { width: 0; padding: 0; border-right: none; }
|
.sidebar.collapsed { width: 0; padding: 0; border-right: none; }
|
||||||
.sidebar-logo { text-align: center; margin-bottom: 36px; white-space: nowrap; flex-shrink: 0; }
|
.sidebar-logo { text-align: center; margin-bottom: 36px; white-space: nowrap; flex-shrink: 0; }
|
||||||
.sidebar-logo img { width: 90px; }
|
.sidebar-logo img { width: 90px; }
|
||||||
.sidebar-menu { display: flex; flex-direction: column; white-space: nowrap; }
|
.sidebar-menu { display: flex; flex-direction: column; white-space: nowrap; }
|
||||||
.sidebar-link { display: flex; align-items: center; gap: 12px; padding: 11px 18px; margin-bottom: 8px; border-radius: 12px; color: #64748b; text-decoration: none; font-weight: 500; transition: all 0.2s ease; }
|
.sidebar-link { display: flex; align-items: center; gap: 12px; padding: 11px 18px; margin-bottom: 8px; border-radius: 12px; color: #64748b; text-decoration: none; font-weight: 500; font-size: 14px; transition: all 0.2s ease; }
|
||||||
.sidebar-link:hover { background: #e6f0ff; color: #1d4ed8; }
|
.sidebar-link:hover { background: #e6f0ff; color: #1d4ed8; }
|
||||||
.sidebar-link.active { background: #e6f0ff; color: #1d4ed8; }
|
.sidebar-link.active { background: #e6f0ff; color: #1d4ed8; }
|
||||||
.sidebar-icon { width: 20px; height: 20px; flex-shrink: 0; }
|
.sidebar-icon { width: 20px; height: 20px; flex-shrink: 0; object-fit: contain; }
|
||||||
.sidebar-logout { margin-top: auto; flex-shrink: 0; }
|
|
||||||
.sidebar-logout button { width: 100%; border: none; background: transparent; color: #ef4444; font-weight: 600; padding: 10px; text-align: left; border-radius: 12px; cursor: pointer; }
|
/* Logout — disamain dengan layout guru */
|
||||||
|
.sidebar-logout {
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid #f1f5f9;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.sidebar-logout button {
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: #ef4444;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
text-align: left;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
transition: background 0.2s;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
.sidebar-logout button:hover { background: #fef2f2; }
|
.sidebar-logout button:hover { background: #fef2f2; }
|
||||||
|
.sidebar-logout svg { width: 18px; height: 18px; flex-shrink: 0; }
|
||||||
|
|
||||||
.sidebar-toggle-btn { position: fixed; top: 50%; transform: translateY(-50%); left: 260px; z-index: 1000; width: 22px; height: 48px; background: #2b8ef3; border: none; border-radius: 0 10px 10px 0; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: left 0.3s ease, background 0.2s; box-shadow: 2px 0 8px rgba(43,142,243,0.3); }
|
.sidebar-toggle-btn { position: fixed; top: 50%; transform: translateY(-50%); left: 260px; z-index: 1000; width: 22px; height: 48px; background: #2b8ef3; border: none; border-radius: 0 10px 10px 0; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: left 0.3s ease, background 0.2s; box-shadow: 2px 0 8px rgba(43,142,243,0.3); }
|
||||||
.sidebar-toggle-btn:hover { background: #1a7ae0; }
|
.sidebar-toggle-btn:hover { background: #1a7ae0; }
|
||||||
|
|
@ -32,10 +63,11 @@
|
||||||
.sidebar-toggle-btn.collapsed .toggle-arrow { transform: rotate(180deg); }
|
.sidebar-toggle-btn.collapsed .toggle-arrow { transform: rotate(180deg); }
|
||||||
|
|
||||||
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; height: 100vh; overflow: hidden; }
|
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; height: 100vh; overflow: hidden; }
|
||||||
.topbar { background: #2b8ef3; margin: 20px 20px 0; padding: 16px 24px; border-radius: 16px; color: white; display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; }
|
.topbar { background: #2b8ef3; margin: 20px 20px 0; padding: 16px 24px; border-radius: 16px; color: white; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 8px 24px rgba(43,142,243,0.25); flex-shrink: 0; }
|
||||||
.topbar-left { font-weight: 600; font-size: 16px; display: flex; align-items: center; gap: 10px; }
|
.topbar-left { font-weight: 600; font-size: 16px; display: flex; align-items: center; gap: 10px; }
|
||||||
.topbar-right { display: flex; align-items: center; gap: 14px; }
|
.topbar-right { display: flex; align-items: center; gap: 14px; }
|
||||||
.content { padding: 20px 28px 28px; flex: 1; overflow-y: auto; }
|
|
||||||
|
.content { padding: 28px 28px 28px; flex: 1; overflow-y: auto; }
|
||||||
|
|
||||||
/* NOTIF */
|
/* NOTIF */
|
||||||
.notif-wrap { position: relative; }
|
.notif-wrap { position: relative; }
|
||||||
|
|
@ -52,7 +84,7 @@
|
||||||
.notif-item { display: flex; align-items: flex-start; gap: 12px; padding: 13px 18px; border-bottom: 1px solid #f8fafc; transition: background 0.15s; cursor: default; }
|
.notif-item { display: flex; align-items: flex-start; gap: 12px; padding: 13px 18px; border-bottom: 1px solid #f8fafc; transition: background 0.15s; cursor: default; }
|
||||||
.notif-item:hover { background: #f8faff; }
|
.notif-item:hover { background: #f8faff; }
|
||||||
.notif-item:last-child { border-bottom: none; }
|
.notif-item:last-child { border-bottom: none; }
|
||||||
.notif-icon-wrap { width: 36px; height: 36px; border-radius: 12px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 16px; }
|
.notif-icon-wrap { width: 36px; height: 36px; border-radius: 12px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||||
.notif-icon-materi { background: #e8f4ff; }
|
.notif-icon-materi { background: #e8f4ff; }
|
||||||
.notif-icon-tugas { background: #fff7e6; }
|
.notif-icon-tugas { background: #fff7e6; }
|
||||||
.notif-body { flex: 1; min-width: 0; }
|
.notif-body { flex: 1; min-width: 0; }
|
||||||
|
|
@ -60,7 +92,7 @@
|
||||||
.notif-message { font-size: 12px; color: #475569; margin-bottom: 2px; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.notif-message { font-size: 12px; color: #475569; margin-bottom: 2px; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.notif-time { font-size: 10px; color: #94a3b8; white-space: nowrap; margin-top: 2px; }
|
.notif-time { font-size: 10px; color: #94a3b8; white-space: nowrap; margin-top: 2px; }
|
||||||
.notif-empty { padding: 32px 18px; text-align: center; }
|
.notif-empty { padding: 32px 18px; text-align: center; }
|
||||||
.notif-empty-icon { font-size: 36px; margin-bottom: 8px; }
|
.notif-empty-icon { margin-bottom: 8px; display: flex; justify-content: center; }
|
||||||
.notif-empty-text { font-size: 13px; color: #94a3b8; }
|
.notif-empty-text { font-size: 13px; color: #94a3b8; }
|
||||||
|
|
||||||
.topbar-avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; border: 2px solid rgba(255,255,255,0.5); cursor: pointer; transition: all 0.2s; display: block; }
|
.topbar-avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; border: 2px solid rgba(255,255,255,0.5); cursor: pointer; transition: all 0.2s; display: block; }
|
||||||
|
|
@ -105,27 +137,41 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="siswa-wrapper">
|
<div class="siswa-wrapper">
|
||||||
<aside class="sidebar collapsed" id="mainSidebar">
|
<aside class="sidebar collapsed" id="mainSidebar">
|
||||||
<div class="sidebar-logo"><img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo SMK"></div>
|
<div class="sidebar-logo">
|
||||||
|
<img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo SMK">
|
||||||
|
</div>
|
||||||
<nav class="sidebar-menu">
|
<nav class="sidebar-menu">
|
||||||
<a href="{{ route('siswa.dashboard') }}" class="sidebar-link {{ request()->routeIs('siswa.dashboard') ? 'active' : '' }}">
|
<a href="{{ route('siswa.dashboard') }}" class="sidebar-link {{ request()->routeIs('siswa.dashboard') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon" alt=""><span>Dashboard</span>
|
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon" alt="Dashboard">
|
||||||
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('siswa.materi.index') }}" class="sidebar-link {{ request()->routeIs('siswa.materi*') ? 'active' : '' }}">
|
<a href="{{ route('siswa.materi.index') }}" class="sidebar-link {{ request()->routeIs('siswa.materi*') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt=""><span>Materi</span>
|
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="Materi">
|
||||||
|
<span>Materi</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('siswa.tugas.index') }}" class="sidebar-link {{ request()->routeIs('siswa.tugas*') ? 'active' : '' }}">
|
<a href="{{ route('siswa.tugas.index') }}" class="sidebar-link {{ request()->routeIs('siswa.tugas*') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt=""><span>Tugas</span>
|
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt="Tugas">
|
||||||
|
<span>Tugas</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('siswa.challenge.index') }}" class="sidebar-link {{ request()->routeIs('siswa.challenge*') ? 'active' : '' }}">
|
<a href="{{ route('siswa.challenge.index') }}" class="sidebar-link {{ request()->routeIs('siswa.challenge*') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/challenge.png') }}" class="sidebar-icon" alt=""><span>Challenge</span>
|
<img src="{{ asset('images/icon/sidebar/challenge.png') }}" class="sidebar-icon" alt="Challenge">
|
||||||
|
<span>Challenge</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('siswa.leaderboard.index') }}" class="sidebar-link {{ request()->routeIs('siswa.leaderboard*') ? 'active' : '' }}">
|
<a href="{{ route('siswa.leaderboard.index') }}" class="sidebar-link {{ request()->routeIs('siswa.leaderboard*') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon" alt=""><span>Leaderboard</span>
|
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon" alt="Leaderboard">
|
||||||
|
<span>Leaderboard</span>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
<form action="{{ route('siswa.logout') }}" method="POST" class="sidebar-logout">
|
<form action="{{ route('siswa.logout') }}" method="POST" class="sidebar-logout">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-danger w-100">Logout</button>
|
<button type="submit">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
|
||||||
|
<polyline points="16 17 21 12 16 7"/>
|
||||||
|
<line x1="21" y1="12" x2="9" y2="12"/>
|
||||||
|
</svg>
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
|
|
@ -135,7 +181,10 @@
|
||||||
|
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header class="topbar">
|
<header class="topbar">
|
||||||
<div class="topbar-left">👋 Hai, {{ Auth::guard('siswa')->user()->nama ?? 'Siswa' }}</div>
|
<div class="topbar-left">
|
||||||
|
<img src="{{ asset('images/icon/siswadb/wavinghand.png') }}" alt="Hai" class="icon-sm">
|
||||||
|
Hai, {{ Auth::guard('siswa')->user()->nama ?? 'Siswa' }}
|
||||||
|
</div>
|
||||||
<div class="topbar-right">
|
<div class="topbar-right">
|
||||||
<div class="notif-wrap" id="notifWrap">
|
<div class="notif-wrap" id="notifWrap">
|
||||||
<button class="notif-btn" id="notifBtn" onclick="toggleNotif(event)">
|
<button class="notif-btn" id="notifBtn" onclick="toggleNotif(event)">
|
||||||
|
|
@ -148,14 +197,19 @@
|
||||||
<span class="notif-head-count" id="notifCount">7 hari terakhir</span>
|
<span class="notif-head-count" id="notifCount">7 hari terakhir</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="notif-list" id="notifList">
|
<div class="notif-list" id="notifList">
|
||||||
<div class="notif-empty"><div class="notif-empty-icon">🔔</div><div class="notif-empty-text">Memuat notifikasi...</div></div>
|
<div class="notif-empty">
|
||||||
|
<div class="notif-empty-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswadb/notif.png') }}" alt="Tidak ada notifikasi" class="icon-md">
|
||||||
|
</div>
|
||||||
|
<div class="notif-empty-text">Memuat notifikasi...</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php $siswa = Auth::guard('siswa')->user(); @endphp
|
@php $siswa = Auth::guard('siswa')->user(); @endphp
|
||||||
@if($siswa->foto_profil)
|
@if($siswa->foto_profil)
|
||||||
<img src="{{ Storage::url($siswa->foto_profil) }}" class="topbar-avatar" id="topbar-foto" onclick="openProfileModal()" alt="Profil">
|
<img src="{{ Storage::url($siswa->foto_profil) }}" class="topbar-avatar" id="topbar-foto" onclick="openProfileModal()" alt="Foto profil {{ $siswa->nama }}">
|
||||||
@else
|
@else
|
||||||
<div class="topbar-avatar-icon" id="topbar-foto-icon" onclick="openProfileModal()">
|
<div class="topbar-avatar-icon" id="topbar-foto-icon" onclick="openProfileModal()">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/></svg>
|
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/></svg>
|
||||||
|
|
@ -170,7 +224,9 @@
|
||||||
{{-- PROFILE MODAL --}}
|
{{-- PROFILE MODAL --}}
|
||||||
<div class="profile-modal-overlay" id="profileModalOverlay" onclick="closeOnOverlay(event)">
|
<div class="profile-modal-overlay" id="profileModalOverlay" onclick="closeOnOverlay(event)">
|
||||||
<div class="profile-modal">
|
<div class="profile-modal">
|
||||||
<button class="modal-close" onclick="closeProfileModal()"><svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
|
<button class="modal-close" onclick="closeProfileModal()">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||||
|
</button>
|
||||||
<div class="modal-title">Edit Profil</div>
|
<div class="modal-title">Edit Profil</div>
|
||||||
<div class="modal-subtitle">Perbarui foto profil dan password</div>
|
<div class="modal-subtitle">Perbarui foto profil dan password</div>
|
||||||
<div id="modal-toast" class="modal-toast"></div>
|
<div id="modal-toast" class="modal-toast"></div>
|
||||||
|
|
@ -178,9 +234,12 @@
|
||||||
@csrf
|
@csrf
|
||||||
<div class="foto-upload-area">
|
<div class="foto-upload-area">
|
||||||
<div class="foto-circle">
|
<div class="foto-circle">
|
||||||
@if($siswa->foto_profil) <img src="{{ Storage::url($siswa->foto_profil) }}" id="modal-foto-preview" alt="">
|
@if($siswa->foto_profil)
|
||||||
@else <svg id="modal-foto-icon" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/></svg>
|
<img src="{{ Storage::url($siswa->foto_profil) }}" id="modal-foto-preview" alt="Foto profil saat ini">
|
||||||
<img src="" id="modal-foto-preview" alt="" style="display:none"> @endif
|
@else
|
||||||
|
<svg id="modal-foto-icon" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/></svg>
|
||||||
|
<img src="" id="modal-foto-preview" alt="Preview foto profil" style="display:none">
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="foto-info">
|
<div class="foto-info">
|
||||||
<p>JPG, PNG, WEBP · Maks. 2MB</p>
|
<p>JPG, PNG, WEBP · Maks. 2MB</p>
|
||||||
|
|
@ -188,24 +247,44 @@
|
||||||
<input type="file" name="foto_profil" id="modal-foto-input" accept="image/*" style="display:none">
|
<input type="file" name="foto_profil" id="modal-foto-input" accept="image/*" style="display:none">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-field"><label class="modal-label">NISN <span>(tidak dapat diubah)</span></label><input type="text" class="modal-input" value="{{ $siswa->nisn }}" disabled></div>
|
<div class="modal-field">
|
||||||
<div class="modal-field"><label class="modal-label">Nama Lengkap <span>(tidak dapat diubah)</span></label><input type="text" class="modal-input" value="{{ $siswa->nama }}" disabled></div>
|
<label class="modal-label">NISN <span>(tidak dapat diubah)</span></label>
|
||||||
|
<input type="text" class="modal-input" value="{{ $siswa->nisn }}" disabled>
|
||||||
|
</div>
|
||||||
|
<div class="modal-field">
|
||||||
|
<label class="modal-label">Nama Lengkap <span>(tidak dapat diubah)</span></label>
|
||||||
|
<input type="text" class="modal-input" value="{{ $siswa->nama }}" disabled>
|
||||||
|
</div>
|
||||||
<hr class="modal-divider">
|
<hr class="modal-divider">
|
||||||
<div class="modal-field"><label class="modal-label">Password Baru <span>(kosongkan jika tidak ingin mengubah)</span></label><input type="password" name="password" class="modal-input" placeholder="Password baru" autocomplete="new-password"></div>
|
<div class="modal-field">
|
||||||
<div class="modal-field"><label class="modal-label">Konfirmasi Password</label><input type="password" name="password_confirmation" class="modal-input" placeholder="Ulangi password baru" autocomplete="new-password"></div>
|
<label class="modal-label">Password Baru <span>(kosongkan jika tidak ingin mengubah)</span></label>
|
||||||
|
<input type="password" name="password" class="modal-input" placeholder="Password baru" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
<div class="modal-field">
|
||||||
|
<label class="modal-label">Konfirmasi Password</label>
|
||||||
|
<input type="password" name="password_confirmation" class="modal-input" placeholder="Ulangi password baru" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
<button type="submit" class="btn-save-modal" id="btn-save">Simpan Perubahan</button>
|
<button type="submit" class="btn-save-modal" id="btn-save">Simpan Perubahan</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
@php
|
||||||
|
$iconMateri = asset('images/icon/siswadb/buku.png');
|
||||||
|
$iconTugas = asset('images/icon/siswadb/buku.png');
|
||||||
|
$iconNotif = asset('images/icon/siswadb/notif.png');
|
||||||
|
@endphp
|
||||||
<script>
|
<script>
|
||||||
const sidebar=document.getElementById('mainSidebar'),toggleBtn=document.getElementById('sidebarToggleBtn'),SIDEBAR_W=260;
|
const sidebar=document.getElementById('mainSidebar'),toggleBtn=document.getElementById('sidebarToggleBtn'),SIDEBAR_W=260;
|
||||||
function updateTogglePosition(c){toggleBtn.style.left=c?'0px':SIDEBAR_W+'px';c?toggleBtn.classList.add('collapsed'):toggleBtn.classList.remove('collapsed');}
|
function updateTogglePosition(c){toggleBtn.style.left=c?'0px':SIDEBAR_W+'px';c?toggleBtn.classList.add('collapsed'):toggleBtn.classList.remove('collapsed');}
|
||||||
toggleBtn.addEventListener('click',function(){const c=sidebar.classList.contains('collapsed');sidebar.classList.toggle('collapsed');updateTogglePosition(!c);});
|
toggleBtn.addEventListener('click',function(){const c=sidebar.classList.contains('collapsed');sidebar.classList.toggle('collapsed');updateTogglePosition(!c);});
|
||||||
|
|
||||||
const NOTIF_URL='{{ route("siswa.notifikasi") }}';
|
const NOTIF_URL='{{ route("siswa.notifikasi") }}';
|
||||||
const notifIcons={materi:'📖',tugas:'📝'};
|
const notifIcons = {
|
||||||
|
materi: '<img src="{{ $iconMateri }}" alt="Materi baru" class="icon-md">',
|
||||||
|
tugas: '<img src="{{ $iconTugas }}" alt="Tugas baru" class="icon-md">'
|
||||||
|
};
|
||||||
async function fetchNotif(){
|
async function fetchNotif(){
|
||||||
try{
|
try{
|
||||||
const res=await fetch(NOTIF_URL,{headers:{'X-CSRF-TOKEN':document.querySelector('meta[name="csrf-token"]').content}});
|
const res=await fetch(NOTIF_URL,{headers:{'X-CSRF-TOKEN':document.querySelector('meta[name="csrf-token"]').content}});
|
||||||
|
|
@ -215,8 +294,19 @@ function updateTogglePosition(c){toggleBtn.style.left=c?'0px':SIDEBAR_W+'px';c?t
|
||||||
if(data.count>0)badge.textContent=data.count>99?'99+':data.count;
|
if(data.count>0)badge.textContent=data.count>99?'99+':data.count;
|
||||||
count.textContent=`${data.count} notifikasi`;
|
count.textContent=`${data.count} notifikasi`;
|
||||||
list.innerHTML=data.notifications.length===0
|
list.innerHTML=data.notifications.length===0
|
||||||
?`<div class="notif-empty"><div class="notif-empty-icon">🔔</div><div class="notif-empty-text">Tidak ada notifikasi baru</div></div>`
|
?`<div class="notif-empty">
|
||||||
:data.notifications.map(n=>`<div class="notif-item"><div class="notif-icon-wrap notif-icon-${n.type}">${notifIcons[n.type]??'🔔'}</div><div class="notif-body"><div class="notif-title">${n.title}</div><div class="notif-message">${n.message}</div><div class="notif-time">${n.time}</div></div></div>`).join('');
|
<div class="notif-empty-icon"><img src="{{ $iconNotif }}" alt="Tidak ada notifikasi" class="icon-md"></div>
|
||||||
|
<div class="notif-empty-text">Tidak ada notifikasi baru</div>
|
||||||
|
</div>`
|
||||||
|
:data.notifications.map(n=>`
|
||||||
|
<div class="notif-item">
|
||||||
|
<div class="notif-icon-wrap notif-icon-${n.type}">${notifIcons[n.type]??'🔔'}</div>
|
||||||
|
<div class="notif-body">
|
||||||
|
<div class="notif-title">${n.title}</div>
|
||||||
|
<div class="notif-message">${n.message}</div>
|
||||||
|
<div class="notif-time">${n.time}</div>
|
||||||
|
</div>
|
||||||
|
</div>`).join('');
|
||||||
}catch(e){}
|
}catch(e){}
|
||||||
}
|
}
|
||||||
function toggleNotif(e){e.stopPropagation();document.getElementById('notifDropdown').classList.toggle('show');}
|
function toggleNotif(e){e.stopPropagation();document.getElementById('notifDropdown').classList.toggle('show');}
|
||||||
|
|
@ -227,7 +317,13 @@ function openProfileModal(){document.getElementById('profileModalOverlay').class
|
||||||
function closeProfileModal(){document.getElementById('profileModalOverlay').classList.remove('show');document.body.style.overflow='';const t=document.getElementById('modal-toast');t.className='modal-toast';t.textContent='';}
|
function closeProfileModal(){document.getElementById('profileModalOverlay').classList.remove('show');document.body.style.overflow='';const t=document.getElementById('modal-toast');t.className='modal-toast';t.textContent='';}
|
||||||
function closeOnOverlay(e){if(e.target===document.getElementById('profileModalOverlay'))closeProfileModal();}
|
function closeOnOverlay(e){if(e.target===document.getElementById('profileModalOverlay'))closeProfileModal();}
|
||||||
document.addEventListener('keydown',e=>{if(e.key==='Escape')closeProfileModal();});
|
document.addEventListener('keydown',e=>{if(e.key==='Escape')closeProfileModal();});
|
||||||
document.getElementById('modal-foto-input').addEventListener('change',function(){const f=this.files[0];if(!f)return;const u=URL.createObjectURL(f);const p=document.getElementById('modal-foto-preview');const i=document.getElementById('modal-foto-icon');p.src=u;p.style.display='block';if(i)i.style.display='none';});
|
document.getElementById('modal-foto-input').addEventListener('change',function(){
|
||||||
|
const f=this.files[0];if(!f)return;
|
||||||
|
const u=URL.createObjectURL(f);
|
||||||
|
const p=document.getElementById('modal-foto-preview');
|
||||||
|
const i=document.getElementById('modal-foto-icon');
|
||||||
|
p.src=u;p.style.display='block';if(i)i.style.display='none';
|
||||||
|
});
|
||||||
document.getElementById('profile-form').addEventListener('submit',async function(e){
|
document.getElementById('profile-form').addEventListener('submit',async function(e){
|
||||||
e.preventDefault();const btn=document.getElementById('btn-save');const toast=document.getElementById('modal-toast');
|
e.preventDefault();const btn=document.getElementById('btn-save');const toast=document.getElementById('modal-toast');
|
||||||
btn.disabled=true;btn.textContent='Menyimpan...';const fd=new FormData(this);
|
btn.disabled=true;btn.textContent='Menyimpan...';const fd=new FormData(this);
|
||||||
|
|
@ -235,10 +331,31 @@ function closeOnOverlay(e){if(e.target===document.getElementById('profileModalOv
|
||||||
const res=await fetch('{{ route("siswa.profile.update") }}',{method:'POST',headers:{'X-CSRF-TOKEN':document.querySelector('meta[name="csrf-token"]').content},body:fd});
|
const res=await fetch('{{ route("siswa.profile.update") }}',{method:'POST',headers:{'X-CSRF-TOKEN':document.querySelector('meta[name="csrf-token"]').content},body:fd});
|
||||||
const data=await res.json();
|
const data=await res.json();
|
||||||
if(data.success){
|
if(data.success){
|
||||||
if(data.foto_url){const tf=document.getElementById('topbar-foto');const ti=document.getElementById('topbar-foto-icon');if(tf){tf.src=data.foto_url+'?t='+Date.now();}else if(ti){const img=document.createElement('img');img.src=data.foto_url+'?t='+Date.now();img.className='topbar-avatar';img.id='topbar-foto';img.onclick=openProfileModal;img.alt='Profil';ti.replaceWith(img);}const mp=document.getElementById('modal-foto-preview');const mi=document.getElementById('modal-foto-icon');if(mp){mp.src=data.foto_url;mp.style.display='block';}if(mi)mi.style.display='none';}
|
if(data.foto_url){
|
||||||
|
const tf=document.getElementById('topbar-foto');
|
||||||
|
const ti=document.getElementById('topbar-foto-icon');
|
||||||
|
if(tf){tf.src=data.foto_url+'?t='+Date.now();}
|
||||||
|
else if(ti){
|
||||||
|
const img=document.createElement('img');
|
||||||
|
img.src=data.foto_url+'?t='+Date.now();
|
||||||
|
img.className='topbar-avatar';
|
||||||
|
img.id='topbar-foto';
|
||||||
|
img.onclick=openProfileModal;
|
||||||
|
img.alt='Foto profil {{ $siswa->nama }}';
|
||||||
|
ti.replaceWith(img);
|
||||||
|
}
|
||||||
|
const mp=document.getElementById('modal-foto-preview');
|
||||||
|
const mi=document.getElementById('modal-foto-icon');
|
||||||
|
if(mp){mp.src=data.foto_url;mp.style.display='block';}
|
||||||
|
if(mi)mi.style.display='none';
|
||||||
|
}
|
||||||
toast.className='modal-toast success';toast.textContent='✓ '+data.message;
|
toast.className='modal-toast success';toast.textContent='✓ '+data.message;
|
||||||
this.querySelector('[name="password"]').value='';this.querySelector('[name="password_confirmation"]').value='';
|
this.querySelector('[name="password"]').value='';
|
||||||
}else{const err=data.errors?Object.values(data.errors).flat().join(' · '):'Terjadi kesalahan.';toast.className='modal-toast error';toast.textContent=err;}
|
this.querySelector('[name="password_confirmation"]').value='';
|
||||||
|
}else{
|
||||||
|
const err=data.errors?Object.values(data.errors).flat().join(' · '):'Terjadi kesalahan.';
|
||||||
|
toast.className='modal-toast error';toast.textContent=err;
|
||||||
|
}
|
||||||
}catch(err){toast.className='modal-toast error';toast.textContent='Gagal terhubung ke server.';}
|
}catch(err){toast.className='modal-toast error';toast.textContent='Gagal terhubung ke server.';}
|
||||||
finally{btn.disabled=false;btn.textContent='Simpan Perubahan';}
|
finally{btn.disabled=false;btn.textContent='Simpan Perubahan';}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,61 +4,120 @@
|
||||||
|
|
||||||
@push('styles')
|
@push('styles')
|
||||||
<style>
|
<style>
|
||||||
.page-title { font-size: 28px; font-weight: 800; margin-top: -20px; margin-bottom: 6px; }
|
/* ── Ikon utilitas ─────────────────────────────────────── */
|
||||||
|
.icon-medal { width: 28px; height: 28px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-star { width: 16px; height: 16px; object-fit: contain; vertical-align: middle; margin-right: 2px; }
|
||||||
|
.icon-crown { width: 24px; height: 24px; object-fit: contain; display: block; }
|
||||||
|
.icon-rank { width: 24px; height: 24px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-book { width: 20px; height: 20px; object-fit: contain; vertical-align: middle; margin-right: 6px; }
|
||||||
|
.icon-target { width: 36px; height: 36px; object-fit: contain; vertical-align: middle; }
|
||||||
|
.icon-empty { width: 72px; height: 72px; object-fit: contain; margin-bottom: 12px; }
|
||||||
|
.icon-loader { width: 40px; height: 40px; object-fit: contain; margin-bottom: 8px; }
|
||||||
|
|
||||||
|
/* ── Page header ───────────────────────────────────────── */
|
||||||
|
.page-title {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1e293b;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 24px; }
|
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 24px; }
|
||||||
|
|
||||||
|
/* ── Podium ────────────────────────────────────────────── */
|
||||||
.podium-wrap { display: flex; align-items: flex-end; justify-content: center; gap: 12px; margin-bottom: 32px; }
|
.podium-wrap { display: flex; align-items: flex-end; justify-content: center; gap: 12px; margin-bottom: 32px; }
|
||||||
.podium-item { display: flex; flex-direction: column; align-items: center; gap: 8px; }
|
.podium-item { display: flex; flex-direction: column; align-items: center; gap: 8px; }
|
||||||
|
|
||||||
.podium-avatar { border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: 800; color: white; position: relative; overflow: hidden; flex-shrink: 0; width: 56px; height: 56px; }
|
.podium-avatar {
|
||||||
.podium-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
|
border-radius: 50%;
|
||||||
.podium-crown { position: absolute; top: -16px; font-size: 18px; z-index: 1; pointer-events: none; }
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: white;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible; /* crown perlu keluar area */
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
}
|
||||||
|
.podium-avatar-inner {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.podium-avatar-inner img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.podium-crown {
|
||||||
|
position: absolute;
|
||||||
|
top: -22px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 2;
|
||||||
|
pointer-events: none;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.rank-1 .podium-avatar { background: linear-gradient(135deg,#f59e0b,#d97706); width:68px; height:68px; font-size:26px; }
|
.rank-1 .podium-avatar { background: linear-gradient(135deg,#f59e0b,#d97706); width: 68px; height: 68px; font-size: 26px; }
|
||||||
.rank-2 .podium-avatar { background: linear-gradient(135deg,#94a3b8,#64748b); }
|
.rank-2 .podium-avatar { background: linear-gradient(135deg,#94a3b8,#64748b); }
|
||||||
.rank-3 .podium-avatar { background: linear-gradient(135deg,#f97316,#ea580c); }
|
.rank-3 .podium-avatar { background: linear-gradient(135deg,#f97316,#ea580c); }
|
||||||
|
|
||||||
.podium-name { font-size:13px; font-weight:700; color:#1e293b; text-align:center; max-width:90px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
.podium-name { font-size: 13px; font-weight: 700; color: #1e293b; text-align: center; max-width: 90px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.podium-exp { font-size:12px; color:#64748b; }
|
.podium-exp { font-size: 12px; color: #64748b; display: flex; align-items: center; gap: 3px; }
|
||||||
|
|
||||||
.podium-bar { border-radius:12px 12px 0 0; width:80px; display:flex; align-items:center; justify-content:center; font-size:20px; font-weight:800; color:white; }
|
.podium-bar { border-radius: 12px 12px 0 0; width: 80px; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 800; color: white; }
|
||||||
.rank-1 .podium-bar { height:80px; background:linear-gradient(135deg,#f59e0b,#d97706); }
|
.rank-1 .podium-bar { height: 80px; background: linear-gradient(135deg,#f59e0b,#d97706); }
|
||||||
.rank-2 .podium-bar { height:60px; background:linear-gradient(135deg,#94a3b8,#64748b); }
|
.rank-2 .podium-bar { height: 60px; background: linear-gradient(135deg,#94a3b8,#64748b); }
|
||||||
.rank-3 .podium-bar { height:44px; background:linear-gradient(135deg,#f97316,#ea580c); }
|
.rank-3 .podium-bar { height: 44px; background: linear-gradient(135deg,#f97316,#ea580c); }
|
||||||
|
|
||||||
.my-rank-banner { background:linear-gradient(135deg,#667eea,#764ba2); border-radius:16px; padding:16px 20px; color:white; display:flex; align-items:center; gap:16px; margin-bottom:20px; }
|
/* ── My rank banner ────────────────────────────────────── */
|
||||||
.my-rank-avatar { width:48px; height:48px; border-radius:50%; object-fit:cover; border:2px solid rgba(255,255,255,0.5); flex-shrink:0; }
|
.my-rank-banner { background: linear-gradient(135deg,#667eea,#764ba2); border-radius: 16px; padding: 16px 20px; color: white; display: flex; align-items: center; gap: 16px; margin-bottom: 20px; }
|
||||||
.my-rank-avatar-placeholder { width:48px; height:48px; border-radius:50%; background:rgba(255,255,255,0.2); display:flex; align-items:center; justify-content:center; font-size:20px; font-weight:800; flex-shrink:0; }
|
.my-rank-avatar { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; border: 2px solid rgba(255,255,255,0.5); flex-shrink: 0; }
|
||||||
.my-rank-num { font-size:36px; font-weight:800; line-height:1; }
|
.my-rank-avatar-placeholder { width: 48px; height: 48px; border-radius: 50%; background: rgba(255,255,255,0.2); display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 800; flex-shrink: 0; }
|
||||||
.my-rank-info { flex:1; }
|
.my-rank-num { font-size: 36px; font-weight: 800; line-height: 1; }
|
||||||
.my-rank-label { font-size:12px; opacity:0.8; margin-bottom:2px; }
|
.my-rank-info { flex: 1; }
|
||||||
.my-rank-nama { font-size:16px; font-weight:700; }
|
.my-rank-label { font-size: 12px; opacity: 0.8; margin-bottom: 2px; }
|
||||||
.my-rank-exp { font-size:13px; opacity:0.9; }
|
.my-rank-nama { font-size: 16px; font-weight: 700; }
|
||||||
|
.my-rank-exp { font-size: 13px; opacity: 0.9; display: flex; align-items: center; gap: 4px; }
|
||||||
|
|
||||||
.custom-card { background:white; border-radius:20px; border:2px solid #e5e5e5; padding:22px; }
|
/* ── Card & list ───────────────────────────────────────── */
|
||||||
.section-title { font-size:15px; font-weight:700; color:#1e293b; margin-bottom:16px; display:flex; align-items:center; justify-content:space-between; }
|
.custom-card { background: white; border-radius: 20px; border: 2px solid #e5e5e5; padding: 22px; }
|
||||||
|
.section-title { font-size: 15px; font-weight: 700; color: #1e293b; margin-bottom: 16px; display: flex; align-items: center; justify-content: space-between; }
|
||||||
|
|
||||||
.live-dot { width:8px; height:8px; border-radius:50%; background:#22c55e; box-shadow:0 0 6px #22c55e; animation: pulse 2s ease-in-out infinite; display:inline-block; margin-right:6px; }
|
.live-dot { width: 8px; height: 8px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 6px #22c55e; animation: pulse 2s ease-in-out infinite; display: inline-block; margin-right: 6px; }
|
||||||
@keyframes pulse { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:0.5;transform:scale(0.8)} }
|
@keyframes pulse { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:0.5;transform:scale(0.8)} }
|
||||||
|
|
||||||
.lb-row { display:flex; align-items:center; gap:12px; padding:10px 14px; border-radius:12px; margin-bottom:8px; transition:background 0.15s; }
|
.lb-row { display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-radius: 12px; margin-bottom: 8px; transition: background 0.15s; }
|
||||||
.lb-row:hover { background:#f8fafc; }
|
.lb-row:hover { background: #f8fafc; }
|
||||||
.lb-row.highlight { background:#f0eeff; border:2px solid #c4b5fd; }
|
.lb-row.highlight { background: #f0eeff; border: 2px solid #c4b5fd; }
|
||||||
|
|
||||||
.lb-rank { width:32px; height:32px; border-radius:50%; background:#e2e8f0; display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:700; color:#64748b; flex-shrink:0; }
|
.lb-rank { width: 32px; height: 32px; border-radius: 50%; background: #e2e8f0; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700; color: #64748b; flex-shrink: 0; }
|
||||||
.lb-rank.gold { background:#fef3c7; color:#d97706; }
|
.lb-rank.gold { background: #fef3c7; color: #d97706; }
|
||||||
.lb-rank.silver { background:#f1f5f9; color:#64748b; }
|
.lb-rank.silver { background: #f1f5f9; color: #64748b; }
|
||||||
.lb-rank.bronze { background:#ffedd5; color:#ea580c; }
|
.lb-rank.bronze { background: #ffedd5; color: #ea580c; }
|
||||||
|
/* rank badge gambar tidak perlu background bulat */
|
||||||
|
.lb-rank.has-img { background: transparent; }
|
||||||
|
|
||||||
.lb-avatar { width:36px; height:36px; border-radius:50%; object-fit:cover; flex-shrink:0; border:2px solid #e2e8f0; }
|
.lb-avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; flex-shrink: 0; border: 2px solid #e2e8f0; }
|
||||||
.lb-avatar-placeholder { width:36px; height:36px; border-radius:50%; background:#e6f0ff; display:flex; align-items:center; justify-content:center; font-size:14px; font-weight:700; color:#2b8ef3; flex-shrink:0; }
|
.lb-avatar-placeholder { width: 36px; height: 36px; border-radius: 50%; background: #e6f0ff; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 700; color: #2b8ef3; flex-shrink: 0; }
|
||||||
|
|
||||||
.lb-nama { flex:1; font-size:14px; font-weight:600; color:#1e293b; }
|
.lb-nama { flex: 1; font-size: 14px; font-weight: 600; color: #1e293b; }
|
||||||
.lb-nisn { font-size:12px; color:#94a3b8; }
|
.lb-nisn { font-size: 12px; color: #94a3b8; }
|
||||||
.lb-exp { font-size:14px; font-weight:700; color:#667eea; }
|
.lb-exp { font-size: 14px; font-weight: 700; color: #667eea; display: flex; align-items: center; gap: 3px; }
|
||||||
|
|
||||||
.semester-badge { display:inline-block; background:#f0eeff; color:#667eea; font-size:12px; font-weight:700; padding:4px 12px; border-radius:99px; margin-bottom:20px; }
|
.semester-badge { display: inline-block; background: #f0eeff; color: #667eea; font-size: 12px; font-weight: 700; padding: 4px 12px; border-radius: 99px; margin-bottom: 20px; }
|
||||||
.empty-state { text-align:center; padding:40px 20px; color:#94a3b8; }
|
.empty-state { text-align: center; padding: 40px 20px; color: #94a3b8; }
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
|
|
@ -66,7 +125,10 @@
|
||||||
|
|
||||||
@php $siswaLogin = Auth::guard('siswa')->user(); @endphp
|
@php $siswaLogin = Auth::guard('siswa')->user(); @endphp
|
||||||
|
|
||||||
<h3 class="page-title">🏅 Leaderboard</h3>
|
<h3 class="page-title">
|
||||||
|
<img src="{{ asset('images/icon/siswal/medal-pita.png') }}" alt="Ikon medal leaderboard" class="icon-medal">
|
||||||
|
Leaderboard
|
||||||
|
</h3>
|
||||||
<p class="page-subtitle">Peringkat siswa berdasarkan total EXP yang dikumpulkan.</p>
|
<p class="page-subtitle">Peringkat siswa berdasarkan total EXP yang dikumpulkan.</p>
|
||||||
|
|
||||||
<span class="semester-badge">Semester {{ $semester }} · {{ $tahunAjaran }}</span>
|
<span class="semester-badge">Semester {{ $semester }} · {{ $tahunAjaran }}</span>
|
||||||
|
|
@ -74,7 +136,9 @@
|
||||||
{{-- Container di-render real-time via JavaScript --}}
|
{{-- Container di-render real-time via JavaScript --}}
|
||||||
<div id="leaderboard-container">
|
<div id="leaderboard-container">
|
||||||
<div style="text-align:center;padding:40px;color:#94a3b8;">
|
<div style="text-align:center;padding:40px;color:#94a3b8;">
|
||||||
<div style="font-size:32px;margin-bottom:8px">⏳</div>
|
<div>
|
||||||
|
<img src="{{ asset('images/icon/siswal/jam-pasir.png') }}" alt="Memuat data" class="icon-loader">
|
||||||
|
</div>
|
||||||
<p style="font-size:13px">Memuat data...</p>
|
<p style="font-size:13px">Memuat data...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -86,51 +150,80 @@
|
||||||
const currentSiswaId = {{ $siswaLogin->id_siswa }};
|
const currentSiswaId = {{ $siswaLogin->id_siswa }};
|
||||||
const jsonUrl = '{{ route("siswa.leaderboard.json") }}';
|
const jsonUrl = '{{ route("siswa.leaderboard.json") }}';
|
||||||
|
|
||||||
|
/* URL aset — dioper dari Blade agar JS tidak perlu tahu base URL */
|
||||||
|
const ASSETS = {
|
||||||
|
star: '{{ asset('images/icon/siswal/star.png') }}',
|
||||||
|
crown: '{{ asset('images/icon/siswal/crown.png') }}',
|
||||||
|
rank1: '{{ asset('images/icon/siswal/1.png') }}',
|
||||||
|
rank2: '{{ asset('images/icon/siswal/2.png') }}',
|
||||||
|
rank3: '{{ asset('images/icon/siswal/3.png') }}',
|
||||||
|
book: '{{ asset('images/icon/siswal/buku1.png') }}',
|
||||||
|
target: '{{ asset('images/icon/siswal/target.png') }}',
|
||||||
|
empty: '{{ asset('images/icon/siswal/lb.png') }}',
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ── Helper: avatar untuk banner "posisimu" ── */
|
||||||
function avatarHtml(item, size = 'normal') {
|
function avatarHtml(item, size = 'normal') {
|
||||||
const isLarge = size === 'large';
|
const isLarge = size === 'large';
|
||||||
const w = isLarge ? 48 : 36;
|
|
||||||
const fontSize = isLarge ? 20 : 14;
|
|
||||||
|
|
||||||
if (item.foto_url) {
|
if (item.foto_url) {
|
||||||
const cls = isLarge ? 'my-rank-avatar' : 'lb-avatar';
|
const cls = isLarge ? 'my-rank-avatar' : 'lb-avatar';
|
||||||
return `<img src="${item.foto_url}?t=${Date.now()}" class="${cls}" alt="">`;
|
return `<img src="${item.foto_url}?t=${Date.now()}" class="${cls}" alt="Foto profil ${escHtml(item.nama)}">`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initial = item.nama ? item.nama.charAt(0).toUpperCase() : '?';
|
const initial = item.nama ? item.nama.charAt(0).toUpperCase() : '?';
|
||||||
if (isLarge) {
|
if (isLarge) {
|
||||||
return `<div class="my-rank-avatar-placeholder">${initial}</div>`;
|
return `<div class="my-rank-avatar-placeholder" aria-label="Inisial ${escHtml(item.nama)}">${initial}</div>`;
|
||||||
}
|
}
|
||||||
return `<div class="lb-avatar-placeholder">${initial}</div>`;
|
return `<div class="lb-avatar-placeholder" aria-label="Inisial ${escHtml(item.nama)}">${initial}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function podiumAvatarHtml(item, rankClass) {
|
/* ── Helper: avatar di dalam podium ── */
|
||||||
|
function podiumAvatarHtml(item) {
|
||||||
if (item.foto_url) {
|
if (item.foto_url) {
|
||||||
return `<img src="${item.foto_url}?t=${Date.now()}" alt="" style="width:100%;height:100%;object-fit:cover;border-radius:50%;">`;
|
return `<img src="${item.foto_url}?t=${Date.now()}" alt="Foto profil ${escHtml(item.nama)}">`;
|
||||||
}
|
}
|
||||||
return item.nama ? item.nama.charAt(0).toUpperCase() : '?';
|
const initial = item.nama ? item.nama.charAt(0).toUpperCase() : '?';
|
||||||
|
return `<span aria-hidden="true">${initial}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rankBadge(ranking) {
|
/* ── Helper: badge angka / gambar di kolom rank ── */
|
||||||
if (ranking === 1) return '🥇';
|
function rankBadgeHtml(ranking) {
|
||||||
if (ranking === 2) return '🥈';
|
if (ranking === 1) return `<img src="${ASSETS.rank1}" alt="Peringkat 1" class="icon-rank">`;
|
||||||
if (ranking === 3) return '🥉';
|
if (ranking === 2) return `<img src="${ASSETS.rank2}" alt="Peringkat 2" class="icon-rank">`;
|
||||||
|
if (ranking === 3) return `<img src="${ASSETS.rank3}" alt="Peringkat 3" class="icon-rank">`;
|
||||||
return ranking;
|
return ranking;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rankClass(ranking) {
|
function rankCssClass(ranking) {
|
||||||
if (ranking === 1) return 'gold';
|
if (ranking === 1) return 'gold has-img';
|
||||||
if (ranking === 2) return 'silver';
|
if (ranking === 2) return 'silver has-img';
|
||||||
if (ranking === 3) return 'bronze';
|
if (ranking === 3) return 'bronze has-img';
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Escape HTML sederhana ── */
|
||||||
|
function escHtml(str) {
|
||||||
|
return String(str ?? '')
|
||||||
|
.replace(/&/g,'&').replace(/</g,'<')
|
||||||
|
.replace(/>/g,'>').replace(/"/g,'"');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Render bintang + angka EXP ── */
|
||||||
|
function expHtml(exp) {
|
||||||
|
return `<img src="${ASSETS.star}" alt="EXP" class="icon-star">${Number(exp).toLocaleString('id')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ══════════════════════════════════════════════════════════
|
||||||
|
RENDER UTAMA
|
||||||
|
══════════════════════════════════════════════════════════ */
|
||||||
function renderLeaderboard(data) {
|
function renderLeaderboard(data) {
|
||||||
const { leaderboard, myRank } = data;
|
const { leaderboard, myRank } = data;
|
||||||
|
|
||||||
if (!leaderboard || leaderboard.length === 0) {
|
if (!leaderboard || leaderboard.length === 0) {
|
||||||
document.getElementById('leaderboard-container').innerHTML = `
|
document.getElementById('leaderboard-container').innerHTML = `
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div style="font-size:52px;margin-bottom:12px">📊</div>
|
<img src="${ASSETS.empty}" alt="Leaderboard kosong" class="icon-empty">
|
||||||
<p style="font-size:15px;font-weight:600;color:#475569">Belum ada data leaderboard.</p>
|
<p style="font-size:15px;font-weight:600;color:#475569">Belum ada data leaderboard.</p>
|
||||||
<p style="font-size:13px">Kerjakan challenge untuk masuk leaderboard!</p>
|
<p style="font-size:13px">Kerjakan challenge untuk masuk leaderboard!</p>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
@ -141,42 +234,48 @@ function renderLeaderboard(data) {
|
||||||
const second = leaderboard.find(x => x.ranking === 2);
|
const second = leaderboard.find(x => x.ranking === 2);
|
||||||
const third = leaderboard.find(x => x.ranking === 3);
|
const third = leaderboard.find(x => x.ranking === 3);
|
||||||
|
|
||||||
// Podium
|
/* ── Podium ── */
|
||||||
let podiumHtml = '';
|
let podiumHtml = '';
|
||||||
if (first) {
|
if (first) {
|
||||||
podiumHtml = `<div class="podium-wrap">`;
|
podiumHtml = `<div class="podium-wrap">`;
|
||||||
|
|
||||||
if (second) podiumHtml += `
|
if (second) podiumHtml += `
|
||||||
<div class="podium-item rank-2">
|
<div class="podium-item rank-2">
|
||||||
<div class="podium-avatar">${podiumAvatarHtml(second)}</div>
|
<div class="podium-avatar">
|
||||||
<div class="podium-name">${second.nama}</div>
|
<div class="podium-avatar-inner">${podiumAvatarHtml(second)}</div>
|
||||||
<div class="podium-exp">⭐ ${Number(second.exp).toLocaleString('id')}</div>
|
</div>
|
||||||
|
<div class="podium-name">${escHtml(second.nama)}</div>
|
||||||
|
<div class="podium-exp">${expHtml(second.exp)}</div>
|
||||||
<div class="podium-bar">2</div>
|
<div class="podium-bar">2</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
podiumHtml += `
|
podiumHtml += `
|
||||||
<div class="podium-item rank-1">
|
<div class="podium-item rank-1">
|
||||||
<div class="podium-avatar">
|
<div class="podium-avatar">
|
||||||
<span class="podium-crown">👑</span>
|
<span class="podium-crown">
|
||||||
${podiumAvatarHtml(first)}
|
<img src="${ASSETS.crown}" alt="Mahkota juara 1" class="icon-crown">
|
||||||
|
</span>
|
||||||
|
<div class="podium-avatar-inner">${podiumAvatarHtml(first)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="podium-name">${first.nama}</div>
|
<div class="podium-name">${escHtml(first.nama)}</div>
|
||||||
<div class="podium-exp">⭐ ${Number(first.exp).toLocaleString('id')}</div>
|
<div class="podium-exp">${expHtml(first.exp)}</div>
|
||||||
<div class="podium-bar">1</div>
|
<div class="podium-bar">1</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
if (third) podiumHtml += `
|
if (third) podiumHtml += `
|
||||||
<div class="podium-item rank-3">
|
<div class="podium-item rank-3">
|
||||||
<div class="podium-avatar">${podiumAvatarHtml(third)}</div>
|
<div class="podium-avatar">
|
||||||
<div class="podium-name">${third.nama}</div>
|
<div class="podium-avatar-inner">${podiumAvatarHtml(third)}</div>
|
||||||
<div class="podium-exp">⭐ ${Number(third.exp).toLocaleString('id')}</div>
|
</div>
|
||||||
|
<div class="podium-name">${escHtml(third.nama)}</div>
|
||||||
|
<div class="podium-exp">${expHtml(third.exp)}</div>
|
||||||
<div class="podium-bar">3</div>
|
<div class="podium-bar">3</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
podiumHtml += `</div>`;
|
podiumHtml += `</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// My rank banner
|
/* ── Banner "Posisimu" ── */
|
||||||
let bannerHtml = '';
|
let bannerHtml = '';
|
||||||
if (myRank) {
|
if (myRank) {
|
||||||
bannerHtml = `
|
bannerHtml = `
|
||||||
|
|
@ -185,28 +284,28 @@ function renderLeaderboard(data) {
|
||||||
<div class="my-rank-num">#${myRank.ranking}</div>
|
<div class="my-rank-num">#${myRank.ranking}</div>
|
||||||
<div class="my-rank-info">
|
<div class="my-rank-info">
|
||||||
<div class="my-rank-label">Posisimu saat ini</div>
|
<div class="my-rank-label">Posisimu saat ini</div>
|
||||||
<div class="my-rank-nama">${myRank.nama}</div>
|
<div class="my-rank-nama">${escHtml(myRank.nama)}</div>
|
||||||
<div class="my-rank-exp">⭐ ${Number(myRank.exp).toLocaleString('id')} EXP</div>
|
<div class="my-rank-exp">${expHtml(myRank.exp)} EXP</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size:32px">🎯</div>
|
<img src="${ASSETS.target}" alt="Target peringkat" class="icon-target">
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table rows
|
/* ── Baris tabel ── */
|
||||||
let rowsHtml = leaderboard.map(item => {
|
const rowsHtml = leaderboard.map(item => {
|
||||||
const isMe = item.id_siswa === currentSiswaId;
|
const isMe = item.id_siswa === currentSiswaId;
|
||||||
return `
|
return `
|
||||||
<div class="lb-row ${isMe ? 'highlight' : ''}">
|
<div class="lb-row ${isMe ? 'highlight' : ''}">
|
||||||
<div class="lb-rank ${rankClass(item.ranking)}">${rankBadge(item.ranking)}</div>
|
<div class="lb-rank ${rankCssClass(item.ranking)}">${rankBadgeHtml(item.ranking)}</div>
|
||||||
${avatarHtml(item)}
|
${avatarHtml(item)}
|
||||||
<div style="flex:1">
|
<div style="flex:1">
|
||||||
<div class="lb-nama">
|
<div class="lb-nama">
|
||||||
${item.nama}
|
${escHtml(item.nama)}
|
||||||
${isMe ? '<span style="background:#c4b5fd;color:#4c1d95;font-size:10px;padding:2px 7px;border-radius:99px;font-weight:700;margin-left:4px">Kamu</span>' : ''}
|
${isMe ? '<span style="background:#c4b5fd;color:#4c1d95;font-size:10px;padding:2px 7px;border-radius:99px;font-weight:700;margin-left:4px">Kamu</span>' : ''}
|
||||||
</div>
|
</div>
|
||||||
<div class="lb-nisn">${item.nisn}</div>
|
<div class="lb-nisn">${escHtml(item.nisn)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="lb-exp">⭐ ${Number(item.exp).toLocaleString('id')}</div>
|
<div class="lb-exp">${expHtml(item.exp)}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
|
|
@ -215,28 +314,32 @@ function renderLeaderboard(data) {
|
||||||
${bannerHtml}
|
${bannerHtml}
|
||||||
<div class="custom-card">
|
<div class="custom-card">
|
||||||
<p class="section-title">
|
<p class="section-title">
|
||||||
<span>📋 Semua Peringkat</span>
|
<span>
|
||||||
<span><span class="live-dot"></span><span style="font-size:11px;color:#22c55e;font-weight:600">Live</span></span>
|
<img src="${ASSETS.book}" alt="Ikon daftar peringkat" class="icon-book">
|
||||||
|
Semua Peringkat
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span class="live-dot"></span>
|
||||||
|
<span style="font-size:11px;color:#22c55e;font-weight:600">Live</span>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
${rowsHtml}
|
${rowsHtml}
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Polling setiap 10 detik
|
/* ══════════════════════════════════════════════════════════
|
||||||
|
POLLING
|
||||||
|
══════════════════════════════════════════════════════════ */
|
||||||
async function pollLeaderboard() {
|
async function pollLeaderboard() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(jsonUrl);
|
const res = await fetch(jsonUrl);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
renderLeaderboard(data);
|
renderLeaderboard(data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Diam-diam gagal, coba lagi nanti
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mulai polling
|
|
||||||
setInterval(pollLeaderboard, 10000);
|
setInterval(pollLeaderboard, 10000);
|
||||||
|
|
||||||
// Load langsung saat halaman buka
|
|
||||||
pollLeaderboard();
|
pollLeaderboard();
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #1e293b;
|
color: #1e293b;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mapel-grid {
|
.mapel-grid {
|
||||||
|
|
@ -45,7 +48,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 24px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mapel-nama {
|
.mapel-nama {
|
||||||
|
|
@ -81,32 +83,41 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state .empty-icon {
|
.empty-state .empty-icon {
|
||||||
font-size: 48px;
|
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<h1 class="page-title">📚 Mata Pelajaran</h1>
|
<h1 class="page-title">
|
||||||
|
<img src="{{ asset('images/icon/siswam/stacked.png') }}" alt="Ikon mata pelajaran" class="icon-md">
|
||||||
|
Mata Pelajaran
|
||||||
|
</h1>
|
||||||
|
|
||||||
@if($mapelList->isEmpty())
|
@if($mapelList->isEmpty())
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div class="empty-icon">📭</div>
|
<div class="empty-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswam/mailbox.png') }}" alt="Belum ada mata pelajaran" class="icon-mascot" style="width:80px; margin-top:0;">
|
||||||
|
</div>
|
||||||
<p>Belum ada mata pelajaran untuk kelasmu.</p>
|
<p>Belum ada mata pelajaran untuk kelasmu.</p>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="mapel-grid">
|
<div class="mapel-grid">
|
||||||
@foreach($mapelList as $mapel)
|
@foreach($mapelList as $mapel)
|
||||||
<a href="{{ route('siswa.materi.show', $mapel['id_mengajar']) }}" class="mapel-card">
|
<a href="{{ route('siswa.materi.show', $mapel['id_mengajar']) }}" class="mapel-card">
|
||||||
<div class="mapel-icon">📖</div>
|
<div class="mapel-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswam/mapel.png') }}" alt="Ikon mapel" class="icon-md">
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="mapel-nama">{{ $mapel['nama_mapel'] }}</p>
|
<p class="mapel-nama">{{ $mapel['nama_mapel'] }}</p>
|
||||||
<p class="mapel-guru">{{ $mapel['nama_guru'] }}</p>
|
<p class="mapel-guru">{{ $mapel['nama_guru'] }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mapel-badge">
|
<div class="mapel-badge">
|
||||||
📄 {{ $mapel['jumlah_materi'] }} Materi
|
<img src="{{ asset('images/icon/siswam/jml-m.png') }}" alt="Jumlah materi" class="icon-sm">
|
||||||
|
{{ $mapel['jumlah_materi'] }} Materi
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.mapel-header-icon {
|
.mapel-header-icon {
|
||||||
font-size: 36px;
|
|
||||||
background: rgba(255,255,255,0.2);
|
background: rgba(255,255,255,0.2);
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
|
|
@ -80,7 +79,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 22px;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,7 +146,11 @@
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state .empty-icon { font-size: 48px; margin-bottom: 12px; }
|
.empty-state .empty-icon {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
|
|
@ -157,7 +159,9 @@
|
||||||
<a href="{{ route('siswa.materi.index') }}" class="back-link">← Kembali ke Mata Pelajaran</a>
|
<a href="{{ route('siswa.materi.index') }}" class="back-link">← Kembali ke Mata Pelajaran</a>
|
||||||
|
|
||||||
<div class="mapel-header">
|
<div class="mapel-header">
|
||||||
<div class="mapel-header-icon">📖</div>
|
<div class="mapel-header-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswam/mapel.png') }}" alt="Ikon mata pelajaran" class="icon-md">
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="mapel-header-title">{{ optional($mengajar->mapel)->nama_mapel ?? '-' }}</p>
|
<p class="mapel-header-title">{{ optional($mengajar->mapel)->nama_mapel ?? '-' }}</p>
|
||||||
<p class="mapel-header-sub">Guru: {{ optional($mengajar->guru)->nama ?? '-' }} • {{ $materiList->count() }} Materi</p>
|
<p class="mapel-header-sub">Guru: {{ optional($mengajar->guru)->nama ?? '-' }} • {{ $materiList->count() }} Materi</p>
|
||||||
|
|
@ -166,7 +170,9 @@
|
||||||
|
|
||||||
@if($materiList->isEmpty())
|
@if($materiList->isEmpty())
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div class="empty-icon">📭</div>
|
<div class="empty-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswam/mailbox.png') }}" alt="Belum ada materi" class="icon-mascot" style="width:80px; margin-top:0;">
|
||||||
|
</div>
|
||||||
<p>Belum ada materi yang diupload untuk mata pelajaran ini.</p>
|
<p>Belum ada materi yang diupload untuk mata pelajaran ini.</p>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
|
|
@ -178,22 +184,31 @@
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
$iconClass = match(true) {
|
$iconClass = match(true) {
|
||||||
in_array($ext, ['pdf']) => 'pdf',
|
in_array($ext, ['pdf']) => 'pdf',
|
||||||
in_array($ext, ['doc','docx']) => 'doc',
|
in_array($ext, ['doc','docx']) => 'doc',
|
||||||
in_array($ext, ['jpg','jpeg','png']) => 'img',
|
in_array($ext, ['jpg','jpeg','png']) => 'img',
|
||||||
default => 'other',
|
default => 'other',
|
||||||
};
|
};
|
||||||
|
|
||||||
$iconEmoji = match($iconClass) {
|
$iconSrc = match($iconClass) {
|
||||||
'pdf' => '📄',
|
'pdf' => asset('images/icon/siswam/pdf.png'),
|
||||||
'doc' => '📝',
|
'doc' => asset('images/icon/siswam/doc.png'),
|
||||||
'img' => '🖼️',
|
'img' => asset('images/icon/siswam/image.png'),
|
||||||
default => '📎',
|
default => asset('images/icon/siswam/link.png'),
|
||||||
|
};
|
||||||
|
|
||||||
|
$iconAlt = match($iconClass) {
|
||||||
|
'pdf' => 'File PDF',
|
||||||
|
'doc' => 'File Word',
|
||||||
|
'img' => 'File Gambar',
|
||||||
|
default => 'File lainnya',
|
||||||
};
|
};
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="materi-card">
|
<div class="materi-card">
|
||||||
<div class="materi-file-icon {{ $iconClass }}">{{ $iconEmoji }}</div>
|
<div class="materi-file-icon {{ $iconClass }}">
|
||||||
|
<img src="{{ $iconSrc }}" alt="{{ $iconAlt }}" class="icon-md">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="materi-info">
|
<div class="materi-info">
|
||||||
<p class="materi-judul">{{ $materi->judul_materi }}</p>
|
<p class="materi-judul">{{ $materi->judul_materi }}</p>
|
||||||
|
|
@ -209,7 +224,8 @@
|
||||||
<a href="{{ asset('storage/' . $materi->lampiran_materi) }}"
|
<a href="{{ asset('storage/' . $materi->lampiran_materi) }}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="btn-download">
|
class="btn-download">
|
||||||
⬇️ Unduh
|
<img src="{{ asset('images/icon/siswam/download.png') }}" alt="Unduh materi" class="icon-sm">
|
||||||
|
Unduh
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
<span class="btn-no-file">Tidak ada file</span>
|
<span class="btn-no-file">Tidak ada file</span>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #1e293b;
|
color: #1e293b;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TABS */
|
/* TABS */
|
||||||
|
|
@ -89,9 +92,9 @@
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tugas-card.status-belum { border-left-color: #2b8ef3; }
|
.tugas-card.status-belum { border-left-color: #2b8ef3; }
|
||||||
.tugas-card.status-terlambat { border-left-color: #ef4444; }
|
.tugas-card.status-terlambat { border-left-color: #ef4444; }
|
||||||
.tugas-card.status-selesai { border-left-color: #22c55e; }
|
.tugas-card.status-selesai { border-left-color: #22c55e; }
|
||||||
|
|
||||||
.tugas-icon {
|
.tugas-icon {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
|
|
@ -100,7 +103,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 22px;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,7 +175,11 @@
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-icon { font-size: 48px; margin-bottom: 12px; }
|
.empty-state .empty-icon {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* ALERT */
|
/* ALERT */
|
||||||
.alert-success {
|
.alert-success {
|
||||||
|
|
@ -184,6 +190,9 @@
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-error {
|
.alert-error {
|
||||||
|
|
@ -194,20 +203,32 @@
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<h1 class="page-title">📋 Tugas</h1>
|
<h1 class="page-title">
|
||||||
|
<img src="{{ asset('images/icon/siswat/buku1.png') }}" alt="Ikon tugas" class="icon-md">
|
||||||
|
Tugas
|
||||||
|
</h1>
|
||||||
|
|
||||||
@if(session('success'))
|
@if(session('success'))
|
||||||
<div class="alert-success">✅ {{ session('success') }}</div>
|
<div class="alert-success">
|
||||||
|
<img src="{{ asset('images/icon/siswat/v.png') }}" alt="Berhasil" class="icon-sm">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(session('error'))
|
@if(session('error'))
|
||||||
<div class="alert-error">❌ {{ session('error') }}</div>
|
<div class="alert-error">
|
||||||
|
<img src="{{ asset('images/icon/siswat/x.png') }}" alt="Gagal" class="icon-sm">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- TABS --}}
|
{{-- TABS --}}
|
||||||
|
|
@ -230,7 +251,9 @@
|
||||||
<div id="tab-belum" class="tab-panel active">
|
<div id="tab-belum" class="tab-panel active">
|
||||||
@if($tugasBelum->isEmpty())
|
@if($tugasBelum->isEmpty())
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div class="empty-icon">🎉</div>
|
<div class="empty-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/confetti.png') }}" alt="Semua tugas sudah dikerjakan" class="icon-mascot" style="width:80px; margin-top:0;">
|
||||||
|
</div>
|
||||||
<p>Semua tugas sudah dikerjakan!</p>
|
<p>Semua tugas sudah dikerjakan!</p>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
|
|
@ -238,7 +261,9 @@
|
||||||
@foreach($tugasBelum as $tugas)
|
@foreach($tugasBelum as $tugas)
|
||||||
<a href="{{ route('siswa.tugas.show', $tugas['id_tugas']) }}"
|
<a href="{{ route('siswa.tugas.show', $tugas['id_tugas']) }}"
|
||||||
class="tugas-card status-belum">
|
class="tugas-card status-belum">
|
||||||
<div class="tugas-icon">📋</div>
|
<div class="tugas-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/buku1.png') }}" alt="Tugas belum dikerjakan" class="icon-md">
|
||||||
|
</div>
|
||||||
<div class="tugas-info">
|
<div class="tugas-info">
|
||||||
<p class="tugas-judul">{{ $tugas['judul'] }}</p>
|
<p class="tugas-judul">{{ $tugas['judul'] }}</p>
|
||||||
<p class="tugas-meta">{{ $tugas['nama_mapel'] }} • {{ $tugas['nama_guru'] }}</p>
|
<p class="tugas-meta">{{ $tugas['nama_mapel'] }} • {{ $tugas['nama_guru'] }}</p>
|
||||||
|
|
@ -258,7 +283,9 @@ class="tugas-card status-belum">
|
||||||
<div id="tab-terlambat" class="tab-panel">
|
<div id="tab-terlambat" class="tab-panel">
|
||||||
@if($tugasTerlambat->isEmpty())
|
@if($tugasTerlambat->isEmpty())
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div class="empty-icon">✅</div>
|
<div class="empty-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/v.png') }}" alt="Tidak ada tugas terlambat" class="icon-mascot" style="width:80px; margin-top:0;">
|
||||||
|
</div>
|
||||||
<p>Tidak ada tugas terlambat!</p>
|
<p>Tidak ada tugas terlambat!</p>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
|
|
@ -266,7 +293,9 @@ class="tugas-card status-belum">
|
||||||
@foreach($tugasTerlambat as $tugas)
|
@foreach($tugasTerlambat as $tugas)
|
||||||
<a href="{{ route('siswa.tugas.show', $tugas['id_tugas']) }}"
|
<a href="{{ route('siswa.tugas.show', $tugas['id_tugas']) }}"
|
||||||
class="tugas-card status-terlambat">
|
class="tugas-card status-terlambat">
|
||||||
<div class="tugas-icon">⏰</div>
|
<div class="tugas-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/alarm.png') }}" alt="Tugas terlambat" class="icon-md">
|
||||||
|
</div>
|
||||||
<div class="tugas-info">
|
<div class="tugas-info">
|
||||||
<p class="tugas-judul">{{ $tugas['judul'] }}</p>
|
<p class="tugas-judul">{{ $tugas['judul'] }}</p>
|
||||||
<p class="tugas-meta">{{ $tugas['nama_mapel'] }} • {{ $tugas['nama_guru'] }}</p>
|
<p class="tugas-meta">{{ $tugas['nama_mapel'] }} • {{ $tugas['nama_guru'] }}</p>
|
||||||
|
|
@ -286,7 +315,9 @@ class="tugas-card status-terlambat">
|
||||||
<div id="tab-selesai" class="tab-panel">
|
<div id="tab-selesai" class="tab-panel">
|
||||||
@if($tugasSelesai->isEmpty())
|
@if($tugasSelesai->isEmpty())
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div class="empty-icon">📭</div>
|
<div class="empty-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/mailbox.png') }}" alt="Belum ada tugas dikumpulkan" class="icon-mascot" style="width:80px; margin-top:0;">
|
||||||
|
</div>
|
||||||
<p>Belum ada tugas yang dikumpulkan.</p>
|
<p>Belum ada tugas yang dikumpulkan.</p>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
|
|
@ -294,7 +325,9 @@ class="tugas-card status-terlambat">
|
||||||
@foreach($tugasSelesai as $tugas)
|
@foreach($tugasSelesai as $tugas)
|
||||||
<a href="{{ route('siswa.tugas.show', $tugas['id_tugas']) }}"
|
<a href="{{ route('siswa.tugas.show', $tugas['id_tugas']) }}"
|
||||||
class="tugas-card status-selesai">
|
class="tugas-card status-selesai">
|
||||||
<div class="tugas-icon">✅</div>
|
<div class="tugas-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/v.png') }}" alt="Tugas selesai" class="icon-md">
|
||||||
|
</div>
|
||||||
<div class="tugas-info">
|
<div class="tugas-info">
|
||||||
<p class="tugas-judul">{{ $tugas['judul'] }}</p>
|
<p class="tugas-judul">{{ $tugas['judul'] }}</p>
|
||||||
<p class="tugas-meta">{{ $tugas['nama_mapel'] }} • {{ $tugas['nama_guru'] }}</p>
|
<p class="tugas-meta">{{ $tugas['nama_mapel'] }} • {{ $tugas['nama_guru'] }}</p>
|
||||||
|
|
@ -303,7 +336,10 @@ class="tugas-card status-selesai">
|
||||||
<span class="status-badge badge-selesai">Dikumpulkan</span>
|
<span class="status-badge badge-selesai">Dikumpulkan</span>
|
||||||
@if($tugas['exp'] > 0)
|
@if($tugas['exp'] > 0)
|
||||||
<br>
|
<br>
|
||||||
<span class="exp-badge">⭐ {{ $tugas['exp'] }} EXP</span>
|
<span class="exp-badge">
|
||||||
|
<img src="{{ asset('images/icon/siswat/star.png') }}" alt="EXP" class="icon-sm">
|
||||||
|
{{ $tugas['exp'] }} EXP
|
||||||
|
</span>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,9 @@
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #1e293b;
|
color: #1e293b;
|
||||||
margin: 0 0 20px;
|
margin: 0 0 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-area {
|
.upload-area {
|
||||||
|
|
@ -116,7 +119,11 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-icon { font-size: 36px; margin-bottom: 10px; }
|
.upload-icon {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.upload-text {
|
.upload-text {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
@ -183,7 +190,11 @@
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sudah-kumpul-icon { font-size: 40px; margin-bottom: 10px; }
|
.sudah-kumpul-icon {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.sudah-kumpul-title {
|
.sudah-kumpul-title {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
|
|
@ -224,6 +235,12 @@
|
||||||
color: #9a3412;
|
color: #9a3412;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.terlambat-warning-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.alert-success {
|
.alert-success {
|
||||||
background: #dcfce7;
|
background: #dcfce7;
|
||||||
color: #166534;
|
color: #166534;
|
||||||
|
|
@ -232,6 +249,9 @@
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-error {
|
.alert-error {
|
||||||
|
|
@ -242,6 +262,9 @@
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
@ -251,15 +274,21 @@
|
||||||
<a href="{{ route('siswa.tugas.index') }}" class="back-link">← Kembali ke Daftar Tugas</a>
|
<a href="{{ route('siswa.tugas.index') }}" class="back-link">← Kembali ke Daftar Tugas</a>
|
||||||
|
|
||||||
@if(session('success'))
|
@if(session('success'))
|
||||||
<div class="alert-success">✅ {{ session('success') }}</div>
|
<div class="alert-success">
|
||||||
|
<img src="{{ asset('images/icon/siswat/v.png') }}" alt="Berhasil" class="icon-sm">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if(session('error'))
|
@if(session('error'))
|
||||||
<div class="alert-error">❌ {{ session('error') }}</div>
|
<div class="alert-error">
|
||||||
|
<img src="{{ asset('images/icon/siswat/x.png') }}" alt="Gagal" class="icon-sm">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- DETAIL TUGAS --}}
|
{{-- DETAIL TUGAS --}}
|
||||||
@php
|
@php
|
||||||
$headerClass = $sudahKumpul ? 'selesai' : ($terlambat ? 'terlambat' : '');
|
$headerClass = $sudahKumpul ? 'selesai' : ($terlambat ? 'terlambat' : '');
|
||||||
$deadlineClass = $terlambat ? '' : 'aman';
|
$deadlineClass = $terlambat ? '' : 'aman';
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
|
|
@ -268,13 +297,16 @@
|
||||||
|
|
||||||
<div class="tugas-meta-row">
|
<div class="tugas-meta-row">
|
||||||
<span class="meta-chip">
|
<span class="meta-chip">
|
||||||
📚 {{ optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-' }}
|
<img src="{{ asset('images/icon/siswat/stacked.png') }}" alt="Mata pelajaran" class="icon-sm">
|
||||||
|
{{ optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="meta-chip">
|
<span class="meta-chip">
|
||||||
👨🏫 {{ optional(optional($tugas->mengajar)->guru)->nama ?? '-' }}
|
<img src="{{ asset('images/icon/siswat/guru.png') }}" alt="Guru" class="icon-sm">
|
||||||
|
{{ optional(optional($tugas->mengajar)->guru)->nama ?? '-' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="meta-chip deadline-chip {{ $deadlineClass }}">
|
<span class="meta-chip deadline-chip {{ $deadlineClass }}">
|
||||||
⏰ Deadline: {{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }}
|
<img src="{{ asset('images/icon/siswat/alarm.png') }}" alt="Deadline" class="icon-sm">
|
||||||
|
Deadline: {{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -288,7 +320,9 @@
|
||||||
{{-- WARNING TERLAMBAT --}}
|
{{-- WARNING TERLAMBAT --}}
|
||||||
@if($terlambat && !$sudahKumpul)
|
@if($terlambat && !$sudahKumpul)
|
||||||
<div class="terlambat-warning">
|
<div class="terlambat-warning">
|
||||||
<span style="font-size:20px">⚠️</span>
|
<span class="terlambat-warning-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/alert.png') }}" alt="Peringatan terlambat" class="icon-md">
|
||||||
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<strong>Deadline sudah lewat!</strong><br>
|
<strong>Deadline sudah lewat!</strong><br>
|
||||||
Kamu masih bisa mengumpulkan tugas ini, tapi akan ditandai sebagai <strong>terlambat</strong>.
|
Kamu masih bisa mengumpulkan tugas ini, tapi akan ditandai sebagai <strong>terlambat</strong>.
|
||||||
|
|
@ -299,14 +333,19 @@
|
||||||
{{-- SUDAH DIKUMPULKAN --}}
|
{{-- SUDAH DIKUMPULKAN --}}
|
||||||
@if($sudahKumpul)
|
@if($sudahKumpul)
|
||||||
<div class="sudah-kumpul-card">
|
<div class="sudah-kumpul-card">
|
||||||
<div class="sudah-kumpul-icon">🎉</div>
|
<div class="sudah-kumpul-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/confetti.png') }}" alt="Tugas sudah dikumpulkan" class="icon-mascot" style="width:80px; margin-top:0;">
|
||||||
|
</div>
|
||||||
<p class="sudah-kumpul-title">Tugas sudah dikumpulkan!</p>
|
<p class="sudah-kumpul-title">Tugas sudah dikumpulkan!</p>
|
||||||
<p class="sudah-kumpul-sub">
|
<p class="sudah-kumpul-sub">
|
||||||
Dikumpulkan pada {{ \Carbon\Carbon::parse($pengumpulan->tanggal_submit)->format('d M Y, H:i') }}
|
Dikumpulkan pada {{ \Carbon\Carbon::parse($pengumpulan->tanggal_submit)->format('d M Y, H:i') }}
|
||||||
• Status: <strong>{{ ucfirst($pengumpulan->status) }}</strong>
|
• Status: <strong>{{ ucfirst($pengumpulan->status) }}</strong>
|
||||||
</p>
|
</p>
|
||||||
@if($pengumpulan->exp > 0)
|
@if($pengumpulan->exp > 0)
|
||||||
<div class="exp-display">⭐ {{ $pengumpulan->exp }} EXP didapat</div>
|
<div class="exp-display">
|
||||||
|
<img src="{{ asset('images/icon/siswat/star.png') }}" alt="EXP" class="icon-sm">
|
||||||
|
{{ $pengumpulan->exp }} EXP didapat
|
||||||
|
</div>
|
||||||
@else
|
@else
|
||||||
<p style="font-size:13px;color:#16a34a;margin-top:8px">
|
<p style="font-size:13px;color:#16a34a;margin-top:8px">
|
||||||
EXP akan diberikan setelah guru menilai tugasmu.
|
EXP akan diberikan setelah guru menilai tugasmu.
|
||||||
|
|
@ -327,7 +366,10 @@
|
||||||
{{-- FORM SUBMIT --}}
|
{{-- FORM SUBMIT --}}
|
||||||
@else
|
@else
|
||||||
<div class="submit-card">
|
<div class="submit-card">
|
||||||
<p class="submit-title">📤 Upload Jawaban</p>
|
<p class="submit-title">
|
||||||
|
<img src="{{ asset('images/icon/siswat/upload.png') }}" alt="Upload jawaban" class="icon-md">
|
||||||
|
Upload Jawaban
|
||||||
|
</p>
|
||||||
|
|
||||||
<form action="{{ route('siswa.tugas.submit', $tugas->id_tugas) }}"
|
<form action="{{ route('siswa.tugas.submit', $tugas->id_tugas) }}"
|
||||||
method="POST"
|
method="POST"
|
||||||
|
|
@ -336,7 +378,10 @@
|
||||||
@csrf
|
@csrf
|
||||||
|
|
||||||
@error('lampiran_tugas')
|
@error('lampiran_tugas')
|
||||||
<div class="alert-error" style="margin-bottom:16px">❌ {{ $message }}</div>
|
<div class="alert-error" style="margin-bottom:16px">
|
||||||
|
<img src="{{ asset('images/icon/siswat/x.png') }}" alt="Error validasi" class="icon-sm">
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
@enderror
|
@enderror
|
||||||
|
|
||||||
<div class="upload-area" id="uploadArea">
|
<div class="upload-area" id="uploadArea">
|
||||||
|
|
@ -345,13 +390,15 @@
|
||||||
id="fileInput"
|
id="fileInput"
|
||||||
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png"
|
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png"
|
||||||
required>
|
required>
|
||||||
<div class="upload-icon">☁️</div>
|
<div class="upload-icon">
|
||||||
|
<img src="{{ asset('images/icon/siswat/upload.png') }}" alt="Upload file" class="icon-mascot" style="width:48px; margin-top:0;">
|
||||||
|
</div>
|
||||||
<p class="upload-text"><strong>Klik untuk pilih file</strong> atau drag & drop di sini</p>
|
<p class="upload-text"><strong>Klik untuk pilih file</strong> atau drag & drop di sini</p>
|
||||||
<p class="upload-hint">PDF, DOC, DOCX, JPG, PNG • Maks. 5MB</p>
|
<p class="upload-hint">PDF, DOC, DOCX, JPG, PNG • Maks. 5MB</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="file-preview" id="filePreview">
|
<div class="file-preview" id="filePreview">
|
||||||
<span style="font-size:22px">📎</span>
|
<img src="{{ asset('images/icon/siswat/buku1.png') }}" alt="File terpilih" class="icon-md">
|
||||||
<span class="file-preview-name" id="fileName">-</span>
|
<span class="file-preview-name" id="fileName">-</span>
|
||||||
<span class="file-preview-size" id="fileSize">-</span>
|
<span class="file-preview-size" id="fileSize">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -386,7 +433,6 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Drag & drop highlight
|
|
||||||
uploadArea.addEventListener('dragover', (e) => {
|
uploadArea.addEventListener('dragover', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
uploadArea.classList.add('drag-over');
|
uploadArea.classList.add('drag-over');
|
||||||
|
|
|
||||||