This commit is contained in:
RetasyaSalsabila 2026-04-09 21:12:24 +07:00
parent be6db46930
commit 3dfee40774
73 changed files with 941 additions and 325 deletions

View File

@ -16,12 +16,10 @@ public function index()
{ {
$guru = Auth::guard('guru')->user(); $guru = Auth::guard('guru')->user();
// Ambil mengajar dengan relasi mapel & kelas
// Group by id_mapel agar tidak duplikat jika guru ajar mapel sama di kelas berbeda
$mengajars = Mengajar::with(['mapel', 'kelas']) $mengajars = Mengajar::with(['mapel', 'kelas'])
->where('id_guru', $guru->id_guru) ->where('id_guru', $guru->id_guru)
->get() ->get()
->groupBy('id_mapel'); // group by mapel ->groupBy('id_mapel');
return view('guru.mapel.index', compact('mengajars')); return view('guru.mapel.index', compact('mengajars'));
} }
@ -43,7 +41,6 @@ public function storeMateri(Request $request)
'lampiran_materi.max' => 'Ukuran file maksimal 10MB.', 'lampiran_materi.max' => 'Ukuran file maksimal 10MB.',
]); ]);
// Pastikan mengajar ini milik guru yang login
$mengajar = Mengajar::where('id_mengajar', $request->id_mengajar) $mengajar = Mengajar::where('id_mengajar', $request->id_mengajar)
->where('id_guru', $guru->id_guru) ->where('id_guru', $guru->id_guru)
->firstOrFail(); ->firstOrFail();
@ -78,20 +75,29 @@ public function storeTugas(Request $request)
'judul_tugas' => 'required|string|max:200', 'judul_tugas' => 'required|string|max:200',
'keterangan' => 'nullable|string', 'keterangan' => 'nullable|string',
'deadline' => 'required|date|after:now', 'deadline' => 'required|date|after:now',
'lampiran_tugas' => 'nullable|file|max:10240', // semua tipe file, maks 10MB
], [ ], [
'deadline.after' => 'Deadline harus lebih dari waktu sekarang.', 'deadline.after' => 'Deadline harus lebih dari waktu sekarang.',
'lampiran_tugas.max' => 'Ukuran file maksimal 10MB.',
]); ]);
// Pastikan mengajar ini milik guru yang login
$mengajar = Mengajar::where('id_mengajar', $request->id_mengajar) $mengajar = Mengajar::where('id_mengajar', $request->id_mengajar)
->where('id_guru', $guru->id_guru) ->where('id_guru', $guru->id_guru)
->firstOrFail(); ->firstOrFail();
$path = null;
if ($request->hasFile('lampiran_tugas')) {
$file = $request->file('lampiran_tugas');
$filename = 'tugas_' . $guru->id_guru . '_' . time() . '.' . $file->getClientOriginalExtension();
$path = $file->storeAs('tugas', $filename, 'public');
}
Tugas::create([ Tugas::create([
'id_mengajar' => $request->id_mengajar, 'id_mengajar' => $request->id_mengajar,
'judul_tugas' => $request->judul_tugas, 'judul_tugas' => $request->judul_tugas,
'keterangan' => $request->keterangan, 'keterangan' => $request->keterangan,
'deadline' => $request->deadline, 'deadline' => $request->deadline,
'lampiran' => $path,
]); ]);
return redirect()->route('guru.mapel.index') return redirect()->route('guru.mapel.index')
@ -105,7 +111,6 @@ public function historyMateri()
{ {
$guru = Auth::guard('guru')->user(); $guru = Auth::guard('guru')->user();
// Ambil id_mengajar milik guru ini
$idMengajars = Mengajar::where('id_guru', $guru->id_guru) $idMengajars = Mengajar::where('id_guru', $guru->id_guru)
->pluck('id_mengajar'); ->pluck('id_mengajar');
@ -130,7 +135,6 @@ public function destroyMateri($id)
->where('id_materi', $id) ->where('id_materi', $id)
->firstOrFail(); ->firstOrFail();
// Hapus file jika ada
if ($materi->lampiran_materi && \Storage::disk('public')->exists($materi->lampiran_materi)) { if ($materi->lampiran_materi && \Storage::disk('public')->exists($materi->lampiran_materi)) {
\Storage::disk('public')->delete($materi->lampiran_materi); \Storage::disk('public')->delete($materi->lampiran_materi);
} }
@ -193,6 +197,11 @@ public function destroyTugas($id)
->where('id_tugas', $id) ->where('id_tugas', $id)
->firstOrFail(); ->firstOrFail();
// Hapus file lampiran jika ada
if ($tugas->lampiran && \Storage::disk('public')->exists($tugas->lampiran)) {
\Storage::disk('public')->delete($tugas->lampiran);
}
$tugas->delete(); $tugas->delete();
return redirect()->route('guru.tugas.history') return redirect()->route('guru.tugas.history')

View File

@ -17,6 +17,7 @@ class Tugas extends Model
'judul_tugas', 'judul_tugas',
'keterangan', 'keterangan',
'deadline', 'deadline',
'lampiran',
]; ];
protected $casts = [ protected $casts = [

View File

@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('tugas', function (Blueprint $table) {
$table->string('lampiran')->nullable()->after('deadline');
});
}
public function down(): void
{
Schema::table('tugas', function (Blueprint $table) {
$table->dropColumn('lampiran');
});
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,203 @@
@extends('guru.layouts.app')
@section('title', 'History Materi')
@push('styles')
<style>
.page-title {
font-size: 28px;
font-weight: 800;
margin-bottom: 6px;
margin-top: -20px;
}
.back-link {
display: inline-flex;
align-items: center;
gap: 8px;
color: #2b8ef3;
font-weight: 600;
font-size: 14px;
text-decoration: none;
margin-bottom: 20px;
}
.back-link:hover { text-decoration: underline; }
.custom-card {
background: white;
border-radius: 20px;
border: 2px solid #e5e5e5;
padding: 25px;
}
.table-header { background: #a5e6ba; }
.mapel-badge {
display: inline-block;
background: #e6f0ff;
color: #1d4ed8;
font-size: 12px;
font-weight: 600;
padding: 3px 10px;
border-radius: 99px;
}
.kelas-badge {
display: inline-block;
background: #f0fdf4;
color: #166534;
font-size: 12px;
font-weight: 600;
padding: 3px 10px;
border-radius: 99px;
}
.file-icon { font-size: 20px; }
.btn-hapus {
background: #fee2e2;
color: #ef4444;
border: none;
border-radius: 8px;
padding: 5px 12px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
.btn-hapus:hover { background: #fca5a5; }
.btn-unduh {
background: #e6f0ff;
color: #2b8ef3;
border: none;
border-radius: 8px;
padding: 5px 12px;
font-size: 13px;
font-weight: 600;
text-decoration: none;
transition: background 0.2s;
display: inline-block;
}
.btn-unduh:hover { background: #bfdbfe; color: #1d4ed8; }
.alert-success-custom {
background: #dcfce7;
color: #166534;
border-radius: 10px;
padding: 12px 16px;
margin-bottom: 16px;
font-weight: 500;
font-size: 14px;
}
.empty-state {
text-align: center;
padding: 50px 20px;
color: #94a3b8;
}
</style>
@endpush
@section('content')
<a href="{{ route('guru.mapel.index') }}" class="back-link"> Kembali ke Mata Pelajaran</a>
<h3 class="page-title"><img src="{{ asset('images/icon/gurud/file.png') }}" class="topbar-waving" alt="Waving">History Materi</h3>
<p style="color:#64748b;font-size:14px;margin-bottom:20px">
Semua materi yang pernah Anda upload.
</p>
@if(session('success'))
<div class="alert-success-custom"><img src="{{ asset('images/icon/gurud/v.png') }}" class="topbar-waving" alt="Waving">{{ session('success') }}</div>
@endif
<div class="custom-card">
@if($materiList->isEmpty())
<div class="empty-state">
<div style="font-size:48px;margin-bottom:12px">📭</div>
<p>Belum ada materi yang diupload.</p>
</div>
@else
<table class="table align-middle">
<thead class="table-header text-center">
<tr>
<th>No</th>
<th>Judul Materi</th>
<th>Mata Pelajaran</th>
<th>Kelas</th>
<th>Tanggal Upload</th>
<th>File</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@foreach($materiList as $i => $materi)
<tr>
<td class="text-center">{{ $materiList->firstItem() + $i }}</td>
<td>
<div style="font-weight:600;color:#1e293b">{{ $materi->judul_materi }}</div>
@if($materi->deskripsi)
<div style="font-size:12px;color:#94a3b8;margin-top:2px">
{{ Str::limit($materi->deskripsi, 60) }}
</div>
@endif
</td>
<td class="text-center">
<span class="mapel-badge">
{{ optional(optional($materi->mengajar)->mapel)->nama_mapel ?? '-' }}
</span>
</td>
<td class="text-center">
<span class="kelas-badge">
{{ optional(optional($materi->mengajar)->kelas)->tingkat }}
{{ optional(optional($materi->mengajar)->kelas)->nama_kelas ?? '-' }}
</span>
</td>
<td class="text-center" style="font-size:13px;color:#64748b">
{{ \Carbon\Carbon::parse($materi->tanggal_upload)->format('d M Y, H:i') }}
</td>
<td class="text-center">
@if($materi->lampiran_materi)
@php
$ext = strtolower(pathinfo($materi->lampiran_materi, PATHINFO_EXTENSION));
$icon = match(true) {
in_array($ext, ['pdf']) => '📄',
in_array($ext, ['doc','docx']) => '📝',
in_array($ext, ['ppt','pptx']) => '📊',
in_array($ext, ['jpg','jpeg','png']) => '🖼️',
default => '📎',
};
@endphp
<a href="{{ asset('storage/' . $materi->lampiran_materi) }}"
target="_blank" class="btn-unduh">
{{ $icon }} Unduh
</a>
@else
<span style="font-size:12px;color:#94a3b8">Tidak ada file</span>
@endif
</td>
<td class="text-center">
<form action="{{ route('guru.materi.destroy', $materi->id_materi) }}"
method="POST"
onsubmit="return confirm('Yakin hapus materi ini?')">
@csrf
@method('DELETE')
<button type="submit" class="btn-hapus">🗑️ Hapus</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="d-flex justify-content-end mt-3">
{{ $materiList->links() }}
</div>
@endif
</div>
@endsection

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -54,12 +54,22 @@
.action-icon { width: 20px; cursor: pointer; margin: 0 4px; } .action-icon { width: 20px; cursor: pointer; margin: 0 4px; }
/* Icon kecil inline (di dalam teks / badge / label) */
.inline-icon {
width: 16px;
height: 16px;
vertical-align: middle;
display: inline-block;
}
.deadline-badge { .deadline-badge {
font-size: 11px; font-size: 11px;
font-weight: 700; font-weight: 700;
padding: 3px 8px; padding: 3px 8px;
border-radius: 99px; border-radius: 99px;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
} }
.deadline-aktif { background: #dcfce7; color: #16a34a; } .deadline-aktif { background: #dcfce7; color: #16a34a; }
@ -93,6 +103,9 @@
margin-bottom: 16px; margin-bottom: 16px;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
} }
/* ── MODAL SHARED ─────────────────────────────────── */ /* ── MODAL SHARED ─────────────────────────────────── */
@ -110,7 +123,13 @@
border-radius: 16px 16px 0 0; border-radius: 16px 16px 0 0;
padding: 18px 24px; padding: 18px 24px;
} }
.modal-header-yellow .modal-title { font-weight: 800; font-size: 18px; } .modal-header-yellow .modal-title {
font-weight: 800;
font-size: 18px;
display: flex;
align-items: center;
gap: 8px;
}
.modal-header-yellow .btn-close { filter: none; } .modal-header-yellow .btn-close { filter: none; }
/* Header ungu (Edit — tetap seperti semula) */ /* Header ungu (Edit — tetap seperti semula) */
@ -344,6 +363,9 @@
.soal-scroll-area::-webkit-scrollbar-thumb:hover { background: #94a3b8; } .soal-scroll-area::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
.section-divider { .section-divider {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px; font-size: 13px;
font-weight: 700; font-weight: 700;
color: #667eea; color: #667eea;
@ -374,20 +396,23 @@
<h3 class="page-title">DAFTAR CHALLENGE</h3> <h3 class="page-title">DAFTAR CHALLENGE</h3>
@if(session('success')) @if(session('success'))
<div class="alert-success-custom"> {{ session('success') }}</div> <div class="alert-success-custom">
<img src="{{ asset('images/icon/gurud/v.png') }}" class="inline-icon" alt="Berhasil">
{{ session('success') }}
</div>
@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" alt="Tambah"> Tambah Challenge <img src="{{ asset('images/icon/main/add.png') }}" class="inline-icon" alt="Tambah Challenge"> 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" alt="Cari"> <img src="{{ asset('images/icon/main/search.png') }}" class="inline-icon" alt="Cari">
</button> </button>
</div> </div>
</form> </form>
@ -425,7 +450,11 @@
<td style="font-weight:700;color:#667eea">{{ $ch->exp }} EXP</td> <td style="font-weight:700;color:#667eea">{{ $ch->exp }} EXP</td>
<td> <td>
<span class="deadline-badge {{ $isLewat ? 'deadline-lewat' : 'deadline-aktif' }}"> <span class="deadline-badge {{ $isLewat ? 'deadline-lewat' : 'deadline-aktif' }}">
{{ $isLewat ? '⏰ Lewat' : '✅ Aktif' }} @if($isLewat)
<img src="{{ asset('images/icon/gurud/alarm.png') }}" class="inline-icon" alt="Lewat"> Lewat
@else
<img src="{{ asset('images/icon/gurud/v.png') }}" class="inline-icon" alt="Aktif"> Aktif
@endif
</span> </span>
<div style="font-size:11px;color:#64748b;margin-top:3px"> <div style="font-size:11px;color:#64748b;margin-top:3px">
{{ \Carbon\Carbon::parse($ch->tenggat_waktu)->format('d M Y, H:i') }} {{ \Carbon\Carbon::parse($ch->tenggat_waktu)->format('d M Y, H:i') }}
@ -434,18 +463,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" alt="Edit"> <img src="{{ asset('images/icon/main/edit.png') }}" class="action-icon" alt="Edit Challenge">
</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" alt="Detail"> <img src="{{ asset('images/icon/main/search.png') }}" class="action-icon" alt="Lihat 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" alt="Hapus"> <img src="{{ asset('images/icon/main/del.png') }}" class="action-icon" alt="Hapus Challenge">
</button> </button>
</form> </form>
</td> </td>
@ -471,7 +500,9 @@
{{-- Header kuning --}} {{-- Header kuning --}}
<div class="modal-header modal-header-yellow"> <div class="modal-header modal-header-yellow">
<h5 class="modal-title">🏆 Tambah Challenge Baru</h5> <h5 class="modal-title">
<img src="{{ asset('images/icon/gurud/piala.png') }}" class="inline-icon" alt="Piala"> 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>
@ -493,7 +524,9 @@
{{-- ─── STEP 1: Info Challenge ─── --}} {{-- ─── STEP 1: Info Challenge ─── --}}
<div class="step-panel active" id="tambah-step-1"> <div class="step-panel active" id="tambah-step-1">
<div class="section-divider">📋 Informasi Challenge</div> <div class="section-divider">
<img src="{{ asset('images/icon/gurud/buku1.png') }}" class="inline-icon" alt="Informasi"> Informasi Challenge
</div>
<div class="row g-3 mb-2"> <div class="row g-3 mb-2">
<div class="col-8"> <div class="col-8">
<label>Judul Challenge <span class="text-danger">*</span></label> <label>Judul Challenge <span class="text-danger">*</span></label>
@ -529,7 +562,9 @@
</div> </div>
</div> </div>
<div class="section-divider">🏫 Target Kelas</div> <div class="section-divider">
<img src="{{ asset('images/icon/gurud/school.png') }}" class="inline-icon" alt="Kelas"> Target Kelas
</div>
<div class="kelas-checkbox-grid mb-1"> <div class="kelas-checkbox-grid mb-1">
@foreach($kelas as $k) @foreach($kelas as $k)
<label class="kelas-check-item"> <label class="kelas-check-item">
@ -544,7 +579,9 @@
{{-- ─── STEP 2: Soal ─── --}} {{-- ─── STEP 2: Soal ─── --}}
<div class="step-panel" id="tambah-step-2"> <div class="step-panel" id="tambah-step-2">
<div class="section-divider" style="flex-shrink:0">📝 Daftar Soal</div> <div class="section-divider" style="flex-shrink:0">
<img src="{{ asset('images/icon/gurud/buku1.png') }}" class="inline-icon" alt="Soal"> Daftar Soal
</div>
<div id="soalContainer" class="soal-scroll-area"></div> <div id="soalContainer" class="soal-scroll-area"></div>
<div style="flex-shrink:0;padding-top:8px"> <div style="flex-shrink:0;padding-top:8px">
<button type="button" class="btn-tambah-soal" onclick="tambahSoal('soalContainer')"> <button type="button" class="btn-tambah-soal" onclick="tambahSoal('soalContainer')">
@ -569,7 +606,7 @@
{{-- Submit (step 2, hidden awalnya) --}} {{-- Submit (step 2, hidden awalnya) --}}
<button type="submit" class="btn-green" id="tambah-btn-submit" style="display:none"> <button type="submit" class="btn-green" id="tambah-btn-submit" style="display:none">
💾 Simpan Challenge <img src="{{ asset('images/icon/gurud/save.png') }}" class="inline-icon" alt="Simpan"> Simpan Challenge
</button> </button>
</div> </div>
@ -586,7 +623,9 @@
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-fixed"> <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-yellow"> <div class="modal-header modal-header-yellow">
<h5 class="modal-title">✏️ Edit Challenge</h5> <h5 class="modal-title">
<img src="{{ asset('images/icon/gurud/pencil.png') }}" class="inline-icon" alt="Edit"> 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>
@ -608,7 +647,9 @@
{{-- ─── STEP 1: Info Challenge ─── --}} {{-- ─── STEP 1: Info Challenge ─── --}}
<div class="step-panel active" id="edit-step-1"> <div class="step-panel active" id="edit-step-1">
<div class="section-divider">📋 Informasi Challenge</div> <div class="section-divider">
<img src="{{ asset('images/icon/gurud/buku2.png') }}" class="inline-icon" alt="Informasi"> Informasi Challenge
</div>
<div class="row g-3 mb-2"> <div class="row g-3 mb-2">
<div class="col-8"> <div class="col-8">
<label>Judul Challenge <span class="text-danger">*</span></label> <label>Judul Challenge <span class="text-danger">*</span></label>
@ -641,7 +682,9 @@
</div> </div>
</div> </div>
<div class="section-divider">🏫 Target Kelas</div> <div class="section-divider">
<img src="{{ asset('images/icon/gurud/school.png') }}" class="inline-icon" alt="Kelas"> Target Kelas
</div>
<div class="kelas-checkbox-grid mb-1" id="editKelasContainer"> <div class="kelas-checkbox-grid mb-1" id="editKelasContainer">
@foreach($kelas as $k) @foreach($kelas as $k)
<label class="kelas-check-item"> <label class="kelas-check-item">
@ -657,7 +700,9 @@
{{-- ─── STEP 2: Soal ─── --}} {{-- ─── STEP 2: Soal ─── --}}
<div class="step-panel" id="edit-step-2"> <div class="step-panel" id="edit-step-2">
<div class="section-divider" style="flex-shrink:0">📝 Daftar Soal</div> <div class="section-divider" style="flex-shrink:0">
<img src="{{ asset('images/icon/gurud/buku1.png') }}" class="inline-icon" alt="Soal"> Daftar Soal
</div>
<div id="editSoalContainer" class="soal-scroll-area"></div> <div id="editSoalContainer" class="soal-scroll-area"></div>
<div style="flex-shrink:0;padding-top:8px"> <div style="flex-shrink:0;padding-top:8px">
<button type="button" class="btn-tambah-soal" onclick="tambahSoal('editSoalContainer')"> <button type="button" class="btn-tambah-soal" onclick="tambahSoal('editSoalContainer')">
@ -677,7 +722,7 @@
Berikutnya Berikutnya
</button> </button>
<button type="submit" class="btn-green" id="edit-btn-submit" style="display:none"> <button type="submit" class="btn-green" id="edit-btn-submit" style="display:none">
💾 Update Challenge <img src="{{ asset('images/icon/gurud/save.png') }}" class="inline-icon" alt="Simpan"> Update Challenge
</button> </button>
</div> </div>
@ -868,7 +913,6 @@ 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>
{{-- Hidden nilainya diisi recalcExp() --}}
<input type="hidden" name="exp_per_soal[]" value="0"> <input type="hidden" name="exp_per_soal[]" value="0">
<span style="margin-left:auto;background:#f0fdf4;color:#16a34a;font-size:12px;font-weight:700; <span style="margin-left:auto;background:#f0fdf4;color:#16a34a;font-size:12px;font-weight:700;
padding:4px 12px;border-radius:99px;white-space:nowrap"> padding:4px 12px;border-radius:99px;white-space:nowrap">
@ -879,7 +923,7 @@ function tambahSoal(containerId, data = null) {
container.appendChild(card); container.appendChild(card);
renumberSoal(containerId); renumberSoal(containerId);
recalcExp(containerId); // update semua kartu setelah soal baru ditambah recalcExp(containerId);
// Scroll ke soal baru // Scroll ke soal baru
const scrollArea = container.closest('.soal-scroll-area') || container; const scrollArea = container.closest('.soal-scroll-area') || container;
@ -894,7 +938,7 @@ 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 recalcExp(containerId);
} }
function renumberSoal(containerId) { function renumberSoal(containerId) {
@ -908,18 +952,13 @@ function renumberSoal(containerId) {
OPEN 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();
// Paksa step 1
tambahGoStep1(); tambahGoStep1();
// Default 1 soal
tambahSoal('soalContainer'); tambahSoal('soalContainer');
// Recalc EXP otomatis setiap kali angka EXP di step-1 berubah
const expElTambah = document.getElementById('tambah-exp'); const expElTambah = document.getElementById('tambah-exp');
expElTambah.oninput = () => recalcExp('soalContainer'); expElTambah.oninput = () => recalcExp('soalContainer');
@ -933,7 +972,6 @@ function openTambahModal() {
soalCountEdit = 0; soalCountEdit = 0;
document.getElementById('editSoalContainer').innerHTML = ''; document.getElementById('editSoalContainer').innerHTML = '';
// Reset ke step 1
editGoStep1(); editGoStep1();
const res = await fetch(`/admin/challenge/${idChallenge}/edit-data`); const res = await fetch(`/admin/challenge/${idChallenge}/edit-data`);
@ -959,7 +997,6 @@ function openTambahModal() {
const expElEdit = document.getElementById('editExp'); const expElEdit = document.getElementById('editExp');
expElEdit.oninput = () => recalcExp('editSoalContainer'); expElEdit.oninput = () => recalcExp('editSoalContainer');
// Recalc sekali saat modal dibuka
recalcExp('editSoalContainer'); recalcExp('editSoalContainer');
new bootstrap.Modal(document.getElementById('modalEdit')).show(); new bootstrap.Modal(document.getElementById('modalEdit')).show();

View File

@ -26,7 +26,15 @@
border-left: 5px solid #667eea; border-left: 5px solid #667eea;
} }
.info-title { font-size: 22px; font-weight: 800; color: #1e293b; margin: 0 0 12px; } .info-title {
font-size: 22px;
font-weight: 800;
color: #1e293b;
margin: 0 0 12px;
display: flex;
align-items: center;
gap: 8px;
}
.meta-chip { .meta-chip {
display: inline-flex; display: inline-flex;
@ -43,6 +51,14 @@
.meta-chip.green { background: #dcfce7; color: #16a34a; } .meta-chip.green { background: #dcfce7; color: #16a34a; }
.meta-chip.red { background: #fee2e2; color: #dc2626; } .meta-chip.red { background: #fee2e2; color: #dc2626; }
/* Icon kecil inline (di dalam teks / badge / label) */
.inline-icon {
width: 16px;
height: 16px;
vertical-align: middle;
display: inline-block;
}
.kelas-chip { .kelas-chip {
display: inline-block; display: inline-block;
background: #e6f0ff; background: #e6f0ff;
@ -127,7 +143,9 @@
padding: 3px 10px; padding: 3px 10px;
border-radius: 99px; border-radius: 99px;
margin-top: 10px; margin-top: 10px;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
} }
.custom-card { .custom-card {
@ -138,7 +156,15 @@
margin-bottom: 20px; margin-bottom: 20px;
} }
.section-title { font-size: 16px; font-weight: 700; color: #1e293b; margin-bottom: 14px; } .section-title {
font-size: 16px;
font-weight: 700;
color: #1e293b;
margin-bottom: 14px;
display: flex;
align-items: center;
gap: 6px;
}
</style> </style>
<a href="{{ route('admin.challenge.index') }}" class="back-link"> Kembali ke Daftar Challenge</a> <a href="{{ route('admin.challenge.index') }}" class="back-link"> Kembali ke Daftar Challenge</a>
@ -149,15 +175,25 @@
{{-- INFO --}} {{-- INFO --}}
<div class="info-card"> <div class="info-card">
<h2 class="info-title">🏆 {{ $challenge->judul_challenge }}</h2> <h2 class="info-title">
<img src="{{ asset('images/icon/gurud/piala.png') }}" class="inline-icon" alt="Piala">
{{ $challenge->judul_challenge }}
</h2>
<div class="d-flex flex-wrap gap-2 mb-3"> <div class="d-flex flex-wrap gap-2 mb-3">
<span class="meta-chip purple"> {{ $challenge->exp }} EXP</span> <span class="meta-chip purple">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="inline-icon" alt="EXP">
{{ $challenge->exp }} EXP
</span>
<span class="meta-chip {{ $isLewat ? 'red' : 'green' }}"> <span class="meta-chip {{ $isLewat ? 'red' : 'green' }}">
{{ \Carbon\Carbon::parse($challenge->tenggat_waktu)->format('d M Y, H:i') }} <img src="{{ asset('images/icon/gurud/alarm.png') }}" class="inline-icon" alt="Tenggat">
{{ \Carbon\Carbon::parse($challenge->tenggat_waktu)->format('d M Y, H:i') }}
{{ $isLewat ? 'Sudah lewat' : 'Masih aktif' }} {{ $isLewat ? 'Sudah lewat' : 'Masih aktif' }}
</span> </span>
<span class="meta-chip">📝 {{ $challenge->soal->count() }} soal</span> <span class="meta-chip">
<img src="{{ asset('images/icon/gurud/buku1.png') }}" class="inline-icon" alt="Soal">
{{ $challenge->soal->count() }} soal
</span>
</div> </div>
<div class="mb-2"> <div class="mb-2">
@ -175,7 +211,10 @@
{{-- DAFTAR SOAL --}} {{-- DAFTAR SOAL --}}
<div class="custom-card"> <div class="custom-card">
<p class="section-title">📝 Daftar Soal Challenge</p> <p class="section-title">
<img src="{{ asset('images/icon/gurud/buku2.png') }}" class="inline-icon" alt="Daftar Soal">
Daftar Soal Challenge
</p>
@forelse($challenge->soal as $i => $soal) @forelse($challenge->soal as $i => $soal)
<div class="soal-card"> <div class="soal-card">
@ -189,13 +228,18 @@
<span class="opsi-label">{{ $opsi }}</span> <span class="opsi-label">{{ $opsi }}</span>
<span>{{ $soal->$key }}</span> <span>{{ $soal->$key }}</span>
@if($soal->jawaban_benar === $opsi) @if($soal->jawaban_benar === $opsi)
<span style="margin-left:auto;font-size:16px"></span> <span style="margin-left:auto;display:inline-flex;align-items:center">
<img src="{{ asset('images/icon/gurud/v.png') }}" class="inline-icon" alt="Jawaban Benar">
</span>
@endif @endif
</div> </div>
@endforeach @endforeach
</div> </div>
<span class="exp-badge"> {{ $soal->exp_per_soal }} EXP per soal</span> <span class="exp-badge">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="inline-icon" alt="EXP">
{{ $soal->exp_per_soal }} EXP per soal
</span>
</div> </div>
@empty @empty
<p class="text-muted text-center py-3">Belum ada soal.</p> <p class="text-muted text-center py-3">Belum ada soal.</p>

View File

@ -15,6 +15,8 @@
position: relative; overflow: hidden; position: relative; overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease; transition: transform 0.2s ease, box-shadow 0.2s ease;
animation: fadeUp 0.4s ease both; animation: fadeUp 0.4s ease both;
text-decoration: none;
display: block;
} }
.stat-card:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(0,0,0,0.12); } .stat-card:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(0,0,0,0.12); }
.stat-card:nth-child(1) { background: linear-gradient(135deg, #fff7e6, #ffe4b2); animation-delay: 0s; } .stat-card:nth-child(1) { background: linear-gradient(135deg, #fff7e6, #ffe4b2); animation-delay: 0s; }
@ -26,12 +28,27 @@
.stat-card:nth-child(2)::after { background: #22c55e; } .stat-card:nth-child(2)::after { background: #22c55e; }
.stat-card:nth-child(3)::after { background: #2b8ef3; } .stat-card:nth-child(3)::after { background: #2b8ef3; }
.stat-card:nth-child(4)::after { background: #ec4899; } .stat-card:nth-child(4)::after { background: #ec4899; }
.stat-label { font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; margin-bottom: 10px; } .stat-label { font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; margin-bottom: 10px; }
.stat-card:nth-child(1) .stat-label { color: #c2651a; } .stat-card:nth-child(1) .stat-label { color: #c2651a; }
.stat-card:nth-child(2) .stat-label { color: #15803d; } .stat-card:nth-child(2) .stat-label { color: #15803d; }
.stat-card:nth-child(3) .stat-label { color: #1d5fb8; } .stat-card:nth-child(3) .stat-label { color: #1d5fb8; }
.stat-card:nth-child(4) .stat-label { color: #be185d; } .stat-card:nth-child(4) .stat-label { color: #be185d; }
.stat-num { font-size: 42px; font-weight: 800; line-height: 1; color: #0f1f3d; }
.stat-num { font-size: 42px; font-weight: 800; line-height: 1; color: #0f1f3d; margin-bottom: 12px; }
.stat-link {
font-size: 11px; font-weight: 700;
display: inline-flex; align-items: center; gap: 4px;
opacity: 0.6;
transition: opacity 0.2s;
}
.stat-card:hover .stat-link { opacity: 1; }
.stat-card:nth-child(1) .stat-link { color: #c2651a; }
.stat-card:nth-child(2) .stat-link { color: #15803d; }
.stat-card:nth-child(3) .stat-link { color: #1d5fb8; }
.stat-card:nth-child(4) .stat-link { color: #be185d; }
.stat-icon { position: absolute; top: 20px; right: 20px; width: 42px; height: 42px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 20px; opacity: 0.7; } .stat-icon { position: absolute; top: 20px; right: 20px; width: 42px; height: 42px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 20px; opacity: 0.7; }
.stat-card:nth-child(1) .stat-icon { background: rgba(249,115,22,0.15); } .stat-card:nth-child(1) .stat-icon { background: rgba(249,115,22,0.15); }
.stat-card:nth-child(2) .stat-icon { background: rgba(34,197,94,0.15); } .stat-card:nth-child(2) .stat-icon { background: rgba(34,197,94,0.15); }
@ -47,10 +64,8 @@
.card-badge { font-size: 11px; font-weight: 700; background: #e8f4ff; color: #2b8ef3; padding: 3px 10px; border-radius: 99px; text-decoration: none; } .card-badge { font-size: 11px; font-weight: 700; background: #e8f4ff; color: #2b8ef3; padding: 3px 10px; border-radius: 99px; text-decoration: none; }
.card-badge:hover { background: #dbeeff; } .card-badge:hover { background: #dbeeff; }
/* Chart — tinggi responsif */
.chart-wrap { position: relative; height: 220px; } .chart-wrap { position: relative; height: 220px; }
/* Challenge */
.challenge-item { background: #f8faff; border-radius: 14px; padding: 14px 16px; margin-bottom: 10px; border-left: 4px solid #2b8ef3; transition: all 0.2s; } .challenge-item { background: #f8faff; border-radius: 14px; padding: 14px 16px; margin-bottom: 10px; border-left: 4px solid #2b8ef3; transition: all 0.2s; }
.challenge-item:nth-child(2) { border-left-color: #22c55e; } .challenge-item:nth-child(2) { border-left-color: #22c55e; }
.challenge-item:nth-child(3) { border-left-color: #f97316; } .challenge-item:nth-child(3) { border-left-color: #f97316; }
@ -78,9 +93,7 @@
@section('content') @section('content')
@php @php use Carbon\Carbon; @endphp
use Carbon\Carbon;
@endphp
<div class="dash-header"> <div class="dash-header">
<div class="dash-sub">{{ Carbon::now()->isoFormat('dddd, D MMMM Y') }}</div> <div class="dash-sub">{{ Carbon::now()->isoFormat('dddd, D MMMM Y') }}</div>
@ -88,32 +101,35 @@
{{-- STAT CARDS --}} {{-- STAT CARDS --}}
<div class="stat-grid"> <div class="stat-grid">
<div class="stat-card"> <a href="{{ route('admin.guru.index') }}" class="stat-card">
<div class="stat-icon">👨‍🏫</div> <div class="stat-icon"><img src="{{ asset('images/icon/gurud/guru.png') }}" class="topbar-waving" alt="Waving"></div>
<div class="stat-label">Total Guru</div> <div class="stat-label">Total Guru</div>
<div class="stat-num">{{ $totalGuru }}</div> <div class="stat-num">{{ $totalGuru }}</div>
</div> <div class="stat-link">Lihat Data </div>
<div class="stat-card"> </a>
<div class="stat-icon">🏫</div> <a href="{{ route('admin.kelas.index') }}" class="stat-card">
<div class="stat-icon"><img src="{{ asset('images/icon/gurud/school.png') }}" class="topbar-waving" alt="Waving"></div>
<div class="stat-label">Total Kelas</div> <div class="stat-label">Total Kelas</div>
<div class="stat-num">{{ $totalKelas }}</div> <div class="stat-num">{{ $totalKelas }}</div>
</div> <div class="stat-link">Lihat Data </div>
<div class="stat-card"> </a>
<div class="stat-icon">👨‍🎓</div> <a href="{{ route('admin.siswa.index') }}" class="stat-card">
<div class="stat-icon"><img src="{{ asset('images/icon/gurud/siswa.png') }}" class="topbar-waving" alt="Waving"></div>
<div class="stat-label">Total Siswa</div> <div class="stat-label">Total Siswa</div>
<div class="stat-num">{{ $totalSiswa }}</div> <div class="stat-num">{{ $totalSiswa }}</div>
</div> <div class="stat-link">Lihat Data </div>
<div class="stat-card"> </a>
<div class="stat-icon">📚</div> <a href="{{ route('admin.mapel.index') }}" class="stat-card">
<div class="stat-icon"><img src="{{ asset('images/icon/gurud/stacked.png') }}" class="topbar-waving" alt="Waving"></div>
<div class="stat-label">Total Mapel</div> <div class="stat-label">Total Mapel</div>
<div class="stat-num">{{ $totalMapel }}</div> <div class="stat-num">{{ $totalMapel }}</div>
</div> <div class="stat-link">Lihat Data </div>
</a>
</div> </div>
{{-- BOTTOM --}} {{-- BOTTOM --}}
<div class="dash-bottom"> <div class="dash-bottom">
{{-- Bar Chart --}}
<div class="dash-card"> <div class="dash-card">
<div class="card-head"> <div class="card-head">
<div class="card-title">Total Siswa Berdasarkan Kelas</div> <div class="card-title">Total Siswa Berdasarkan Kelas</div>
@ -124,7 +140,6 @@
</div> </div>
</div> </div>
{{-- Challenge Terbaru --}}
<div class="dash-card"> <div class="dash-card">
<div class="card-head"> <div class="card-head">
<div class="card-title">Challenge Terbaru</div> <div class="card-title">Challenge Terbaru</div>
@ -164,21 +179,16 @@
<script> <script>
const labels = @json($chartData->pluck('nama_kelas')); const labels = @json($chartData->pluck('nama_kelas'));
const values = @json($chartData->pluck('siswa_count')); const values = @json($chartData->pluck('siswa_count'));
const colors = [ const colors = [
'rgba(43,142,243,0.85)', 'rgba(43,142,243,0.85)', 'rgba(34,197,94,0.85)', 'rgba(249,115,22,0.85)',
'rgba(34,197,94,0.85)', 'rgba(168,85,247,0.85)', 'rgba(236,72,153,0.85)', 'rgba(234,179,8,0.85)',
'rgba(249,115,22,0.85)',
'rgba(168,85,247,0.85)',
'rgba(236,72,153,0.85)',
'rgba(234,179,8,0.85)',
]; ];
const ctx = document.getElementById('kelasChart').getContext('2d'); const ctx = document.getElementById('kelasChart').getContext('2d');
const kelasChart = new Chart(ctx, { const kelasChart = new Chart(ctx, {
type: 'bar', type: 'bar',
data: { data: {
labels: labels, labels,
datasets: [{ datasets: [{
label: 'Jumlah Siswa', label: 'Jumlah Siswa',
data: values, data: values,
@ -192,25 +202,15 @@
maintainAspectRatio: false, maintainAspectRatio: false,
plugins: { plugins: {
legend: { display: false }, legend: { display: false },
tooltip: { tooltip: { callbacks: { label: ctx => ` ${ctx.parsed.y} siswa` } }
callbacks: { label: ctx => ` ${ctx.parsed.y} siswa` }
}
}, },
scales: { scales: {
y: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { font: { family: 'Poppins', size: 11 }, color: '#94a3b8', stepSize: 1 } },
beginAtZero: true, x: { grid: { display: false }, ticks: { font: { family: 'Poppins', size: 11 }, color: '#64748b' } }
grid: { color: '#f1f5f9' },
ticks: { font: { family: 'Poppins', size: 11 }, color: '#94a3b8', stepSize: 1 }
},
x: {
grid: { display: false },
ticks: { font: { family: 'Poppins', size: 11 }, color: '#64748b' }
}
} }
} }
}); });
// Fix resize saat sidebar toggle
document.getElementById('sidebarToggleBtn')?.addEventListener('click', () => { document.getElementById('sidebarToggleBtn')?.addEventListener('click', () => {
setTimeout(() => kelasChart.resize(), 320); setTimeout(() => kelasChart.resize(), 320);
}); });

View File

@ -51,7 +51,14 @@
width: 150px; width: 150px;
} }
.action-icon { width: 20px; cursor: pointer; margin: 0 5px; } .action-icon {
width: 20px;
height: 20px;
cursor: pointer;
margin: 0 5px;
display: inline-block;
vertical-align: middle;
}
.per-page-select { .per-page-select {
border-radius: 10px; border-radius: 10px;
@ -140,13 +147,19 @@
padding: 12px 16px; padding: 12px 16px;
margin-bottom: 16px; margin-bottom: 16px;
font-weight: 500; font-weight: 500;
display: flex;
align-items: center;
gap: 8px;
} }
</style> </style>
<h3 class="page-title">DAFTAR GURU</h3> <h3 class="page-title">DAFTAR GURU</h3>
@if(session('success')) @if(session('success'))
<div class="alert-success-custom"> {{ session('success') }}</div> <div class="alert-success-custom">
<img src="{{ asset('images/icon/gurud/v.png') }}" width="18" height="18" alt="Berhasil">
{{ session('success') }}
</div>
@endif @endif
<div class="custom-card"> <div class="custom-card">
@ -154,15 +167,15 @@
<div class="d-flex justify-content-between align-items-center mb-3"> <div class="d-flex justify-content-between align-items-center mb-3">
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<button class="btn-primary-custom" data-bs-toggle="modal" data-bs-target="#modalTambah"> <button class="btn-primary-custom" data-bs-toggle="modal" data-bs-target="#modalTambah">
<img src="{{ asset('images/icon/main/add.png') }}" width="18"> <img src="{{ asset('images/icon/main/add.png') }}" width="18" height="18" alt="Tambah">
Tambah Data Tambah Data
</button> </button>
<button class="btn-primary-custom"> <button class="btn-primary-custom">
<img src="{{ asset('images/icon/main/download.png') }}" width="18"> <img src="{{ asset('images/icon/main/download.png') }}" width="18" height="18" alt="Download">
Download PDF Download PDF
</button> </button>
<button class="btn-primary-custom"> <button class="btn-primary-custom">
<img src="{{ asset('images/icon/main/download.png') }}" width="18"> <img src="{{ asset('images/icon/main/download.png') }}" width="18" height="18" alt="Download">
Download Excel Download Excel
</button> </button>
</div> </div>
@ -171,7 +184,7 @@
<div class="search-box"> <div class="search-box">
<input type="text" name="search" placeholder="Cari" value="{{ request('search') }}"> <input type="text" name="search" placeholder="Cari" value="{{ request('search') }}">
<button style="border:none;background:none"> <button style="border:none;background:none">
<img src="{{ asset('images/icon/main/search.png') }}" width="18"> <img src="{{ asset('images/icon/main/search.png') }}" width="18" height="18" alt="Cari">
</button> </button>
</div> </div>
</form> </form>
@ -234,7 +247,7 @@
'{{ addslashes($guru->nama) }}', '{{ addslashes($guru->nama) }}',
{{ $guru->mengajars->map(fn($m) => ['id_mapel' => $m->id_mapel, 'id_kelas' => $m->id_kelas])->toJson() }} {{ $guru->mengajars->map(fn($m) => ['id_mapel' => $m->id_mapel, 'id_kelas' => $m->id_kelas])->toJson() }}
)" 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 guru">
</button> </button>
{{-- TOMBOL HAPUS --}} {{-- TOMBOL HAPUS --}}
@ -244,7 +257,7 @@
@csrf @csrf
@method('DELETE') @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 guru">
</button> </button>
</form> </form>
</td> </td>
@ -422,13 +435,11 @@
<script> <script>
const KELAS_BY_MAPEL_URL = "{{ route('admin.guru.kelasByMapel') }}"; const KELAS_BY_MAPEL_URL = "{{ route('admin.guru.kelasByMapel') }}";
// ===== SAAT MAPEL DIPILIH → fetch kelas otomatis =====
async function onMapelChange(selectMapel) { async function onMapelChange(selectMapel) {
const idMapel = selectMapel.value; const idMapel = selectMapel.value;
const row = selectMapel.closest('.mengajar-row'); const row = selectMapel.closest('.mengajar-row');
const selectKelas = row.querySelector('.select-kelas'); const selectKelas = row.querySelector('.select-kelas');
// Reset kelas
selectKelas.innerHTML = '<option value="">-- Memuat kelas... --</option>'; selectKelas.innerHTML = '<option value="">-- Memuat kelas... --</option>';
selectKelas.disabled = true; selectKelas.disabled = true;
@ -454,7 +465,6 @@
selectKelas.appendChild(opt); selectKelas.appendChild(opt);
}); });
// Jika hanya 1 kelas, langsung pilih otomatis
if (data.length === 1) { if (data.length === 1) {
selectKelas.value = data[0].id_kelas; selectKelas.value = data[0].id_kelas;
} }
@ -466,7 +476,6 @@
} }
} }
// ===== TAMBAH BARIS BARU =====
async function tambahRow(containerId, selectedMapel = null, selectedKelas = null) { async function tambahRow(containerId, selectedMapel = null, selectedKelas = null) {
const template = document.getElementById('rowTemplate'); const template = document.getElementById('rowTemplate');
const clone = template.content.cloneNode(true); const clone = template.content.cloneNode(true);
@ -482,7 +491,6 @@
if (selectedMapel) { if (selectedMapel) {
selectMapel.value = selectedMapel; selectMapel.value = selectedMapel;
// Fetch kelas untuk mapel yang sudah dipilih
try { try {
const res = await fetch(`${KELAS_BY_MAPEL_URL}?id_mapel=${selectedMapel}`); const res = await fetch(`${KELAS_BY_MAPEL_URL}?id_mapel=${selectedMapel}`);
const data = await res.json(); const data = await res.json();
@ -504,7 +512,6 @@
} }
} }
// ===== HAPUS BARIS =====
function hapusRow(btn) { function hapusRow(btn) {
const container = btn.closest('[id$="Rows"]'); const container = btn.closest('[id$="Rows"]');
const rows = container.querySelectorAll('.mengajar-row'); const rows = container.querySelectorAll('.mengajar-row');
@ -515,7 +522,6 @@ function hapusRow(btn) {
btn.closest('.mengajar-row').remove(); btn.closest('.mengajar-row').remove();
} }
// ===== BUKA MODAL EDIT =====
async function openEditModal(idGuru, nip, nama, mengajars) { async function openEditModal(idGuru, nip, nama, mengajars) {
document.getElementById('formEdit').action = "{{ url('admin/guru') }}/" + idGuru; document.getElementById('formEdit').action = "{{ url('admin/guru') }}/" + idGuru;
document.getElementById('editNip').value = nip; document.getElementById('editNip').value = nip;

View File

@ -14,7 +14,7 @@
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; }
.admin-wrapper { display: flex; height: 100vh; overflow: hidden; } .admin-wrapper { display: flex; height: 100vh; overflow: hidden; }
/* ── SIDEBAR (scrollable internally for admin) ── */ /* ── SIDEBAR ── */
.sidebar { .sidebar {
width: 260px; flex-shrink: 0; width: 260px; flex-shrink: 0;
background: #ffffff; background: #ffffff;
@ -27,12 +27,12 @@
} }
.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; height: auto; }
.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: 4px; border-radius: 12px; color: #64748b; text-decoration: none; font-weight: 500; font-size: 14px; transition: all 0.2s ease; } .sidebar-link { display: flex; align-items: center; gap: 12px; padding: 11px 18px; margin-bottom: 4px; 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-section { font-size: 10px; font-weight: 700; color: #94a3b8; letter-spacing: 1px; text-transform: uppercase; padding: 4px 18px; margin: 8px 0 4px; white-space: nowrap; } .sidebar-section { font-size: 10px; font-weight: 700; color: #94a3b8; letter-spacing: 1px; text-transform: uppercase; padding: 4px 18px; margin: 8px 0 4px; white-space: nowrap; }
.sidebar-logout { margin-top: auto; padding-top: 16px; border-top: 1px solid #f1f5f9; flex-shrink: 0; } .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; } .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; }
@ -45,13 +45,16 @@
.toggle-arrow { width: 12px; height: 12px; fill: none; stroke: white; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.3s ease; } .toggle-arrow { width: 12px; height: 12px; fill: none; stroke: white; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.3s ease; }
.sidebar-toggle-btn.collapsed .toggle-arrow { transform: rotate(180deg); } .sidebar-toggle-btn.collapsed .toggle-arrow { transform: rotate(180deg); }
/* ── MAIN (scrollable) ── */ /* ── MAIN ── */
.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; box-shadow: 0 8px 24px rgba(43,142,243,0.25); 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; }
/* ── WAVING HAND — ukuran seragam di semua halaman ── */
.topbar-waving { width: 24px; height: 24px; object-fit: contain; vertical-align: middle; flex-shrink: 0; }
.content { padding: 20px 28px 28px; flex: 1; overflow-y: auto; } .content { padding: 20px 28px 28px; flex: 1; overflow-y: auto; }
/* ── NOTIF BELL ── */ /* ── NOTIF BELL ── */
@ -92,38 +95,19 @@
transition: all 0.2s cubic-bezier(0.34,1.56,0.64,1); transition: all 0.2s cubic-bezier(0.34,1.56,0.64,1);
overflow: hidden; overflow: hidden;
} }
.notif-dropdown.show { opacity: 1; pointer-events: all; transform: translateY(0) scale(1); }
.notif-dropdown.show { .notif-head { padding: 16px 18px 12px; border-bottom: 1px solid #f1f5f9; display: flex; align-items: center; justify-content: space-between; }
opacity: 1; pointer-events: all;
transform: translateY(0) scale(1);
}
.notif-head {
padding: 16px 18px 12px;
border-bottom: 1px solid #f1f5f9;
display: flex; align-items: center; justify-content: space-between;
}
.notif-head-title { font-size: 14px; font-weight: 700; color: #0f1f3d; } .notif-head-title { font-size: 14px; font-weight: 700; color: #0f1f3d; }
.notif-head-count { font-size: 11px; color: #94a3b8; } .notif-head-count { font-size: 11px; color: #94a3b8; }
.notif-list { max-height: 340px; overflow-y: auto; } .notif-list { max-height: 340px; overflow-y: auto; }
.notif-item { .notif-item { display: flex; align-items: flex-start; gap: 12px; padding: 13px 18px; border-bottom: 1px solid #f8fafc; transition: background 0.15s; cursor: default; }
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 { .notif-icon-wrap { width: 36px; height: 36px; border-radius: 12px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 16px; }
width: 36px; height: 36px; border-radius: 12px;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0; font-size: 16px;
}
.notif-icon-materi { background: #e8f4ff; } .notif-icon-materi { background: #e8f4ff; }
.notif-icon-tugas { background: #fff7e6; } .notif-icon-tugas { background: #fff7e6; }
.notif-icon-pengumpulan { background: #eefaf3; } .notif-icon-pengumpulan { background: #eefaf3; }
@ -135,11 +119,12 @@
.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; }
.notif-empty-icon img { width: 36px; height: 36px; object-fit: contain; }
.notif-empty-text { font-size: 13px; color: #94a3b8; } .notif-empty-text { font-size: 13px; color: #94a3b8; }
/* ── TOPBAR AVATAR ── */ /* ── TOPBAR AVATAR ── */
.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; flex-shrink: 0; }
.topbar-avatar:hover { border-color: white; transform: scale(1.05); } .topbar-avatar:hover { border-color: white; transform: scale(1.05); }
.topbar-avatar-icon { width: 36px; height: 36px; border-radius: 50%; background: rgba(255,255,255,0.2); border: 2px solid rgba(255,255,255,0.4); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.2s; flex-shrink: 0; } .topbar-avatar-icon { width: 36px; height: 36px; border-radius: 50%; background: rgba(255,255,255,0.2); border: 2px solid rgba(255,255,255,0.4); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.2s; flex-shrink: 0; }
.topbar-avatar-icon:hover { background: rgba(255,255,255,0.35); } .topbar-avatar-icon:hover { background: rgba(255,255,255,0.35); }
@ -188,34 +173,43 @@
</div> </div>
<nav class="sidebar-menu"> <nav class="sidebar-menu">
<a href="{{ route('admin.dashboard') }}" class="sidebar-link {{ request()->routeIs('admin.dashboard') ? 'active' : '' }}"> <a href="{{ route('admin.dashboard') }}" class="sidebar-link {{ request()->routeIs('admin.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>
<div class="sidebar-section">Data Master</div> <div class="sidebar-section">Data Master</div>
<a href="{{ route('admin.guru.index') }}" class="sidebar-link {{ request()->routeIs('admin.guru.*') ? 'active' : '' }}"> <a href="{{ route('admin.guru.index') }}" class="sidebar-link {{ request()->routeIs('admin.guru.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon" alt=""><span>Daftar Guru</span> <img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon" alt="Daftar Guru">
<span>Daftar Guru</span>
</a> </a>
<a href="{{ route('admin.kelas.index') }}" class="sidebar-link {{ request()->routeIs('admin.kelas.*') ? 'active' : '' }}"> <a href="{{ route('admin.kelas.index') }}" class="sidebar-link {{ request()->routeIs('admin.kelas.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/kelas.png') }}" class="sidebar-icon" alt=""><span>Daftar Kelas</span> <img src="{{ asset('images/icon/sidebar/kelas.png') }}" class="sidebar-icon" alt="Daftar Kelas">
<span>Daftar Kelas</span>
</a> </a>
<a href="{{ route('admin.siswa.index') }}" class="sidebar-link {{ request()->routeIs('admin.siswa.*') ? 'active' : '' }}"> <a href="{{ route('admin.siswa.index') }}" class="sidebar-link {{ request()->routeIs('admin.siswa.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt=""><span>Daftar Siswa</span> <img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt="Daftar Siswa">
<span>Daftar Siswa</span>
</a> </a>
<a href="{{ route('admin.mapel.index') }}" class="sidebar-link {{ request()->routeIs('admin.mapel.*') ? 'active' : '' }}"> <a href="{{ route('admin.mapel.index') }}" class="sidebar-link {{ request()->routeIs('admin.mapel.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt=""><span>Mata Pelajaran</span> <img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="Mata Pelajaran">
<span>Mata Pelajaran</span>
</a> </a>
<div class="sidebar-section">Konten Guru</div> <div class="sidebar-section">Konten Guru</div>
<a href="{{ route('admin.materi.history') }}" class="sidebar-link {{ request()->routeIs('admin.materi.*') ? 'active' : '' }}"> <a href="{{ route('admin.materi.history') }}" class="sidebar-link {{ request()->routeIs('admin.materi.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt=""><span>History Materi</span> <img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="History Materi">
<span>History Materi</span>
</a> </a>
<a href="{{ route('admin.tugas.history') }}" class="sidebar-link {{ request()->routeIs('admin.tugas.*') ? 'active' : '' }}"> <a href="{{ route('admin.tugas.history') }}" class="sidebar-link {{ request()->routeIs('admin.tugas.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon" alt=""><span>History Tugas</span> <img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon" alt="History Tugas">
<span>History Tugas</span>
</a> </a>
<div class="sidebar-section">Gamifikasi</div> <div class="sidebar-section">Gamifikasi</div>
<a href="{{ route('admin.challenge.index') }}" class="sidebar-link {{ request()->routeIs('admin.challenge.*') ? 'active' : '' }}"> <a href="{{ route('admin.challenge.index') }}" class="sidebar-link {{ request()->routeIs('admin.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('admin.leaderboard.index') }}" class="sidebar-link {{ request()->routeIs('admin.leaderboard.*') ? 'active' : '' }}"> <a href="{{ route('admin.leaderboard.index') }}" class="sidebar-link {{ request()->routeIs('admin.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('admin.logout') }}" method="POST" class="sidebar-logout"> <form action="{{ route('admin.logout') }}" method="POST" class="sidebar-logout">
@ -234,13 +228,14 @@
<div class="main"> <div class="main">
<header class="topbar"> <header class="topbar">
<div class="topbar-left"> <div class="topbar-left">
👋 Hai, <span id="topbar-username">{{ Auth::guard('admin')->user()->username ?? 'Admin' }}</span> <img src="{{ asset('images/icon/gurud/wavinghand.png') }}" class="topbar-waving" alt="Waving hand">
Hai, <span id="topbar-username">{{ Auth::guard('admin')->user()->username ?? 'Admin' }}</span>
</div> </div>
<div class="topbar-right"> <div class="topbar-right">
{{-- NOTIF BELL --}} {{-- NOTIF BELL --}}
<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)" aria-label="Notifikasi">
<svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg> <svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
</button> </button>
<div class="notif-badge" id="notifBadge"></div> <div class="notif-badge" id="notifBadge"></div>
@ -251,7 +246,9 @@
</div> </div>
<div class="notif-list" id="notifList"> <div class="notif-list" id="notifList">
<div class="notif-empty"> <div class="notif-empty">
<div class="notif-empty-icon">🔔</div> <div class="notif-empty-icon">
<img src="{{ asset('images/icon/gurud/bell.png') }}" class="topbar-waving" alt="Notifikasi kosong">
</div>
<div class="notif-empty-text">Memuat notifikasi...</div> <div class="notif-empty-text">Memuat notifikasi...</div>
</div> </div>
</div> </div>
@ -260,9 +257,13 @@
@php $admin = Auth::guard('admin')->user(); @endphp @php $admin = Auth::guard('admin')->user(); @endphp
@if($admin->foto_profil) @if($admin->foto_profil)
<img src="{{ Storage::url($admin->foto_profil) }}" class="topbar-avatar" id="topbar-foto" onclick="openProfileModal()" alt="Profil"> <img src="{{ Storage::url($admin->foto_profil) }}"
class="topbar-avatar"
id="topbar-foto"
onclick="openProfileModal()"
alt="Foto profil {{ $admin->username }}">
@else @else
<div class="topbar-avatar-icon" id="topbar-foto-icon" onclick="openProfileModal()"> <div class="topbar-avatar-icon" id="topbar-foto-icon" onclick="openProfileModal()" role="button" aria-label="Edit profil">
<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>
</div> </div>
@endif @endif
@ -278,7 +279,7 @@
{{-- 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()"> <button class="modal-close" onclick="closeProfileModal()" aria-label="Tutup modal">
<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> <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>
<div class="modal-title">Edit Profil</div> <div class="modal-title">Edit Profil</div>
@ -289,10 +290,10 @@
<div class="foto-upload-area"> <div class="foto-upload-area">
<div class="foto-circle"> <div class="foto-circle">
@if($admin->foto_profil) @if($admin->foto_profil)
<img src="{{ Storage::url($admin->foto_profil) }}" id="modal-foto-preview" alt=""> <img src="{{ Storage::url($admin->foto_profil) }}" id="modal-foto-preview" alt="Foto profil saat ini">
@else @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> <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="" style="display:none"> <img src="" id="modal-foto-preview" alt="Preview foto profil" style="display:none">
@endif @endif
</div> </div>
<div class="foto-info"> <div class="foto-info">
@ -429,7 +430,7 @@ function closeOnOverlay(e) { if (e.target === document.getElementById('profileMo
if (data.foto_url) { if (data.foto_url) {
const tf = document.getElementById('topbar-foto'); const ti = document.getElementById('topbar-foto-icon'); const tf = document.getElementById('topbar-foto'); const ti = document.getElementById('topbar-foto-icon');
if (tf) { tf.src = data.foto_url + '?t=' + Date.now(); } 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); } 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 ' + (data.username ?? ''); ti.replaceWith(img); }
const mp = document.getElementById('modal-foto-preview'); const mi = document.getElementById('modal-foto-icon'); 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 (mp) { mp.src = data.foto_url; mp.style.display = 'block'; } if (mi) mi.style.display = 'none';
} }

View File

@ -71,7 +71,7 @@
.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-kelas { font-size: 11px; color: #94a3b8; } .podium-kelas { font-size: 11px; color: #94a3b8; }
.podium-exp { font-size: 12px; color: #64748b; } .podium-exp { font-size: 12px; color: #64748b; display: flex; align-items: center; gap: 4px; }
.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); }
@ -80,7 +80,7 @@
/* Tabel */ /* Tabel */
.custom-card { background: white; border-radius: 20px; border: 2px solid #e5e5e5; padding: 22px; } .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; } .section-title { font-size: 15px; font-weight: 700; color: #1e293b; margin-bottom: 16px; display: flex; align-items: center; gap: 6px; }
.lb-row { display: flex; align-items: center; gap: 14px; padding: 11px 14px; border-radius: 12px; margin-bottom: 6px; transition: background 0.15s; } .lb-row { display: flex; align-items: center; gap: 14px; padding: 11px 14px; border-radius: 12px; margin-bottom: 6px; transition: background 0.15s; }
.lb-row:hover { background: #f8fafc; } .lb-row:hover { background: #f8fafc; }
@ -99,16 +99,23 @@
.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-kelas { font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 99px; } .lb-kelas { font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 99px; }
.lb-exp { font-size: 14px; font-weight: 700; color: #2b8ef3; } .lb-exp { font-size: 14px; font-weight: 700; color: #2b8ef3; display: flex; align-items: center; gap: 4px; }
.semester-badge { display: inline-block; background: #e0f2fe; color: #0369a1; font-size: 12px; font-weight: 700; padding: 4px 12px; border-radius: 99px; margin-bottom: 20px; } .semester-badge { display: inline-block; background: #e0f2fe; color: #0369a1; 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; }
/* Icon sizes */
.icon-title { width: 28px; height: 28px; vertical-align: middle; margin-right: 6px; }
.icon-sm { width: 16px; height: 16px; vertical-align: middle; }
.icon-crown { width: 24px; height: 24px; }
.icon-rank { width: 20px; height: 20px; }
.icon-empty { width: 56px; height: 56px; }
</style> </style>
@endpush @endpush
@section('content') @section('content')
<h3 class="page-title">🏅 Leaderboard</h3> <h3 class="page-title">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>
{{-- Filter --}} {{-- Filter --}}
@ -151,7 +158,9 @@
@if($leaderboard->isEmpty()) @if($leaderboard->isEmpty())
<div class="empty-state"> <div class="empty-state">
<div style="font-size:52px;margin-bottom:12px">📊</div> <div style="margin-bottom:12px">
<img src="{{ asset('images/icon/gurud/lb.png') }}" class="icon-empty topbar-waving" alt="Leaderboard kosong">
</div>
<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">Belum ada siswa yang menyelesaikan challenge pada periode ini.</p> <p style="font-size:13px">Belum ada siswa yang menyelesaikan challenge pada periode ini.</p>
</div> </div>
@ -171,19 +180,27 @@
<div class="podium-avatar">{{ strtoupper(substr($second['nama'],0,1)) }}</div> <div class="podium-avatar">{{ strtoupper(substr($second['nama'],0,1)) }}</div>
<div class="podium-name">{{ $second['nama'] }}</div> <div class="podium-name">{{ $second['nama'] }}</div>
<div class="podium-kelas">{{ $second['nama_kelas'] }}</div> <div class="podium-kelas">{{ $second['nama_kelas'] }}</div>
<div class="podium-exp"> {{ number_format($second['exp']) }}</div> <div class="podium-exp">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-sm topbar-waving" alt="EXP">
{{ number_format($second['exp']) }}
</div>
<div class="podium-bar">2</div> <div class="podium-bar">2</div>
</div> </div>
@endif @endif
<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">
<img src="{{ asset('images/icon/gurud/crown.png') }}" class="icon-crown topbar-waving" alt="Mahkota juara 1">
</span>
{{ strtoupper(substr($first['nama'],0,1)) }} {{ strtoupper(substr($first['nama'],0,1)) }}
</div> </div>
<div class="podium-name">{{ $first['nama'] }}</div> <div class="podium-name">{{ $first['nama'] }}</div>
<div class="podium-kelas">{{ $first['nama_kelas'] }}</div> <div class="podium-kelas">{{ $first['nama_kelas'] }}</div>
<div class="podium-exp"> {{ number_format($first['exp']) }}</div> <div class="podium-exp">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-sm topbar-waving" alt="EXP">
{{ number_format($first['exp']) }}
</div>
<div class="podium-bar">1</div> <div class="podium-bar">1</div>
</div> </div>
@ -192,7 +209,10 @@
<div class="podium-avatar">{{ strtoupper(substr($third['nama'],0,1)) }}</div> <div class="podium-avatar">{{ strtoupper(substr($third['nama'],0,1)) }}</div>
<div class="podium-name">{{ $third['nama'] }}</div> <div class="podium-name">{{ $third['nama'] }}</div>
<div class="podium-kelas">{{ $third['nama_kelas'] }}</div> <div class="podium-kelas">{{ $third['nama_kelas'] }}</div>
<div class="podium-exp"> {{ number_format($third['exp']) }}</div> <div class="podium-exp">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-sm topbar-waving" alt="EXP">
{{ number_format($third['exp']) }}
</div>
<div class="podium-bar">3</div> <div class="podium-bar">3</div>
</div> </div>
@endif @endif
@ -201,7 +221,10 @@
{{-- Tabel --}} {{-- Tabel --}}
<div class="custom-card"> <div class="custom-card">
<p class="section-title">📋 Semua Peringkat ({{ $leaderboard->count() }} siswa)</p> <p class="section-title">
<img src="{{ asset('images/icon/gurud/buku2.png') }}" class="icon-sm topbar-waving" alt="Daftar peringkat">
Semua Peringkat ({{ $leaderboard->count() }} siswa)
</p>
@foreach($leaderboard as $item) @foreach($leaderboard as $item)
@php @php
@ -209,10 +232,14 @@
@endphp @endphp
<div class="lb-row"> <div class="lb-row">
<div class="lb-rank {{ $rankClass }}"> <div class="lb-rank {{ $rankClass }}">
@if($item['ranking']===1) 🥇 @if($item['ranking']===1)
@elseif($item['ranking']===2) 🥈 <img src="{{ asset('images/icon/gurud/1.png') }}" class="icon-rank topbar-waving" alt="Peringkat 1">
@elseif($item['ranking']===3) 🥉 @elseif($item['ranking']===2)
@else {{ $item['ranking'] }} <img src="{{ asset('images/icon/gurud/2.png') }}" class="icon-rank topbar-waving" alt="Peringkat 2">
@elseif($item['ranking']===3)
<img src="{{ asset('images/icon/gurud/3.png') }}" class="icon-rank topbar-waving" alt="Peringkat 3">
@else
{{ $item['ranking'] }}
@endif @endif
</div> </div>
<div style="flex:1"> <div style="flex:1">
@ -220,7 +247,10 @@
<div class="lb-nisn">{{ $item['nisn'] }}</div> <div class="lb-nisn">{{ $item['nisn'] }}</div>
</div> </div>
<span class="lb-kelas">{{ $item['nama_kelas'] }}</span> <span class="lb-kelas">{{ $item['nama_kelas'] }}</span>
<div class="lb-exp"> {{ number_format($item['exp']) }}</div> <div class="lb-exp">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-sm topbar-waving" alt="EXP">
{{ number_format($item['exp']) }}
</div>
</div> </div>
@endforeach @endforeach
</div> </div>

View File

@ -84,7 +84,9 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
transition: background 0.2s; transition: background 0.2s;
} }
@ -99,6 +101,9 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
cursor: pointer; cursor: pointer;
display: inline-flex;
align-items: center;
gap: 4px;
transition: background 0.2s; transition: background 0.2s;
} }
@ -112,6 +117,9 @@
margin-bottom: 16px; margin-bottom: 16px;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
display: flex;
align-items: center;
gap: 6px;
} }
.empty-state { .empty-state {
@ -119,12 +127,19 @@
padding: 50px 20px; padding: 50px 20px;
color: #94a3b8; color: #94a3b8;
} }
/* Icon sizes */
.icon-sm { width: 16px; height: 16px; vertical-align: middle; }
.icon-empty { width: 56px; height: 56px; }
</style> </style>
<h3 class="page-title">HISTORY MATERI</h3> <h3 class="page-title">HISTORY MATERI</h3>
@if(session('success')) @if(session('success'))
<div class="alert-success-custom"> {{ session('success') }}</div> <div class="alert-success-custom">
<img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-sm topbar-waving" alt="Berhasil">
{{ session('success') }}
</div>
@endif @endif
<div class="custom-card"> <div class="custom-card">
@ -132,7 +147,7 @@
{{-- FILTER & SEARCH --}} {{-- FILTER & SEARCH --}}
<form method="GET" action="{{ route('admin.materi.history') }}" class="d-flex flex-wrap gap-2 align-items-center mb-4"> <form method="GET" action="{{ route('admin.materi.history') }}" class="d-flex flex-wrap gap-2 align-items-center mb-4">
<select name="id_guru" class="filter-select" onchange="this.form.submit()"> <select name="id_guru" class="filter-select" onchange="this.form.submit()">
<option value="">👨‍🏫 Semua Guru</option> <option value="">Semua Guru</option>
@foreach($gurus as $guru) @foreach($gurus as $guru)
<option value="{{ $guru->id_guru }}" {{ request('id_guru') == $guru->id_guru ? 'selected' : '' }}> <option value="{{ $guru->id_guru }}" {{ request('id_guru') == $guru->id_guru ? 'selected' : '' }}>
{{ $guru->nama }} {{ $guru->nama }}
@ -144,7 +159,7 @@
<input type="text" name="search" placeholder="Cari judul materi..." <input type="text" name="search" placeholder="Cari judul materi..."
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') }}" class="icon-sm" alt="Cari">
</button> </button>
</div> </div>
@ -160,7 +175,9 @@
@if($materiList->isEmpty()) @if($materiList->isEmpty())
<div class="empty-state"> <div class="empty-state">
<div style="font-size:48px;margin-bottom:12px">📭</div> <div style="margin-bottom:12px">
<img src="{{ asset('images/icon/gurud/mailbox.png') }}" class="icon-empty topbar-waving" alt="Tidak ada materi">
</div>
<p>Tidak ada materi ditemukan.</p> <p>Tidak ada materi ditemukan.</p>
</div> </div>
@else @else
@ -216,17 +233,25 @@
@if($materi->lampiran_materi) @if($materi->lampiran_materi)
@php @php
$ext = strtolower(pathinfo($materi->lampiran_materi, PATHINFO_EXTENSION)); $ext = strtolower(pathinfo($materi->lampiran_materi, PATHINFO_EXTENSION));
$icon = match(true) { $iconSrc = match(true) {
in_array($ext, ['pdf']) => '📄', in_array($ext, ['pdf']) => asset('images/icon/gurud/buku2.png'),
in_array($ext, ['doc','docx']) => '📝', in_array($ext, ['doc','docx']) => asset('images/icon/gurud/buku1.png'),
in_array($ext, ['ppt','pptx']) => '📊', in_array($ext, ['ppt','pptx']) => asset('images/icon/gurud/lb.png'),
in_array($ext, ['jpg','jpeg','png']) => '🖼️', in_array($ext, ['jpg','jpeg','png']) => asset('images/icon/gurud/image.png'),
default => '📎', default => asset('images/icon/gurud/link.png'),
};
$iconAlt = match(true) {
in_array($ext, ['pdf']) => 'File PDF',
in_array($ext, ['doc','docx']) => 'File Word',
in_array($ext, ['ppt','pptx']) => 'File PowerPoint',
in_array($ext, ['jpg','jpeg','png']) => 'File Gambar',
default => 'File Lampiran',
}; };
@endphp @endphp
<a href="{{ asset('storage/' . $materi->lampiran_materi) }}" <a href="{{ asset('storage/' . $materi->lampiran_materi) }}"
target="_blank" class="btn-unduh"> target="_blank" class="btn-unduh">
{{ $icon }} Unduh <img src="{{ $iconSrc }}" class="icon-sm topbar-waving" alt="{{ $iconAlt }}">
Unduh
</a> </a>
@else @else
<span style="font-size:12px;color:#94a3b8">Tidak ada</span> <span style="font-size:12px;color:#94a3b8">Tidak ada</span>
@ -238,7 +263,10 @@
onsubmit="return confirm('Yakin hapus materi ini?')"> onsubmit="return confirm('Yakin hapus materi ini?')">
@csrf @csrf
@method('DELETE') @method('DELETE')
<button type="submit" class="btn-hapus">🗑️ Hapus</button> <button type="submit" class="btn-hapus">
<img src="{{ asset('images/icon/gurud/bin.png') }}" class="icon-sm topbar-waving" alt="Hapus">
Hapus
</button>
</form> </form>
</td> </td>
</tr> </tr>

View File

@ -116,6 +116,9 @@
font-weight: 700; font-weight: 700;
color: #1e293b; color: #1e293b;
margin-bottom: 16px; margin-bottom: 16px;
display: flex;
align-items: center;
gap: 6px;
} }
.table-header { background: #a5e6ba; } .table-header { background: #a5e6ba; }
@ -125,7 +128,9 @@
font-weight: 700; font-weight: 700;
padding: 4px 10px; padding: 4px 10px;
border-radius: 99px; border-radius: 99px;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
} }
.status-dikumpulkan { background: #dcfce7; color: #16a34a; } .status-dikumpulkan { background: #dcfce7; color: #16a34a; }
@ -139,7 +144,9 @@
font-weight: 700; font-weight: 700;
padding: 3px 10px; padding: 3px 10px;
border-radius: 99px; border-radius: 99px;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
} }
.btn-unduh { .btn-unduh {
@ -151,7 +158,9 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
transition: background 0.2s; transition: background 0.2s;
} }
@ -163,7 +172,6 @@
color: #94a3b8; color: #94a3b8;
} }
/* Search di tabel pengumpulan */
.table-search { .table-search {
border: 1px solid #cbd5e1; border: 1px solid #cbd5e1;
border-radius: 10px; border-radius: 10px;
@ -174,6 +182,11 @@
} }
.table-search:focus { border-color: #2b8ef3; } .table-search:focus { border-color: #2b8ef3; }
/* Icon sizes */
.icon-sm { width: 16px; height: 16px; vertical-align: middle; }
.icon-meta { width: 15px; height: 15px; vertical-align: middle; }
.icon-empty { width: 56px; height: 56px; }
</style> </style>
@php @php
@ -191,17 +204,21 @@
<div class="info-meta"> <div class="info-meta">
<span class="meta-chip yellow"> <span class="meta-chip yellow">
👨‍🏫 {{ optional(optional($tugas->mengajar)->guru)->nama ?? '-' }} <img src="{{ asset('images/icon/gurud/guru.png') }}" class="icon-meta topbar-waving" alt="Guru">
{{ optional(optional($tugas->mengajar)->guru)->nama ?? '-' }}
</span> </span>
<span class="meta-chip"> <span class="meta-chip">
📚 {{ optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-' }} <img src="{{ asset('images/icon/gurud/stacked.png') }}" class="icon-meta topbar-waving" alt="Mata Pelajaran">
{{ optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-' }}
</span> </span>
<span class="meta-chip"> <span class="meta-chip">
🏫 {{ optional(optional($tugas->mengajar)->kelas)->tingkat }} <img src="{{ asset('images/icon/gurud/school.png') }}" class="icon-meta topbar-waving" alt="Kelas">
{{ optional(optional($tugas->mengajar)->kelas)->tingkat }}
{{ optional(optional($tugas->mengajar)->kelas)->nama_kelas ?? '-' }} {{ optional(optional($tugas->mengajar)->kelas)->nama_kelas ?? '-' }}
</span> </span>
<span class="meta-chip {{ $isLewat ? 'red' : 'green' }}"> <span class="meta-chip {{ $isLewat ? 'red' : 'green' }}">
{{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }} <img src="{{ asset('images/icon/gurud/alarm.png') }}" class="icon-meta topbar-waving" alt="Deadline">
{{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }}
{{ $isLewat ? 'Sudah lewat' : 'Masih aktif' }} {{ $isLewat ? 'Sudah lewat' : 'Masih aktif' }}
</span> </span>
</div> </div>
@ -232,15 +249,20 @@
{{-- DAFTAR PENGUMPULAN --}} {{-- DAFTAR PENGUMPULAN --}}
<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">
<p class="section-title mb-0">📥 Daftar Pengumpulan Siswa</p> <p class="section-title mb-0">
<img src="{{ asset('images/icon/gurud/pengumpulan.png') }}" class="icon-sm topbar-waving" alt="Pengumpulan">
Daftar Pengumpulan Siswa
</p>
<input type="text" class="table-search" id="searchSiswa" <input type="text" class="table-search" id="searchSiswa"
placeholder="🔍 Cari nama / NISN..." placeholder="Cari nama / NISN..."
onkeyup="filterTable()"> onkeyup="filterTable()">
</div> </div>
@if($tugas->pengumpulanTugas->isEmpty()) @if($tugas->pengumpulanTugas->isEmpty())
<div class="empty-state"> <div class="empty-state">
<div style="font-size:40px;margin-bottom:10px">📭</div> <div style="margin-bottom:10px">
<img src="{{ asset('images/icon/gurud/mailbox.png') }}" class="icon-empty topbar-waving" alt="Belum ada pengumpulan">
</div>
<p>Belum ada siswa yang mengumpulkan tugas ini.</p> <p>Belum ada siswa yang mengumpulkan tugas ini.</p>
</div> </div>
@else @else
@ -275,15 +297,24 @@
</td> </td>
<td class="text-center"> <td class="text-center">
<span class="status-badge status-{{ $kumpul->status }}"> <span class="status-badge status-{{ $kumpul->status }}">
@if($kumpul->status === 'dikumpulkan') Tepat Waktu @if($kumpul->status === 'dikumpulkan')
@elseif($kumpul->status === 'terlambat') Terlambat <img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-sm topbar-waving" alt="Tepat waktu">
@else Belum Tepat Waktu
@elseif($kumpul->status === 'terlambat')
<img src="{{ asset('images/icon/gurud/alarm.png') }}" class="icon-sm topbar-waving" alt="Terlambat">
Terlambat
@else
<img src="{{ asset('images/icon/gurud/x.png') }}" class="icon-sm topbar-waving" alt="Belum dikumpulkan">
Belum
@endif @endif
</span> </span>
</td> </td>
<td class="text-center"> <td class="text-center">
@if($kumpul->exp > 0) @if($kumpul->exp > 0)
<span class="exp-badge"> {{ $kumpul->exp }} EXP</span> <span class="exp-badge">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-sm topbar-waving" alt="EXP">
{{ $kumpul->exp }} EXP
</span>
@else @else
<span style="font-size:12px;color:#94a3b8">Belum dinilai</span> <span style="font-size:12px;color:#94a3b8">Belum dinilai</span>
@endif @endif
@ -292,16 +323,23 @@
@if($kumpul->lampiran_tugas) @if($kumpul->lampiran_tugas)
@php @php
$ext = strtolower(pathinfo($kumpul->lampiran_tugas, PATHINFO_EXTENSION)); $ext = strtolower(pathinfo($kumpul->lampiran_tugas, PATHINFO_EXTENSION));
$icon = match(true) { $iconSrc = match(true) {
in_array($ext, ['pdf']) => '📄', in_array($ext, ['pdf']) => asset('images/icon/gurud/buku2.png'),
in_array($ext, ['doc','docx']) => '📝', in_array($ext, ['doc','docx']) => asset('images/icon/gurud/buku1.png'),
in_array($ext, ['jpg','jpeg','png']) => '🖼️', in_array($ext, ['jpg','jpeg','png']) => asset('images/icon/gurud/image.png'),
default => '📎', default => asset('images/icon/gurud/link.png'),
};
$iconAlt = match(true) {
in_array($ext, ['pdf']) => 'File PDF',
in_array($ext, ['doc','docx']) => 'File Word',
in_array($ext, ['jpg','jpeg','png']) => 'File Gambar',
default => 'File Lampiran',
}; };
@endphp @endphp
<a href="{{ asset('storage/' . $kumpul->lampiran_tugas) }}" <a href="{{ asset('storage/' . $kumpul->lampiran_tugas) }}"
target="_blank" class="btn-unduh"> target="_blank" class="btn-unduh">
{{ $icon }} Unduh <img src="{{ $iconSrc }}" class="icon-sm topbar-waving" alt="{{ $iconAlt }}">
Unduh
</a> </a>
@else @else
<span style="font-size:12px;color:#94a3b8">-</span> <span style="font-size:12px;color:#94a3b8">-</span>

View File

@ -80,7 +80,9 @@
font-weight: 600; font-weight: 600;
padding: 3px 10px; padding: 3px 10px;
border-radius: 99px; border-radius: 99px;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
} }
.deadline-lewat { background: #fee2e2; color: #ef4444; } .deadline-lewat { background: #fee2e2; color: #ef4444; }
@ -101,7 +103,9 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
transition: background 0.2s; transition: background 0.2s;
} }
@ -116,6 +120,9 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
cursor: pointer; cursor: pointer;
display: inline-flex;
align-items: center;
gap: 4px;
transition: background 0.2s; transition: background 0.2s;
} }
@ -129,6 +136,9 @@
margin-bottom: 16px; margin-bottom: 16px;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
display: flex;
align-items: center;
gap: 6px;
} }
.empty-state { .empty-state {
@ -136,12 +146,19 @@
padding: 50px 20px; padding: 50px 20px;
color: #94a3b8; color: #94a3b8;
} }
/* Icon sizes */
.icon-sm { width: 16px; height: 16px; vertical-align: middle; }
.icon-empty { width: 56px; height: 56px; }
</style> </style>
<h3 class="page-title">HISTORY TUGAS</h3> <h3 class="page-title">HISTORY TUGAS</h3>
@if(session('success')) @if(session('success'))
<div class="alert-success-custom"> {{ session('success') }}</div> <div class="alert-success-custom">
<img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-sm topbar-waving" alt="Berhasil">
{{ session('success') }}
</div>
@endif @endif
<div class="custom-card"> <div class="custom-card">
@ -149,7 +166,7 @@
{{-- FILTER & SEARCH --}} {{-- FILTER & SEARCH --}}
<form method="GET" action="{{ route('admin.tugas.history') }}" class="d-flex flex-wrap gap-2 align-items-center mb-4"> <form method="GET" action="{{ route('admin.tugas.history') }}" class="d-flex flex-wrap gap-2 align-items-center mb-4">
<select name="id_guru" class="filter-select" onchange="this.form.submit()"> <select name="id_guru" class="filter-select" onchange="this.form.submit()">
<option value="">👨‍🏫 Semua Guru</option> <option value="">Semua Guru</option>
@foreach($gurus as $guru) @foreach($gurus as $guru)
<option value="{{ $guru->id_guru }}" {{ request('id_guru') == $guru->id_guru ? 'selected' : '' }}> <option value="{{ $guru->id_guru }}" {{ request('id_guru') == $guru->id_guru ? 'selected' : '' }}>
{{ $guru->nama }} {{ $guru->nama }}
@ -161,7 +178,7 @@
<input type="text" name="search" placeholder="Cari judul tugas..." <input type="text" name="search" placeholder="Cari judul tugas..."
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') }}" class="icon-sm" alt="Cari">
</button> </button>
</div> </div>
@ -177,7 +194,9 @@
@if($tugasList->isEmpty()) @if($tugasList->isEmpty())
<div class="empty-state"> <div class="empty-state">
<div style="font-size:48px;margin-bottom:12px">📭</div> <div style="margin-bottom:12px">
<img src="{{ asset('images/icon/gurud/mailbox.png') }}" class="icon-empty topbar-waving" alt="Tidak ada tugas">
</div>
<p>Tidak ada tugas ditemukan.</p> <p>Tidak ada tugas ditemukan.</p>
</div> </div>
@else @else
@ -229,7 +248,13 @@
</td> </td>
<td class="text-center"> <td class="text-center">
<span class="deadline-badge {{ $isLewat ? 'deadline-lewat' : 'deadline-aktif' }}"> <span class="deadline-badge {{ $isLewat ? 'deadline-lewat' : 'deadline-aktif' }}">
{{ $isLewat ? '⏰ Lewat' : '✅ Aktif' }} @if($isLewat)
<img src="{{ asset('images/icon/gurud/alarm.png') }}" class="icon-sm topbar-waving" alt="Deadline lewat">
Lewat
@else
<img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-sm topbar-waving" alt="Deadline aktif">
Aktif
@endif
</span> </span>
<div style="font-size:11px;color:#64748b;margin-top:3px"> <div style="font-size:11px;color:#64748b;margin-top:3px">
{{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }} {{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }}
@ -241,14 +266,18 @@
</td> </td>
<td class="text-center"> <td class="text-center">
<div class="d-flex gap-1 justify-content-center"> <div class="d-flex gap-1 justify-content-center">
<a href="{{ route('admin.tugas.detail', $tugas->id_tugas) }}" <a href="{{ route('admin.tugas.detail', $tugas->id_tugas) }}" class="btn-detail">
class="btn-detail">👁️ Detail</a> <img src="{{ asset('images/icon/gurud/eye.png') }}" class="icon-sm topbar-waving" alt="Lihat detail">
Detail
</a>
<form action="{{ route('admin.tugas.destroy', $tugas->id_tugas) }}" <form action="{{ route('admin.tugas.destroy', $tugas->id_tugas) }}"
method="POST" method="POST"
onsubmit="return confirm('Yakin hapus tugas ini? Semua pengumpulan ikut terhapus.')"> onsubmit="return confirm('Yakin hapus tugas ini? Semua pengumpulan ikut terhapus.')">
@csrf @csrf
@method('DELETE') @method('DELETE')
<button type="submit" class="btn-hapus">🗑️</button> <button type="submit" class="btn-hapus">
<img src="{{ asset('images/icon/gurud/bin.png') }}" class="icon-sm topbar-waving" alt="Hapus tugas">
</button>
</form> </form>
</div> </div>
</td> </td>

View File

@ -29,7 +29,7 @@
.stat-card:nth-child(2) .stat-label { color: #15803d; } .stat-card:nth-child(2) .stat-label { color: #15803d; }
.stat-card:nth-child(3) .stat-label { color: #c2651a; } .stat-card:nth-child(3) .stat-label { color: #c2651a; }
.stat-num { font-size: 42px; font-weight: 800; line-height: 1; color: #0f1f3d; } .stat-num { font-size: 42px; font-weight: 800; line-height: 1; color: #0f1f3d; }
.stat-icon { position: absolute; top: 20px; right: 20px; width: 42px; height: 42px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 20px; opacity: 0.7; } .stat-icon { position: absolute; top: 20px; right: 20px; width: 42px; height: 42px; border-radius: 12px; display: flex; align-items: center; justify-content: center; opacity: 0.7; }
.stat-card:nth-child(1) .stat-icon { background: rgba(43,142,243,0.15); } .stat-card:nth-child(1) .stat-icon { background: rgba(43,142,243,0.15); }
.stat-card:nth-child(2) .stat-icon { background: rgba(34,197,94,0.15); } .stat-card:nth-child(2) .stat-icon { background: rgba(34,197,94,0.15); }
.stat-card:nth-child(3) .stat-icon { background: rgba(249,115,22,0.15); } .stat-card:nth-child(3) .stat-icon { background: rgba(249,115,22,0.15); }
@ -103,19 +103,25 @@
{{-- STAT CARDS --}} {{-- STAT CARDS --}}
<div class="stat-grid"> <div class="stat-grid">
<div class="stat-card"> <div class="stat-card">
<div class="stat-icon">🏫</div> <div class="stat-icon">
<img src="{{ asset('images/icon/gurud/school.png') }}" class="icon-sm" alt="Ikon kelas">
</div>
<div class="stat-label">Kelas Diampu</div> <div class="stat-label">Kelas Diampu</div>
<div class="stat-num">{{ $totalKelas }}</div> <div class="stat-num">{{ $totalKelas }}</div>
<a href="{{ route('guru.kelas.index') }}" class="stat-link">Lihat Data </a> <a href="{{ route('guru.kelas.index') }}" class="stat-link">Lihat Data </a>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<div class="stat-icon">📚</div> <div class="stat-icon">
<img src="{{ asset('images/icon/gurud/stacked.png') }}" class="icon-sm" alt="Ikon mata pelajaran">
</div>
<div class="stat-label">Mata Pelajaran</div> <div class="stat-label">Mata Pelajaran</div>
<div class="stat-num">{{ $totalMapel }}</div> <div class="stat-num">{{ $totalMapel }}</div>
<a href="{{ route('guru.mapel.index') }}" class="stat-link">Lihat Data </a> <a href="{{ route('guru.mapel.index') }}" class="stat-link">Lihat Data </a>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<div class="stat-icon">👨‍🎓</div> <div class="stat-icon">
<img src="{{ asset('images/icon/gurud/siswa.png') }}" class="icon-sm" alt="Ikon siswa">
</div>
<div class="stat-label">Siswa Diajar</div> <div class="stat-label">Siswa Diajar</div>
<div class="stat-num">{{ $totalSiswa }}</div> <div class="stat-num">{{ $totalSiswa }}</div>
<a href="{{ route('guru.siswa.index') }}" class="stat-link">Lihat Data </a> <a href="{{ route('guru.siswa.index') }}" class="stat-link">Lihat Data </a>
@ -148,7 +154,9 @@
</div> </div>
@else @else
<div style="text-align:center;padding:40px 20px;color:#94a3b8;"> <div style="text-align:center;padding:40px 20px;color:#94a3b8;">
<div style="font-size:36px;margin-bottom:8px">📋</div> <div style="margin-bottom:8px">
<img src="{{ asset('images/icon/gurud/buku1.png') }}" class="icon-sm" alt="Belum ada tugas">
</div>
<div style="font-size:13px">Belum ada tugas dibuat.</div> <div style="font-size:13px">Belum ada tugas dibuat.</div>
</div> </div>
@endif @endif

View File

@ -61,15 +61,11 @@
<div class="d-flex justify-content-between align-items-center mb-3"> <div class="d-flex justify-content-between align-items-center mb-3">
<div class="badge-info">
📖 Mode Hanya Lihat (Read Only)
</div>
<form method="GET"> <form method="GET">
<div class="search-box"> <div class="search-box">
<input type="text" name="search" placeholder="Cari" value="{{ request('search') }}"> <input type="text" name="search" placeholder="Cari" value="{{ request('search') }}">
<button style="border:none;background:none"> <button style="border:none;background:none">
<img src="{{ asset('images/icon/main/search.png') }}" width="18"> <img src="{{ asset('images/icon/main/search.png') }}" width="18" height="18" alt="Cari kelas">
</button> </button>
</div> </div>
</form> </form>

View File

@ -37,6 +37,11 @@
.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: 20px 28px 28px; flex: 1; overflow-y: auto; }
/* Shared icon utility classes */
.icon-inline { width: 18px; height: 18px; vertical-align: middle; }
.icon-sm { width: 32px; height: 32px; }
.icon-lg { width: 48px; height: 48px; }
/* NOTIF */ /* NOTIF */
.notif-wrap { position: relative; } .notif-wrap { position: relative; }
.notif-btn { width: 36px; height: 36px; border-radius: 50%; background: rgba(255,255,255,0.2); border: 2px solid rgba(255,255,255,0.4); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.2s; flex-shrink: 0; } .notif-btn { width: 36px; height: 36px; border-radius: 50%; background: rgba(255,255,255,0.2); border: 2px solid rgba(255,255,255,0.4); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.2s; flex-shrink: 0; }
@ -105,21 +110,23 @@
<body> <body>
<div class="wrapper"> <div class="wrapper">
<aside class="sidebar" id="mainSidebar"> <aside class="sidebar" id="mainSidebar">
<div class="sidebar-logo"><img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo"></div> <div class="sidebar-logo">
<img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo SMK">
</div>
<a href="{{ route('guru.dashboard') }}" class="sidebar-link {{ request()->routeIs('guru.dashboard') ? 'active' : '' }}"> <a href="{{ route('guru.dashboard') }}" class="sidebar-link {{ request()->routeIs('guru.dashboard') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon"><span>Dashboard</span> <img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon" alt="Dashboard"><span>Dashboard</span>
</a> </a>
<a href="{{ route('guru.kelas.index') }}" class="sidebar-link {{ request()->routeIs('guru.kelas.*') ? 'active' : '' }}"> <a href="{{ route('guru.kelas.index') }}" class="sidebar-link {{ request()->routeIs('guru.kelas.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/kelas.png') }}" class="sidebar-icon"><span>Daftar Kelas</span> <img src="{{ asset('images/icon/sidebar/kelas.png') }}" class="sidebar-icon" alt="Daftar Kelas"><span>Daftar Kelas</span>
</a> </a>
<a href="{{ route('guru.siswa.index') }}" class="sidebar-link {{ request()->routeIs('guru.siswa.*') ? 'active' : '' }}"> <a href="{{ route('guru.siswa.index') }}" class="sidebar-link {{ request()->routeIs('guru.siswa.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon"><span>Daftar Siswa</span> <img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt="Daftar Siswa"><span>Daftar Siswa</span>
</a> </a>
<a href="{{ route('guru.mapel.index') }}" class="sidebar-link {{ request()->routeIs('guru.mapel.*') ? 'active' : '' }}"> <a href="{{ route('guru.mapel.index') }}" class="sidebar-link {{ request()->routeIs('guru.mapel.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon"><span>Mata Pelajaran</span> <img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="Mata Pelajaran"><span>Mata Pelajaran</span>
</a> </a>
<a href="{{ route('guru.leaderboard.index') }}" class="sidebar-link {{ request()->routeIs('guru.leaderboard.*') ? 'active' : '' }}"> <a href="{{ route('guru.leaderboard.index') }}" class="sidebar-link {{ request()->routeIs('guru.leaderboard.*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon"><span>Leaderboard</span> <img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon" alt="Leaderboard"><span>Leaderboard</span>
</a> </a>
<form action="{{ route('guru.logout') }}" method="POST" class="sidebar-logout"> <form action="{{ route('guru.logout') }}" method="POST" class="sidebar-logout">
@csrf @csrf
@ -137,7 +144,7 @@
<div class="main"> <div class="main">
<header class="topbar"> <header class="topbar">
<div class="topbar-left"> <div class="topbar-left">
<img src="{{ asset('images/icon/main/hi.png') }}" class="topbar-waving" alt="Waving"> <img src="{{ asset('images/icon/gurud/wavinghand.png') }}" class="topbar-waving" alt="Ikon salam">
Selamat datang, {{ Auth::guard('guru')->user()->nama ?? 'Guru' }} Selamat datang, {{ Auth::guard('guru')->user()->nama ?? 'Guru' }}
</div> </div>
<div class="topbar-right"> <div class="topbar-right">
@ -152,14 +159,17 @@
<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/gurud/notif.png') }}" alt="Notifikasi kosong" class="icon-sm"></div>
<div class="notif-empty-text">Memuat notifikasi...</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@php $guru = Auth::guard('guru')->user(); @endphp @php $guru = Auth::guard('guru')->user(); @endphp
@if($guru->foto_profil) @if($guru->foto_profil)
<img src="{{ Storage::url($guru->foto_profil) }}" class="topbar-avatar" id="topbar-foto" onclick="openProfileModal()" alt="Profil"> <img src="{{ Storage::url($guru->foto_profil) }}" class="topbar-avatar" id="topbar-foto" onclick="openProfileModal()" alt="Foto profil {{ $guru->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>
@ -182,7 +192,7 @@
@csrf @csrf
<div class="foto-upload-area"> <div class="foto-upload-area">
<div class="foto-circle"> <div class="foto-circle">
@if($guru->foto_profil) <img src="{{ Storage::url($guru->foto_profil) }}" id="modal-foto-preview" alt=""> @if($guru->foto_profil) <img src="{{ Storage::url($guru->foto_profil) }}" id="modal-foto-preview" alt="Foto profil saat ini">
@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> @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="" style="display:none"> @endif <img src="" id="modal-foto-preview" alt="" style="display:none"> @endif
</div> </div>
@ -219,8 +229,8 @@ function updateToggle(c) { toggleBtn.style.left = c ? '0px' : SIDEBAR_W+'px'; c
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"><div class="notif-empty-icon"><img src="{{ asset('images/icon/gurud/bell.png') }}" alt="Tidak ada notifikasi" class="icon-sm"></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-pengumpulan"></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(''); : data.notifications.map(n => `<div class="notif-item"><div class="notif-icon-wrap notif-icon-pengumpulan"><img src="{{ asset('images/icon/gurud/v.png') }}" alt="Tugas dikumpulkan" class="icon-inline"></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'); }
@ -239,7 +249,7 @@ function closeOnOverlay(e) { if (e.target===document.getElementById('profileModa
const res=await fetch('{{ route("guru.profile.update") }}',{method:'POST',headers:{'X-CSRF-TOKEN':document.querySelector('meta[name="csrf-token"]').content},body:fd}); const res=await fetch('{{ route("guru.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 {{ $guru->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=''; 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; } } else { const err=data.errors?Object.values(data.errors).flat().join(' · '):'Terjadi kesalahan.'; toast.className='modal-toast error'; toast.textContent=err; }

View File

@ -60,7 +60,7 @@
.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: 4px; }
.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); }
@ -68,7 +68,7 @@
.rank-3 .podium-bar { height: 44px; background: linear-gradient(135deg,#f97316,#ea580c); } .rank-3 .podium-bar { height: 44px; background: linear-gradient(135deg,#f97316,#ea580c); }
.custom-card { background: white; border-radius: 20px; border: 2px solid #e5e5e5; padding: 22px; } .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; } .section-title { font-size: 15px; font-weight: 700; color: #1e293b; margin-bottom: 16px; display: flex; align-items: center; gap: 6px; }
.lb-row { display: flex; align-items: center; gap: 14px; padding: 11px 14px; border-radius: 12px; margin-bottom: 6px; transition: background 0.15s; } .lb-row { display: flex; align-items: center; gap: 14px; padding: 11px 14px; border-radius: 12px; margin-bottom: 6px; transition: background 0.15s; }
.lb-row:hover { background: #f8fafc; } .lb-row:hover { background: #f8fafc; }
@ -86,7 +86,7 @@
.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: #2b8ef3; } .lb-exp { font-size: 14px; font-weight: 700; color: #2b8ef3; display: flex; align-items: center; gap: 4px; }
.semester-badge { display: inline-block; background: #e0f2fe; color: #0369a1; font-size: 12px; font-weight: 700; padding: 4px 12px; border-radius: 99px; margin-bottom: 20px; } .semester-badge { display: inline-block; background: #e0f2fe; color: #0369a1; 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; }
@ -100,18 +100,23 @@
color: #c2410c; color: #c2410c;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
} }
</style> </style>
@endpush @endpush
@section('content') @section('content')
<h3 class="page-title">🏅 Leaderboard</h3> <h3 class="page-title">LEADERBOARD</h3>
<p class="page-subtitle">Peringkat siswa di kelas yang Anda ajar.</p> <p class="page-subtitle">Peringkat siswa di kelas yang Anda ajar.</p>
@if($kelasList->isEmpty()) @if($kelasList->isEmpty())
<div class="no-kelas-box"> <div class="no-kelas-box">
⚠️ Anda belum mengajar kelas manapun. Hubungi admin untuk mengatur jadwal mengajar. <img src="{{ asset('images/icon/gurud/alert.png') }}" class="icon-inline" alt="Peringatan">
Anda belum mengajar kelas manapun. Hubungi admin untuk mengatur jadwal mengajar.
</div> </div>
@else @else
@ -155,7 +160,9 @@
@if($leaderboard->isEmpty()) @if($leaderboard->isEmpty())
<div class="empty-state"> <div class="empty-state">
<div style="font-size:52px;margin-bottom:12px">📊</div> <div style="margin-bottom:12px">
<img src="{{ asset('images/icon/gurud/lb.png') }}" class="icon-lg" alt="Leaderboard kosong">
</div>
<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">Belum ada siswa yang menyelesaikan challenge pada periode ini.</p> <p style="font-size:13px">Belum ada siswa yang menyelesaikan challenge pada periode ini.</p>
</div> </div>
@ -174,18 +181,26 @@
<div class="podium-item rank-2"> <div class="podium-item rank-2">
<div class="podium-avatar">{{ strtoupper(substr($second['nama'],0,1)) }}</div> <div class="podium-avatar">{{ strtoupper(substr($second['nama'],0,1)) }}</div>
<div class="podium-name">{{ $second['nama'] }}</div> <div class="podium-name">{{ $second['nama'] }}</div>
<div class="podium-exp"> {{ number_format($second['exp']) }}</div> <div class="podium-exp">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-inline" alt="EXP">
{{ number_format($second['exp']) }}
</div>
<div class="podium-bar">2</div> <div class="podium-bar">2</div>
</div> </div>
@endif @endif
<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">
<img src="{{ asset('images/icon/gurud/crown.png') }}" style="width:22px;height:22px" alt="Mahkota juara 1">
</span>
{{ strtoupper(substr($first['nama'],0,1)) }} {{ strtoupper(substr($first['nama'],0,1)) }}
</div> </div>
<div class="podium-name">{{ $first['nama'] }}</div> <div class="podium-name">{{ $first['nama'] }}</div>
<div class="podium-exp"> {{ number_format($first['exp']) }}</div> <div class="podium-exp">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-inline" alt="EXP">
{{ number_format($first['exp']) }}
</div>
<div class="podium-bar">1</div> <div class="podium-bar">1</div>
</div> </div>
@ -193,7 +208,10 @@
<div class="podium-item rank-3"> <div class="podium-item rank-3">
<div class="podium-avatar">{{ strtoupper(substr($third['nama'],0,1)) }}</div> <div class="podium-avatar">{{ strtoupper(substr($third['nama'],0,1)) }}</div>
<div class="podium-name">{{ $third['nama'] }}</div> <div class="podium-name">{{ $third['nama'] }}</div>
<div class="podium-exp"> {{ number_format($third['exp']) }}</div> <div class="podium-exp">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-inline" alt="EXP">
{{ number_format($third['exp']) }}
</div>
<div class="podium-bar">3</div> <div class="podium-bar">3</div>
</div> </div>
@endif @endif
@ -202,23 +220,33 @@
{{-- Tabel --}} {{-- Tabel --}}
<div class="custom-card"> <div class="custom-card">
<p class="section-title">📋 Semua Peringkat ({{ $leaderboard->count() }} siswa)</p> <p class="section-title">
<img src="{{ asset('images/icon/gurud/buku1.png') }}" class="icon-inline" alt="Daftar peringkat">
Semua Peringkat ({{ $leaderboard->count() }} siswa)
</p>
@foreach($leaderboard as $item) @foreach($leaderboard as $item)
@php $rankClass = match($item['ranking']) { 1=>'gold', 2=>'silver', 3=>'bronze', default=>'' }; @endphp @php $rankClass = match($item['ranking']) { 1=>'gold', 2=>'silver', 3=>'bronze', default=>'' }; @endphp
<div class="lb-row"> <div class="lb-row">
<div class="lb-rank {{ $rankClass }}"> <div class="lb-rank {{ $rankClass }}">
@if($item['ranking']===1) 🥇 @if($item['ranking']===1)
@elseif($item['ranking']===2) 🥈 <img src="{{ asset('images/icon/gurud/1.png') }}" style="width:20px;height:20px" alt="Peringkat 1">
@elseif($item['ranking']===3) 🥉 @elseif($item['ranking']===2)
@else {{ $item['ranking'] }} <img src="{{ asset('images/icon/gurud/2.png') }}" style="width:20px;height:20px" alt="Peringkat 2">
@elseif($item['ranking']===3)
<img src="{{ asset('images/icon/gurud/3.png') }}" style="width:20px;height:20px" alt="Peringkat 3">
@else
{{ $item['ranking'] }}
@endif @endif
</div> </div>
<div style="flex:1"> <div style="flex:1">
<div class="lb-nama">{{ $item['nama'] }}</div> <div class="lb-nama">{{ $item['nama'] }}</div>
<div class="lb-nisn">{{ $item['nisn'] }}</div> <div class="lb-nisn">{{ $item['nisn'] }}</div>
</div> </div>
<div class="lb-exp"> {{ number_format($item['exp']) }}</div> <div class="lb-exp">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-inline" alt="EXP">
{{ number_format($item['exp']) }}
</div>
</div> </div>
@endforeach @endforeach
</div> </div>

View File

@ -29,7 +29,9 @@
font-size: 13px; font-size: 13px;
cursor: pointer; cursor: pointer;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-flex;
align-items: center;
gap: 6px;
} }
.btn-materi { .btn-materi {
@ -132,6 +134,8 @@
color: white; color: white;
} }
.btn-history-tugas:hover { background: #0d9488; color: white; } .btn-history-tugas:hover { background: #0d9488; color: white; }
.alert-success-custom {
background: #dcfce7; background: #dcfce7;
color: #166534; color: #166534;
border-radius: 10px; border-radius: 10px;
@ -139,6 +143,9 @@
margin-bottom: 16px; margin-bottom: 16px;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
} }
.alert-error-custom { .alert-error-custom {
@ -149,7 +156,12 @@
margin-bottom: 16px; margin-bottom: 16px;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
} }
.upload-icon { width: 40px; height: 40px; margin: 0 auto 6px; }
</style> </style>
@endpush @endpush
@ -158,11 +170,17 @@
<h3 class="page-title">MATA PELAJARAN YANG ANDA AJAR</h3> <h3 class="page-title">MATA PELAJARAN YANG ANDA AJAR</h3>
@if(session('success')) @if(session('success'))
<div class="alert-success-custom"> {{ session('success') }}</div> <div class="alert-success-custom">
<img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-inline" alt="Berhasil">
{{ session('success') }}
</div>
@endif @endif
@if(session('error')) @if(session('error'))
<div class="alert-error-custom"> {{ session('error') }}</div> <div class="alert-error-custom">
<img src="{{ asset('images/icon/gurud/x.png') }}" class="icon-inline" alt="Gagal">
{{ session('error') }}
</div>
@endif @endif
<div class="custom-card"> <div class="custom-card">
@ -181,7 +199,6 @@
@php @php
$mapel = $rows->first()->mapel; $mapel = $rows->first()->mapel;
$kelasList = $rows->map(fn($m) => $m->kelas)->filter(); $kelasList = $rows->map(fn($m) => $m->kelas)->filter();
// Ambil id_mengajar pertama sebagai default (bisa dipilih per kelas di modal)
$mengajarOptions = $rows->map(fn($m) => [ $mengajarOptions = $rows->map(fn($m) => [
'id_mengajar' => $m->id_mengajar, 'id_mengajar' => $m->id_mengajar,
'kelas' => optional($m->kelas)->tingkat . ' ' . optional($m->kelas)->nama_kelas, 'kelas' => optional($m->kelas)->tingkat . ' ' . optional($m->kelas)->nama_kelas,
@ -208,7 +225,8 @@
'{{ addslashes(optional($mapel)->nama_mapel) }}', '{{ addslashes(optional($mapel)->nama_mapel) }}',
{{ $mengajarOptions->toJson() }} {{ $mengajarOptions->toJson() }}
)"> )">
📄 Upload Materi <img src="{{ asset('images/icon/gurud/buku1.png') }}" class="icon-inline" alt="Upload materi">
Upload Materi
</button> </button>
<button class="action-btn btn-tugas" <button class="action-btn btn-tugas"
@ -216,17 +234,20 @@
'{{ addslashes(optional($mapel)->nama_mapel) }}', '{{ addslashes(optional($mapel)->nama_mapel) }}',
{{ $mengajarOptions->toJson() }} {{ $mengajarOptions->toJson() }}
)"> )">
📋 Buat Tugas <img src="{{ asset('images/icon/gurud/buku2.png') }}" class="icon-inline" alt="Buat tugas">
Buat Tugas
</button> </button>
<a href="{{ route('guru.materi.history', ['id_mapel' => $idMapel]) }}" <a href="{{ route('guru.materi.history', ['id_mapel' => $idMapel]) }}"
class="action-btn btn-history-materi"> class="action-btn btn-history-materi">
🗂️ History Materi <img src="{{ asset('images/icon/gurud/file.png') }}" class="icon-inline" alt="History materi">
History Materi
</a> </a>
<a href="{{ route('guru.tugas.history', ['id_mapel' => $idMapel]) }}" <a href="{{ route('guru.tugas.history', ['id_mapel' => $idMapel]) }}"
class="action-btn btn-history-tugas"> class="action-btn btn-history-tugas">
📑 History Tugas <img src="{{ asset('images/icon/gurud/history.png') }}" class="icon-inline" alt="History tugas">
History Tugas
</a> </a>
</div> </div>
</td> </td>
@ -251,7 +272,10 @@ class="action-btn btn-history-tugas">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header modal-header-blue"> <div class="modal-header modal-header-blue">
<h5 class="modal-title">📄 Upload Materi <span id="materiMapelLabel"></span></h5> <h5 class="modal-title d-flex align-items-center gap-2">
<img src="{{ asset('images/icon/gurud/add-file.png') }}" class="icon-inline" alt="Upload file">
Upload Materi <span id="materiMapelLabel"></span>
</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>
@ -259,7 +283,6 @@ class="action-btn btn-history-tugas">
@csrf @csrf
<div class="modal-body"> <div class="modal-body">
{{-- Pilih Kelas (jika guru ajar mapel ini di lebih dari 1 kelas) --}}
<div class="mb-3"> <div class="mb-3">
<label>Kelas Tujuan <span class="text-danger">*</span></label> <label>Kelas Tujuan <span class="text-danger">*</span></label>
<select name="id_mengajar" id="materiMengajar" class="form-control" required> <select name="id_mengajar" id="materiMengajar" class="form-control" required>
@ -286,7 +309,7 @@ class="action-btn btn-history-tugas">
<input type="file" name="lampiran_materi" id="materiFile" <input type="file" name="lampiran_materi" id="materiFile"
accept=".pdf,.doc,.docx,.ppt,.pptx,.jpg,.jpeg,.png" accept=".pdf,.doc,.docx,.ppt,.pptx,.jpg,.jpeg,.png"
onchange="previewFile(this, 'materiPreview', 'materiFileName')"> onchange="previewFile(this, 'materiPreview', 'materiFileName')">
<div style="font-size:32px">☁️</div> <img src="{{ asset('images/icon/gurud/cloud.png') }}" class="upload-icon" alt="Upload ke cloud">
<p style="margin:6px 0 0;font-size:14px;color:#64748b"> <p style="margin:6px 0 0;font-size:14px;color:#64748b">
<strong>Klik</strong> atau drag file ke sini <strong>Klik</strong> atau drag file ke sini
</p> </p>
@ -316,15 +339,17 @@ class="action-btn btn-history-tugas">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header modal-header-orange"> <div class="modal-header modal-header-orange">
<h5 class="modal-title">📋 Buat Tugas <span id="tugasMapelLabel"></span></h5> <h5 class="modal-title d-flex align-items-center gap-2">
<img src="{{ asset('images/icon/gurud/buku1.png') }}" class="icon-inline" alt="Buat tugas">
Buat Tugas <span id="tugasMapelLabel"></span>
</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>
<form action="{{ route('guru.tugas.store') }}" method="POST"> <form action="{{ route('guru.tugas.store') }}" method="POST" enctype="multipart/form-data">
@csrf @csrf
<div class="modal-body"> <div class="modal-body">
{{-- Pilih Kelas --}}
<div class="mb-3"> <div class="mb-3">
<label>Kelas Tujuan <span class="text-danger">*</span></label> <label>Kelas Tujuan <span class="text-danger">*</span></label>
<select name="id_mengajar" id="tugasMengajar" class="form-control" required> <select name="id_mengajar" id="tugasMengajar" class="form-control" required>
@ -352,6 +377,21 @@ class="action-btn btn-history-tugas">
<small class="text-muted">Pastikan deadline lebih dari waktu sekarang.</small> <small class="text-muted">Pastikan deadline lebih dari waktu sekarang.</small>
</div> </div>
<div class="mb-3">
<label>Lampiran Tugas <small class="text-muted fw-normal">(Semua tipe file maks 10MB, opsional)</small></label>
<div class="upload-area" id="tugasUploadArea">
<input type="file" name="lampiran_tugas" id="tugasFile"
onchange="previewFile(this, 'tugasPreview', 'tugasFileName')">
<img src="{{ asset('images/icon/gurud/link.png') }}" class="upload-icon" alt="Lampirkan file">
<p style="margin:6px 0 0;font-size:14px;color:#64748b">
<strong>Klik</strong> atau drag file ke sini
</p>
</div>
<div class="file-preview" id="tugasPreview">
📎 <span id="tugasFileName">-</span>
</div>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@ -381,13 +421,13 @@ function openMateriModal(namaMapel, mengajars) {
select.appendChild(opt); select.appendChild(opt);
}); });
// Jika hanya 1 kelas, langsung pilih otomatis
if (mengajars.length === 1) select.value = mengajars[0].id_mengajar; if (mengajars.length === 1) select.value = mengajars[0].id_mengajar;
// Reset form // Reset form
document.querySelector('#modalMateri input[name="judul_materi"]').value = ''; document.querySelector('#modalMateri input[name="judul_materi"]').value = '';
document.querySelector('#modalMateri textarea[name="deskripsi"]').value = ''; document.querySelector('#modalMateri textarea[name="deskripsi"]').value = '';
document.getElementById('materiPreview').classList.remove('show'); document.getElementById('materiPreview').classList.remove('show');
document.getElementById('materiFile').value = '';
new bootstrap.Modal(document.getElementById('modalMateri')).show(); new bootstrap.Modal(document.getElementById('modalMateri')).show();
} }
@ -412,6 +452,8 @@ function openTugasModal(namaMapel, mengajars) {
document.querySelector('#modalTugas input[name="judul_tugas"]').value = ''; document.querySelector('#modalTugas input[name="judul_tugas"]').value = '';
document.querySelector('#modalTugas textarea[name="keterangan"]').value = ''; document.querySelector('#modalTugas textarea[name="keterangan"]').value = '';
document.querySelector('#modalTugas input[name="deadline"]').value = ''; document.querySelector('#modalTugas input[name="deadline"]').value = '';
document.getElementById('tugasPreview').classList.remove('show');
document.getElementById('tugasFile').value = '';
new bootstrap.Modal(document.getElementById('modalTugas')).show(); new bootstrap.Modal(document.getElementById('modalTugas')).show();
} }
@ -421,8 +463,16 @@ function previewFile(input, previewId, nameId) {
const preview = document.getElementById(previewId); const preview = document.getElementById(previewId);
const nameEl = document.getElementById(nameId); const nameEl = document.getElementById(nameId);
if (input.files && input.files[0]) { if (input.files && input.files[0]) {
nameEl.textContent = input.files[0].name + const file = input.files[0];
' (' + (input.files[0].size / 1024 / 1024).toFixed(2) + ' MB)';
if (file.size > 10 * 1024 * 1024) {
alert('❌ Ukuran file melebihi 10MB. Silakan pilih file yang lebih kecil.');
input.value = '';
preview.classList.remove('show');
return;
}
nameEl.textContent = file.name + ' (' + (file.size / 1024 / 1024).toFixed(2) + ' MB)';
preview.classList.add('show'); preview.classList.add('show');
} }
} }

View File

@ -9,6 +9,9 @@
font-weight: 800; font-weight: 800;
margin-bottom: 6px; margin-bottom: 6px;
margin-top: -20px; margin-top: -20px;
display: flex;
align-items: center;
gap: 8px;
} }
.back-link { .back-link {
@ -53,8 +56,6 @@
border-radius: 99px; border-radius: 99px;
} }
.file-icon { font-size: 20px; }
.btn-hapus { .btn-hapus {
background: #fee2e2; background: #fee2e2;
color: #ef4444; color: #ef4444;
@ -65,6 +66,9 @@
font-weight: 600; font-weight: 600;
cursor: pointer; cursor: pointer;
transition: background 0.2s; transition: background 0.2s;
display: inline-flex;
align-items: center;
gap: 5px;
} }
.btn-hapus:hover { background: #fca5a5; } .btn-hapus:hover { background: #fca5a5; }
@ -79,7 +83,9 @@
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
transition: background 0.2s; transition: background 0.2s;
display: inline-block; display: inline-flex;
align-items: center;
gap: 5px;
} }
.btn-unduh:hover { background: #bfdbfe; color: #1d4ed8; } .btn-unduh:hover { background: #bfdbfe; color: #1d4ed8; }
@ -92,6 +98,9 @@
margin-bottom: 16px; margin-bottom: 16px;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
} }
.empty-state { .empty-state {
@ -106,19 +115,27 @@
<a href="{{ route('guru.mapel.index') }}" class="back-link"> Kembali ke Mata Pelajaran</a> <a href="{{ route('guru.mapel.index') }}" class="back-link"> Kembali ke Mata Pelajaran</a>
<h3 class="page-title">🗂️ History Materi</h3> <h3 class="page-title">
<img src="{{ asset('images/icon/gurud/file.png') }}" class="icon-inline" alt="Ikon file">
History Materi
</h3>
<p style="color:#64748b;font-size:14px;margin-bottom:20px"> <p style="color:#64748b;font-size:14px;margin-bottom:20px">
Semua materi yang pernah Anda upload. Semua materi yang pernah Anda upload.
</p> </p>
@if(session('success')) @if(session('success'))
<div class="alert-success-custom"> {{ session('success') }}</div> <div class="alert-success-custom">
<img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-inline" alt="Berhasil">
{{ session('success') }}
</div>
@endif @endif
<div class="custom-card"> <div class="custom-card">
@if($materiList->isEmpty()) @if($materiList->isEmpty())
<div class="empty-state"> <div class="empty-state">
<div style="font-size:48px;margin-bottom:12px">📭</div> <div style="margin-bottom:12px">
<img src="{{ asset('images/icon/gurud/mailbox.png') }}" class="icon-lg" alt="Belum ada materi">
</div>
<p>Belum ada materi yang diupload.</p> <p>Belum ada materi yang diupload.</p>
</div> </div>
@else @else
@ -164,17 +181,24 @@
@if($materi->lampiran_materi) @if($materi->lampiran_materi)
@php @php
$ext = strtolower(pathinfo($materi->lampiran_materi, PATHINFO_EXTENSION)); $ext = strtolower(pathinfo($materi->lampiran_materi, PATHINFO_EXTENSION));
$icon = match(true) { $iconSrc = match(true) {
in_array($ext, ['pdf']) => '📄', in_array($ext, ['pdf']) => asset('images/icon/gurud/file2.png'),
in_array($ext, ['doc','docx']) => '📝', in_array($ext, ['doc','docx']) => asset('images/icon/gurud/buku1.png'),
in_array($ext, ['ppt','pptx']) => '📊', in_array($ext, ['ppt','pptx']) => asset('images/icon/gurud/lb.png'),
in_array($ext, ['jpg','jpeg','png']) => '🖼️', in_array($ext, ['jpg','jpeg','png']) => asset('images/icon/gurud/image.png'),
default => '📎', default => asset('images/icon/gurud/link.png'),
};
$iconAlt = match(true) {
in_array($ext, ['pdf']) => 'File PDF',
in_array($ext, ['doc','docx']) => 'File Word',
in_array($ext, ['ppt','pptx']) => 'File PowerPoint',
in_array($ext, ['jpg','jpeg','png']) => 'File gambar',
default => 'File lampiran',
}; };
@endphp @endphp
<a href="{{ asset('storage/' . $materi->lampiran_materi) }}" <a href="{{ asset('storage/' . $materi->lampiran_materi) }}"
target="_blank" class="btn-unduh"> target="_blank" class="btn-unduh">
{{ $icon }} Unduh <img src="{{ $iconSrc }}" class="icon-inline" alt="{{ $iconAlt }}"> Unduh
</a> </a>
@else @else
<span style="font-size:12px;color:#94a3b8">Tidak ada file</span> <span style="font-size:12px;color:#94a3b8">Tidak ada file</span>
@ -186,7 +210,10 @@
onsubmit="return confirm('Yakin hapus materi ini?')"> onsubmit="return confirm('Yakin hapus materi ini?')">
@csrf @csrf
@method('DELETE') @method('DELETE')
<button type="submit" class="btn-hapus">🗑️ Hapus</button> <button type="submit" class="btn-hapus">
<img src="{{ asset('images/icon/gurud/bin.png') }}" class="icon-inline" alt="Hapus">
Hapus
</button>
</form> </form>
</td> </td>
</tr> </tr>

View File

@ -70,8 +70,9 @@
</div> </div>
<div class="d-flex justify-content-end mt-4"> <div class="d-flex justify-content-end mt-4">
<button type="submit" class="btn btn-primary px-4"> <button type="submit" class="btn btn-primary px-4 d-flex align-items-center gap-2">
💾 Simpan Perubahan <img src="{{ asset('images/icon/gurud/save.png') }}" class="icon-inline" alt="Simpan">
Simpan Perubahan
</button> </button>
</div> </div>

View File

@ -61,15 +61,11 @@
<div class="d-flex justify-content-between align-items-center mb-3"> <div class="d-flex justify-content-between align-items-center mb-3">
<div class="badge-info">
📖 Mode Hanya Lihat (Read Only)
</div>
<form method="GET"> <form method="GET">
<div class="search-box"> <div class="search-box">
<input type="text" name="search" placeholder="Cari" value="{{ request('search') }}"> <input type="text" name="search" placeholder="Cari" value="{{ request('search') }}">
<button style="border:none;background:none"> <button style="border:none;background:none">
<img src="{{ asset('images/icon/main/search.png') }}" width="18"> <img src="{{ asset('images/icon/main/search.png') }}" width="18" height="18" alt="Cari siswa">
</button> </button>
</div> </div>
</form> </form>

View File

@ -9,6 +9,9 @@
font-weight: 800; font-weight: 800;
margin-bottom: 6px; margin-bottom: 6px;
margin-top: -20px; margin-top: -20px;
display: flex;
align-items: center;
gap: 8px;
} }
.back-link { .back-link {
@ -86,6 +89,9 @@
font-weight: 700; font-weight: 700;
color: #1e293b; color: #1e293b;
margin-bottom: 16px; margin-bottom: 16px;
display: flex;
align-items: center;
gap: 8px;
} }
.table-header { background: #a5e6ba; } .table-header { background: #a5e6ba; }
@ -95,7 +101,9 @@
font-weight: 700; font-weight: 700;
padding: 3px 10px; padding: 3px 10px;
border-radius: 99px; border-radius: 99px;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
} }
.status-dikumpulkan { background: #dcfce7; color: #16a34a; } .status-dikumpulkan { background: #dcfce7; color: #16a34a; }
@ -111,7 +119,9 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-flex;
align-items: center;
gap: 5px;
transition: background 0.2s; transition: background 0.2s;
} }
@ -171,14 +181,17 @@
<div class="info-meta"> <div class="info-meta">
<span class="meta-chip"> <span class="meta-chip">
📚 {{ optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-' }} <img src="{{ asset('images/icon/gurud/stacked.png') }}" class="icon-inline" alt="Mata pelajaran">
{{ optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-' }}
</span> </span>
<span class="meta-chip"> <span class="meta-chip">
🏫 {{ optional(optional($tugas->mengajar)->kelas)->tingkat }} <img src="{{ asset('images/icon/gurud/school.png') }}" class="icon-inline" alt="Kelas">
{{ optional(optional($tugas->mengajar)->kelas)->tingkat }}
{{ optional(optional($tugas->mengajar)->kelas)->nama_kelas ?? '-' }} {{ optional(optional($tugas->mengajar)->kelas)->nama_kelas ?? '-' }}
</span> </span>
<span class="meta-chip {{ $isLewat ? 'red' : 'green' }}"> <span class="meta-chip {{ $isLewat ? 'red' : 'green' }}">
Deadline: {{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }} <img src="{{ asset('images/icon/gurud/alarm.png') }}" class="icon-inline" alt="Deadline">
Deadline: {{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }}
{{ $isLewat ? 'Sudah lewat' : 'Masih aktif' }} {{ $isLewat ? 'Sudah lewat' : 'Masih aktif' }}
</span> </span>
</div> </div>
@ -208,11 +221,16 @@
{{-- DAFTAR PENGUMPULAN --}} {{-- DAFTAR PENGUMPULAN --}}
<div class="custom-card"> <div class="custom-card">
<p class="section-title">📥 Daftar Pengumpulan Siswa</p> <p class="section-title">
<img src="{{ asset('images/icon/gurud/pengumpulan.png') }}" class="icon-inline" alt="Pengumpulan tugas">
Daftar Pengumpulan Siswa
</p>
@if($tugas->pengumpulanTugas->isEmpty()) @if($tugas->pengumpulanTugas->isEmpty())
<div class="empty-state"> <div class="empty-state">
<div style="font-size:40px;margin-bottom:10px">📭</div> <div style="margin-bottom:10px">
<img src="{{ asset('images/icon/gurud/mailbox.png') }}" class="icon-lg" alt="Belum ada pengumpulan">
</div>
<p>Belum ada siswa yang mengumpulkan tugas ini.</p> <p>Belum ada siswa yang mengumpulkan tugas ini.</p>
</div> </div>
@else @else
@ -243,17 +261,22 @@
</td> </td>
<td class="text-center"> <td class="text-center">
<span class="status-badge status-{{ $kumpul->status }}"> <span class="status-badge status-{{ $kumpul->status }}">
@if($kumpul->status === 'dikumpulkan') Tepat Waktu @if($kumpul->status === 'dikumpulkan')
@elseif($kumpul->status === 'terlambat') Terlambat <img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-inline" alt="Tepat waktu"> Tepat Waktu
@else Belum @elseif($kumpul->status === 'terlambat')
<img src="{{ asset('images/icon/gurud/alarm.png') }}" class="icon-inline" alt="Terlambat"> Terlambat
@else
<img src="{{ asset('images/icon/gurud/x.png') }}" class="icon-inline" alt="Belum dikumpulkan"> Belum
@endif @endif
</span> </span>
</td> </td>
<td class="text-center"> <td class="text-center">
@if($kumpul->exp > 0) @if($kumpul->exp > 0)
<span style="background:#fef9c3;color:#b45309;font-size:12px; <span style="background:#fef9c3;color:#b45309;font-size:12px;
font-weight:700;padding:3px 10px;border-radius:99px"> font-weight:700;padding:3px 10px;border-radius:99px;
{{ $kumpul->exp }} EXP display:inline-flex;align-items:center;gap:4px">
<img src="{{ asset('images/icon/gurud/star.png') }}" class="icon-inline" alt="EXP">
{{ $kumpul->exp }} EXP
</span> </span>
@else @else
<span style="font-size:12px;color:#94a3b8">Belum dinilai</span> <span style="font-size:12px;color:#94a3b8">Belum dinilai</span>
@ -263,7 +286,7 @@
@if($kumpul->lampiran_tugas) @if($kumpul->lampiran_tugas)
<a href="{{ asset('storage/' . $kumpul->lampiran_tugas) }}" <a href="{{ asset('storage/' . $kumpul->lampiran_tugas) }}"
target="_blank" class="btn-unduh"> target="_blank" class="btn-unduh">
📎 Unduh <img src="{{ asset('images/icon/gurud/link.png') }}" class="icon-inline" alt="Unduh file"> Unduh
</a> </a>
@else @else
<span style="font-size:12px;color:#94a3b8">-</span> <span style="font-size:12px;color:#94a3b8">-</span>

View File

@ -9,6 +9,9 @@
font-weight: 800; font-weight: 800;
margin-bottom: 6px; margin-bottom: 6px;
margin-top: -20px; margin-top: -20px;
display: flex;
align-items: center;
gap: 8px;
} }
.back-link { .back-link {
@ -58,7 +61,9 @@
font-weight: 600; font-weight: 600;
padding: 3px 10px; padding: 3px 10px;
border-radius: 99px; border-radius: 99px;
display: inline-block; display: inline-flex;
align-items: center;
gap: 4px;
} }
.deadline-lewat { background: #fee2e2; color: #ef4444; } .deadline-lewat { background: #fee2e2; color: #ef4444; }
@ -79,7 +84,9 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-flex;
align-items: center;
gap: 5px;
transition: background 0.2s; transition: background 0.2s;
} }
@ -95,6 +102,9 @@
font-weight: 600; font-weight: 600;
cursor: pointer; cursor: pointer;
transition: background 0.2s; transition: background 0.2s;
display: inline-flex;
align-items: center;
gap: 5px;
} }
.btn-hapus:hover { background: #fca5a5; } .btn-hapus:hover { background: #fca5a5; }
@ -107,6 +117,9 @@
margin-bottom: 16px; margin-bottom: 16px;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
} }
.empty-state { .empty-state {
@ -121,19 +134,27 @@
<a href="{{ route('guru.mapel.index') }}" class="back-link"> Kembali ke Mata Pelajaran</a> <a href="{{ route('guru.mapel.index') }}" class="back-link"> Kembali ke Mata Pelajaran</a>
<h3 class="page-title">📑 History Tugas</h3> <h3 class="page-title">
<img src="{{ asset('images/icon/gurud/history.png') }}" class="icon-inline" alt="Ikon history">
History Tugas
</h3>
<p style="color:#64748b;font-size:14px;margin-bottom:20px"> <p style="color:#64748b;font-size:14px;margin-bottom:20px">
Semua tugas yang pernah Anda buat. Semua tugas yang pernah Anda buat.
</p> </p>
@if(session('success')) @if(session('success'))
<div class="alert-success-custom"> {{ session('success') }}</div> <div class="alert-success-custom">
<img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-inline" alt="Berhasil">
{{ session('success') }}
</div>
@endif @endif
<div class="custom-card"> <div class="custom-card">
@if($tugasList->isEmpty()) @if($tugasList->isEmpty())
<div class="empty-state"> <div class="empty-state">
<div style="font-size:48px;margin-bottom:12px">📭</div> <div style="margin-bottom:12px">
<img src="{{ asset('images/icon/gurud/mailbox.png') }}" class="icon-lg" alt="Belum ada tugas">
</div>
<p>Belum ada tugas yang dibuat.</p> <p>Belum ada tugas yang dibuat.</p>
</div> </div>
@else @else
@ -177,9 +198,15 @@
</span> </span>
</td> </td>
<td class="text-center"> <td class="text-center">
<span class="deadline-badge {{ $isLewat ? 'deadline-lewat' : 'deadline-aktif' }}"> @if($isLewat)
{{ $isLewat ? '⏰ Lewat' : '✅ Aktif' }} <span class="deadline-badge deadline-lewat">
<img src="{{ asset('images/icon/gurud/alarm.png') }}" class="icon-inline" alt="Deadline lewat"> Lewat
</span> </span>
@else
<span class="deadline-badge deadline-aktif">
<img src="{{ asset('images/icon/gurud/v.png') }}" class="icon-inline" alt="Deadline aktif"> Aktif
</span>
@endif
<div style="font-size:12px;color:#64748b;margin-top:4px"> <div style="font-size:12px;color:#64748b;margin-top:4px">
{{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }} {{ \Carbon\Carbon::parse($tugas->deadline)->format('d M Y, H:i') }}
</div> </div>
@ -192,14 +219,16 @@
<div class="d-flex gap-1 justify-content-center"> <div class="d-flex gap-1 justify-content-center">
<a href="{{ route('guru.tugas.detail', $tugas->id_tugas) }}" <a href="{{ route('guru.tugas.detail', $tugas->id_tugas) }}"
class="btn-detail"> class="btn-detail">
👁️ Detail <img src="{{ asset('images/icon/gurud/detail.png') }}" class="icon-inline" alt="Detail tugas"> Detail
</a> </a>
<form action="{{ route('guru.tugas.destroy', $tugas->id_tugas) }}" <form action="{{ route('guru.tugas.destroy', $tugas->id_tugas) }}"
method="POST" method="POST"
onsubmit="return confirm('Yakin hapus tugas ini? Semua pengumpulan juga akan terhapus.')"> onsubmit="return confirm('Yakin hapus tugas ini? Semua pengumpulan juga akan terhapus.')">
@csrf @csrf
@method('DELETE') @method('DELETE')
<button type="submit" class="btn-hapus">🗑️</button> <button type="submit" class="btn-hapus">
<img src="{{ asset('images/icon/gurud/bin.png') }}" class="icon-inline" alt="Hapus tugas">
</button>
</form> </form>
</div> </div>
</td> </td>