Website statis satu halaman untuk kelas PPLG 1 (Pengembangan Perangkat Lunak dan Gim) — menampilkan profil kelas, struktur pengurus & siswa per angkatan, prestasi, dokumentasi kegiatan (feed Instagram), dan kontak. Tema terang/gelap dengan toggle di navbar; kunjungan pertama otomatis ikut sistem.
- Vue 3 —
<script setup>+ Composition API - TypeScript — type check ketat via
vue-tsc - Vite — dev server & build produksi
- Tailwind CSS v4 — via plugin
@tailwindcss/vite, token warna didefinisikan disrc/style.css(@theme) - anime.js v4 — motion system: entrance reveal-on-scroll, staggered grid, stat count-up
- lucide-vue-next — ikon
npm install # pasang dependensi
npm run dev # server pengembangan (http://localhost:5173)
npm run build # build produksi + type check (hasil di dist/)
npm run preview # pratinjau hasil build produksi├── DESIGN.md # ⭐ Sistem desain & aturan anti-slop
├── docs/
│ └── color_palette.md # Sumber resmi palet warna
├── public/
│ └── favicon.svg # Favicon kelas (monogram < 1 >)
├── src/
│ ├── components/ # Satu komponen per section
│ │ ├── Navbar.vue # Navigasi sticky + toggle terang/gelap + menu mobile
│ │ ├── HeroSection.vue # Hero tipografi editorial + strip metrik
│ │ ├── AboutSection.vue # Profil wali kelas, visi, pilar keahlian
│ │ ├── StructureSection.vue# Pengurus harian (ledger) & divisi teknis
│ │ ├── AchievementsSection.vue # Rekam prestasi (ledger)
│ │ ├── ActivitiesSection.vue # Timeline dokumentasi kegiatan
│ │ └── FooterSection.vue # Kontak, sosmed, form pesan (mailto)
│ ├── composables/ # Composable (useTheme untuk tema terang/gelap, useReveal untuk motion anime.js)
│ ├── data/
│ │ ├── types.ts # Interface TypeScript semua data
│ │ └── classData.ts # ⭐ SEMUA KONTEN KELAS ADA DI SINI
│ ├── App.vue # Komposisi seluruh section
│ ├── main.ts # Entry point
│ └── style.css # Token Tailwind (@theme) + utilitas grid
└── index.html # Meta, font Google (Plus Jakarta Sans, Fira Code)
Seluruh konten terpusat di src/data/classData.ts — tidak perlu menyentuh komponen:
| Data | Konstanta |
|---|---|
| Nama kelas, sekolah, wali kelas, sosmed, kontak | classConfig |
| Menu navigasi | navItems |
| Statistik hero | statsData |
| Fokus keahlian (web/mobile/gim) | focusAreas |
| Pengurus harian (ketua, sekretaris, dll.) | classLeaders |
| Divisi teknis + projek berjalan | divisionsData |
| Showcase projek siswa (repo/demo link) | showcaseProjects |
| Prestasi lomba | achievementsData |
| Agenda kegiatan | activitiesData |
Saat ini semua nama orang, sekolah, tautan repo/demo, dan sosmed adalah placeholder fiktif — ganti dengan data kelas yang sebenarnya.
Section Kegiatan menampilkan jejak feed Instagram kelas secara statis. Karena Instagram CDN image URL kadaluarsa dalam hitungan hari, gambar tidak pernah disimpan sebagai URL CDN — melainkan diunduh ke dalam repo pada waktu build, lalu ditulis ke src/data/instagram.json dengan path lokal /ig/<id>.<ext>. Frontend hanya membaca JSON + melayani berkas gambar statis dari public/ig/.
Alurnya:
scripts/fetch-instagram.mjs(zero-dependency, ESM) membaca JSON feed profil IG dariINSTAGRAM_FEED_URL, atau dari fixture lokal via--input <path>.- Script menormalkan defensif entry (menerima top-level array,
{ posts }, atau varianmedia/data/edges; serta kuncisnake_casedancamelCase), mengurutkan berdasarkantimestamp(terbaru dulu), lalu mengambil maksimal 6 posting. - Setiap gambar diunduh/disalin ke
public/ig/<sanitized-id>.<ext>(ekstensi dariContent-Typeuntuk URL jarak jauh, atau magic bytes untuk berkas lokal). Posting VIDEO/CAROUSEL memakaithumbnail_url; posting tanpa gambar yang dapat pakai dilewati. - Hasil ditulis ke
src/data/instagram.json(fetchedAt+postsdenganmediaUrllokal/ig/...). - Berkas lama di
public/ig/yang tidak lagi direferensi dibersihkan — kecuali berkas bernamasample-*(placeholder designer, tidak pernah dihapus).
Menyiapkan feed asli (produksi, server sendiri):
Situs dijalankan di VPS Linux + Nginx static. Refresh feed Instagram tidak lagi
menggunakan GitHub Actions — dilakukan langsung di server via scripts/refresh-feed.sh
yang dijadwalkan sebagai cron harian pukul 00:00 WIB.
- Buat widget feed publik IG kelas di Behold.so dan salin URL JSON feed-nya.
- Di server, set env var
INSTAGRAM_FEED_URL(export di crontab,/etc/environment, atau pakaisystemd EnvironmentFile— lihat komentar discripts/refresh-feed.sh). - Jadwalkan cron harian (pakai
TZ=Asia/Jakartaagar 00:00 WIB tepat):TZ=Asia/Jakarta 0 0 * * * /path/to/pplg/scripts/refresh-feed.sh >> /var/log/pplg-feed.log 2>&1
- Deploy awal / manual ke Nginx docroot via
scripts/deploy.sh:Contoh Nginx server block (WEB_ROOT=/var/www/pplg ./scripts/deploy.sh
root=WEB_ROOT):Static file tidak perlu reload Nginx — cukup copy ulang keserver { listen 80; server_name example.com; root /var/www/pplg; index index.html; location / { try_files $uri $uri/ /index.html; } }
WEB_ROOTsetelah build.
Menjalankan secara lokal:
# Pakai feed langsung (perlu koneksi jaringan)
INSTAGRAM_FEED_URL="https://..." npm run fetch:instagram
# Atau pakai fixture lokal (offline, cocok untuk pengembangan & CI)
node scripts/fetch-instagram.mjs --input scripts/__fixtures__/feed.sample.jsonCatatan:
src/data/instagram.jsondan gambar dipublic/ig/*.jpgadalah berkas hasil (generated) dan di-gitignore — tidak di-commit ke repo. Pada fresh clone,prebuild(scripts/ensure-instagram.mjs) menciptakan fallback{ "fetchedAt": "...", "posts": [] }agarvue-tsc+vite buildtetap lolos. Jangan diedit tangan — jalankan kembali skrip atau biarkanscripts/refresh-feed.shyang menggenerasinya. Placeholdersample-*.svgdipublic/ig/disimpan skrip tak terhapuskan; setelah feed asli aktif, posting sampel di JSON diganti secara alami oleh posting riil, dan berkas SVG placeholder dapat dihapus manual bila tidak lagi dipakai.
Warna mengikuti docs/color_palette.md dan sudah dipetakan sebagai token Tailwind v4 di src/style.css. Gunakan utility token (mis. bg-primary-700, text-neutral-500) — jangan hardcode kode hex di komponen.
Arah visual, anatomi section, dan aturan desain (termasuk daftar pola AI-slop yang dilarang) didokumentasikan lengkap di DESIGN.md — baca sebelum menambah section baru.
- Form "Kirim Pesan" di footer bekerja tanpa backend: membuka aplikasi email dengan isi pesan terisi otomatis (
mailto:) ke email kelas. - Tema: Toggle di navbar beralih antara mode Terang dan Gelap (tanpa opsi "system"). Pilihan disimpan di localStorage (
pplg-theme). Kunjungan pertama tanpa pilihan tersimpan otomatis mengikuti preferensi OS secara real-time. - Situs sepenuhnya statis — hasil build di
dist/bisa di-deploy ke Netlify, Vercel, GitHub Pages, atau hosting statis apa pun.