diff --git a/groups/ApeNameTeamE/PROJECT_CONTEXT.md b/groups/ApeNameTeamE/PROJECT_CONTEXT.md new file mode 100644 index 0000000..de03b10 --- /dev/null +++ b/groups/ApeNameTeamE/PROJECT_CONTEXT.md @@ -0,0 +1,273 @@ +# PROJECT CONTEXT +## Website Statis Halaman Beasiswa — Informatika UNTAN + +> File ini adalah konteks utama proyek untuk AI assistant (Antigravity). +> Baca file ini setiap kali kamu membantu pengerjaan proyek ini. + +--- + +## 🎯 Apa yang Dibangun? + +**Single static landing page** berbasis HTML/CSS/JS murni (native web) untuk menampilkan informasi beasiswa bagi mahasiswa aktif, alumni, dan masyarakat umum Program Studi Informatika, Universitas Tanjungpura (UNTAN), Pontianak. + +Website ini bukan aplikasi web dinamis. Tidak ada backend, tidak ada database, tidak ada login. Update konten dilakukan dengan mengedit file JSON dan push ke GitHub → auto-deploy via Puify ke server prodi. + +--- + +## 🏗️ Tech Stack + +| Layer | Teknologi | +|---|---| +| Markup | HTML5 | +| Styling | CSS3 + Tailwind CSS | +| Interaktivitas | Vanilla JavaScript (ES6+) | +| Font | Google Fonts (Inter / Poppins) | +| Ikon | Font Awesome | +| Animasi | AOS.js (Animate on Scroll) | +| Carousel | Swiper.js | +| Hosting | Dedicated Server Prodi UNTAN via Puify | +| Version Control | Git + GitHub | + +**Tidak boleh menggunakan:** Framework berat (React, Vue, Angular), backend (Node.js, PHP, Python), database (MySQL, MongoDB). + +--- + +## 📐 Desain + +- **Figma Project:** https://www.figma.com/design/rG6JYG19CWziaPMhbJ2NPL/PPL-FIGMA?node-id=0-1 +- **Prototype:** https://www.figma.com/proto/rG6JYG19CWziaPMhbJ2NPL/PPL-FIGMA?node-id=120-1247 + +### Warna Utama + +| Variabel | Hex | Penggunaan | +|---|---|---| +| Primary (Biru) | `#2B4590` | Navbar, heading, tombol, border aktif | +| Secondary (Kuning) | `#F5A623` | CTA, aksen, badge | +| Background | `#FFFFFF` | Latar halaman | +| Text | `#1A1A1A` | Body text | +| Accent | `#6B7280` | Caption, label, border | +| Success | `#10B981` | Badge "Buka" | +| Danger | `#EF4444` | Badge "Ditutup" | +| Overlay | `#00000080` | Background popup | + +### Tipografi +- **Font:** Inter (utama) / Poppins (heading) +- H1: 48–64px bold | H2: 32–40px semibold | H3: 24–28px semibold +- Body: 16–18px regular | Caption: 12–14px + +--- + +## 📄 Struktur Halaman (Top → Bottom) + +``` +[NAVBAR - Sticky] + Logo UNTAN | Menu: Beranda, Beasiswa, Testimoni, Kontak | Toggle ID/EN + +[#hero - Hero Section] + Judul: "Beasiswa Studi & Penelitian" + Sub: Teknik Informatika Universitas Tanjungpura + Deskripsi singkat tentang beasiswa + CTA Button (kuning): "Lihat Daftar Beasiswa →" + Foto ilustrasi mahasiswa (kanan) + +[#statistics - Statistik Counter] + 3 angka dengan animasi scroll: + - Total Mahasiswa Penerima Beasiswa Semester Ini + - Total Penerima Beasiswa Pembiayaan Pemerintah + - Total Penerima Beasiswa Pembiayaan Swasta + +[#directory - Direktori Beasiswa] + - Tab filter: Semua | Sedang Buka | Ditutup | Pemerintah | Swasta + - Search bar (real-time) + - Grid kartu beasiswa: + * Desktop: 3 kolom + * Tablet: 2 kolom + * Mobile: 1 kolom + - Tiap kartu: thumbnail, badge status, nama, deskripsi singkat, tanggal, tombol "Selengkapnya →" + - Klik "Selengkapnya →" → buka POPUP MODAL + +[POPUP MODAL - Detail Beasiswa] + - Nama + thumbnail/logo beasiswa + - Badge status (Buka / Ditutup) + - Syarat umum (ringkasan/bullet) + - Kontak yang bisa dihubungi + - Tombol "Info Lebih Lanjut" → buka URL sumber resmi (tab baru) + - Tutup: tombol ×, klik luar area, tekan Escape + +[#testimonial - Testimoni Penerima Beasiswa] + - Carousel / grid kartu + - Tiap kartu: foto, nama, nama beasiswa yang diterima, kutipan singkat + - Navigasi carousel jika > 3 testimoni + +[#cta - Call to Action] + - Judul: "Ingin Mengetahui Info Lebih Lanjut?" + - Dua tombol: + * "Daftar Beasiswa" (scroll ke #directory) + * "Hubungi Kami" (WhatsApp admin) + +[#footer - Footer] + - Logo Informatika UNTAN + - Alamat prodi, email, telepon, WhatsApp + - Ikon media sosial + - Ilustrasi khas Pontianak (dekorasi bawah) +``` + +--- + +## 📁 Struktur File Proyek + +``` +project-root/ +├── index.html +├── assets/ +│ ├── css/ +│ │ └── style.css +│ ├── js/ +│ │ ├── main.js # Init AOS, smooth scroll, sticky navbar +│ │ ├── filter.js # Filter tab + real-time search +│ │ ├── popup.js # Modal detail beasiswa +│ │ ├── counter.js # Animasi counter statistik +│ │ ├── carousel.js # Carousel testimoni (Swiper.js) +│ │ └── i18n.js # Toggle bahasa ID/EN +│ └── images/ +│ ├── hero/ +│ ├── beasiswa/ # Logo/thumbnail beasiswa +│ └── testimoni/ # Foto penerima +├── data/ +│ ├── beasiswa.json +│ └── testimoni.json +└── README.md +``` + +--- + +## 🗃️ Format Data + +### `data/beasiswa.json` +```json +[ + { + "id": "bsw-001", + "nama": "Beasiswa Adaro Foundation 2026", + "kategori": "Swasta", + "status": "Ditutup", + "thumbnail": "assets/images/beasiswa/adaro.jpg", + "deskripsi_singkat": "Beasiswa untuk mahasiswa S1 & D4 dengan IPK minimal 3.00...", + "syarat_umum": [ + "Mahasiswa aktif S1/D4", + "IPK minimal 3.00", + "Berasal dari keluarga kurang mampu" + ], + "kontak": "Admin Prodi / Kemahasiswaan UNTAN", + "tanggal_buka": "2026-01-01", + "tanggal_tutup": "2026-04-09", + "url_sumber": "https://...", + "tags": ["S1", "Swasta"] + } +] +``` + +### `data/testimoni.json` +```json +[ + { + "id": "tsm-001", + "nama": "Aulia Rahman", + "foto": "assets/images/testimoni/aulia.jpg", + "nama_beasiswa": "Beasiswa Prestasi", + "kutipan": "Beasiswa ini benar-benar membuka jalan bagi saya untuk fokus sepenuhnya pada pendidikan..." + } +] +``` + +--- + +## ⚙️ Fitur Interaktif yang Harus Diimplementasikan + +| Fitur | Status | File | +|---|---|---| +| Sticky Navbar (transparent → solid saat scroll) | ⏳ | `main.js` | +| Hamburger Menu | ⏳ | `main.js` | +| Smooth Scroll ke seksi | ⏳ | `main.js` | +| Active State Navbar (IntersectionObserver) | ⏳ | `main.js` | +| Animasi AOS (elemen muncul saat scroll) | ⏳ | `main.js` | +| Counter Animasi Statistik | ⏳ | `counter.js` | +| Render kartu beasiswa dari JSON | ⏳ | `filter.js` | +| Filter tab (Semua/Buka/Ditutup/Pemerintah/Swasta) | ⏳ | `filter.js` | +| Real-time search | ⏳ | `filter.js` | +| Popup Modal detail beasiswa | ⏳ | `popup.js` | +| Tutup popup (×, klik luar, Escape) | ⏳ | `popup.js` | +| Carousel testimoni (Swiper.js) | ⏳ | `carousel.js` | +| Toggle bahasa ID/EN | ⏳ | `i18n.js` | + +--- + +## 📱 Responsive Breakpoints + +```css +/* Mobile first */ +/* Default: mobile < 768px */ +/* Tablet: */ @media (min-width: 768px) { ... } +/* Laptop: */ @media (min-width: 1024px) { ... } +/* Desktop: */ @media (min-width: 1280px) { ... } +``` + +--- + +## 🔒 Aturan Keamanan Kode + +- Semua link eksternal: `target="_blank" rel="noopener noreferrer"` +- Tidak ada hardcoded data sensitif di source code +- Input search di-sanitasi sebelum digunakan untuk filter DOM +- Tidak menggunakan `innerHTML` dengan input pengguna langsung (cegah XSS) + +--- + +## 👥 Tim & Peran + +| Nama | Peran | +|---|---| +| Djapianus Thebrianto | Project Manager | +| Derangga Aray Abimanyu | Backend Developer (data, scraping, JSON) | +| Destra Aulia Faza Ananda Putra | Frontend Developer (HTML, CSS, JS) | +| Dian Satrio Prayogo | UI/UX Designer (Figma) | +| Jonathan Geral Nababan | Quality Assurance (testing) | + +--- + +## 📋 Hal Penting untuk AI Assistant + +1. **Ini bukan React/Vue/Angular.** Semua harus ditulis dalam HTML/CSS/Tailwind/Vanilla JS. +2. **Data beasiswa dibaca dari `data/beasiswa.json`** — bukan hardcoded di HTML. +3. **Warna wajib sesuai palet resmi** — jangan gunakan warna lain sembarangan. +4. **Mobile-first** — tulis CSS dari ukuran kecil dulu, baru ke besar. +5. **Popup harus bisa ditutup 3 cara:** tombol ×, klik overlay, tekan Escape. +6. **Filter dan search bisa aktif bersamaan** (kumulatif, bukan saling menggantikan). +7. **Navbar berubah warna saat scroll** — transparent di atas hero, solid biru setelah scroll turun. +8. **Semua animasi pakai AOS.js** — inisialisasi di `main.js` dengan `AOS.init()`. +9. **Carousel testimoni pakai Swiper.js** — touch-friendly untuk mobile. +10. **Tidak ada `alert()`, `console.log()` di production code.** + +--- + +## 🚀 Cara Kerja Deployment + +``` +Developer push ke GitHub + ↓ + Puify detects push + ↓ + Auto-deploy ke server + ↓ + Website live (Dev) + ↓ + Approved → Production +``` + +--- + +## 📎 Dokumen Terkait + +- `SRS.md` — Spesifikasi kebutuhan lengkap (use case, NFR, batasan) +- `SDD.md` — Desain teknis lengkap (arsitektur, komponen, schema data) +- Figma: https://www.figma.com/design/rG6JYG19CWziaPMhbJ2NPL/PPL-FIGMA?node-id=0-1 diff --git a/groups/ApeNameTeamE/SDD.md b/groups/ApeNameTeamE/SDD.md new file mode 100644 index 0000000..ebbef87 --- /dev/null +++ b/groups/ApeNameTeamE/SDD.md @@ -0,0 +1,329 @@ +# Software Design Document (SDD) +## Website Statis Halaman Beasiswa — One-Page HTML +### Program Studi Informatika — Universitas Tanjungpura + +| Field | Detail | +|---|---| +| Nama Proyek | Pengembangan Website Statis Halaman Beasiswa | +| Kelompok | Ape Nama Team E | +| Versi | 1.0 | +| Fase SDLC | Design (aktif) | +| Dosen | Izuardo Zulkarnain, S.Pd., M.T | +| Semester | Genap 2025/2026 | + +--- + +## 1. Pendahuluan + +### 1.1 Tujuan Dokumen +SDD ini mendeskripsikan perancangan teknis website beasiswa Informatika UNTAN sebagai one-page HTML native. Dokumen ini menjadi panduan tim dalam mengimplementasikan: +- Fitur popup detail beasiswa +- Integrasi data hasil scraping & survei admin +- Otomatisasi deployment via Puify (push-to-deploy) + +### 1.2 Stack Teknologi + +| Layer | Teknologi | Keterangan | +|---|---|---| +| Markup | HTML5 | Struktur konten | +| Styling | CSS3 / Tailwind CSS | Layout responsif | +| Interaktivitas | JavaScript (Vanilla / Alpine.js) | Animasi, scroll, toggle | +| Font & Ikon | Google Fonts / Font Awesome | Tipografi & ikon | +| Hosting | Puify (SaaS) | Auto-deploy dari repo ke server | +| Server | Dedicated Server Prodi | Dev & Production | +| Version Control | Git + GitHub | Kolaborasi & push-to-deploy | + +### 1.3 Posisi dalam SDLC + +| Fase | Status | +|---|---| +| Requirement | ✅ Selesai | +| Design | 🔄 Aktif | +| Implementation | ⏳ Belum | +| Testing | ⏳ Belum | +| Deployment | ⏳ Belum | + +--- + +## 2. Arsitektur Halaman (Site Architecture) + +### 2.1 Konsep One-Page Website +Single-page statis — semua konten dalam satu file HTML utama. Navigasi menggunakan **smooth scroll**. Detail beasiswa (syarat umum) ditampilkan via **popup modal** agar halaman tetap bersih. + +### 2.2 Struktur Seksi (Vertikal, Atas → Bawah) + +| No | ID | Nama Seksi | Konten Utama | +|---|---|---|---| +| 1 | `#hero` | Hero / Landing | Judul "Beasiswa Studi & Penelitian", deskripsi, CTA "Lihat Daftar Beasiswa", foto ilustrasi mahasiswa | +| 2 | `#statistics` | Statistik Counter | 3 angka animasi: Total Penerima Semester Ini, Total Pemerintah, Total Swasta | +| 3 | `#directory` | Direktori Beasiswa | Grid kartu (3 kolom desktop, 2 tablet, 1 mobile), tab filter, real-time search, popup detail | +| 4 | `#testimonial` | Testimoni | Carousel/grid testimoni: foto, nama, beasiswa, kutipan singkat | +| 5 | `#cta` | Call-to-Action | Banner ajakan + tombol WhatsApp admin + Instagram kemahasiswaan | +| 6 | `#footer` | Footer | Logo prodi, alamat, email, telepon, WA, ikon sosmed, dekorasi ilustrasi Pontianak | + +### 2.3 Navigasi +**Sticky navbar** yang selalu terlihat saat scroll. + +| Perangkat | Perilaku Navbar | +|---|---| +| Desktop/Laptop | Horizontal, semua item terlihat | +| Tablet | Horizontal, item muat; sisanya dropdown | +| Mobile | Hamburger menu (≡) — tap untuk expand vertikal | + +--- + +## 3. Desain Visual & Identitas + +### 3.1 Color Palette + +| Peran | Nama | Hex | Digunakan Untuk | +|---|---|---|---| +| Primary | Biru Informatika | `#2B4590` | Navbar, heading, tombol primary, border aktif | +| Secondary | Kuning/Oranye | `#F5A623` | CTA button, aksen, badge | +| Background | White | `#FFFFFF` | Latar halaman utama | +| Text | Dark Gray | `#1A1A1A` | Body text, paragraf | +| Accent | Abu-abu | `#6B7280` | Caption, label, border | +| Success | Hijau | `#10B981` | Badge status "Buka" | +| Danger | Merah | `#EF4444` | Badge status "Ditutup" | +| Overlay | Hitam + Transparansi | `#00000080` | Background popup modal | + +### 3.2 Tipografi + +| Elemen | Font Family | Ukuran | Weight | +|---|---|---|---| +| Heading H1 | Poppins / Inter | 48–64px | 700 (Bold) | +| Heading H2 | Poppins / Inter | 32–40px | 600 (SemiBold) | +| Heading H3 | Poppins / Inter | 24–28px | 600 (SemiBold) | +| Body Text | Inter / Poppins | 16–18px | 400 (Regular) | +| Caption/Label | Inter / Poppins | 12–14px | 400–500 | +| Navbar | Inter | 14–16px | 500 (Medium) | +| Button | Inter | 14–16px | 600 (SemiBold) | + +### 3.3 Komponen UI + +| Komponen | Spesifikasi | +|---|---| +| Navbar | Sticky; transparent di atas hero → solid biru `#2B4590` saat scroll; toggle ID/EN di kanan | +| Hero Section | Full-height, overlay gradient gelap, judul besar, deskripsi, CTA kuning kontras | +| Card Beasiswa | Border subtle, shadow ringan; hover: scale sedikit + shadow lebih dalam; thumbnail 100% lebar | +| Button Primary | Solid biru, teks putih | +| Button Secondary | Outline biru | +| Button Ghost | Tanpa border | +| Badge Status | Rounded pill; Hijau "Buka", Merah "Ditutup" | +| Tab Filter | Underline active state, smooth transition, teks hitam, garis bawah aktif biru | +| Popup Modal | Center screen, dark overlay, border-radius 12px, close button (×) kanan atas | +| Footer | Background `#1A1A1A`, teks putih, 3–4 kolom desktop | + +--- + +## 4. Desain Mockup (UI/UX) + +### 4.1 Alat Desain +**Figma** — kolaborasi realtime, wireframe + hi-fidelity prototype. + +- **Figma Project:** https://www.figma.com/design/rG6JYG19CWziaPMhbJ2NPL/PPL-FIGMA?node-id=0-1 +- **Prototype Interaktif:** https://www.figma.com/proto/rG6JYG19CWziaPMhbJ2NPL/PPL-FIGMA?node-id=120-1247 + +### 4.2 Tahapan Desain +1. **Wireframe (Lo-Fi)** — sketsa hitam-putih, fokus layout & posisi elemen +2. **Mockup (Hi-Fi)** — desain lengkap dengan warna, font, dan aset visual +3. **Prototype** — mockup yang bisa diklik untuk simulasi navigasi antar seksi +4. **User Testing** — validasi desain bersama calon pengguna + +### 4.3 Breakpoint & Resolusi + +| Perangkat | Resolusi Mockup | +|---|---| +| Desktop Monitor | 1920 × 1080 | +| Laptop | 1366 × 768 | +| Tablet Portrait | 768 × 1024 | +| Tablet Landscape | 1024 × 768 | +| Mobile / HP | 390 × 844 | + +--- + +## 5. Desain Responsif + +### 5.1 Strategi: Mobile-First +Desain dimulai dari layar terkecil → diperluas ke layar lebih besar via CSS media query. Memastikan performa optimal di koneksi lambat. + +### 5.2 Breakpoint + +| Perangkat | Breakpoint | Resolusi Umum | +|---|---|---| +| Desktop Monitor | `>= 1280px` | 1920×1080, 2560×1440 | +| Laptop | `>= 1024px` | 1366×768, 1440×900 | +| Tablet | `>= 768px` | 768×1024, 820×1180 | +| Mobile | `< 768px` | 360×800, 390×844, 414×896 | + +### 5.3 Perubahan Layout per Breakpoint + +| Elemen | Mobile (<768px) | Tablet (768–1279px) | Desktop (≥1280px) | +|---|---|---|---| +| Navbar | Hamburger menu | Hamburger / partial menu | Horizontal full menu | +| Hero Section | Teks atas, gambar bawah | Teks kiri, gambar kanan 50/50 | Teks kiri, gambar kanan lebar | +| Card Grid | 1 kolom | 2 kolom | 3–4 kolom | +| Teks Body | 16px | 16–17px | 17–18px | +| Padding Section | 24px 16px | 40px 32px | 80px 64px | +| Footer | Stack vertikal | 2 kolom | 3–4 kolom | + +### 5.4 Hasil Uji Responsivitas + +| No | Perangkat/Browser | Ukuran | Status | Catatan | +|---|---|---|---|---| +| 1 | Chrome Desktop | 1920×1080 | ✅ Lulus | Layout proporsional, spacing rapi | +| 2 | Chrome Mobile Sim. | 390×844 | ✅ Lulus | Card grid 1 kolom, teks 16px nyaman | +| 3 | Firefox Desktop | 1440×900 | ✅ Lulus | Konsisten dengan Chrome Desktop | +| 4 | iPhone (Safari) | 390×844 | ✅ Lulus | Hero stack sempurna, padding aman | +| 5 | Android Chrome | 360×800 | ✅ Lulus | Touch target ideal, gambar proporsional | +| 6 | iPad (Safari) | 768×1024 | ✅ Lulus | Hero 50/50, spasi sentuh lega | + +--- + +## 6. Use Case Diagram + +### 6.1 Aktor Sistem + +| Aktor | Deskripsi | +|---|---| +| Pengunjung Umum | Mahasiswa aktif, alumni, calon mahasiswa, dosen, masyarakat — tanpa autentikasi | +| Admin Prodi | Pengelola konten: memperbarui data beasiswa, testimoni, statistik via push-to-repo | + +### 6.2 Daftar Use Case & Skenario + +Lihat detail lengkap di SRS.md. Ringkasan: + +| Kode | Nama | Aktor | +|---|---|---| +| UC-01 | Melihat Daftar Beasiswa | Pengunjung Umum | +| UC-02 | Memfilter Beasiswa Berdasarkan Kategori | Pengunjung Umum | +| UC-03 | Mencari Beasiswa | Pengunjung Umum | +| UC-04 | Melihat Detail Beasiswa (Popup) | Pengunjung Umum | +| UC-05 | Mengakses Sumber Resmi Beasiswa | Pengunjung Umum | +| UC-06 | Menghubungi Admin via CTA | Pengunjung Umum | +| UC-07 | Melihat Testimoni Penerima Beasiswa | Pengunjung Umum | +| UC-08 | Mengganti Bahasa Tampilan (ID/EN) | Pengunjung Umum | +| UC-09 | Memperbarui Data Beasiswa | Admin Prodi | + +**Relasi antar UC:** UC-04 `<>` UC-05 (popup detail menyertakan akses sumber resmi) + +--- + +## 7. Fitur Interaktif (Client-Side) + +Tidak ada backend API. Semua interaktivitas dijalankan di sisi klien. + +| No | Fitur | Teknologi | Keterangan | +|---|---|---|---| +| 1 | Smooth Scroll Navigasi | CSS `scroll-behavior` / JS | Scroll halus ke seksi saat klik menu | +| 2 | Sticky Navbar | CSS `position:sticky` / JS scroll | Navbar tetap di atas saat scroll | +| 3 | Hamburger Menu | JavaScript + CSS toggle | Menu responsif layar kecil | +| 4 | Active State Navbar | JS `IntersectionObserver` | Highlight menu sesuai seksi terlihat | +| 5 | Animasi Masuk (AOS) | AOS.js / CSS animation | Elemen muncul saat pertama kali di viewport | +| 6 | Counter Animasi | JavaScript | Angka statistik berjalan saat di-scroll | +| 7 | Filter Real-Time | Vanilla JavaScript | Filter kartu saat klik tab, tanpa reload | +| 8 | Pencarian Real-Time | Vanilla JavaScript | Cari beasiswa saat ketik di search bar | +| 9 | Popup Modal Detail | Vanilla JavaScript | Detail beasiswa dalam modal; tutup via ×, klik luar, atau Escape | +| 10 | Toggle Bahasa ID/EN | Vanilla JS + localStorage | Ubah teks tanpa reload, simpan preference di session | +| 11 | Carousel Testimoni | Vanilla JS / Swiper.js | Navigasi testimoni left/right; touch swipe di mobile | +| 12 | Form Kontak (Opsional) | Formspree / EmailJS / mailto | Kirim pesan tanpa backend | +| 13 | Lightbox Galeri (Opsional) | Fancybox / vanilla JS | Gambar fullscreen saat diklik | + +--- + +## 8. Layanan Pihak Ketiga + +| Layanan | Kegunaan | Gratis? | +|---|---|---| +| Google Fonts | Tipografi (Inter/Poppins) | ✅ Ya | +| Font Awesome | Ikon UI | ✅ Ya (tier dasar) | +| Google Maps Embed | Peta lokasi di seksi kontak | ✅ Ya (basic embed) | +| Formspree | Form kontak tanpa backend | ✅ Ya (tier dasar) | +| AOS.js | Animasi scroll (Animate on Scroll) | ✅ Ya (open source) | +| Swiper.js | Carousel testimoni | ✅ Ya (open source) | + +--- + +## 9. Desain Keamanan + +### 9.1 Keamanan Form Kontak +- Validasi client-side: semua field wajib diisi, format email dicek sebelum submit +- Rate limiting: Formspree/EmailJS membatasi pengiriman untuk mencegah spam +- reCAPTCHA (Opsional): Google reCAPTCHA v3 untuk mencegah bot + +### 9.2 Keamanan Konten +- **Tidak ada data sensitif** — website tidak menyimpan data pengguna (no login, no database) +- **HTTPS wajib** — sertifikat SSL/TLS pada server hosting prodi +- **Content Security Policy** — meta CSP header untuk mencegah XSS +- **External link** — semua link eksternal menggunakan `rel="noopener noreferrer"` + +--- + +## 10. Struktur File yang Direkomendasikan + +``` +project-root/ +├── index.html # File HTML utama (one-page) +├── assets/ +│ ├── css/ +│ │ └── style.css # Custom CSS (jika tidak full Tailwind) +│ ├── js/ +│ │ ├── main.js # Logika utama: scroll, navbar, AOS init +│ │ ├── filter.js # Filter & pencarian beasiswa +│ │ ├── popup.js # Modal popup detail beasiswa +│ │ ├── counter.js # Animasi counter statistik +│ │ ├── carousel.js # Carousel testimoni +│ │ └── i18n.js # Toggle bahasa ID/EN +│ └── images/ +│ ├── hero/ # Foto hero section +│ ├── beasiswa/ # Thumbnail logo beasiswa +│ └── testimoni/ # Foto penerima beasiswa +├── data/ +│ ├── beasiswa.json # Data beasiswa (diupdate oleh admin) +│ └── testimoni.json # Data testimoni +└── README.md # Panduan setup & deployment +``` + +--- + +## 11. Data Schema + +### 11.1 Schema Beasiswa (`beasiswa.json`) +```json +{ + "id": "string", + "nama": "string", + "kategori": "Pemerintah | Swasta", + "status": "Buka | Ditutup", + "thumbnail": "path/to/image.jpg", + "deskripsi_singkat": "string (max 150 char)", + "syarat_umum": ["string", "string"], + "kontak": "string", + "tanggal_buka": "YYYY-MM-DD", + "tanggal_tutup": "YYYY-MM-DD", + "url_sumber": "https://...", + "tags": ["S1", "S2", "Magang", "Luar Negeri"] +} +``` + +### 11.2 Schema Testimoni (`testimoni.json`) +```json +{ + "id": "string", + "nama": "string", + "foto": "path/to/foto.jpg", + "nama_beasiswa": "string", + "kutipan": "string (max 200 char)" +} +``` + +--- + +## 12. Referensi + +1. IEEE Standard 1016-2009 — Software Design Descriptions +2. W3C — HTML5 & CSS3 Specification (https://www.w3.org) +3. Google — Web Fundamentals: Responsive Web Design +4. MDN Web Docs — CSS Media Queries +5. Figma — Design Tool Documentation +6. Nurhikmat et al. (2024) — Optimasi Responsivitas Web dengan Mobile-First Design. JINTEKS. diff --git a/groups/ApeNameTeamE/SRS.md b/groups/ApeNameTeamE/SRS.md new file mode 100644 index 0000000..71f675f --- /dev/null +++ b/groups/ApeNameTeamE/SRS.md @@ -0,0 +1,337 @@ +# Software Requirements Specification (SRS) +## Pengembangan Website Statis Halaman Beasiswa +### Program Studi Informatika — Universitas Tanjungpura + +| Field | Detail | +|---|---| +| Nama Proyek | Pengembangan Website Statis Halaman Beasiswa | +| Kelompok | Ape Nama Team E | +| Versi | 1.1 | +| Tanggal | 01/05/2026 | +| Dosen | Izuardo Zulkarnain, S.Pd., M.T | +| Mata Kuliah | Proyek Perangkat Lunak — Semester Genap 2025/2026 | + +**Anggota Tim:** +- Djapianus Thebrianto — Project Manager +- Derangga Aray Abimanyu — Backend Developer +- Destra Aulia Faza Ananda Putra — Frontend Developer +- Dian Satrio Prayogo — UI/UX Designer +- Jonathan Geral Nababan — Quality Assurance + +--- + +## 1. Pendahuluan + +### 1.1 Tujuan Dokumen + +SRS ini memberikan spesifikasi teknis dan fungsional untuk pengembangan Website Statis Beasiswa Informatika Universitas Tanjungpura. Dokumen ini memastikan: + +- Pengembang membangun sistem dengan kode sederhana yang mudah di-maintain melalui mekanisme push-to-repo ke dedicated server prodi. +- Penyajian data beasiswa (nama & syarat umum) dilakukan melalui fitur **Pop-up** dengan akses langsung ke admin via WhatsApp dan Instagram kemahasiswaan UNTAN. +- Proyek mengalihkan alur data dari portal universitas/survei admin ke static page dengan **availability 24 jam**. + +**Ditujukan kepada:** Tim Ape Nama Team E, Product Owner (dosen), dan Administrator Prodi. + +### 1.2 Ruang Lingkup + +Website statis single-page yang menjadi pusat informasi beasiswa, riset, dan pengembangan karir — terintegrasi dengan infrastruktur server Prodi Informatika UNTAN. + +**Fitur yang dicakup:** +- Direktori beasiswa (mahasiswa aktif, alumni, S2 luar negeri, magang) +- Detail beasiswa via popup (nama + syarat umum) +- Data beasiswa dari web scraping sumber resmi +- Seksi testimoni penerima beasiswa (foto, profil, kutipan) +- Toggle bahasa Indonesia / Inggris (bilingual) +- CTA ke WhatsApp admin & Instagram kemahasiswaan UNTAN + +**Yang TIDAK dicakup:** +- Formulir pendaftaran (diarahkan ke URL asli penyedia) +- Halaman admin berbasis web (update via push-to-repo) +- Database — data bersifat statis (JSON/JS di repositori) + +### 1.3 Definisi & Akronim + +| Istilah | Definisi | +|---|---| +| Native Website | Web dengan HTML, CSS, JS murni tanpa framework kompleks | +| Scraping | Pengambilan data otomatis dari website eksternal | +| Dedicated Server | Server milik Prodi Informatika UNTAN (Dev & Production) | +| Pop-up / Modal | Jendela overlay di atas halaman tanpa reload | +| CTA | Call-to-Action — tombol ajakan ke WhatsApp/Instagram | +| Availability | Kemampuan sistem beroperasi 24 jam | +| Puify | Platform SaaS otomatisasi deployment dari repo ke server | + +### 1.4 Referensi +- IEEE Std 830-1998 — Software Requirements Specifications +- UU No. 27 Tahun 2022 tentang Perlindungan Data Pribadi (UU PDP) + +--- + +## 2. Deskripsi Umum Sistem + +### 2.1 Perspektif Produk + +Produk baru berdiri sendiri sebagai **single static landing page** — bukan pengganti sistem lama. Website ini hadir sebagai transformasi digital dari penyebaran info beasiswa yang sebelumnya manual (portal, surat kabar mahasiswa, grup medsos) ke satu platform terpusat. + +**Integrasi eksternal (satu arah):** +- Website resmi penyedia beasiswa (data via scraping) +- API Website Informatika UNTAN (konten artikel/berita) +- WhatsApp & Instagram Kemahasiswaan UNTAN (CTA) + +Tidak ada antarmuka admin berbasis web. Semua update konten via **push ke GitHub → auto-deploy ke server** melalui Puify. + +### 2.2 Fungsi Utama Sistem + +| Kode | Fungsi | Deskripsi | +|---|---|---| +| F01 | Direktori Beasiswa | Grid kartu beasiswa aktif, S2, magang, penelitian dari berbagai sumber resmi | +| F02 | Filter & Pencarian | Saring berdasarkan kategori (Semua/Buka/Ditutup/Pemerintah/Swasta) + real-time search | +| F03 | Detail via Pop-up | Modal berisi nama, syarat umum, kontak, tautan sumber resmi | +| F04 | Testimoni | Foto, nama, nama beasiswa, kutipan dari penerima beasiswa | +| F05 | CTA Hubungi Admin | Tombol cepat ke WhatsApp admin & Instagram kemahasiswaan | +| F06 | Bilingual ID/EN | Toggle bahasa Indonesia ↔ Inggris tanpa reload | +| F07 | Update via Repository | Admin edit file data + push → halaman publik auto-update | + +### 2.3 Kelas Pengguna + +| Kelas | Karakteristik | Hak Akses | +|---|---|---| +| Pengunjung Umum | Mahasiswa aktif, alumni, masyarakat — tanpa login | Lihat konten, filter, search, buka popup, akses link eksternal | +| Admin Prodi | Staf/mahasiswa dengan kemampuan Git dasar | Edit file data di GitHub → push → deploy otomatis | + +### 2.4 Lingkungan Operasional + +| Komponen | Spesifikasi | +|---|---| +| Platform | Browser modern: Chrome ≥v100, Firefox ≥v100, Edge ≥v100, Safari ≥v15 | +| Server/Hosting | Dedicated server Prodi Informatika UNTAN (Dev & Production) via Puify | +| Database | Tidak ada — data di file statis JSON/JS di repositori | +| Bahasa Pemrograman | HTML5, CSS3 + Tailwind CSS, JavaScript ES6+ | +| Version Control | Git / GitHub | +| Koneksi | Min 1 Mbps (dasar), 10 Mbps (optimal) | + +### 2.5 Asumsi & Ketergantungan + +**Asumsi:** +- Pengunjung menggunakan browser modern dengan JS ES6+ dan CSS3 aktif +- Data beasiswa sudah diverifikasi admin sebelum dipublikasikan +- Perangkat pengunjung mendukung akses WhatsApp (app atau web) + +**Ketergantungan:** +- Dedicated server Prodi UNTAN harus aktif untuk availability 24 jam +- Update data bergantung pada keaktifan admin melakukan push secara berkala +- Fitur berita bergantung pada stabilitas API Website Informatika UNTAN +- CTA bergantung pada keaktifan nomor WhatsApp & akun Instagram kemahasiswaan + +--- + +## 3. Kebutuhan Fungsional + +### 3.1 Daftar Use Case + +| UC ID | Nama Use Case | Aktor | Prioritas (MoSCoW) | +|---|---|---|---| +| UC-01 | Melihat Daftar Beasiswa | Pengunjung Umum | Must Have | +| UC-02 | Memfilter Beasiswa Berdasarkan Kategori | Pengunjung Umum | Must Have | +| UC-03 | Mencari Beasiswa | Pengunjung Umum | Must Have | +| UC-04 | Melihat Detail Beasiswa (Popup) | Pengunjung Umum | Must Have | +| UC-05 | Mengakses Sumber Informasi Beasiswa | Pengunjung Umum | Must Have | +| UC-06 | Menghubungi Admin via CTA | Pengunjung Umum | Must Have | +| UC-07 | Melihat Testimoni Penerima Beasiswa | Pengunjung Umum | Should Have | +| UC-08 | Mengganti Bahasa Tampilan (ID/EN) | Pengunjung Umum | Should Have | +| UC-09 | Memperbarui Data Beasiswa | Admin Prodi | Must Have | + +### 3.2 Detail Use Case + +#### UC-01: Melihat Daftar Beasiswa +| Field | Detail | +|---|---| +| Aktor | Pengunjung Umum | +| Precondition | Halaman berhasil dimuat di browser | +| Trigger | Pengunjung membuka URL atau scroll ke seksi Daftar Beasiswa | +| Main Flow | 1. Pengunjung buka URL halaman
2. Sistem tampilkan hero, statistik, daftar beasiswa
3. Kartu ditampilkan grid: 3 kolom desktop / 2 tablet / 1 mobile
4. Tiap kartu: thumbnail, badge status, nama, deskripsi singkat, tanggal, tombol "Selengkapnya"
5. Paginasi tampil di bawah grid jika beasiswa > 1 halaman | +| Alt Flow | 3a. Koneksi lambat → skeleton loading
3b. Tidak ada data → tampil "Belum ada beasiswa tersedia saat ini." | +| Postcondition | Pengunjung dapat melihat seluruh daftar beasiswa | + +#### UC-02: Memfilter Beasiswa Berdasarkan Kategori +| Field | Detail | +|---|---| +| Aktor | Pengunjung Umum | +| Precondition | Halaman dimuat, daftar beasiswa tampil | +| Trigger | Pengunjung klik salah satu tab filter | +| Main Flow | 1. Tampil tab: Semua \| Sedang Buka \| Ditutup \| Pemerintah \| Swasta
2. Pengunjung klik tab
3. Sistem real-time filter beasiswa sesuai kategori
4. Tab aktif ditandai bold/underline/warna
5. Jumlah hasil diperbarui | +| Alt Flow | 3a. Tidak ada hasil → "Tidak ada beasiswa pada kategori ini."
3b. Klik "Semua" → tampil semua beasiswa | +| Postcondition | Daftar beasiswa sesuai filter yang dipilih | + +#### UC-03: Mencari Beasiswa +| Field | Detail | +|---|---| +| Aktor | Pengunjung Umum | +| Precondition | Halaman dimuat, kolom pencarian tersedia | +| Trigger | Pengunjung mengetik di kolom pencarian | +| Main Flow | 1. Pengunjung klik kolom pencarian
2. Ketik kata kunci (misal: "Pertamina", "KIP", "luar negeri")
3. Sistem real-time filter kartu yang nama/deskripsinya cocok
4. Hapus kata kunci → kembali ke tampilan penuh
5. Filter dan pencarian dapat aktif bersamaan (kumulatif) | +| Alt Flow | 3a. Tidak ada hasil → "Tidak ditemukan beasiswa yang sesuai pencarian Anda." | +| Postcondition | Daftar beasiswa sesuai kata kunci | + +#### UC-04: Melihat Detail Beasiswa (Popup) +| Field | Detail | +|---|---| +| Aktor | Pengunjung Umum | +| Precondition | Kartu beasiswa tampil, pengunjung menemukan beasiswa yang diinginkan | +| Trigger | Klik tombol "Selengkapnya →" pada kartu | +| Main Flow | 1. Klik "Selengkapnya →"
2. Sistem tampilkan modal popup berisi: nama + thumbnail, badge status, syarat umum ringkasan, kontak, tombol "Info Lebih Lanjut" (→ URL sumber resmi di tab baru)
3. Background di-overlay gelap
4. Tutup via: tombol ×, klik di luar area, atau tekan Escape | +| Alt Flow | 4a. Klik "Info Lebih Lanjut" → jalankan UC-05 | +| Postcondition | Pengunjung mendapat info ringkas dan dapat lanjut ke sumber resmi | + +#### UC-05: Mengakses Sumber Informasi Beasiswa +| Field | Detail | +|---|---| +| Aktor | Pengunjung Umum | +| Precondition | Popup detail terbuka, tombol "Info Lebih Lanjut" tersedia | +| Trigger | Klik tombol "Info Lebih Lanjut" di popup | +| Main Flow | 1. Klik tombol
2. Sistem buka URL sumber resmi di tab baru
3. Popup di tab asal tetap terbuka | +| Alt Flow | 3a. URL tidak tersedia → "Tautan tidak tersedia. Silakan hubungi admin prodi." | +| Postcondition | Pengunjung diarahkan ke sumber resmi beasiswa | + +#### UC-06: Menghubungi Admin via CTA +| Field | Detail | +|---|---| +| Aktor | Pengunjung Umum | +| Precondition | Pengunjung ingin info lebih lanjut | +| Trigger | Scroll ke seksi CTA, klik salah satu tombol | +| Main Flow | 1. Scroll ke CTA ("Ingin Tahu Lebih Banyak tentang Beasiswa?")
2. Tampil dua tombol: "Hubungi Admin" (WhatsApp) + "Instagram Beasiswa" (IG kemahasiswaan)
3. Klik tombol → buka platform di tab baru | +| Alt Flow | 4a. Tanpa WhatsApp terinstall → buka WhatsApp Web | +| Postcondition | Pengunjung terhubung dengan admin atau follow Instagram | + +#### UC-07: Melihat Testimoni Penerima Beasiswa +| Field | Detail | +|---|---| +| Aktor | Pengunjung Umum | +| Precondition | Halaman dimuat, data testimoni tersedia di source code | +| Trigger | Scroll ke seksi Testimoni | +| Main Flow | 1. Scroll ke seksi Testimoni
2. Tampil kartu testimoni: foto, nama, nama beasiswa, kutipan singkat
3. Jika > 3 testimoni → navigasi carousel/tombol selanjutnya | +| Alt Flow | 2a. Belum ada data → seksi tidak ditampilkan atau tampil placeholder | +| Postcondition | Pengunjung mendapat gambaran pengalaman penerima beasiswa | + +#### UC-08: Mengganti Bahasa Tampilan (ID/EN) +| Field | Detail | +|---|---| +| Aktor | Pengunjung Umum | +| Precondition | Toggle ID\|EN tersedia di header navigasi | +| Trigger | Klik toggle bahasa di pojok kanan header | +| Main Flow | 1. Pengunjung lihat toggle ID \| EN di kanan atas
2. Klik bahasa yang diinginkan
3. Seluruh teks berubah tanpa reload
4. Pilihan tersimpan di session (tidak reset saat scroll/filter) | +| Alt Flow | 3a. Konten hanya tersedia 1 bahasa → tetap tampil bahasa aslinya | +| Postcondition | Halaman tampil dalam bahasa yang dipilih | + +#### UC-09: Memperbarui Data Beasiswa +| Field | Detail | +|---|---| +| Aktor | Admin Prodi | +| Precondition | Admin punya akses repo, ada info beasiswa baru/perubahan status | +| Trigger | Admin mendapat informasi update dari survei/portal/sumber lain | +| Main Flow | 1. Admin dapat info baru/perubahan status
2. Edit file data beasiswa (nama, kategori, status, syarat, kontak, URL)
3. Simpan dan push ke GitHub
4. Halaman publik auto-update dalam waktu singkat via Puify | +| Alt Flow | 3a. Error saat deploy → halaman publik tidak berubah, admin perbaiki dan push ulang | +| Postcondition | Info beasiswa terbaru tersedia di halaman publik 24/7 | + +--- + +## 4. Kebutuhan Antarmuka Eksternal + +### 4.1 Antarmuka Pengguna (UI) + +- Responsive design: breakpoint 320px (mobile), 768px (tablet), 1280px (desktop) +- Warna utama: Biru Informatika `#2B4590` dan Kuning `#F5A623` (branding UNTAN) +- Font: Inter atau Poppins, minimal 14px untuk body text +- Waktu respons antarmuka ≤ 3 detik pada koneksi 10 Mbps +- Aksesibilitas WCAG 2.1 level AA (kontras warna, ARIA label, navigasi keyboard) +- Semua elemen interaktif memiliki feedback visual saat hover/klik + +**Halaman / Seksi:** + +| Seksi | ID | Konten Utama | +|---|---|---| +| Header & Navigasi | — | Navbar sticky, logo UNTAN, toggle ID/EN, info ticker | +| Hero | `#hero` | Judul "Beasiswa Studi & Penelitian", deskripsi, CTA kuning, foto mahasiswa | +| Statistik Counter | `#statistics` | 3 angka animasi: Total Penerima, Pemerintah, Swasta | +| Direktori Beasiswa | `#directory` | Grid kartu, tab filter, real-time search, popup detail | +| Testimoni | `#testimonial` | Carousel foto+nama+kutipan penerima beasiswa | +| CTA | `#cta` | Banner ajakan + tombol WhatsApp & Instagram | +| Footer | `#footer` | Logo, alamat, kontak, sosial media, ilustrasi Pontianak | + +### 4.2 Antarmuka Hardware +- Browser modern: Chrome/Firefox/Edge ≥v100, Safari ≥v15 +- Koneksi minimal 1 Mbps; optimal 10 Mbps +- Resolusi minimal 320px lebar +- Tidak butuh hardware khusus (kamera, printer, sensor, dll.) + +### 4.3 Antarmuka Software + +| Layanan | Tujuan | Protokol | +|---|---|---| +| Dedicated Server + Puify | Hosting dev & production, auto-deploy dari GitHub | HTTPS | +| GitHub | Version control, kolaborasi, deliverable akhir | HTTPS/SSH | +| Sumber Resmi Beasiswa | Link eksternal di popup (dibuka tab baru) | HTTPS | +| WhatsApp / Instagram UNTAN | Tombol CTA | HTTPS / wa.me | +| Figma | Desain mockup & wireframe acuan implementasi | HTTPS | +| Web Scraper | Ambil data beasiswa dari sumber resmi | HTTPS | + +### 4.4 Antarmuka Komunikasi +- Semua file dikirim via HTTPS dengan sertifikat SSL/TLS valid +- Fitur interaktif (filter, search, toggle bahasa, popup, counter) berjalan client-side (JS) — tanpa request ke server +- Semua link eksternal: `target="_blank"` + `rel="noopener noreferrer"` +- Tidak menggunakan cookie, session storage, atau autentikasi pengguna (v1.0) + +--- + +## 5. Kebutuhan Non-Fungsional + +### NFR-01: Performa +- **P-01** Loading halaman ≤ 3 detik pada koneksi 10 Mbps +- **P-02** Filter beasiswa merespons < 0,5 detik setelah klik +- **P-03** Tetap responsif dan optimal di desktop, tablet, dan smartphone + +### NFR-02: Keamanan +- **S-01** Semua komunikasi via HTTPS dengan SSL/TLS +- **S-02** Source code bersih dari script berbahaya, bebas celah XSS +- **S-03** Semua link CTA dan pendaftaran mengarah ke sumber resmi tervalidasi + +### NFR-03: Skalabilitas +- **SC-01** Mampu menampilkan minimal 100 data beasiswa tanpa penurunan performa +- **SC-02** Struktur kode memungkinkan penambahan kategori baru tanpa perubahan besar +- **SC-03** Sistem bilingual mendukung penambahan bahasa baru di masa depan + +### NFR-04: Ketersediaan & Reliabilitas +- **R-01** Uptime minimal 99% selama masa operasional +- **R-02** Dapat diakses 24 jam selama server aktif +- **R-03** Backup source code via Git/GitHub untuk pemulihan data + +### NFR-05: Usability +- **U-01** Antarmuka bilingual ID/EN +- **U-02** Pengguna menemukan info beasiswa dalam < 2 menit via navigasi & filter +- **U-03** Tombol CTA di Hero kontras dan posisinya jelas + +### NFR-06: Maintainability +- **M-01** Tech stack: HTML5, CSS3 + Tailwind CSS, JavaScript ES6+ — kode rapi dan mudah dipelihara +- **M-02** Semua perubahan dikelola via Git/GitHub (version control) +- **M-03** Dokumentasi teknis & panduan deployment disertakan saat penyerahan akhir + +--- + +## 6. Batasan & Kendala + +### 6.1 Batasan Implementasi +- Tech stack terkunci: HTML5, CSS3, Tailwind CSS, JavaScript ES6+, Figma, Git/GitHub +- Single static landing page — tidak ada backend, database, atau login +- Harus berjalan optimal di Chrome, Firefox, Edge versi terbaru +- Wajib responsif: desktop, tablet, smartphone + +### 6.2 Batasan Proyek +- Durasi: 10 hari kerja (1 Mei – 11 Mei 2026) +- Tim: 5 orang dengan peran tetap (PM, Backend, Frontend, UI/UX, QA) +- Revisi antarmuka/konten sesuai batas yang disepakati +- Penambahan fitur baru saat development = di luar ruang lingkup utama + +### 6.3 Regulasi & Standar +- UU PDP No. 27/2022 untuk pengelolaan data testimoni mahasiswa +- Visual harus selaras branding resmi Informatika UNTAN +- Memenuhi prinsip aksesibilitas dasar (navigasi jelas, tampilan informatif) diff --git a/groups/ApeNameTeamE/assets/css/style.css b/groups/ApeNameTeamE/assets/css/style.css new file mode 100644 index 0000000..b5d684b --- /dev/null +++ b/groups/ApeNameTeamE/assets/css/style.css @@ -0,0 +1,1474 @@ +/* ===================================================== + INFORMATIKA UNTAN — Website Beasiswa + Custom CSS (Complementary to Tailwind CSS) + ===================================================== */ + +/* ===== CSS VARIABLES ===== */ +:root { + --color-primary: #003150; + --color-secondary: #feb404; + --color-bg: #FFFFFF; + --color-text: #1A1A1A; + --color-accent: #6B7280; + --color-success: #10B981; + --color-danger: #EF4444; + --color-overlay: rgba(0, 0, 0, 0.5); + --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + --font-serif: 'Roboto Condensed', sans-serif; + --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + --shadow-sm: 0 1px 3px rgba(0,0,0,0.08); + --shadow-card: 0 2px 12px rgba(0,0,0,0.08); + --shadow-card-hover: 0 8px 30px rgba(43,69,144,0.15); + --shadow-popup: 0 20px 60px rgba(0,0,0,0.3); + --radius: 12px; + --navbar-height: 108px; /* 60px top bar putih + 48px main nav kuning */ +} + +/* ===== BASE RESET ===== */ +*, *::before, *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + scroll-behavior: smooth; + font-size: 16px; +} + +body { + font-family: var(--font-sans); + color: var(--color-text); + line-height: 1.65; + overflow-x: hidden; + background: var(--color-bg); +} + +/* ===== SCROLLBAR ===== */ +::-webkit-scrollbar { width: 5px; } +::-webkit-scrollbar-track { background: #f1f5f9; } +::-webkit-scrollbar-thumb { + background: var(--color-primary); + border-radius: 3px; +} + +/* ===== STICKY NAVBAR ===== */ +#navbar { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + transition: var(--transition); +} + +/* ── Top Bar (DARK NAVY sesuai Figma) ── */ +.navbar-top { + background: #003150; + height: 60px; + display: flex; + align-items: center; +} + +/* Logo emblem */ +.navbar-logo-emblem { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; +} + +.navbar-logo-name { + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 15px; + font-weight: 800; + color: #ffffff; + line-height: 1; + letter-spacing: 0.5px; +} + +.navbar-logo-sub { + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 9px; + font-weight: 600; + color: rgba(255,255,255,0.55); + letter-spacing: 1px; + margin-top: 2px; +} + +/* "SATU UNTAN" text */ +.navbar-satu { + font-size: 11px; + font-weight: 700; + color: rgba(255,255,255,0.85); + letter-spacing: 0.5px; + text-transform: uppercase; +} + +/* Icon buttons on top bar (dark bg version) */ +.navbar-icon-btn { + width: 32px; + height: 32px; + border-radius: 50%; + background: rgba(255,255,255,0.12); + border: 1px solid rgba(255,255,255,0.2); + display: flex; + align-items: center; + justify-content: center; + color: rgba(255,255,255,0.8); + cursor: pointer; + transition: var(--transition); +} + +.navbar-icon-btn:hover { + background: rgba(255,255,255,0.22); + color: #ffffff; +} + +.navbar-search-btn { + width: 32px; + height: 32px; + border-radius: 50%; + background: none; + border: none; + display: flex; + align-items: center; + justify-content: center; + color: rgba(255,255,255,0.75); + cursor: pointer; + transition: var(--transition); +} + +.navbar-search-btn:hover { color: #ffffff; } + +/* Language Toggle — dark top bar */ +#lang-toggle { + display: flex; + align-items: center; + gap: 4px; +} + +.lang-btn { + padding: 0; + font-size: 11px; + font-weight: 500; + color: rgba(255,255,255,0.6); + cursor: pointer; + border: none; + background: none; + transition: var(--transition); + letter-spacing: 0.5px; +} + +.lang-btn:hover { + color: #ffffff; +} + +.lang-btn.active { + font-weight: 800; + color: #ffffff; +} + +.lang-divider { + color: rgba(255,255,255,0.4); + font-size: 10px; + margin: 0 2px; +} + +/* ── Main Nav Bar (KUNING) ── */ +.navbar-main { + background: var(--color-secondary); + height: 48px; + display: flex; + align-items: center; +} + +/* Nav links — teks gelap di atas latar kuning */ +.nav-link { + position: relative; + color: #0a1530; + text-decoration: none; + transition: color 0.2s; + white-space: nowrap; +} + +.nav-link:hover { + color: #000000; +} + +.nav-link.active { + color: #000000 !important; +} + +/* ===== INFO TICKER ===== */ +.ticker-wrapper { + background: var(--color-primary); + border-top: 1px solid rgba(255,255,255,0.05); + height: 40px; + display: flex; + align-items: center; + overflow: hidden; + + /* Sticky behavior */ + position: fixed; + top: 108px; + left: 0; + right: 0; + z-index: 40; + transform: translateY(-100%); + opacity: 0; + transition: transform 0.3s ease, opacity 0.3s ease; +} + +.ticker-wrapper.show-ticker { + transform: translateY(0); + opacity: 1; +} + +/* Badge wrapper */ +.ticker-badge-block { + flex-shrink: 0; + background: rgba(0,0,0,0.15); /* Slightly darker than primary */ + height: 100%; + display: flex; + align-items: center; + padding: 0 20px; + border-right: 1px solid rgba(255,255,255,0.1); + position: relative; + z-index: 2; +} + +/* Badge "INFO TERBARU" */ +.ticker-badge { + background: var(--color-secondary); + color: #1a1a1a; + font-size: 10px; + font-weight: 800; + padding: 4px 8px; + border-radius: 2px; + white-space: nowrap; + letter-spacing: 0.8px; + text-transform: uppercase; +} + +/* Area overflow ticker */ +.ticker-scroll-area { + flex: 1; + overflow: hidden; + height: 100%; + position: relative; + display: flex; + align-items: center; +} + +/* Inner wrapper: dua salinan teks side-by-side, dianimasikan */ +.ticker-inner { + display: flex; + align-items: center; + animation: ticker-scroll 40s linear infinite; + will-change: transform; +} + +.ticker-inner:hover { + animation-play-state: paused; +} + +/* Setiap salinan teks ticker */ +.ticker-track { + display: inline-flex; + align-items: center; + white-space: nowrap; + font-size: 12px; + font-weight: 500; + color: rgba(255,255,255,0.85); + padding-left: 20px; +} + +@keyframes ticker-scroll { + 0% { transform: translateX(0); } + 100% { transform: translateX(-50%); } +} + +/* ===== HERO SECTION ===== */ +.hero-section { + min-height: 500px; + position: relative; + display: flex; + align-items: center; + padding: 48px 0 60px; + overflow: hidden; +} + +/* Background — solid dark blue sesuai Figma */ +.hero-bg { + position: absolute; + inset: 0; + background: #003150; + z-index: 0; +} + +/* Subtle dot grid overlay */ +.hero-bg::before { + content: ''; + position: absolute; + inset: 0; + background-image: + radial-gradient(circle at 10% 80%, rgba(245,166,35,0.08) 0%, transparent 40%), + radial-gradient(circle at 90% 20%, rgba(255,255,255,0.03) 0%, transparent 35%); +} + +.hero-bg::after { + content: ''; + position: absolute; + inset: 0; + background-image: radial-gradient(rgba(255,255,255,0.025) 1px, transparent 1px); + background-size: 28px 28px; +} + +.hero-content { + position: relative; + z-index: 10; +} + +/* Badge hero — outline style sesuai Figma (border kuning, bg transparan) */ +.hero-badge { + display: inline-flex; + align-items: center; + gap: 6px; + border: 1.5px solid var(--color-secondary); + color: var(--color-secondary); + background: rgba(245, 166, 35, 0.08); + font-size: 11px; + font-weight: 700; + padding: 6px 16px; + border-radius: 999px; + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 20px; +} + +.hero-title { + font-family: var(--font-serif); + font-size: clamp(36px, 5vw, 60px); + font-weight: 800; + color: white; + line-height: 1.15; + margin-bottom: 12px; +} + +.hero-subtitle { + font-size: 15px; + color: rgba(255,255,255,0.75); + font-style: italic; + margin-bottom: 16px; +} + +.hero-desc { + font-size: 14px; + color: rgba(255,255,255,0.65); + line-height: 1.7; + max-width: 440px; + margin-bottom: 32px; +} + +/* CTA button — kuning solid, teks gelap (sesuai Figma) */ +.hero-cta { + display: inline-flex; + align-items: center; + gap: 8px; + background: var(--color-secondary); + color: #1a1a1a; + font-weight: 700; + font-size: 14px; + padding: 13px 26px; + border-radius: 8px; + text-decoration: none; + transition: var(--transition); + box-shadow: 0 4px 16px rgba(245,166,35,0.35); +} + +.hero-cta:hover { + background: #e8960f; + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(245,166,35,0.45); + color: #1a1a1a; +} + +.hero-cta i { + transition: transform 0.3s; + font-size: 13px; +} + +.hero-cta:hover i { transform: translateX(4px); } + +/* Hero image — foto lebih besar dan rounded sesuai Figma */ +.hero-image-wrap { + position: relative; + max-width: 480px; + margin-left: auto; +} + +.hero-image-wrap img { + width: 100%; + height: 400px; + object-fit: cover; + border-radius: 16px; + box-shadow: 0 20px 50px rgba(0,0,0,0.45); + border: 2px solid rgba(255,255,255,0.1); + display: block; +} + +/* Small decorative circle */ +.hero-image-wrap::before { + content: ''; + position: absolute; + bottom: -12px; + right: -12px; + width: 60px; + height: 60px; + border: 3px solid var(--color-secondary); + border-radius: 50%; + opacity: 0.3; + z-index: -1; +} + +/* ===== STATISTICS SECTION ===== */ +.stats-section { + background: var(--color-secondary); + padding: 36px 0; +} + +.stat-item { + text-align: center; + padding: 0 20px; + position: relative; +} + +.stat-item + .stat-item::before { + content: ''; + position: absolute; + left: 0; + top: 15%; + height: 70%; + width: 1px; + background: rgba(255,255,255,0.35); +} + +.stat-number { + font-family: var(--font-serif); + font-size: clamp(36px, 5vw, 52px); + font-weight: 800; + color: #1a1a1a; + line-height: 1; + letter-spacing: -1px; +} + +.stat-label { + font-size: 11px; + color: #2d2d2d; + margin-top: 8px; + line-height: 1.45; + font-weight: 500; +} + +/* ===== SECTION LABEL & BADGE ===== */ +.section-badge { + display: inline-flex; + align-items: center; + border: 1px solid rgba(245, 166, 35, 0.4); + background: rgba(245, 166, 35, 0.12); + color: var(--color-secondary); + font-size: 11px; + font-weight: 700; + padding: 5px 14px; + border-radius: 999px; + text-transform: uppercase; + letter-spacing: 1px; +} + +.section-label { + font-size: 11px; + font-weight: 800; + color: var(--color-secondary); + text-transform: uppercase; + letter-spacing: 2px; + display: block; + margin-bottom: 6px; +} + +.section-title { + font-family: var(--font-serif); + font-size: clamp(32px, 4vw, 42px); + font-weight: 800; + color: #003150; + line-height: 1.2; + margin-bottom: 12px; + letter-spacing: -0.5px; +} + +.section-desc { + font-size: 14px; + color: #64748b; + line-height: 1.65; + max-width: 600px; +} + +/* Button Panduan Beasiswa */ +.btn-panduan { + display: inline-flex; + align-items: center; + gap: 8px; + background: rgba(245, 166, 35, 0.12); + border: 1px solid rgba(245, 166, 35, 0.3); + color: var(--color-secondary); + font-weight: 600; + font-size: 13px; + padding: 10px 20px; + border-radius: 6px; + text-decoration: none; + transition: var(--transition); +} + +.btn-panduan:hover { + background: rgba(245, 166, 35, 0.2); + border-color: rgba(245, 166, 35, 0.5); +} + +/* ===== FILTER TABS ===== */ +.filter-tabs { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; +} + +.filter-tab { + padding: 8px 20px; + font-size: 12px; + font-weight: 600; + border-radius: 999px; + border: 1px solid #e5e7eb; + background: white; + color: #4b5563; + cursor: pointer; + transition: var(--transition); + white-space: nowrap; + letter-spacing: 0.3px; +} + +.filter-tab:hover { + border-color: #d1d5db; + color: #003150; + background: #f9fafb; +} + +.filter-tab.active { + background: #003150; + color: white; + border-color: #003150; + box-shadow: none; +} + +/* ===== SEARCH INPUT ===== */ +.search-wrapper { + position: relative; +} + +.search-input { + width: 100%; + padding: 9px 16px 9px 38px; + border: 1px solid #e5e7eb; + border-radius: 999px; + font-size: 13px; + font-family: var(--font-inter); + color: var(--color-text); + outline: none; + transition: var(--transition); + background: white; +} + +.search-input:focus { + border-color: var(--color-primary); + box-shadow: 0 0 0 3px rgba(43,69,144,0.08); +} + +.search-input::placeholder { + color: #9ca3af; +} + +.search-icon { + position: absolute; + left: 14px; + top: 50%; + transform: translateY(-50%); + color: #9ca3af; + font-size: 13px; + pointer-events: none; +} + +/* ===== SORT BUTTON ===== */ +.btn-sort { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 9px 20px; + background: white; + border: 1px solid #e5e7eb; + border-radius: 999px; + color: #4b5563; + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: var(--transition); + white-space: nowrap; +} + +.btn-sort:hover { + background: #f9fafb; + border-color: #d1d5db; + color: #003150; +} + +/* ===== SCHOLARSHIP CARDS ===== */ +.scholarship-card { + background: white; + border-radius: var(--radius); + box-shadow: var(--shadow-card); + overflow: hidden; + transition: var(--transition); + border: 1px solid #f0f4f8; + display: flex; + flex-direction: column; + position: relative; + cursor: default; +} + +.scholarship-card:hover { + box-shadow: var(--shadow-card-hover); + transform: translateY(-5px); + border-color: rgba(43,69,144,0.1); +} + +.card-img-wrap { + width: 100%; + height: 165px; + overflow: hidden; + background: #f0f4ff; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.card-img-wrap img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease; +} + +.scholarship-card:hover .card-img-wrap img { + transform: scale(1.04); +} + +.card-body { + padding: 16px; + flex: 1; + display: flex; + flex-direction: column; +} + +.badge-status { + display: inline-flex; + align-items: center; + gap: 5px; + font-size: 10px; + font-weight: 700; + padding: 3px 10px; + border-radius: 999px; + text-transform: uppercase; + letter-spacing: 0.5px; + align-self: flex-start; + margin-bottom: 8px; +} + +.badge-buka { + background: #d1fae5; + color: #065f46; +} + +.badge-buka::before { + content: '●'; + font-size: 8px; +} + +.badge-ditutup { + background: #fee2e2; + color: #991b1b; +} + +.badge-ditutup::before { + content: '○'; + font-size: 8px; +} + +.card-title { + font-size: 14px; + font-weight: 700; + color: var(--color-primary); + line-height: 1.4; + margin-bottom: 8px; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.card-desc { + font-size: 12px; + color: var(--color-accent); + line-height: 1.55; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + flex: 1; + margin-bottom: 10px; +} + +.card-date { + display: flex; + align-items: center; + gap: 6px; + font-size: 11px; + color: #94a3b8; +} + +.card-date i { + color: var(--color-secondary); + font-size: 10px; +} + +.card-footer { + padding: 12px 16px; + border-top: 1px solid #f1f5f9; +} + +.btn-selengkapnya { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12px; + font-weight: 700; + color: var(--color-secondary); + background: none; + border: none; + cursor: pointer; + padding: 0; + transition: var(--transition); + font-family: var(--font-inter); +} + +.btn-selengkapnya:hover { + color: var(--color-primary); + gap: 10px; +} + +/* ===== EMPTY STATE ===== */ +.empty-state { + grid-column: 1 / -1; + text-align: center; + padding: 64px 24px; + color: #94a3b8; +} + +.empty-state i { + font-size: 48px; + color: #e2e8f0; + margin-bottom: 16px; + display: block; +} + +/* ===== PAGINATION ===== */ +.pagination-container { + display: flex; + align-items: center; + gap: 6px; + justify-content: center; + margin-top: 40px; +} + +.page-btn { + width: 38px; + height: 38px; + border-radius: 8px; + border: 2px solid #e2e8f0; + background: white; + color: #64748b; + font-size: 13px; + font-weight: 600; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: var(--transition); + font-family: var(--font-inter); +} + +.page-btn:hover:not(:disabled) { + border-color: var(--color-primary); + color: var(--color-primary); + background: #eff3ff; +} + +.page-btn.active { + background: var(--color-primary); + border-color: var(--color-primary); + color: white; + box-shadow: 0 4px 12px rgba(43,69,144,0.3); +} + +.page-btn:disabled { + opacity: 0.38; + cursor: not-allowed; +} + +/* ===== POPUP MODAL ===== */ +#popup-overlay { + position: fixed; + inset: 0; + z-index: 9999; + display: none; + align-items: center; + justify-content: center; + padding: 16px; +} + +#popup-overlay.show { + display: flex; +} + +.popup-backdrop { + position: absolute; + inset: 0; + background: var(--color-overlay); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); +} + +.popup-modal { + position: relative; + background: white; + border-radius: 20px; + box-shadow: var(--shadow-popup); + width: 100%; + max-width: 500px; + max-height: 90vh; + overflow-y: auto; + z-index: 10; + transition: opacity 0.25s ease, transform 0.25s ease; + opacity: 0; + transform: scale(0.92) translateY(8px); +} + +#popup-overlay.show .popup-modal { + opacity: 1; + transform: scale(1) translateY(0); +} + +.popup-close { + position: absolute; + top: 14px; + right: 14px; + z-index: 20; + width: 34px; + height: 34px; + border-radius: 50%; + background: rgba(255,255,255,0.9); + backdrop-filter: blur(4px); + border: none; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + color: #374151; + font-size: 14px; + transition: var(--transition); + box-shadow: 0 2px 8px rgba(0,0,0,0.12); +} + +.popup-close:hover { + background: #f1f5f9; + transform: rotate(90deg); +} + +.popup-hero { + width: 100%; + height: 200px; + object-fit: cover; + display: block; + border-radius: 20px 20px 0 0; +} + +.popup-hero-logo { + width: 100%; + height: 200px; + background: linear-gradient(135deg, #EEF2FF 0%, #E0E7FF 100%); + display: flex; + align-items: center; + justify-content: center; + border-radius: 20px 20px 0 0; +} + +.popup-hero-logo img { + max-height: 100px; + max-width: 75%; + object-fit: contain; +} + +.popup-body { + padding: 24px; +} + +.popup-kategori-row { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 12px; +} + +.popup-kategori { + font-size: 11px; + color: var(--color-accent); + font-weight: 600; + background: #f1f5f9; + padding: 3px 10px; + border-radius: 999px; +} + +.popup-title { + font-family: var(--font-serif); + font-size: 20px; + font-weight: 700; + color: var(--color-primary); + line-height: 1.3; + margin-bottom: 10px; +} + +.popup-desc { + font-size: 13px; + color: #4b5563; + line-height: 1.65; + margin-bottom: 20px; +} + +.popup-section-title { + font-size: 12px; + font-weight: 700; + color: #374151; + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.popup-section-title i { + color: var(--color-secondary); +} + +.syarat-list { + list-style: none; + display: flex; + flex-direction: column; + gap: 8px; + margin-bottom: 20px; +} + +.syarat-list li { + display: flex; + align-items: flex-start; + gap: 8px; + font-size: 13px; + color: #4b5563; + line-height: 1.5; +} + +.syarat-list li i { + color: var(--color-success); + font-size: 11px; + margin-top: 3px; + flex-shrink: 0; +} + +.popup-periode { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; + background: #f8fafc; + border-radius: 10px; + padding: 14px 16px; + margin-bottom: 20px; +} + +.popup-periode-item label { + font-size: 10px; + color: #94a3b8; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + display: block; + margin-bottom: 4px; +} + +.popup-periode-item span { + font-size: 13px; + font-weight: 600; + color: #374151; +} + +.popup-kontak { + background: #fffbf0; + border: 1px solid #fde68a; + border-radius: 10px; + padding: 12px 14px; + margin-bottom: 20px; + font-size: 13px; + color: #92400e; + display: flex; + align-items: flex-start; + gap: 8px; +} + +.popup-kontak i { + color: var(--color-secondary); + margin-top: 1px; + flex-shrink: 0; +} + +.popup-cta { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + width: 100%; + background: var(--color-primary); + color: white; + font-weight: 700; + font-size: 14px; + padding: 14px 20px; + border-radius: 12px; + text-decoration: none; + transition: var(--transition); + border: none; + cursor: pointer; +} + +.popup-cta:hover { + background: #1e3272; + transform: translateY(-1px); + box-shadow: 0 6px 20px rgba(43,69,144,0.3); + color: white; +} + +.popup-cta.disabled { + background: #94a3b8; + pointer-events: none; +} + +.popup-cta i { + transition: transform 0.3s; +} + +.popup-cta:hover i { + transform: translateX(4px); +} + +/* ===== TESTIMONIALS ===== */ +.testimonials-section { + background: #f8fafc; + padding: 72px 0; +} + +.testimonial-card { + background: white; + border-radius: 16px; + padding: 28px 22px; + text-align: center; + box-shadow: 0 4px 20px rgba(0,0,0,0.06); + transition: var(--transition); + border: 1px solid #f0f4f8; + height: 100%; +} + +.testimonial-card:hover { + box-shadow: 0 10px 36px rgba(43,69,144,0.12); + transform: translateY(-5px); +} + +.testimonial-avatar { + width: 82px; + height: 82px; + border-radius: 50%; + object-fit: cover; + margin: 0 auto 16px; + border: 3px solid var(--color-secondary); + display: block; +} + +.testimonial-name { + font-family: var(--font-serif); + font-size: 15px; + font-weight: 700; + color: var(--color-primary); + margin-bottom: 4px; +} + +.testimonial-beasiswa { + font-size: 11px; + color: var(--color-secondary); + font-weight: 600; + margin-bottom: 14px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.testimonial-quote { + font-size: 13px; + color: #4b5563; + line-height: 1.65; + font-style: italic; + position: relative; +} + +/* Swiper custom styles */ +.swiper-pagination-bullet { + background: #cbd5e1 !important; + opacity: 1 !important; + width: 8px !important; + height: 8px !important; + transition: var(--transition); +} + +.swiper-pagination-bullet-active { + background: var(--color-secondary) !important; + width: 24px !important; + border-radius: 4px !important; +} + +/* ===== CTA SECTION ===== */ +.cta-section { + padding: 72px 0; + background: #f8fafc; +} + +.cta-card { + background: #003150; + border-radius: 24px; + padding: 64px 40px; + text-align: center; + position: relative; + overflow: hidden; +} + +.cta-card::before, +.cta-card::after { + content: ''; + position: absolute; + border-radius: 50%; + background: rgba(255,255,255,0.04); +} + +.cta-card::before { + width: 300px; + height: 300px; + top: -100px; + right: -80px; +} + +.cta-card::after { + width: 200px; + height: 200px; + bottom: -60px; + left: -60px; +} + +.cta-title { + font-family: var(--font-serif); + font-size: clamp(22px, 3vw, 30px); + font-weight: 700; + color: white; + margin-bottom: 12px; + position: relative; + z-index: 1; +} + +.cta-desc { + font-size: 14px; + color: rgba(255,255,255,0.68); + max-width: 420px; + margin: 0 auto 32px; + line-height: 1.65; + position: relative; + z-index: 1; +} + +.cta-buttons { + display: flex; + gap: 14px; + justify-content: center; + flex-wrap: wrap; + position: relative; + z-index: 1; +} + +.cta-btn-primary { + display: inline-flex; + align-items: center; + gap: 8px; + background: var(--color-secondary); + color: #0a1530; + font-weight: 700; + font-size: 13px; + padding: 13px 26px; + border-radius: 8px; + text-decoration: none; + transition: var(--transition); + box-shadow: 0 4px 16px rgba(245,166,35,0.4); +} + +.cta-btn-primary:hover { + background: #e8960f; + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(245,166,35,0.5); + color: #0a1530; +} + +.cta-btn-secondary { + display: inline-flex; + align-items: center; + gap: 8px; + background: transparent; + border: 2px solid rgba(255,255,255,0.5); + color: white; + font-weight: 700; + font-size: 13px; + padding: 11px 26px; + border-radius: 10px; + text-decoration: none; + transition: var(--transition); + cursor: pointer; +} + + +.cta-btn-secondary:hover { + background: rgba(255,255,255,0.12); + border-color: white; + color: white; + transform: translateY(-2px); +} + +/* ===== FOOTER ===== */ +.site-footer { + background: var(--color-primary); + color: white; + position: relative; + overflow: hidden; +} + +.footer-top { + padding: 52px 0 32px; +} + +.footer-follow-title { + text-align: center; + color: white; + font-size: 11px; + font-weight: 700; + letter-spacing: 2px; + margin-bottom: 12px; +} + +.social-icons { + display: flex; + justify-content: center; + gap: 16px; + margin-bottom: 40px; +} + +.social-icon { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-size: 16px; + transition: var(--transition); + text-decoration: none; +} + +.social-icon:hover { + color: var(--color-secondary); + transform: translateY(-2px); +} + +.footer-logo { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + margin-bottom: 20px; +} + +.footer-logo img { + height: 44px; + width: auto; + object-fit: contain; +} + +.footer-logo-text { + text-align: left; + margin-left: 8px; +} + +.footer-logo-text .name { + font-family: var(--font-serif); + font-size: 20px; + font-weight: 700; + color: white; + line-height: 1.2; + letter-spacing: 2px; +} + +.footer-logo-text .sub { + font-size: 10px; + color: rgba(255,255,255,0.7); + margin-top: 2px; + letter-spacing: 1px; +} + +.footer-address { + text-align: center; + color: rgba(255,255,255,0.6); + font-size: 12px; + line-height: 1.8; + margin-top: 32px; +} + +.footer-address i { + color: var(--color-secondary); +} + +.address-main { + margin-bottom: 16px; +} + +.address-contact { + font-size: 11px; + color: rgba(255,255,255,0.5); + margin-bottom: 40px; +} + +.footer-divider { + border: none; + border-top: 1px solid rgba(255,255,255,0.08); + margin: 28px 0 20px; +} + +.footer-copy { + text-align: center; + font-size: 11px; + color: rgba(255,255,255,0.28); + padding-bottom: 28px; +} + +.footer-illustration { + width: 100%; + display: block; + max-height: 180px; + object-fit: cover; + object-position: top; +} + +/* ===== BREADCRUMB ===== */ +.breadcrumb { + display: flex; + align-items: center; + gap: 8px; + font-size: 11px; + color: rgba(255,255,255,0.5); + margin-bottom: 24px; +} + +.breadcrumb a { + color: rgba(255,255,255,0.5); + text-decoration: none; + transition: color 0.2s; +} + +.breadcrumb a:hover { + color: rgba(255,255,255,0.85); +} + +.breadcrumb .sep { + font-size: 9px; +} + +.breadcrumb .current { + color: rgba(255,255,255,0.85); +} + +/* ===== ANIMATIONS ===== */ +@keyframes fadeInUp { + from { opacity: 0; transform: translateY(18px); } + to { opacity: 1; transform: translateY(0); } +} + +.fade-in-up { + animation: fadeInUp 0.45s ease forwards; +} + +/* Skeleton loading */ +.skeleton { + background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%); + background-size: 200% 100%; + animation: shimmer 1.6s infinite; + border-radius: 8px; +} + +@keyframes shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +/* ===== RESPONSIVE ===== */ +@media (max-width: 767px) { + :root { --navbar-height: 104px; } + + .hero-section { padding: 32px 0 48px; min-height: auto; } + .hero-title { font-size: 32px; } + .hero-image-wrap { display: none; } + + .stats-section { padding: 24px 0; } + .stat-item + .stat-item::before { display: none; } + + .cta-card { padding: 40px 20px; } + + .filter-tabs { gap: 6px; } + .filter-tab { padding: 7px 12px; font-size: 10px; } + + .popup-modal { border-radius: 14px; } + .popup-periode { grid-template-columns: 1fr; } + + .testimonial-card { padding: 22px 16px; } +} + +@media (min-width: 768px) and (max-width: 1023px) { + .hero-image-wrap img { height: 300px; } +} + +@media (min-width: 1024px) { + .hero-section { min-height: 540px; } +} diff --git a/groups/ApeNameTeamE/assets/images/hero/mahasiswa.png b/groups/ApeNameTeamE/assets/images/hero/mahasiswa.png new file mode 100644 index 0000000..b8244c2 Binary files /dev/null and b/groups/ApeNameTeamE/assets/images/hero/mahasiswa.png differ diff --git a/groups/ApeNameTeamE/assets/images/hero/pontianak-illustration.png b/groups/ApeNameTeamE/assets/images/hero/pontianak-illustration.png new file mode 100644 index 0000000..922a0e0 Binary files /dev/null and b/groups/ApeNameTeamE/assets/images/hero/pontianak-illustration.png differ diff --git a/groups/ApeNameTeamE/assets/images/logo/logo-untan.png b/groups/ApeNameTeamE/assets/images/logo/logo-untan.png new file mode 100644 index 0000000..3d45d4e Binary files /dev/null and b/groups/ApeNameTeamE/assets/images/logo/logo-untan.png differ diff --git a/groups/ApeNameTeamE/assets/js/carousel.js b/groups/ApeNameTeamE/assets/js/carousel.js new file mode 100644 index 0000000..3f8ad16 --- /dev/null +++ b/groups/ApeNameTeamE/assets/js/carousel.js @@ -0,0 +1,109 @@ +// ===================================================== +// carousel.js — Swiper.js Carousel Testimoni +// Touch-friendly, auto-play, responsive breakpoints +// ===================================================== + +let testimoniSwiper = null; + +/** Render slide testimoni ke dalam swiper-wrapper */ +function renderTestimoniSlides(data) { + const wrapper = document.getElementById('testimonial-wrapper'); + if (!wrapper) return; + + wrapper.innerHTML = data.map(t => ` +
+
+ Foto ${t.nama} +
+ ${t.nama.charAt(0).toUpperCase()} +
+ +
${t.nama}
+
${t.nama_beasiswa}
+

"${t.kutipan}"

+
+
+ `).join(''); +} + +/** Inisialisasi Swiper setelah slide di-render */ +function initSwiper(count) { + if (testimoniSwiper) { + testimoniSwiper.destroy(true, true); + testimoniSwiper = null; + } + + testimoniSwiper = new Swiper('.testimonial-swiper', { + slidesPerView: 1, + spaceBetween: 24, + loop: count > 3, + centerInsufficientSlides: true, + autoplay: { + delay: 4500, + disableOnInteraction: false, + pauseOnMouseEnter: true, + }, + pagination: { + el: '.testimonial-pagination', + clickable: true, + }, + grabCursor: true, + breakpoints: { + 640: { slidesPerView: 2 }, + 1024: { slidesPerView: 3 }, + }, + a11y: { + prevSlideMessage: 'Slide sebelumnya', + nextSlideMessage: 'Slide berikutnya', + }, + }); +} + +/** Fetch data testimoni dan render */ +async function initCarousel() { + const section = document.getElementById('testimonial'); + + try { + const res = await fetch('data/testimoni.json'); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + + const data = await res.json(); + + if (!data || data.length === 0) { + // Sembunyikan seksi testimoni jika data kosong (sesuai UC-07 Alt Flow) + section?.classList.add('hidden'); + return; + } + + renderTestimoniSlides(data); + + // Init Swiper setelah DOM di-render + requestAnimationFrame(() => initSwiper(data.length)); + + } catch { + // Jika gagal fetch, sembunyikan seksi (graceful degradation) + section?.classList.add('hidden'); + } +} + +document.addEventListener('DOMContentLoaded', initCarousel); diff --git a/groups/ApeNameTeamE/assets/js/counter.js b/groups/ApeNameTeamE/assets/js/counter.js new file mode 100644 index 0000000..b68851a --- /dev/null +++ b/groups/ApeNameTeamE/assets/js/counter.js @@ -0,0 +1,53 @@ +// ===================================================== +// counter.js — Animasi Counter Statistik +// Menggunakan IntersectionObserver + requestAnimationFrame +// ===================================================== + +/** + * Animasi angka dari 0 ke nilai target + * @param {HTMLElement} el - Elemen yang menampilkan angka + * @param {number} target - Angka target + * @param {number} duration - Durasi animasi dalam ms + */ +function animateCounter(el, target, duration = 1800) { + const startTime = performance.now(); + + function update(currentTime) { + const elapsed = currentTime - startTime; + const progress = Math.min(elapsed / duration, 1); + + // Ease out cubic — percepat di awal, lambat di akhir + const eased = 1 - Math.pow(1 - progress, 3); + const current = Math.round(eased * target); + + el.textContent = current; + + if (progress < 1) { + requestAnimationFrame(update); + } + } + + requestAnimationFrame(update); +} + +function initCounters() { + const counters = document.querySelectorAll('[data-counter]'); + if (!counters.length) return; + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach(entry => { + if (entry.isIntersecting && !entry.target.dataset.animated) { + entry.target.dataset.animated = 'true'; + const target = parseInt(entry.target.dataset.counter, 10) || 0; + animateCounter(entry.target, target); + } + }); + }, + { threshold: 0.6 } + ); + + counters.forEach(el => observer.observe(el)); +} + +document.addEventListener('DOMContentLoaded', initCounters); diff --git a/groups/ApeNameTeamE/assets/js/filter.js b/groups/ApeNameTeamE/assets/js/filter.js new file mode 100644 index 0000000..adc1ac6 --- /dev/null +++ b/groups/ApeNameTeamE/assets/js/filter.js @@ -0,0 +1,242 @@ +// ===================================================== +// filter.js — Fetch JSON, Render Kartu, Filter Tab, Pencarian, Paginasi +// Filter dan search berjalan KUMULATIF (sesuai PROJECT_CONTEXT rule #6) +// ===================================================== + +const ITEMS_PER_PAGE = 6; // 2 baris × 3 kolom desktop + +let allData = []; // Semua data beasiswa dari JSON +let activeFilter = 'semua'; +let searchKeyword = ''; +let currentPage = 1; + +// Format tanggal +function formatDate(str) { + if (!str) return '—'; + const d = new Date(str); + if (isNaN(d.getTime())) return str; + return d.toLocaleDateString('id-ID', { + day: 'numeric', month: 'long', year: 'numeric' + }); +} + +// Sanitasi string untuk mencegah XSS pada search +function sanitize(str) { + return str.replace(/[<>&"']/g, c => + ({ '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[c]) + ); +} + +/** + * Buat elemen kartu beasiswa + * Gunakan textContent/setAttribute — hindari langsung innerHTML dari user input + */ +function createCard(bsw) { + const isBuka = bsw.status === 'Buka'; + + const article = document.createElement('article'); + article.className = 'scholarship-card fade-in-up'; + article.setAttribute('role', 'listitem'); + article.setAttribute('data-id', bsw.id); + + article.innerHTML = ` +
+ ${bsw.nama} +
+
+ + ${bsw.status} + +

${bsw.nama}

+

${bsw.deskripsi_singkat}

+
+ + ${formatDate(bsw.tanggal_tutup)} +
+
+ + `; + + return article; +} + +/** + * Filter data KUMULATIF: filter tab DAN search harus terpenuhi keduanya + */ +function getFiltered() { + const kw = searchKeyword.toLowerCase(); + + return allData.filter(bsw => { + // Cocok dengan filter tab + const matchFilter = + activeFilter === 'semua' || + bsw.status === activeFilter || + bsw.kategori === activeFilter; + + // Cocok dengan pencarian (nama atau deskripsi atau tags) + const matchSearch = + !kw || + bsw.nama.toLowerCase().includes(kw) || + bsw.deskripsi_singkat.toLowerCase().includes(kw) || + (bsw.tags || []).some(t => t.toLowerCase().includes(kw)); + + return matchFilter && matchSearch; + }); +} + +/** Render kartu + paginasi ke DOM */ +function renderCards() { + const grid = document.getElementById('beasiswa-grid'); + const pagCont = document.getElementById('pagination'); + const filtered = getFiltered(); + + // Bersihkan grid + grid.innerHTML = ''; + + if (filtered.length === 0) { + grid.innerHTML = ` +
+ +

+ Tidak ada beasiswa ditemukan +

+

+ Coba ubah filter atau kata kunci pencarian Anda +

+
`; + pagCont.innerHTML = ''; + return; + } + + // Hitung paginasi + const totalPages = Math.ceil(filtered.length / ITEMS_PER_PAGE); + if (currentPage > totalPages) currentPage = totalPages; + + const start = (currentPage - 1) * ITEMS_PER_PAGE; + const items = filtered.slice(start, start + ITEMS_PER_PAGE); + + // Render kartu dengan delay animasi berurutan + items.forEach((bsw, i) => { + const card = createCard(bsw); + card.style.animationDelay = `${i * 55}ms`; + grid.appendChild(card); + }); + + renderPagination(totalPages, pagCont); +} + +/** Render tombol-tombol paginasi */ +function renderPagination(total, container) { + container.innerHTML = ''; + if (total <= 1) return; + + const make = (content, page, disabled = false, isActive = false) => { + const btn = document.createElement('button'); + btn.className = `page-btn${isActive ? ' active' : ''}`; + btn.innerHTML = content; + btn.disabled = disabled; + btn.setAttribute('aria-label', typeof page === 'number' ? `Halaman ${page}` : content); + if (!disabled) { + btn.addEventListener('click', () => { + currentPage = page; + renderCards(); + // Scroll halus ke atas direktori + const dir = document.getElementById('directory'); + if (dir) { + const top = dir.getBoundingClientRect().top + window.scrollY - 120; + window.scrollTo({ top, behavior: 'smooth' }); + } + }); + } + return btn; + }; + + // Prev + container.appendChild(make('', currentPage - 1, currentPage === 1)); + + // Halaman + for (let i = 1; i <= total; i++) { + container.appendChild(make(i, i, false, i === currentPage)); + } + + // Next + container.appendChild(make('', currentPage + 1, currentPage === total)); +} + +/** Inisialisasi tab filter */ +function initFilterTabs() { + document.querySelectorAll('.filter-tab').forEach(btn => { + btn.addEventListener('click', () => { + document.querySelectorAll('.filter-tab').forEach(b => { + b.classList.remove('active'); + b.setAttribute('aria-selected', 'false'); + }); + btn.classList.add('active'); + btn.setAttribute('aria-selected', 'true'); + activeFilter = btn.dataset.filter; + currentPage = 1; + renderCards(); + }); + }); +} + +/** Inisialisasi real-time search */ +function initSearch() { + const input = document.getElementById('search-input'); + if (!input) return; + + input.addEventListener('input', () => { + // Sanitasi input sebelum digunakan (cegah XSS) + searchKeyword = sanitize(input.value).trim(); + currentPage = 1; + renderCards(); + }); +} + +/** Fetch data JSON dan render */ +async function initDirectory() { + const grid = document.getElementById('beasiswa-grid'); + + try { + const res = await fetch('data/beasiswa.json'); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + + allData = await res.json(); + + // Simpan ke window agar popup.js bisa akses + window.beasiswaData = allData; + + renderCards(); + } catch (err) { + grid.innerHTML = ` +
+ +

+ Gagal memuat data beasiswa +

+

+ Pastikan menggunakan live server. Silakan refresh atau hubungi admin. +

+
`; + } +} + +document.addEventListener('DOMContentLoaded', () => { + initFilterTabs(); + initSearch(); + initDirectory(); +}); diff --git a/groups/ApeNameTeamE/assets/js/i18n.js b/groups/ApeNameTeamE/assets/js/i18n.js new file mode 100644 index 0000000..963b8fc --- /dev/null +++ b/groups/ApeNameTeamE/assets/js/i18n.js @@ -0,0 +1,128 @@ +// ===================================================== +// i18n.js — Toggle Bahasa Indonesia / English +// Sesuai PROJECT_CONTEXT: tersimpan di sessionStorage +// ===================================================== + +const i18nData = { + id: { + 'nav.tentang': 'TENTANG KAMI', + 'nav.program': 'PROGRAM', + 'nav.sdm': 'SDM', + 'nav.fasilitas': 'FASILITAS', + 'nav.agenda': 'KARYA & AGENDA', + 'nav.kontak': 'KONTAK', + 'breadcrumb.home': 'Beranda', + 'breadcrumb.profile': 'Profil', + 'breadcrumb.scholarship': 'Beasiswa', + 'hero.badge': 'Program Beasiswa', + 'hero.title': 'Beasiswa Studi &
Penelitian', + 'hero.subtitle': 'Teknik Informatika Universitas Tanjungpura', + 'hero.desc': 'Temukan berbagai peluang beasiswa untuk mendukung perjalanan akademik dan penelitian Anda. Program Studi Informatika UNTAN berkomitmen membantu mahasiswa meraih prestasi terbaik.', + 'hero.cta': 'Lihat Daftar Beasiswa', + 'stats.total': 'Total Mahasiswa Penerima
Beasiswa Semester Ini', + 'stats.gov': 'Total Penerima Beasiswa
Pembiayaan Pemerintah', + 'stats.private': 'Total Penerima Beasiswa
Pembiayaan Swasta', + 'dir.label': 'Daftar Beasiswa', + 'dir.title': 'Daftar Beasiswa', + 'dir.desc': 'Temukan beragam beasiswa dari berbagai sumber resmi yang tersedia untuk mahasiswa aktif, alumni, dan calon mahasiswa Program Studi Informatika UNTAN.', + 'dir.receive': 'Terima Bantuan Beasiswa?', + 'filter.all': 'SEMUA', + 'filter.open': 'Sedang Buka', + 'filter.closed': 'Ditutup', + 'filter.gov': 'Pemerintah', + 'filter.private': 'Swasta', + 'search.placeholder': 'Cari Nama Beasiswa...', + 'testimonial.title': 'Apa Kata Mereka?', + 'testimonial.desc': 'Cerita inspiratif dari para penerima beasiswa Program Studi Informatika UNTAN', + 'cta.title': 'Ingin Mengetahui Info Lebih Lanjut?', + 'cta.desc': 'Hubungi admin prodi atau ikuti Instagram kemahasiswaan UNTAN untuk informasi terbaru tentang beasiswa dan program akademik.', + 'cta.btn1': 'DAFTAR BEASISWA', + 'cta.btn2': 'Hubungi Kami', + 'ticker': 'Pendaftaran Beasiswa KIP Kuliah 2026 telah dibuka!  —  Beasiswa Pertamina Foundation open hingga Agustus 2026  —  Daftarkan diri Anda sekarang!  —  Info lengkap tersedia di halaman direktori beasiswa  —  Beasiswa LPDP S2 masih tersedia hingga September 2026  — ', + }, + en: { + 'nav.tentang': 'ABOUT US', + 'nav.program': 'PROGRAMS', + 'nav.sdm': 'HUMAN RESOURCES', + 'nav.fasilitas': 'FACILITIES', + 'nav.agenda': 'WORKS & EVENTS', + 'nav.kontak': 'CONTACT', + 'breadcrumb.home': 'Home', + 'breadcrumb.profile': 'Profile', + 'breadcrumb.scholarship': 'Scholarship', + 'hero.badge': 'Scholarship Program', + 'hero.title': 'Study & Research
Scholarships', + 'hero.subtitle': 'Informatics Engineering, Tanjungpura University', + 'hero.desc': 'Discover various scholarship opportunities to support your academic and research journey. The Informatics Study Program at UNTAN is committed to helping students achieve excellence.', + 'hero.cta': 'View Scholarships', + 'stats.total': 'Total Scholarship
Recipients This Semester', + 'stats.gov': 'Total Government
Scholarship Recipients', + 'stats.private': 'Total Private
Scholarship Recipients', + 'dir.label': 'Scholarship Directory', + 'dir.title': 'Scholarship Directory', + 'dir.desc': 'Find various scholarships from official sources available for active students, alumni, and prospective students of the UNTAN Informatics Study Program.', + 'dir.receive': 'Need Scholarship Aid?', + 'filter.all': 'ALL', + 'filter.open': 'Open', + 'filter.closed': 'Closed', + 'filter.gov': 'Government', + 'filter.private': 'Private', + 'search.placeholder': 'Search Scholarship Name...', + 'testimonial.title': 'What They Say?', + 'testimonial.desc': 'Inspiring stories from scholarship recipients at UNTAN Informatics Study Program', + 'cta.title': 'Want to Know More?', + 'cta.desc': 'Contact the program admin or follow UNTAN student affairs Instagram for the latest scholarship and academic program information.', + 'cta.btn1': 'SCHOLARSHIP LIST', + 'cta.btn2': 'Contact Us', + 'ticker': 'KIP Kuliah Scholarship 2026 registration is now open!  —  Pertamina Foundation Scholarship open until August 2026  —  Register now!  —  Full info available in the scholarship directory  —  LPDP S2 Scholarship available until September 2026  — ', + } +}; + +// Load saved language from session storage +let currentLang = sessionStorage.getItem('lang') || 'id'; + +function applyTranslations(lang) { + const t = i18nData[lang]; + if (!t) return; + + // Apply data-i18n attributes + document.querySelectorAll('[data-i18n]').forEach(el => { + const key = el.getAttribute('data-i18n'); + if (t[key] !== undefined) { + el.innerHTML = t[key]; + } + }); + + // Apply data-i18n-placeholder attributes + document.querySelectorAll('[data-i18n-placeholder]').forEach(el => { + const key = el.getAttribute('data-i18n-placeholder'); + if (t[key] !== undefined) { + el.placeholder = t[key]; + } + }); + + // Update HTML lang attribute + document.documentElement.lang = lang === 'id' ? 'id' : 'en'; +} + +function setLanguage(lang) { + if (lang !== 'id' && lang !== 'en') return; + currentLang = lang; + sessionStorage.setItem('lang', lang); + + // Update button visual states + document.querySelectorAll('.lang-btn').forEach(btn => { + const isActive = btn.dataset.lang === lang; + btn.classList.toggle('active', isActive); + }); + + applyTranslations(lang); +} + +// Expose globally so onclick in HTML works +window.setLanguage = setLanguage; + +// Initialize on DOM ready +document.addEventListener('DOMContentLoaded', () => { + setLanguage(currentLang); +}); diff --git a/groups/ApeNameTeamE/assets/js/main.js b/groups/ApeNameTeamE/assets/js/main.js new file mode 100644 index 0000000..9bf70cf --- /dev/null +++ b/groups/ApeNameTeamE/assets/js/main.js @@ -0,0 +1,177 @@ +// ===================================================== +// main.js — Inisialisasi Utama +// Sticky Navbar, Hamburger Menu, Smooth Scroll, AOS, Active Nav +// ===================================================== + +document.addEventListener('DOMContentLoaded', () => { + + // ─── AOS (Animate on Scroll) ──────────────────────── + AOS.init({ + duration: 700, + easing: 'ease-out-cubic', + once: true, + offset: 50, + }); + + + // ─── Sticky Navbar ────────────────────────────────── + // Navbar sudah fixed di CSS; tidak perlu mengubah warna karena + // warna primary sudah menjadi identitas halaman ini. + // Namun kita tambahkan shadow saat scroll untuk depth effect. + const navbar = document.getElementById('navbar'); + + const handleScroll = () => { + if (window.scrollY > 10) { + navbar.style.boxShadow = '0 4px 20px rgba(0,0,0,0.25)'; + } else { + navbar.style.boxShadow = 'none'; + } + }; + + window.addEventListener('scroll', handleScroll, { passive: true }); + handleScroll(); // initial call + + + // ─── Ticker Visibility (Muncul setelah Hero & Stats) ─ + const ticker = document.querySelector('.ticker-wrapper'); + const statsSection = document.getElementById('statistics'); + + const handleTickerVisibility = () => { + if (!ticker || !statsSection) return; + + // Ticker muncul setelah melewati batas bawah elemen statistik + const statsBottom = statsSection.offsetTop + statsSection.offsetHeight; + + if (window.scrollY > statsBottom) { + ticker.classList.add('show-ticker'); + } else { + ticker.classList.remove('show-ticker'); + } + }; + + window.addEventListener('scroll', handleTickerVisibility, { passive: true }); + // Call once on load with a slight delay to ensure layout is ready + setTimeout(handleTickerVisibility, 100); + + + // ─── Hamburger Menu (Mobile) ───────────────────────── + const hamburger = document.getElementById('hamburger'); + const mobileMenu = document.getElementById('mobile-menu'); + + hamburger?.addEventListener('click', () => { + const isOpen = !mobileMenu.classList.contains('hidden'); + mobileMenu.classList.toggle('hidden'); + + // Toggle icon + const icon = hamburger.querySelector('i'); + if (isOpen) { + icon.className = 'fas fa-bars text-lg'; + } else { + icon.className = 'fas fa-times text-lg'; + } + + // Aksesibilitas + hamburger.setAttribute('aria-expanded', String(!isOpen)); + }); + + + // ─── Smooth Scroll untuk anchor links ────────────── + // Sesuai SDD: CSS scroll-behavior + JS fallback dengan offset + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', e => { + const href = anchor.getAttribute('href'); + const target = document.querySelector(href); + if (!target) return; + + e.preventDefault(); + + const navHeight = navbar.offsetHeight || 110; + const top = target.getBoundingClientRect().top + window.scrollY - navHeight - 4; + window.scrollTo({ top, behavior: 'smooth' }); + + // Tutup mobile menu jika sedang terbuka + mobileMenu?.classList.add('hidden'); + const icon = hamburger?.querySelector('i'); + if (icon) icon.className = 'fas fa-bars text-lg'; + }); + }); + + + // ─── Active Nav Link via IntersectionObserver ────── + // Sesuai SDD fitur #4: highlight menu sesuai seksi yang terlihat + const sections = document.querySelectorAll('section[id]'); + const navLinks = document.querySelectorAll('a.nav-link'); + + const sectionObserver = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + navLinks.forEach(link => { + link.classList.remove('active'); + if (link.getAttribute('href') === `#${entry.target.id}`) { + link.classList.add('active'); + } + }); + } + }); + }, + { rootMargin: '-30% 0px -65% 0px' } + ); + + sections.forEach(s => sectionObserver.observe(s)); + + + // ─── Back to Top visibility ──────────────────────── + const backToTop = document.getElementById('back-to-top'); + if (backToTop) { + window.addEventListener('scroll', () => { + if (window.scrollY > 400) { + backToTop.classList.remove('opacity-0', 'pointer-events-none'); + backToTop.classList.add('opacity-100'); + } else { + backToTop.classList.add('opacity-0', 'pointer-events-none'); + backToTop.classList.remove('opacity-100'); + } + }, { passive: true }); + + backToTop.addEventListener('click', () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }); + } + + // ─── Contact Us Modal (Hubungi Kami) ──────────────── + const btnOpenContact = document.getElementById('btn-open-contact'); + const contactOverlay = document.getElementById('contact-overlay'); + const contactModal = document.getElementById('contact-modal'); + const contactClose = document.getElementById('contact-close'); + const contactBackdrop = document.getElementById('contact-backdrop'); + + const openContactModal = () => { + if (!contactOverlay) return; + contactOverlay.classList.remove('hidden'); + contactOverlay.classList.add('flex'); + // Animasi muncul + setTimeout(() => { + contactOverlay.classList.remove('opacity-0'); + contactModal.classList.remove('scale-95'); + contactModal.classList.add('scale-100'); + }, 10); + }; + + const closeContactModal = () => { + if (!contactOverlay) return; + contactOverlay.classList.add('opacity-0'); + contactModal.classList.remove('scale-100'); + contactModal.classList.add('scale-95'); + // Tunggu animasi selesai baru di-hide + setTimeout(() => { + contactOverlay.classList.remove('flex'); + contactOverlay.classList.add('hidden'); + }, 300); + }; + + if (btnOpenContact) btnOpenContact.addEventListener('click', openContactModal); + if (contactClose) contactClose.addEventListener('click', closeContactModal); + if (contactBackdrop) contactBackdrop.addEventListener('click', closeContactModal); + +}); // end DOMContentLoaded diff --git a/groups/ApeNameTeamE/assets/js/popup.js b/groups/ApeNameTeamE/assets/js/popup.js new file mode 100644 index 0000000..759f4d9 --- /dev/null +++ b/groups/ApeNameTeamE/assets/js/popup.js @@ -0,0 +1,158 @@ +// ===================================================== +// popup.js — Modal Detail Beasiswa +// Tutup via: tombol ×, klik overlay, tekan Escape +// ===================================================== + +const overlay = document.getElementById('popup-overlay'); +const modal = document.getElementById('popup-modal'); +const closeBtn = document.getElementById('popup-close'); +const popupBody = document.getElementById('popup-content'); + +// Format tanggal ke format Indonesia +function fmtDate(str) { + if (!str) return '—'; + const d = new Date(str); + if (isNaN(d.getTime())) return str; + return d.toLocaleDateString('id-ID', { + day: 'numeric', + month: 'long', + year: 'numeric' + }); +} + +/** + * Buka popup modal untuk beasiswa dengan ID tertentu + * Data diambil dari window.beasiswaData yang diset oleh filter.js + */ +function openPopup(id) { + const data = window.beasiswaData || []; + const bsw = data.find(b => b.id === id); + if (!bsw) return; + + const isBuka = bsw.status === 'Buka'; + const badgeClass = isBuka ? 'badge-buka' : 'badge-ditutup'; + + // Bangun list syarat umum + const syaratItems = (bsw.syarat_umum || []) + .map(s => ` +
  • + + ${s} +
  • `) + .join(''); + + const syaratHTML = syaratItems + ? `` + : `

    + Syarat belum tersedia. Kunjungi sumber resmi. +

    `; + + const hasUrl = bsw.url_sumber && bsw.url_sumber !== '#'; + + // Render konten popup + popupBody.innerHTML = ` + + ${bsw.nama} + + + `; + + // Tampilkan overlay + overlay.classList.add('show'); + document.body.style.overflow = 'hidden'; + + // Set focus ke modal untuk aksesibilitas + setTimeout(() => modal.focus(), 50); +} + +/** Tutup popup modal */ +function closePopup() { + overlay.classList.remove('show'); + document.body.style.overflow = ''; +} + +// === Event Listeners untuk menutup popup === + +// 1. Tombol × close +closeBtn?.addEventListener('click', closePopup); + +// 2. Klik di luar area modal (backdrop) +document.getElementById('popup-backdrop')?.addEventListener('click', closePopup); + +// 3. Tekan Escape +document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && overlay.classList.contains('show')) { + closePopup(); + } +}); + +// Expose ke global (dipanggil dari onclick di kartu) +window.openPopup = openPopup; +window.closePopup = closePopup; diff --git a/groups/ApeNameTeamE/data/beasiswa.json b/groups/ApeNameTeamE/data/beasiswa.json new file mode 100644 index 0000000..ddc98fb --- /dev/null +++ b/groups/ApeNameTeamE/data/beasiswa.json @@ -0,0 +1,198 @@ +[ + { + "id": "bsw-001", + "nama": "Boustany Foundation Scholarship, MBA - Harvard University", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1541339907198-e08756dedf3f?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa bergengsi dari Boustany Foundation untuk program MBA di Harvard University, Amerika Serikat, bagi calon pemimpin bisnis dunia.", + "syarat_umum": [ + "Diterima atau mendaftar di program MBA Harvard Business School", + "Memiliki rekam jejak prestasi akademik dan profesional yang luar biasa", + "Menunjukkan potensi kepemimpinan dan kontribusi internasional", + "Melengkapi aplikasi beasiswa secara online melalui situs resmi Boustany Foundation" + ], + "kontak": "Boustany Foundation — boustany-foundation.com", + "tanggal_buka": "2026-05-21", + "tanggal_tutup": "2027-05-31", + "url_sumber": "https://www.schoters.com/id/beasiswa/boustany-foundation-scholarship-mba-harvard-university-1", + "tags": ["S2", "Swasta", "Amerika Serikat", "Partially Funded", "MBA"] + }, + { + "id": "bsw-002", + "nama": "La Trobe University - La Trobe High Achiever Scholarship (S1)", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1523240795612-9a054b0db644?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa dari La Trobe University Australia untuk mahasiswa internasional jenjang S1 berprestasi tinggi yang ingin melanjutkan studi di Melbourne.", + "syarat_umum": [ + "Mendaftar sebagai mahasiswa internasional jenjang S1 (Undergraduate) di La Trobe University", + "Memiliki nilai akademik yang sangat baik (High Achiever)", + "Tidak sedang menerima beasiswa penuh lainnya dari La Trobe University", + "Memenuhi persyaratan masuk dan kemampuan bahasa Inggris La Trobe University" + ], + "kontak": "La Trobe University Admissions — latrobe.edu.au", + "tanggal_buka": "2023-09-29", + "tanggal_tutup": "2026-12-31", + "url_sumber": "https://www.schoters.com/id/beasiswa/la-trobe-university-la-trobe-high-achiever-scholarship-2", + "tags": ["S1", "Swasta", "Australia", "Partially Funded"] + }, + { + "id": "bsw-003", + "nama": "Charles Sturt University - International Student Support Scholarship", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1560472354-b33ff0c44a43?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa dukungan dari Charles Sturt University bagi mahasiswa internasional jenjang S1 yang mendaftar di kampus yang berlokasi di New South Wales, Australia.", + "syarat_umum": [ + "Mendaftar sebagai mahasiswa internasional penuh waktu (full-time) jenjang S1", + "Memenuhi persyaratan penerimaan akademik Charles Sturt University", + "Memiliki kemampuan Bahasa Inggris yang memadai (IELTS/TOEFL)", + "Mendaftar melalui jalur penerimaan internasional resmi" + ], + "kontak": "Charles Sturt University International — csu.edu.au", + "tanggal_buka": "2026-05-21", + "tanggal_tutup": "2026-12-31", + "url_sumber": "https://www.schoters.com/id/beasiswa/charles-sturt-university-international-student-support-scholarship-3", + "tags": ["S1", "Swasta", "Australia", "Partially Funded"] + }, + { + "id": "bsw-004", + "nama": "La Trobe University - La Trobe High Achiever Scholarship (S2)", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1529156069898-49953e39b3ac?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa dari La Trobe University Australia untuk mahasiswa internasional jenjang S2 (Postgraduate) dengan pencapaian akademik tinggi.", + "syarat_umum": [ + "Mendaftar sebagai mahasiswa internasional jenjang S2 di La Trobe University", + "Memiliki nilai akademik yang sangat baik di jenjang sarjana sebelumnya", + "Memenuhi persyaratan bahasa Inggris yang ditetapkan", + "Tidak sedang menerima beasiswa lain dari universitas yang sama" + ], + "kontak": "La Trobe University Admissions — latrobe.edu.au", + "tanggal_buka": "2023-09-29", + "tanggal_tutup": "2026-12-31", + "url_sumber": "https://www.schoters.com/id/beasiswa/la-trobe-university-la-trobe-high-achiever-scholarship-4", + "tags": ["S2", "Swasta", "Australia", "Partially Funded"] + }, + { + "id": "bsw-005", + "nama": "ETH Zurich - Excellence Scholarship & Opportunity Programme (ESOP)", + "kategori": "Pemerintah", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1497366754035-f200968a6e72?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa bergengsi dari ETH Zurich (salah satu universitas teknik terbaik dunia) untuk mahasiswa S2 internasional yang unggul secara akademik.", + "syarat_umum": [ + "Mendaftar program Master (S2) di ETH Zurich", + "Lulus ujian penerimaan ETH Zurich atau memiliki setara gelar sarjana yang diakui", + "Menunjukkan prestasi akademik luar biasa (biasanya masuk 10% terbaik angkatan)", + "Melengkapi formulir aplikasi beasiswa ESOP yang terpisah dari aplikasi studi", + "Mendapatkan surat rekomendasi dari akademisi berwenang" + ], + "kontak": "ETH Zurich Scholarship Office — ethz.ch", + "tanggal_buka": "2026-11-01", + "tanggal_tutup": "2026-11-30", + "url_sumber": "https://www.schoters.com/id/beasiswa/eth-zurich-excellence-scholarship-opportunity-programme-esop-5", + "tags": ["S2", "Pemerintah", "Swiss", "Fully Funded", "Prestasi"] + }, + { + "id": "bsw-006", + "nama": "STUST - Scholarship for International Students (S3, Fully Funded)", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1580582932707-520aed937b7b?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa penuh (fully funded) dari Southern Taiwan University of Science and Technology untuk mahasiswa internasional jenjang S3 (Doktoral).", + "syarat_umum": [ + "Mendaftar program Doktoral (S3) di STUST, Taiwan", + "Memiliki gelar magister (S2) yang diakui", + "Memenuhi persyaratan kemampuan bahasa Inggris atau Mandarin", + "Menyerahkan proposal penelitian yang relevan dengan bidang studi yang dipilih", + "Mendapatkan persetujuan dari calon pembimbing (supervisor) di STUST" + ], + "kontak": "STUST International Affairs Office — stust.edu.tw", + "tanggal_buka": "2026-09-15", + "tanggal_tutup": "2026-11-30", + "url_sumber": "https://www.schoters.com/id/beasiswa/southern-taiwan-university-of-science-and-technology-the-stust-scholarship-for-international-students-6", + "tags": ["S3", "Swasta", "Taiwan", "Fully Funded"] + }, + { + "id": "bsw-007", + "nama": "STUST - Scholarship for International Students (S2, Partially Funded)", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1606761568499-6d2451b23c66?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa parsial (partially funded) dari Southern Taiwan University of Science and Technology untuk mahasiswa internasional jenjang S2 (Magister).", + "syarat_umum": [ + "Mendaftar program Magister (S2) di STUST, Taiwan", + "Memiliki gelar sarjana (S1) yang diakui", + "Memenuhi persyaratan kemampuan bahasa Inggris atau Mandarin", + "Melengkapi berkas aplikasi secara online melalui portal resmi STUST", + "Menyertakan transkrip nilai dan surat motivasi" + ], + "kontak": "STUST International Affairs Office — stust.edu.tw", + "tanggal_buka": "2026-09-15", + "tanggal_tutup": "2026-11-30", + "url_sumber": "https://www.schoters.com/id/beasiswa/southern-taiwan-university-of-science-and-technology-the-stust-scholarship-for-international-students-7", + "tags": ["S2", "Swasta", "Taiwan", "Partially Funded"] + }, + { + "id": "bsw-008", + "nama": "University of Melbourne - Melbourne International Undergraduate Scholarship", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1504711434969-e33886168f5c?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa untuk mahasiswa internasional berprestasi yang mendaftar program S1 di University of Melbourne, salah satu universitas terbaik di Australia.", + "syarat_umum": [ + "Merupakan mahasiswa internasional (bukan warga negara Australia atau New Zealand)", + "Mendaftar program sarjana (S1 / Undergraduate) di University of Melbourne", + "Memiliki hasil akademik yang sangat luar biasa di tingkat sekolah menengah atas", + "Memenuhi persyaratan kemampuan bahasa Inggris (IELTS minimal 6.5)", + "Beasiswa diberikan otomatis berdasarkan nilai akademik, tidak perlu aplikasi terpisah" + ], + "kontak": "University of Melbourne Future Students — unimelb.edu.au", + "tanggal_buka": "2026-05-21", + "tanggal_tutup": "2026-10-31", + "url_sumber": "https://www.schoters.com/id/beasiswa/university-of-melbourne-melbourne-international-undergraduate-scholarship-8", + "tags": ["S1", "Swasta", "Australia", "Partially Funded", "Prestasi"] + }, + { + "id": "bsw-009", + "nama": "Charles Darwin University - CDU Global Merit Scholarship", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1434030216411-0b793f4b4173?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa merit global dari Charles Darwin University (CDU) di Darwin, Australia, untuk mahasiswa internasional S1 yang memiliki rekam jejak akademik yang kuat.", + "syarat_umum": [ + "Mendaftar sebagai mahasiswa internasional baru (new international student) di CDU", + "Mendaftar untuk program sarjana (Undergraduate/S1) penuh waktu", + "Memiliki nilai ujian akhir sekolah yang baik (dikonversi ke skala CDU)", + "Memenuhi persyaratan bahasa Inggris (IELTS 6.0 atau setara)", + "Tidak sedang menerima potongan biaya kuliah lainnya dari CDU" + ], + "kontak": "CDU International — cdu.edu.au", + "tanggal_buka": "2026-05-21", + "tanggal_tutup": "2026-10-09", + "url_sumber": "https://www.schoters.com/id/beasiswa/charles-darwin-university-cdu-global-merit-scholarship-9", + "tags": ["S1", "Swasta", "Australia", "Partially Funded"] + }, + { + "id": "bsw-010", + "nama": "Deakin University - Vice-Chancellor's International Scholarship", + "kategori": "Swasta", + "status": "Buka", + "thumbnail": "https://images.unsplash.com/photo-1541339907198-e08756dedf3f?w=400&q=80&auto=format&fit=crop", + "deskripsi_singkat": "Beasiswa bergengsi dari Wakil Rektor (Vice-Chancellor) Deakin University untuk mahasiswa internasional terbaik yang akan menempuh studi S1 atau S2 di Australia.", + "syarat_umum": [ + "Merupakan mahasiswa internasional (bukan warga negara Australia/New Zealand)", + "Mendaftar untuk program S1 (Undergraduate) atau S2 (Postgraduate Coursework) di Deakin", + "Memiliki rekam jejak akademik yang sangat baik dan konsisten", + "Memenuhi persyaratan masuk dan kemampuan bahasa Inggris Deakin University", + "Mengajukan aplikasi beasiswa sebelum tanggal penutupan yang ditetapkan" + ], + "kontak": "Deakin University International — deakin.edu.au", + "tanggal_buka": "2026-05-21", + "tanggal_tutup": "2026-09-25", + "url_sumber": "https://www.schoters.com/id/beasiswa/deakin-university-vice-chancellor-s-international-scholarship-10", + "tags": ["S1", "S2", "Swasta", "Australia", "Partially Funded", "Prestasi"] + } +] diff --git a/groups/ApeNameTeamE/data/testimoni.json b/groups/ApeNameTeamE/data/testimoni.json new file mode 100644 index 0000000..ba40b1e --- /dev/null +++ b/groups/ApeNameTeamE/data/testimoni.json @@ -0,0 +1,9 @@ +[ + { + "id": "tsm-001", + "nama": "Violaine Gunawan", + "foto": "https://ui-avatars.com/api/?name=Violaine+Gunawan&background=111a2f&color=fff&size=200&rounded=true", + "nama_beasiswa": "Beasiswa Bakti BCA 2026", + "kutipan": "Beasiswa ini sangat berdampak besar. Tantangannya menyeimbangkan kuliah, asisten praktikum, organisasi, dan projek besar beasiswa. Namun, relasi di kampus dan masyarakat jadi bertambah luas. Tips: Jangan takut mencoba, pahami fokus beasiswa, sesuaikan visi misi, dan aktiflah berorganisasi!" + } +] diff --git a/groups/ApeNameTeamE/index.html b/groups/ApeNameTeamE/index.html index d7d58d3..43767bd 100644 --- a/groups/ApeNameTeamE/index.html +++ b/groups/ApeNameTeamE/index.html @@ -1,1338 +1,601 @@ - - + + - - - Group 10 – Ape Name Tim E | Informatika UNTAN - - - - - - + + - - + -