forked from izu/student-web-if-development-kit
fixing-layout #3
@@ -569,6 +569,51 @@ const translations = {
|
||||
kontrib_guideline_3: "Sertakan fakta dan data yang akurat dan dapat diverifikasi.",
|
||||
kontrib_guideline_4: "Hindari plagiarisme. Karya harus orisinal.",
|
||||
kontrib_guideline_5: "Tim redaksi berhak menyunting konten untuk keperluan editorial.",
|
||||
|
||||
// --- Group 06: ACAAB - Prestasi & Karya Mahasiswa ---
|
||||
grp_acaab_hero_badge: "MAHASISWA & PRESTASI",
|
||||
grp_acaab_hero_title: "Sorotan dan Prestasi Karya Mahasiswa",
|
||||
grp_acaab_hero_desc: "Galeri pencapaian, penghargaan, dan portofolio inovasi teknologi yang dikembangkan oleh mahasiswa Program Studi Informatika Universitas Tanjungpura.",
|
||||
grp_acaab_stats_heading: "Pencapaian dalam Angka",
|
||||
grp_acaab_stats_total_ach: "Total Prestasi",
|
||||
grp_acaab_stats_total_proj: "Total Karya",
|
||||
grp_acaab_stats_intl: "Internasional",
|
||||
grp_acaab_stats_national: "Nasional",
|
||||
grp_acaab_stats_regional: "Regional",
|
||||
grp_acaab_stats_data_note: "Data dikumpulkan per",
|
||||
grp_acaab_ach_title: "Prestasi Mahasiswa",
|
||||
grp_acaab_ach_desc: "Daftar pencapaian dan penghargaan yang diraih oleh mahasiswa Informatika UNTAN di berbagai kompetisi.",
|
||||
grp_acaab_ach_search: "Cari prestasi...",
|
||||
grp_acaab_ach_filter_level: "Semua Level",
|
||||
grp_acaab_ach_filter_cat: "Semua Kategori",
|
||||
grp_acaab_ach_filter_year: "Semua Tahun",
|
||||
grp_acaab_ach_showing: "Menampilkan",
|
||||
grp_acaab_ach_results: "prestasi",
|
||||
grp_acaab_ach_load_more: "Tampilkan Lebih Banyak",
|
||||
grp_acaab_ach_show_less: "Tampilkan Lebih Sedikit",
|
||||
grp_acaab_ach_empty: "Tidak ada prestasi yang cocok dengan filter.",
|
||||
grp_acaab_ach_loading: "Memuat data prestasi...",
|
||||
grp_acaab_ach_error: "Gagal memuat data prestasi.",
|
||||
grp_acaab_proj_title: "Top Projects & Portofolio",
|
||||
grp_acaab_proj_desc: "Jelajahi inovasi digital dan aplikasi nyata yang dikembangkan oleh mahasiswa Informatika UNTAN.",
|
||||
grp_acaab_proj_scroll_hint: "← Geser untuk melihat lebih banyak →",
|
||||
grp_acaab_proj_search: "Cari karya...",
|
||||
grp_acaab_proj_filter_cat: "Semua Kategori",
|
||||
grp_acaab_proj_filter_year: "Semua Tahun",
|
||||
grp_acaab_proj_load_more: "Tampilkan Lebih Banyak",
|
||||
grp_acaab_proj_empty: "Tidak ada karya yang cocok dengan filter.",
|
||||
grp_acaab_proj_loading: "Memuat data karya...",
|
||||
grp_acaab_proj_error: "Gagal memuat data karya.",
|
||||
grp_acaab_modal_team: "Tim / Peserta",
|
||||
grp_acaab_modal_generation: "Angkatan",
|
||||
grp_acaab_modal_members: "Anggota Tim",
|
||||
grp_acaab_modal_visit: "Kunjungi Proyek",
|
||||
grp_acaab_modal_read_more: "Selengkapnya",
|
||||
grp_acaab_modal_no_link: "Link tidak tersedia",
|
||||
grp_acaab_cta_badge: "HUBUNGI KAMI",
|
||||
grp_acaab_cta_title: "Ingin Tahu Lebih Lanjut?",
|
||||
grp_acaab_cta_desc: "Tertarik bergabung dengan Program Studi Informatika UNTAN, mendaftarkan prestasi mahasiswa, atau menjalin kerja sama? Hubungi kami sekarang.",
|
||||
grp_acaab_cta_btn: "Chat via WhatsApp",
|
||||
},
|
||||
|
||||
en: {
|
||||
@@ -1135,6 +1180,51 @@ const translations = {
|
||||
kontrib_guideline_3: "Include accurate and verifiable facts and data.",
|
||||
kontrib_guideline_4: "Avoid plagiarism. Work must be original.",
|
||||
kontrib_guideline_5: "The editorial team reserves the right to edit content for editorial purposes.",
|
||||
|
||||
// --- Group 06: ACAAB - Prestasi & Karya Mahasiswa ---
|
||||
grp_acaab_hero_badge: "STUDENTS & ACHIEVEMENTS",
|
||||
grp_acaab_hero_title: "Student Spotlights & Achievements",
|
||||
grp_acaab_hero_desc: "Gallery of accomplishments, awards, and technology innovation portfolios developed by Informatics students of Tanjungpura University.",
|
||||
grp_acaab_stats_heading: "Achievements by the Numbers",
|
||||
grp_acaab_stats_total_ach: "Total Achievements",
|
||||
grp_acaab_stats_total_proj: "Total Projects",
|
||||
grp_acaab_stats_intl: "International",
|
||||
grp_acaab_stats_national: "National",
|
||||
grp_acaab_stats_regional: "Regional",
|
||||
grp_acaab_stats_data_note: "Data collected as of",
|
||||
grp_acaab_ach_title: "Student Achievements",
|
||||
grp_acaab_ach_desc: "List of awards and accomplishments by Informatics UNTAN students in various competitions.",
|
||||
grp_acaab_ach_search: "Search achievements...",
|
||||
grp_acaab_ach_filter_level: "All Levels",
|
||||
grp_acaab_ach_filter_cat: "All Categories",
|
||||
grp_acaab_ach_filter_year: "All Years",
|
||||
grp_acaab_ach_showing: "Showing",
|
||||
grp_acaab_ach_results: "achievements",
|
||||
grp_acaab_ach_load_more: "Show More",
|
||||
grp_acaab_ach_show_less: "Show Less",
|
||||
grp_acaab_ach_empty: "No achievements match the current filter.",
|
||||
grp_acaab_ach_loading: "Loading achievements...",
|
||||
grp_acaab_ach_error: "Failed to load achievements.",
|
||||
grp_acaab_proj_title: "Top Projects & Portfolios",
|
||||
grp_acaab_proj_desc: "Explore digital innovations and real-world applications developed by Informatics UNTAN students.",
|
||||
grp_acaab_proj_scroll_hint: "← Scroll to see more →",
|
||||
grp_acaab_proj_search: "Search projects...",
|
||||
grp_acaab_proj_filter_cat: "All Categories",
|
||||
grp_acaab_proj_filter_year: "All Years",
|
||||
grp_acaab_proj_load_more: "Show More",
|
||||
grp_acaab_proj_empty: "No projects match the current filter.",
|
||||
grp_acaab_proj_loading: "Loading projects...",
|
||||
grp_acaab_proj_error: "Failed to load projects.",
|
||||
grp_acaab_modal_team: "Team / Participant",
|
||||
grp_acaab_modal_generation: "Batch Year",
|
||||
grp_acaab_modal_members: "Team Members",
|
||||
grp_acaab_modal_visit: "Visit Project",
|
||||
grp_acaab_modal_read_more: "Read More",
|
||||
grp_acaab_modal_no_link: "Link not available",
|
||||
grp_acaab_cta_badge: "CONTACT US",
|
||||
grp_acaab_cta_title: "Want to Know More?",
|
||||
grp_acaab_cta_desc: "Interested in joining the Informatics Study Program at UNTAN, registering a student achievement, or establishing a partnership? Contact us now.",
|
||||
grp_acaab_cta_btn: "Chat via WhatsApp",
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 238 KiB |
+360
-32
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id" class="scroll-smooth">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -7,9 +8,12 @@
|
||||
<link rel="stylesheet" href="../../assets/global/output.css">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
|
||||
rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
<link rel="stylesheet" href="./style.css">
|
||||
<style>
|
||||
/* ===== MOBILE NAV STABILITY FIX =====
|
||||
Prevents logo bar from collapsing/shifting on Android when
|
||||
address bar hides/shows and triggers viewport reflow.
|
||||
@@ -293,6 +297,7 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="text-slate-800 antialiased bg-white selection:bg-untan-yellow selection:text-black">
|
||||
|
||||
<a href="#main-content" class="skip-link" data-i18n="skip_to_content">Langsung ke Konten Utama</a>
|
||||
@@ -1139,18 +1144,339 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main id="main-content" class="pt-[88px] lg:pt-[160px] min-h-screen bg-white">
|
||||
<main id="main-content" class="pt-[88px] lg:pt-[160px] min-h-screen bg-white">
|
||||
<div class="container mx-auto px-4 lg:px-8 py-12">
|
||||
<div class="mb-8 pb-8 border-b border-slate-200">
|
||||
<span class="bg-untan-yellow text-slate-900 text-[10px] font-bold uppercase tracking-widest px-2 py-0.5 inline-block mb-3">Tugas Halaman Statis</span>
|
||||
<span
|
||||
class="bg-untan-yellow text-slate-900 text-[10px] font-bold uppercase tracking-widest px-2 py-0.5 inline-block mb-3">Tugas
|
||||
Halaman Statis</span>
|
||||
<h1 class="text-3xl lg:text-4xl font-bold text-slate-900 mb-2">Sorotan dan Prestasi Karya Mahasiswa</h1>
|
||||
<p class="text-slate-500 text-sm">Kelompok 06 — ACAAB · Informatika UNTAN 2026</p>
|
||||
<p class="text-slate-500 text-sm">Kelompok 06 — ACAAB · Informatika UNTAN 2026
|
||||
</p>
|
||||
</div>
|
||||
<div id="assignment-body" class="prose prose-slate max-w-none">
|
||||
<!-- ================= START: BAGIAN YANG DIEDIT KELOMPOK ================= -->
|
||||
<p>Tulis konten halaman kelompok di sini.</p>
|
||||
<h3>Subjudul</h3>
|
||||
<p>Gunakan paragraf, list, tabel, gambar, dan elemen konten lainnya.</p>
|
||||
|
||||
<!-- ── BREADCRUMB ─────────────────────────────────────────────────────── -->
|
||||
<nav class="not-prose py-3" aria-label="Breadcrumb">
|
||||
<ol class="flex items-center gap-1 text-[10px] text-slate-500 font-medium tracking-wide uppercase">
|
||||
<li><a href="https://informatika.untan.ac.id" target="_blank" rel="noopener noreferrer"
|
||||
class="hover:text-blue-600 transition-colors">Beranda</a></li>
|
||||
<li><span class="mx-1 text-slate-300" aria-hidden="true">/</span></li>
|
||||
<li><span class="text-slate-800 font-bold" aria-current="page"
|
||||
data-i18n="grp_acaab_hero_badge">Mahasiswa & Prestasi</span></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<!-- ── HERO ───────────────────────────────────────────────────────────── -->
|
||||
<section id="acaab-hero"
|
||||
class="not-prose acaab-full-bleed bg-untan-navy text-white relative overflow-hidden"
|
||||
style="padding-top:3rem;padding-bottom:0;margin-top:0.5rem;">
|
||||
<!-- Decorative glow -->
|
||||
<div class="absolute top-0 right-0 w-80 h-80 rounded-full pointer-events-none"
|
||||
style="background:rgba(254,180,1,0.08);filter:blur(80px);margin-right:-5rem;margin-top:-5rem;">
|
||||
</div>
|
||||
|
||||
<div class="container mx-auto px-4 lg:px-8">
|
||||
<div style="display:grid;grid-template-columns:1fr;gap:1.5rem;align-items:center;"
|
||||
class="lg-hero-grid">
|
||||
<!-- Left: text -->
|
||||
<div style="padding:1.5rem 0 2rem;max-width:640px;">
|
||||
<span class="acaab-fade-in"
|
||||
style="display:inline-block;background:#feb401;color:#0f172a;font-size:0.65rem;font-weight:700;letter-spacing:0.15em;text-transform:uppercase;padding:0.2rem 0.625rem;margin-bottom:0.75rem;"
|
||||
data-i18n="grp_acaab_hero_badge">MAHASISWA & PRESTASI</span>
|
||||
<h1 class="acaab-fade-in"
|
||||
style="font-size:clamp(1.875rem,3.5vw,2.5rem);font-weight:700;line-height:1.2;letter-spacing:-0.01em;margin:0 0 0.75rem;font-family:'Roboto Condensed',sans-serif;"
|
||||
data-i18n="grp_acaab_hero_title">Sorotan dan Prestasi Karya Mahasiswa</h1>
|
||||
<p class="acaab-fade-in"
|
||||
style="color:rgba(255,255,255,0.7);font-size:0.9375rem;line-height:1.7;margin:0;"
|
||||
data-i18n="grp_acaab_hero_desc">Temukan pencapaian luar biasa mahasiswa Informatika
|
||||
UNTAN.</p>
|
||||
</div>
|
||||
<!-- Right: image -->
|
||||
<div id="acaab-hero-img-wrap"
|
||||
style="display:flex;justify-content:flex-end;align-items:flex-end;position:relative;">
|
||||
<div
|
||||
style="position:absolute;bottom:0;width:280px;height:280px;background:rgba(103,232,249,0.06);border-radius:50%;filter:blur(60px);">
|
||||
</div>
|
||||
<div style="position:relative;">
|
||||
<img src="./hero.png" alt="Mahasiswa Informatika UNTAN"
|
||||
style="position:relative;z-index:10;width:100%;max-width:320px;height:auto;object-fit:contain;opacity:0.95;filter:drop-shadow(0 15px 35px rgba(0,0,0,0.25));transition:transform 0.5s;"
|
||||
onerror="this.style.display='none'">
|
||||
<!-- Gradient fades over image -->
|
||||
<div
|
||||
style="position:absolute;bottom:0;left:0;width:100%;height:8rem;background:linear-gradient(to top,#003150,transparent);z-index:20;pointer-events:none;">
|
||||
</div>
|
||||
<div
|
||||
style="position:absolute;top:0;left:0;height:100%;width:4rem;background:linear-gradient(to right,#003150,transparent);z-index:20;pointer-events:none;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Responsive: 2-column on desktop -->
|
||||
<style>
|
||||
@media (min-width:1024px) {
|
||||
.lg-hero-grid {
|
||||
grid-template-columns: 1fr 1fr !important;
|
||||
}
|
||||
|
||||
#acaab-hero-img-wrap img {
|
||||
max-width: 420px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</section>
|
||||
|
||||
<!-- ── STATS (yellow card) ────────────────────────────────────────────── -->
|
||||
<div id="acaab-stats" class="not-prose" style="padding:1.5rem 0 0;">
|
||||
<div
|
||||
style="background:#feb401;border-radius:0.75rem;box-shadow:0 10px 30px -10px rgba(253,184,19,0.4);padding:1.25rem 1.5rem 1.5rem;">
|
||||
|
||||
<div style="display:flex;flex-wrap:wrap;gap:1.5rem;">
|
||||
<!-- Prestasi Block -->
|
||||
<div style="flex:4;min-width:240px;">
|
||||
<div style="background:#003150;border-radius:0.5rem;padding:0.5rem 0.75rem;text-align:center;margin-bottom:1.25rem;">
|
||||
<span style="color:white;font-size:0.875rem;font-weight:800;letter-spacing:0.12em;text-transform:uppercase;"
|
||||
data-i18n="grp_acaab_stats_total_ach">Total Prestasi</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:0.25rem;">
|
||||
<!-- Prestasi Mahasiswa (total) -->
|
||||
<div style="flex:1;text-align:center;padding:0 0.15rem;">
|
||||
<div id="stat-total-ach"
|
||||
style="font-size:clamp(2rem,4.5vw,4rem);font-weight:900;color:#003150;line-height:1;font-family:'Roboto Condensed',sans-serif;">
|
||||
0</div>
|
||||
<div style="font-size:clamp(0.5rem,1.2vw,0.85rem);font-weight:800;text-transform:uppercase;letter-spacing:0.08em;color:#003150;margin-top:0.5rem;line-height:1.3;word-break:break-word;">
|
||||
Prestasi<br>Mahasiswa</div>
|
||||
</div>
|
||||
<!-- Internasional -->
|
||||
<div style="flex:1;text-align:center;padding:0 0.15rem;">
|
||||
<div id="stat-intl"
|
||||
style="font-size:clamp(2rem,4.5vw,4rem);font-weight:900;color:#003150;line-height:1;font-family:'Roboto Condensed',sans-serif;">
|
||||
0</div>
|
||||
<div style="font-size:clamp(0.5rem,1.2vw,0.85rem);font-weight:800;text-transform:uppercase;letter-spacing:0.08em;color:#003150;margin-top:0.5rem;word-break:break-word;"
|
||||
data-i18n="grp_acaab_stats_intl">Internasional</div>
|
||||
</div>
|
||||
<!-- Nasional -->
|
||||
<div style="flex:1;text-align:center;padding:0 0.15rem;">
|
||||
<div id="stat-national"
|
||||
style="font-size:clamp(2rem,4.5vw,4rem);font-weight:900;color:#003150;line-height:1;font-family:'Roboto Condensed',sans-serif;">
|
||||
0</div>
|
||||
<div style="font-size:clamp(0.5rem,1.2vw,0.85rem);font-weight:800;text-transform:uppercase;letter-spacing:0.08em;color:#003150;margin-top:0.5rem;word-break:break-word;"
|
||||
data-i18n="grp_acaab_stats_national">Nasional</div>
|
||||
</div>
|
||||
<!-- Regional -->
|
||||
<div style="flex:1;text-align:center;padding:0 0.15rem;">
|
||||
<div id="stat-regional"
|
||||
style="font-size:clamp(2rem,4.5vw,4rem);font-weight:900;color:#003150;line-height:1;font-family:'Roboto Condensed',sans-serif;">
|
||||
0</div>
|
||||
<div style="font-size:clamp(0.5rem,1.2vw,0.85rem);font-weight:800;text-transform:uppercase;letter-spacing:0.08em;color:#003150;margin-top:0.5rem;word-break:break-word;"
|
||||
data-i18n="grp_acaab_stats_regional">Regional</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Proyek Block -->
|
||||
<div style="flex:1;min-width:120px;">
|
||||
<div style="background:#003150;border-radius:0.5rem;padding:0.5rem 0.75rem;text-align:center;margin-bottom:1.25rem;">
|
||||
<span style="color:white;font-size:0.875rem;font-weight:800;letter-spacing:0.12em;text-transform:uppercase;"
|
||||
data-i18n="grp_acaab_stats_total_proj">Total Portofolio</span>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:center;">
|
||||
<!-- Proyek Mahasiswa (total) -->
|
||||
<div style="text-align:center;padding:0 0.15rem;">
|
||||
<div id="stat-total-proj"
|
||||
style="font-size:clamp(2rem,4.5vw,4rem);font-weight:900;color:#003150;line-height:1;font-family:'Roboto Condensed',sans-serif;">
|
||||
0</div>
|
||||
<div style="font-size:clamp(0.5rem,1.2vw,0.85rem);font-weight:800;text-transform:uppercase;letter-spacing:0.08em;color:#003150;margin-top:0.5rem;line-height:1.3;word-break:break-word;">
|
||||
Proyek<br>Mahasiswa</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- Data note -->
|
||||
<p id="acaab-data-note"
|
||||
style="font-size:0.6rem;font-weight:600;color:#94a3b8;letter-spacing:0.05em;text-align:right;padding-right:0.25rem;margin:0.5rem 0 0;">
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- ── ACHIEVEMENT GRID ────────────────────────────────────────────────── -->
|
||||
<section id="acaab-ach-section" class="not-prose" style="padding:2.5rem 0 3rem;">
|
||||
<div style="margin-bottom:2rem;">
|
||||
<h2 style="font-size:clamp(1.5rem,3vw,2.25rem);font-weight:900;color:#003150;margin:0 0 0.5rem;font-family:'Roboto Condensed',sans-serif;"
|
||||
data-i18n="grp_acaab_ach_title">Prestasi Mahasiswa</h2>
|
||||
<p style="color:#64748b;font-size:1rem;max-width:42rem;margin:0;line-height:1.6;"
|
||||
data-i18n="grp_acaab_ach_desc">Daftar pencapaian dan penghargaan yang diraih oleh mahasiswa Informatika UNTAN di berbagai kompetisi.</p>
|
||||
</div>
|
||||
|
||||
<!-- Filter panel — gold top border matching original -->
|
||||
<div id="acaab-ach-filters"
|
||||
style="background:rgba(255,255,255,0.8);backdrop-filter:blur(12px);padding:1rem;border-radius:0.5rem;box-shadow:0 1px 3px rgba(0,0,0,0.08);border-top:4px solid #feb401;margin-bottom:2rem;">
|
||||
<!-- Row 1: Label + Reset -->
|
||||
<div
|
||||
style="display:flex;align-items:center;justify-content:space-between;margin-bottom:0.75rem;">
|
||||
<div
|
||||
style="display:flex;align-items:center;gap:0.5rem;font-size:0.875rem;font-weight:700;color:#003150;font-family:'Roboto Condensed',sans-serif;">
|
||||
<i class="fas fa-filter" style="font-size:0.8rem;"></i>
|
||||
<span>Filter Prestasi</span>
|
||||
</div>
|
||||
<button id="acaab-ach-reset"
|
||||
style="display:none;align-items:center;gap:0.25rem;font-size:0.75rem;font-weight:700;color:#64748b;background:none;border:none;cursor:pointer;"
|
||||
data-i18n="btn_reset_filter">
|
||||
<i class="fas fa-times" style="font-size:0.7rem;"></i> Reset Filter
|
||||
</button>
|
||||
</div>
|
||||
<!-- Row 2: Search -->
|
||||
<div style="position:relative;margin-bottom:0.75rem;">
|
||||
<i class="fas fa-search"
|
||||
style="position:absolute;left:0.75rem;top:50%;transform:translateY(-50%);color:#94a3b8;font-size:0.8rem;pointer-events:none;"></i>
|
||||
<input id="acaab-ach-search" type="search"
|
||||
style="width:100%;background:#f8fafc;color:#334155;font-size:0.875rem;border-radius:0.375rem;padding:0.5rem 0.75rem 0.5rem 2.25rem;border:1px solid #e2e8f0;outline:none;box-sizing:border-box;"
|
||||
placeholder="Cari prestasi..." data-i18n-placeholder="grp_acaab_ach_search">
|
||||
</div>
|
||||
<!-- Row 3: Dropdowns -->
|
||||
<div style="display:flex;flex-wrap:wrap;gap:0.625rem;">
|
||||
<select id="acaab-ach-level"
|
||||
style="flex:1;min-width:130px;background:#f8fafc;color:#334155;font-size:0.8rem;font-weight:700;border-radius:0.375rem;padding:0.5rem 0.75rem;border:1px solid #e2e8f0;cursor:pointer;"></select>
|
||||
<select id="acaab-ach-cat"
|
||||
style="flex:1;min-width:130px;background:#f8fafc;color:#334155;font-size:0.8rem;font-weight:700;border-radius:0.375rem;padding:0.5rem 0.75rem;border:1px solid #e2e8f0;cursor:pointer;"></select>
|
||||
<select id="acaab-ach-year"
|
||||
style="flex:1;min-width:120px;background:#f8fafc;color:#334155;font-size:0.8rem;font-weight:700;border-radius:0.375rem;padding:0.5rem 0.75rem;border:1px solid #e2e8f0;cursor:pointer;"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Result count -->
|
||||
<p id="acaab-ach-count" style="font-size:0.8rem;color:#64748b;margin-bottom:1rem;"></p>
|
||||
|
||||
<!-- Cards grid -->
|
||||
<div id="acaab-ach-grid"
|
||||
style="display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:2rem;justify-content:center;">
|
||||
</div>
|
||||
|
||||
<!-- Pagination buttons -->
|
||||
<div style="text-align:center;margin-top:2rem;display:flex;gap:0.75rem;justify-content:center;">
|
||||
<button id="acaab-ach-more"
|
||||
style="display:none;padding:0.625rem 1.5rem;background:#003150;color:white;border:none;border-radius:0.5rem;font-weight:700;font-size:0.875rem;cursor:pointer;"
|
||||
data-i18n="grp_acaab_ach_load_more">Tampilkan Lebih Banyak</button>
|
||||
<button id="acaab-ach-less"
|
||||
style="display:none;padding:0.625rem 1.5rem;background:white;color:#003150;border:1px solid #003150;border-radius:0.5rem;font-weight:700;font-size:0.875rem;cursor:pointer;"
|
||||
data-i18n="grp_acaab_ach_show_less">Tampilkan Lebih Sedikit</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── PROJECT CAROUSEL ───────────────────────────────────────────────── -->
|
||||
<section id="acaab-proj-section" class="not-prose acaab-full-bleed" style="padding:2.5rem 0 3rem;background:#f8fafc;">
|
||||
<div class="container mx-auto px-4 lg:px-8">
|
||||
<!-- Section header row: title + scroll buttons (seperti di React source) -->
|
||||
<div
|
||||
style="display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:1rem;margin-bottom:1.5rem;">
|
||||
<div style="flex:1;min-width:250px;">
|
||||
<h2 style="font-size:clamp(1.5rem,3vw,2.25rem);font-weight:900;color:#003150;margin:0 0 0.5rem;font-family:'Roboto Condensed',sans-serif;"
|
||||
data-i18n="grp_acaab_proj_title">Top Projects Portofolio</h2>
|
||||
<p style="color:#64748b;font-size:1rem;max-width:42rem;margin:0;line-height:1.6;"
|
||||
data-i18n="grp_acaab_proj_desc">Jelajahi inovasi digital dan aplikasi nyata yang dikembangkan oleh mahasiswa Informatika UNTAN.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter panel -->
|
||||
<div id="acaab-proj-filters"
|
||||
style="background:rgba(255,255,255,0.8);backdrop-filter:blur(12px);padding:1rem;border-radius:0.5rem;box-shadow:0 1px 3px rgba(0,0,0,0.08);border-top:4px solid #feb401;margin-bottom:1.25rem;">
|
||||
<div
|
||||
style="display:flex;align-items:center;justify-content:space-between;margin-bottom:0.75rem;">
|
||||
<div
|
||||
style="display:flex;align-items:center;gap:0.5rem;font-size:0.875rem;font-weight:700;color:#003150;font-family:'Roboto Condensed',sans-serif;">
|
||||
<i class="fas fa-filter" style="font-size:0.8rem;"></i>
|
||||
<span>Filter Portofolio</span>
|
||||
</div>
|
||||
<button id="acaab-proj-reset"
|
||||
style="display:none;align-items:center;gap:0.25rem;font-size:0.75rem;font-weight:700;color:#64748b;background:none;border:none;cursor:pointer;"
|
||||
data-i18n="btn_reset_filter">
|
||||
<i class="fas fa-times" style="font-size:0.7rem;"></i> Reset Filter
|
||||
</button>
|
||||
</div>
|
||||
<div style="position:relative;margin-bottom:0.75rem;">
|
||||
<i class="fas fa-search"
|
||||
style="position:absolute;left:0.75rem;top:50%;transform:translateY(-50%);color:#94a3b8;font-size:0.8rem;pointer-events:none;"></i>
|
||||
<input id="acaab-proj-search" type="search"
|
||||
style="width:100%;background:#f8fafc;color:#334155;font-size:0.875rem;border-radius:0.375rem;padding:0.5rem 0.75rem 0.5rem 2.25rem;border:1px solid #e2e8f0;outline:none;box-sizing:border-box;"
|
||||
placeholder="Cari karya..." data-i18n-placeholder="grp_acaab_proj_search">
|
||||
</div>
|
||||
<div style="display:flex;flex-wrap:wrap;gap:0.625rem;">
|
||||
<select id="acaab-proj-cat"
|
||||
style="flex:1;min-width:130px;background:#f8fafc;color:#334155;font-size:0.8rem;font-weight:700;border-radius:0.375rem;padding:0.5rem 0.75rem;border:1px solid #e2e8f0;cursor:pointer;"></select>
|
||||
<select id="acaab-proj-year"
|
||||
style="flex:1;min-width:120px;background:#f8fafc;color:#334155;font-size:0.8rem;font-weight:700;border-radius:0.375rem;padding:0.5rem 0.75rem;border:1px solid #e2e8f0;cursor:pointer;"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scroll hint -->
|
||||
<p style="font-size:0.7rem;color:#94a3b8;text-align:center;margin-bottom:0.75rem;"
|
||||
data-i18n="grp_acaab_proj_scroll_hint">← Geser untuk melihat lebih banyak →</p>
|
||||
|
||||
<!-- Carousel track -->
|
||||
<div id="acaab-proj-track" class="acaab-carousel-track acaab-hide-scrollbar"
|
||||
style="display:flex;gap:1.25rem;overflow-x:auto;padding-bottom:1rem;"></div>
|
||||
|
||||
<!-- Scroll control buttons (bawah) -->
|
||||
<div style="display:flex;justify-content:center;align-items:center;gap:1rem;margin-top:1rem;">
|
||||
<button id="acaab-proj-prev" aria-label="Geser kiri"
|
||||
style="width:3rem;height:3rem;border-radius:50%;border:2px solid rgba(0,49,80,0.2);display:flex;align-items:center;justify-content:center;color:#003150;background:white;cursor:pointer;transition:all 0.2s;">
|
||||
<i class="fas fa-chevron-left" style="font-size:1rem;"></i>
|
||||
</button>
|
||||
<button id="acaab-proj-next" aria-label="Geser kanan"
|
||||
style="width:3rem;height:3rem;border-radius:50%;border:2px solid rgba(0,49,80,0.2);display:flex;align-items:center;justify-content:center;color:#003150;background:white;cursor:pointer;transition:all 0.2s;">
|
||||
<i class="fas fa-chevron-right" style="font-size:1rem;"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Load more -->
|
||||
<div style="text-align:center;margin-top:1.5rem;">
|
||||
<button id="acaab-proj-more"
|
||||
style="display:none;padding:0.625rem 1.5rem;background:#003150;color:white;border:none;border-radius:0.5rem;font-weight:700;font-size:0.875rem;cursor:pointer;"
|
||||
data-i18n="grp_acaab_proj_load_more">Tampilkan Lebih Banyak</button>
|
||||
</div>
|
||||
</div><!-- /inner container -->
|
||||
</section>
|
||||
|
||||
<!-- ── CTA ────────────────────────────────────────────────────────────── -->
|
||||
<section class="not-prose acaab-full-bleed bg-untan-navy"
|
||||
style="padding:3.5rem 0; margin-bottom: 3rem;">
|
||||
<div class="container mx-auto px-4 lg:px-8">
|
||||
<!-- Inner card: kuning transparan dengan border, rounded-2xl -->
|
||||
<div
|
||||
style="background:rgba(254,180,1,0.08);border:1px solid rgba(254,180,1,0.2);border-radius:1rem;padding:2.5rem 2rem;">
|
||||
<div class="acaab-cta-inner">
|
||||
<!-- Kiri: teks -->
|
||||
<div>
|
||||
<span
|
||||
style="display:inline-block;background:#feb401;color:#0f172a;font-size:0.625rem;font-weight:700;letter-spacing:0.15em;text-transform:uppercase;padding:0.2rem 0.5rem;border-radius:2px;margin-bottom:1rem;"
|
||||
data-i18n="grp_acaab_cta_badge">HUBUNGI KAMI</span>
|
||||
<h2 style="color:white;font-size:clamp(1.5rem,2.5vw,1.875rem);font-weight:700;margin:0 0 0.75rem;font-family:'Roboto Condensed',sans-serif;line-height:1.2;"
|
||||
data-i18n="grp_acaab_cta_title">Ingin Tahu Lebih Lanjut?</h2>
|
||||
<p style="color:#cbd5e1;font-size:0.9375rem;line-height:1.65;max-width:480px;margin:0;"
|
||||
data-i18n="grp_acaab_cta_desc">Tertarik bergabung dengan Program Studi
|
||||
Informatika UNTAN, mendaftarkan prestasi mahasiswa, atau menjalin kerja sama?
|
||||
Hubungi kami sekarang.</p>
|
||||
</div>
|
||||
<!-- Kanan: tombol WA -->
|
||||
<div style="flex-shrink:0;">
|
||||
<a id="acaab-cta-wa" href="#" target="_blank" rel="noopener noreferrer"
|
||||
style="display:inline-flex;align-items:center;gap:0.625rem;background:#25D366;color:white;padding:0.75rem 1.5rem;border-radius:9999px;font-weight:700;font-size:0.9375rem;text-decoration:none;box-shadow:0 4px 15px rgba(37,211,102,0.25);white-space:nowrap;transition:background 0.2s,transform 0.2s;">
|
||||
<i class="fab fa-whatsapp" style="font-size:1.125rem;"></i>
|
||||
<span data-i18n="grp_acaab_cta_btn">Chat via WhatsApp</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Modal container (diisi oleh main.js) -->
|
||||
<div id="acaab-modal" class="not-prose"></div>
|
||||
|
||||
<!-- ================= END: BAGIAN YANG DIEDIT KELOMPOK ================= -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -1215,8 +1541,8 @@
|
||||
</div>
|
||||
|
||||
<div class="w-full relative z-0 mt-4 pointer-events-none flex justify-center">
|
||||
<img src="../../assets/global/footer.png" alt="Footer Illustration" class="w-full h-auto object-cover object-bottom"
|
||||
style="object-position: bottom;">
|
||||
<img src="../../assets/global/footer.png" alt="Footer Illustration"
|
||||
class="w-full h-auto object-cover object-bottom" style="object-position: bottom;">
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -1312,27 +1638,29 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const mobileBtn = document.getElementById('mobile-menu-button');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
const closeMobileBtn= document.getElementById('close-mobile-menu');
|
||||
if (mobileBtn && mobileMenu) {
|
||||
mobileBtn.addEventListener('click', function() {
|
||||
const isOpen = !mobileMenu.classList.contains('-translate-x-full');
|
||||
mobileMenu.classList.toggle('-translate-x-full');
|
||||
mobileBtn.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
|
||||
});
|
||||
}
|
||||
if (closeMobileBtn && mobileMenu) {
|
||||
closeMobileBtn.addEventListener('click', function() {
|
||||
mobileMenu.classList.add('-translate-x-full');
|
||||
if (mobileBtn) mobileBtn.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
(function () {
|
||||
const mobileBtn = document.getElementById('mobile-menu-button');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
const closeMobileBtn = document.getElementById('close-mobile-menu');
|
||||
if (mobileBtn && mobileMenu) {
|
||||
mobileBtn.addEventListener('click', function () {
|
||||
const isOpen = !mobileMenu.classList.contains('-translate-x-full');
|
||||
mobileMenu.classList.toggle('-translate-x-full');
|
||||
mobileBtn.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
|
||||
});
|
||||
}
|
||||
if (closeMobileBtn && mobileMenu) {
|
||||
closeMobileBtn.addEventListener('click', function () {
|
||||
mobileMenu.classList.add('-translate-x-full');
|
||||
if (mobileBtn) mobileBtn.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script src="../../assets/global/localization.js"></script>
|
||||
<script src="./main.js"></script>
|
||||
<script src="../../assets/global/localization.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,837 @@
|
||||
/**
|
||||
* main.js — ACAAB Prestasi & Karya Mahasiswa
|
||||
* Vanilla JS: fetch data Directus CMS, render sections, handle interactions.
|
||||
*/
|
||||
|
||||
// ─── Constants ────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_BASE = 'https://api.ifuntanhub.dev';
|
||||
const LANG_KEY = 'if_untan_lang';
|
||||
|
||||
const BIDANG_MAP = {
|
||||
1: 'Kecerdasan Buatan', 2: 'Cyber Security', 3: 'Data',
|
||||
4: 'Software Engineering', 5: 'Competitive Programming', 6: 'IoT',
|
||||
7: 'Smart City', 8: 'Web3', 9: 'Karya Tulis Ilmiah', 10: 'Robotik',
|
||||
};
|
||||
|
||||
// ─── Utilities ────────────────────────────────────────────────────────────────
|
||||
|
||||
function escHtml(str) {
|
||||
if (str === null || str === undefined) return '';
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function getLang() {
|
||||
try {
|
||||
return localStorage.getItem(LANG_KEY) ||
|
||||
(navigator.language && navigator.language.startsWith('en') ? 'en' : 'id');
|
||||
} catch (_) { return 'id'; }
|
||||
}
|
||||
|
||||
// Baca dari translations global yang didefinisikan localization.js
|
||||
function t(key) {
|
||||
try {
|
||||
const lang = getLang();
|
||||
if (typeof translations !== 'undefined' && translations[lang] && translations[lang][key]) {
|
||||
return translations[lang][key];
|
||||
}
|
||||
} catch (_) {}
|
||||
return key;
|
||||
}
|
||||
|
||||
// ─── Data Transformation ──────────────────────────────────────────────────────
|
||||
|
||||
function extractRank(title) {
|
||||
const m = (title || '').match(/(Juara\s+\d+|Juara\s+Harapan\s*\d*|Top\s+\d+|Finalis|Peringkat\s+\d+|Medali\s+\w+)/i);
|
||||
return m ? m[0] : 'Pemenang';
|
||||
}
|
||||
|
||||
function extractLevel(title, category) {
|
||||
const text = ((title || '') + ' ' + (category || '')).toLowerCase();
|
||||
if (/internasional|international|global|world|asean|unesco/.test(text)) return 'Internasional';
|
||||
if (/regional|kalbar|kalimantan|provinsi|kota|kabupaten|lokal/.test(text)) return 'Regional';
|
||||
return 'Nasional';
|
||||
}
|
||||
|
||||
function extractCompetition(title) {
|
||||
return (title || '')
|
||||
.replace(/^(Juara\s+\d+|Juara\s+Harapan\s*\d*|Top\s+\d+|Finalis|Peringkat\s+\d+|Medali\s+\w+)\s+(di\s+|pada\s+|dalam\s+)?/i, '')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function getImageUrl(item, seed) {
|
||||
if (item.galeri && Array.isArray(item.galeri) && item.galeri.length > 0) {
|
||||
const first = item.galeri[0];
|
||||
const imgId = typeof first === 'string' ? first : (first.directus_files_id || first.id);
|
||||
if (imgId) return `${API_BASE}/assets/${imgId}`;
|
||||
}
|
||||
if (item.foto) return `${API_BASE}/assets/${item.foto}`;
|
||||
return `https://picsum.photos/seed/${seed}/800/600`;
|
||||
}
|
||||
|
||||
function transformAchievement(item) {
|
||||
const id = String(item.id);
|
||||
const title = item.nama_prestasi || 'Untitled Achievement';
|
||||
|
||||
let category = 'Umum';
|
||||
if (item.bidang_id) {
|
||||
category = (typeof item.bidang_id === 'object' && item.bidang_id.nama_bidang)
|
||||
? item.bidang_id.nama_bidang
|
||||
: (BIDANG_MAP[item.bidang_id] || 'Umum');
|
||||
}
|
||||
|
||||
const rank = extractRank(title);
|
||||
const level = extractLevel(title, category);
|
||||
const competition = extractCompetition(title);
|
||||
const year = parseInt(item.tahun) || new Date().getFullYear();
|
||||
const anggota = Array.isArray(item.anggota) ? item.anggota : [];
|
||||
const team = item.nama_tim || (anggota.length > 0 ? anggota[0].nama : 'Mahasiswa');
|
||||
const avatar = (item.nama_tim || title || 'IF').substring(0, 2).toUpperCase();
|
||||
const description = item.deskripsi ||
|
||||
`${team} berhasil meraih prestasi luar biasa sebagai ${rank} dalam ajang ${competition} tahun ${year} pada bidang ${category.toLowerCase()}.`;
|
||||
|
||||
return {
|
||||
id, title, category, competition, rank, year, level, description,
|
||||
team,
|
||||
nim: item.nim || '',
|
||||
generation: item.angkatan ? `Angkatan ${item.angkatan}` : 'Informatika',
|
||||
image: getImageUrl(item, `prestasi-${id}`),
|
||||
avatar,
|
||||
members: anggota.map(m => ({ nama: m.nama || '', angkatan: m.angkatan ? parseInt(m.angkatan) : undefined })),
|
||||
};
|
||||
}
|
||||
|
||||
function transformProject(item) {
|
||||
const id = String(item.id);
|
||||
const title = item.nama_proyek || 'Untitled Project';
|
||||
const anggota = Array.isArray(item.anggota) ? item.anggota : [];
|
||||
const studentName = item.nama_mahasiswa || (anggota.length > 0 ? anggota[0].nama : 'Mahasiswa');
|
||||
const year = parseInt(item.tahun) || new Date().getFullYear();
|
||||
const description = item.deskripsi || 'Tidak ada deskripsi.';
|
||||
|
||||
let categories = [];
|
||||
if (item.bidang && Array.isArray(item.bidang)) {
|
||||
categories = item.bidang.map(b => {
|
||||
if (b.bidang_id && typeof b.bidang_id === 'object' && b.bidang_id.nama_bidang) return b.bidang_id.nama_bidang;
|
||||
if (typeof b.bidang_id === 'number') return BIDANG_MAP[b.bidang_id] || 'Umum';
|
||||
return 'Umum';
|
||||
}).filter(Boolean);
|
||||
}
|
||||
if (categories.length === 0) categories = ['Umum'];
|
||||
|
||||
let link = item.url || null;
|
||||
if (link && !/^https?:\/\//i.test(link)) link = `https://${link}`;
|
||||
|
||||
return {
|
||||
id, title, studentName, year, description, categories, link,
|
||||
nim: item.nim || '',
|
||||
image: getImageUrl(item, `project-${id}`),
|
||||
catatan: item.catatan || '',
|
||||
members: anggota.map(m => ({ nama: m.nama || '', nim: m.nim || '' })),
|
||||
};
|
||||
}
|
||||
|
||||
// ─── API Fetch ────────────────────────────────────────────────────────────────
|
||||
|
||||
async function fetchAchievements() {
|
||||
const res = await fetch(`${API_BASE}/items/prestasi?fields=*.*`);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const { data } = await res.json();
|
||||
return (data || [])
|
||||
.filter(item => item.status === 'published')
|
||||
.map(transformAchievement);
|
||||
}
|
||||
|
||||
async function fetchProjects() {
|
||||
const res = await fetch(`${API_BASE}/items/portfolio?fields=*,bidang.bidang_id.nama_bidang,galeri.*`);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const { data } = await res.json();
|
||||
return (data || [])
|
||||
.filter(item => item.status === 'published')
|
||||
.map(transformProject);
|
||||
}
|
||||
|
||||
// ─── App State ────────────────────────────────────────────────────────────────
|
||||
|
||||
let achievements = [];
|
||||
let projects = [];
|
||||
let achVisible = 3;
|
||||
let projVisible = 6;
|
||||
|
||||
let achFilter = { search: '', level: '', cat: '', year: '' };
|
||||
let projFilter = { search: '', cat: '', year: '' };
|
||||
|
||||
// ─── Init ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
initWaButton();
|
||||
|
||||
// Loading placeholders
|
||||
showSkeleton('acaab-ach-grid', 3);
|
||||
showSkeleton('acaab-proj-track', 4);
|
||||
|
||||
const [achResult, projResult] = await Promise.allSettled([
|
||||
fetchAchievements(),
|
||||
fetchProjects(),
|
||||
]);
|
||||
|
||||
if (achResult.status === 'fulfilled') {
|
||||
achievements = achResult.value.sort((a, b) => b.year - a.year);
|
||||
} else {
|
||||
console.error('[ACAAB] achievements error:', achResult.reason);
|
||||
showError('acaab-ach-grid', t('grp_acaab_ach_error'));
|
||||
}
|
||||
|
||||
if (projResult.status === 'fulfilled') {
|
||||
projects = projResult.value;
|
||||
} else {
|
||||
console.error('[ACAAB] projects error:', projResult.reason);
|
||||
showError('acaab-proj-track', t('grp_acaab_proj_error'));
|
||||
}
|
||||
|
||||
initStats();
|
||||
initAchievements();
|
||||
initProjects();
|
||||
updateDataNote();
|
||||
});
|
||||
|
||||
// Re-render saat bahasa berubah dari kit navbar
|
||||
document.addEventListener('languageChanged', () => {
|
||||
updateStats();
|
||||
renderAchievements();
|
||||
buildAchFilterOptions();
|
||||
renderProjects();
|
||||
buildProjFilterOptions();
|
||||
updateWaButton();
|
||||
updateDataNote();
|
||||
updateSearchPlaceholders();
|
||||
});
|
||||
|
||||
// ─── Skeleton / Error ─────────────────────────────────────────────────────────
|
||||
|
||||
function showSkeleton(containerId, count) {
|
||||
const el = document.getElementById(containerId);
|
||||
if (!el) return;
|
||||
el.innerHTML = Array(count).fill(0).map(() =>
|
||||
`<div class="acaab-skeleton" style="height:220px;border-radius:0.75rem;"></div>`
|
||||
).join('');
|
||||
}
|
||||
|
||||
function showError(containerId, msg) {
|
||||
const el = document.getElementById(containerId);
|
||||
if (el) el.innerHTML = `<p style="color:#ef4444;padding:1rem 0;grid-column:1/-1;">${escHtml(msg)}</p>`;
|
||||
}
|
||||
|
||||
// ─── Stats ────────────────────────────────────────────────────────────────────
|
||||
|
||||
function initStats() {
|
||||
updateStats();
|
||||
|
||||
const statsEl = document.getElementById('acaab-stats');
|
||||
if (!statsEl) return;
|
||||
|
||||
const intl = achievements.filter(a => a.level === 'Internasional').length;
|
||||
const national = achievements.filter(a => a.level === 'Nasional').length;
|
||||
const regional = achievements.filter(a => a.level === 'Regional').length;
|
||||
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (!entry.isIntersecting) return;
|
||||
animateCount('stat-total-ach', achievements.length, 1600);
|
||||
animateCount('stat-total-proj', projects.length, 1600);
|
||||
animateCount('stat-intl', intl, 1200);
|
||||
animateCount('stat-national', national, 1350);
|
||||
animateCount('stat-regional', regional, 1500);
|
||||
observer.disconnect();
|
||||
});
|
||||
}, { threshold: 0.4 });
|
||||
|
||||
observer.observe(statsEl);
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
const set = (id, val) => { const el = document.getElementById(id); if (el) el.textContent = val; };
|
||||
set('stat-total-ach', achievements.length);
|
||||
set('stat-total-proj', projects.length);
|
||||
set('stat-intl', achievements.filter(a => a.level === 'Internasional').length);
|
||||
set('stat-national', achievements.filter(a => a.level === 'Nasional').length);
|
||||
set('stat-regional', achievements.filter(a => a.level === 'Regional').length);
|
||||
}
|
||||
|
||||
function animateCount(elId, target, duration) {
|
||||
const el = document.getElementById(elId);
|
||||
if (!el) return;
|
||||
const start = performance.now();
|
||||
(function step(now) {
|
||||
const p = Math.min((now - start) / duration, 1);
|
||||
const eased = 1 - Math.pow(1 - p, 4); // easeOutQuart
|
||||
el.textContent = Math.round(target * eased).toLocaleString();
|
||||
if (p < 1) requestAnimationFrame(step);
|
||||
})(start);
|
||||
}
|
||||
|
||||
function updateDataNote() {
|
||||
const el = document.getElementById('acaab-data-note');
|
||||
if (!el) return;
|
||||
const lang = getLang();
|
||||
const locale = lang === 'en' ? 'en-US' : 'id-ID';
|
||||
const date = new Date().toLocaleDateString(locale, { day: 'numeric', month: 'long', year: 'numeric' });
|
||||
el.textContent = `${t('grp_acaab_stats_data_note')} ${date}`;
|
||||
}
|
||||
|
||||
// ─── Achievements ─────────────────────────────────────────────────────────────
|
||||
|
||||
const ACH_INIT = 3;
|
||||
const ACH_MORE = 3;
|
||||
|
||||
const LEVEL_CLASS = {
|
||||
Internasional: 'acaab-badge-intl',
|
||||
Nasional: 'acaab-badge-nasional',
|
||||
Regional: 'acaab-badge-regional',
|
||||
};
|
||||
|
||||
function initAchievements() {
|
||||
buildAchFilterOptions();
|
||||
renderAchievements();
|
||||
bindAchEvents();
|
||||
}
|
||||
|
||||
function buildAchFilterOptions() {
|
||||
const levelSel = document.getElementById('acaab-ach-level');
|
||||
const catSel = document.getElementById('acaab-ach-cat');
|
||||
const yearSel = document.getElementById('acaab-ach-year');
|
||||
if (!levelSel || !catSel || !yearSel) return;
|
||||
|
||||
const levels = ['Internasional', 'Nasional', 'Regional'];
|
||||
const cats = [...new Set(achievements.map(a => a.category))].sort();
|
||||
const years = [...new Set(achievements.map(a => String(a.year)))].filter(Boolean).sort((a, b) => b - a);
|
||||
|
||||
levelSel.innerHTML = `<option value="">${escHtml(t('grp_acaab_ach_filter_level'))}</option>` +
|
||||
levels.map(l => `<option value="${escHtml(l)}"${achFilter.level === l ? ' selected' : ''}>${escHtml(l)}</option>`).join('');
|
||||
catSel.innerHTML = `<option value="">${escHtml(t('grp_acaab_ach_filter_cat'))}</option>` +
|
||||
cats.map(c => `<option value="${escHtml(c)}"${achFilter.cat === c ? ' selected' : ''}>${escHtml(c)}</option>`).join('');
|
||||
yearSel.innerHTML = `<option value="">${escHtml(t('grp_acaab_ach_filter_year'))}</option>` +
|
||||
years.map(y => `<option value="${escHtml(y)}"${achFilter.year === y ? ' selected' : ''}>${escHtml(y)}</option>`).join('');
|
||||
}
|
||||
|
||||
function filterAchievements() {
|
||||
const q = achFilter.search.toLowerCase();
|
||||
return achievements.filter(a => {
|
||||
const matchSearch = !q || [a.title, a.team, a.category, a.competition]
|
||||
.some(s => (s || '').toLowerCase().includes(q));
|
||||
const matchLevel = !achFilter.level || a.level === achFilter.level;
|
||||
const matchCat = !achFilter.cat || a.category === achFilter.cat;
|
||||
const matchYear = !achFilter.year || String(a.year) === achFilter.year;
|
||||
return matchSearch && matchLevel && matchCat && matchYear;
|
||||
});
|
||||
}
|
||||
|
||||
function renderAchievements() {
|
||||
const grid = document.getElementById('acaab-ach-grid');
|
||||
const countEl = document.getElementById('acaab-ach-count');
|
||||
const moreBtn = document.getElementById('acaab-ach-more');
|
||||
const lessBtn = document.getElementById('acaab-ach-less');
|
||||
const resetBtn= document.getElementById('acaab-ach-reset');
|
||||
if (!grid) return;
|
||||
|
||||
const filtered = filterAchievements();
|
||||
const visible = filtered.slice(0, achVisible);
|
||||
const hasFilter = achFilter.search || achFilter.level || achFilter.cat || achFilter.year;
|
||||
|
||||
if (countEl) countEl.textContent =
|
||||
`${t('grp_acaab_ach_showing')} ${filtered.length} ${t('grp_acaab_ach_results')}`;
|
||||
if (resetBtn) resetBtn.style.display = hasFilter ? 'flex' : 'none';
|
||||
|
||||
if (filtered.length === 0) {
|
||||
grid.innerHTML = `<p style="color:#64748b;padding:0.5rem 0;grid-column:1/-1;">${escHtml(t('grp_acaab_ach_empty'))}</p>`;
|
||||
if (moreBtn) moreBtn.style.display = 'none';
|
||||
if (lessBtn) lessBtn.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
grid.innerHTML = visible.map((a, i) => achCardHtml(a, i)).join('');
|
||||
|
||||
if (moreBtn) moreBtn.style.display = achVisible < filtered.length ? 'inline-block' : 'none';
|
||||
if (lessBtn) lessBtn.style.display = achVisible > ACH_INIT ? 'inline-block' : 'none';
|
||||
|
||||
grid.querySelectorAll('.acaab-ach-card').forEach(card => {
|
||||
card.addEventListener('click', (e) => {
|
||||
// Biarkan tombol yang merupakan link tetap berfungsi
|
||||
if (e.target.closest('a')) return;
|
||||
const ach = achievements.find(a => a.id === card.dataset.id);
|
||||
if (ach) openAchModal(ach);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function achCardHtml(a, idx) {
|
||||
return `
|
||||
<article class="acaab-ach-card acaab-fade-in" data-id="${escHtml(a.id)}" style="animation-delay:${idx * 0.05}s;cursor:pointer;">
|
||||
<div class="acaab-ach-top-bar"></div>
|
||||
<!-- Image h-56 (224px) -->
|
||||
<div style="position:relative;height:224px;overflow:hidden;background:#f1f5f9;">
|
||||
<img src="${escHtml(a.image)}" alt="${escHtml(a.title)}" loading="lazy" class="acaab-card-img"
|
||||
style="width:100%;height:100%;object-fit:cover;"
|
||||
onerror="this.src='https://placehold.co/800x600/003150/FDB813?text=Informatika+UNTAN'">
|
||||
<!-- Rank badge top-left: white pill dengan trophy icon -->
|
||||
<div style="position:absolute;top:0.75rem;left:0.75rem;background:rgba(255,255,255,0.95);backdrop-filter:blur(4px);color:#003150;font-weight:700;padding:0.25rem 0.625rem;border-radius:9999px;box-shadow:0 1px 3px rgba(0,0,0,0.15);display:flex;align-items:center;gap:0.375rem;font-size:0.72rem;z-index:2;">
|
||||
<i class="fas fa-trophy" style="color:#feb401;font-size:0.65rem;"></i>
|
||||
${escHtml(a.rank)}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Content p-6 -->
|
||||
<div style="padding:1.5rem;display:flex;flex-direction:column;flex-grow:1;">
|
||||
<!-- Category + Year row -->
|
||||
<div style="display:flex;align-items:center;gap:0.75rem;margin-bottom:0.75rem;">
|
||||
<span style="color:#1e40af;font-size:0.72rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;">${escHtml(a.category)}</span>
|
||||
<span style="color:#94a3b8;font-size:0.72rem;font-weight:500;display:flex;align-items:center;gap:0.25rem;border-left:1px solid #e2e8f0;padding-left:0.625rem;">
|
||||
<i class="fas fa-calendar-alt" style="font-size:0.6rem;"></i> ${escHtml(String(a.year))}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Title -->
|
||||
<h3 class="acaab-card-title acaab-line-clamp-2" style="font-size:1.125rem;font-weight:700;color:#003150;margin:0 0 0.75rem;line-height:1.35;font-family:'Roboto Condensed',sans-serif;">${escHtml(a.title)}</h3>
|
||||
<!-- Description 3 lines -->
|
||||
<p class="acaab-line-clamp-3" style="color:#475569;font-size:0.875rem;line-height:1.6;margin:0 0 1.5rem;flex-grow:1;">${escHtml(a.description)}</p>
|
||||
<!-- Bottom -->
|
||||
<div style="border-top:1px solid #f1f5f9;padding-top:1rem;margin-top:auto;">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;">
|
||||
<!-- Avatar + team + generation -->
|
||||
<div style="display:flex;align-items:center;gap:0.625rem;">
|
||||
<div style="width:2rem;height:2rem;border-radius:0.375rem;background:rgba(0,49,80,0.05);border:1px solid rgba(0,49,80,0.1);display:flex;align-items:center;justify-content:center;color:#003150;font-weight:700;font-size:0.65rem;flex-shrink:0;">${escHtml(a.avatar)}</div>
|
||||
<div>
|
||||
<span style="font-weight:700;color:#1e293b;display:block;font-size:0.8125rem;line-height:1.2;">${escHtml(a.team)}</span>
|
||||
<span style="color:#64748b;display:block;font-size:0.72rem;margin-top:0.1rem;">${escHtml(a.generation)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Level badge -->
|
||||
<span style="background:#f1f5f9;color:#475569;font-size:0.575rem;padding:0.2rem 0.5rem;border-radius:0.25rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;white-space:nowrap;">${escHtml(a.level)}</span>
|
||||
</div>
|
||||
<!-- Full-width CTA button -->
|
||||
<button class="acaab-ach-readmore acaab-ach-read-btn" data-id="${escHtml(a.id)}"
|
||||
style="width:100%;padding:0.625rem;border-radius:0.375rem;background:rgba(0,49,80,0.05);color:#003150;font-weight:700;font-size:0.875rem;border:none;cursor:pointer;transition:background 0.2s,color 0.2s;min-height:44px;">
|
||||
${escHtml(t('grp_acaab_modal_read_more'))}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>`;
|
||||
}
|
||||
|
||||
function bindAchEvents() {
|
||||
const search = document.getElementById('acaab-ach-search');
|
||||
const level = document.getElementById('acaab-ach-level');
|
||||
const cat = document.getElementById('acaab-ach-cat');
|
||||
const year = document.getElementById('acaab-ach-year');
|
||||
const reset = document.getElementById('acaab-ach-reset');
|
||||
const moreBtn = document.getElementById('acaab-ach-more');
|
||||
const lessBtn = document.getElementById('acaab-ach-less');
|
||||
|
||||
const onChange = () => {
|
||||
achFilter.search = search ? search.value.trim() : '';
|
||||
achFilter.level = level ? level.value : '';
|
||||
achFilter.cat = cat ? cat.value : '';
|
||||
achFilter.year = year ? year.value : '';
|
||||
achVisible = ACH_INIT;
|
||||
renderAchievements();
|
||||
};
|
||||
|
||||
if (search) search.addEventListener('input', onChange);
|
||||
if (level) level.addEventListener('change', onChange);
|
||||
if (cat) cat.addEventListener('change', onChange);
|
||||
if (year) year.addEventListener('change', onChange);
|
||||
|
||||
if (reset) reset.addEventListener('click', () => {
|
||||
achFilter = { search: '', level: '', cat: '', year: '' };
|
||||
if (search) search.value = '';
|
||||
if (level) level.value = '';
|
||||
if (cat) cat.value = '';
|
||||
if (year) year.value = '';
|
||||
achVisible = ACH_INIT;
|
||||
renderAchievements();
|
||||
});
|
||||
|
||||
if (moreBtn) moreBtn.addEventListener('click', () => { achVisible += ACH_MORE; renderAchievements(); });
|
||||
if (lessBtn) lessBtn.addEventListener('click', () => {
|
||||
achVisible = ACH_INIT;
|
||||
document.getElementById('acaab-ach-section')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
renderAchievements();
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Achievement Modal ────────────────────────────────────────────────────────
|
||||
|
||||
function infoRow(icon, label, value) {
|
||||
if (!value) return '';
|
||||
return `<div style="display:flex;gap:0.625rem;align-items:flex-start;">
|
||||
<span style="color:#feb401;margin-top:0.125rem;flex-shrink:0;"><i class="fas fa-${icon}" style="font-size:0.75rem;"></i></span>
|
||||
<div>
|
||||
<p style="font-size:0.6rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin:0 0 0.125rem;line-height:1;">${escHtml(label)}</p>
|
||||
<p style="font-size:0.875rem;font-weight:600;color:#1e293b;margin:0;line-height:1.3;">${escHtml(value)}</p>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function memberItem(nama, sub) {
|
||||
const initial = (nama || '?').charAt(0).toUpperCase();
|
||||
return `<li style="display:flex;align-items:center;gap:0.5rem;background:#f8fafc;padding:0.5rem 0.75rem;border-radius:0.375rem;">
|
||||
<span style="width:1.5rem;height:1.5rem;border-radius:50%;background:rgba(254,180,1,0.2);color:#b45309;display:flex;align-items:center;justify-content:center;font-size:0.72rem;font-weight:700;flex-shrink:0;">${initial}</span>
|
||||
<div style="display:flex;flex-direction:column;">
|
||||
<span style="font-size:0.875rem;font-weight:600;color:#334155;line-height:1.2;">${escHtml(nama)}</span>
|
||||
${sub ? `<span style="font-size:0.65rem;color:#94a3b8;margin-top:0.125rem;">${escHtml(sub)}</span>` : ''}
|
||||
</div>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
function openAchModal(a) {
|
||||
const membersHtml = a.members && a.members.length > 0 ? `
|
||||
<div style="border-top:1px solid #f1f5f9;padding-top:1rem;margin-bottom:1rem;">
|
||||
<p style="font-size:0.6rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin:0 0 0.5rem;">Anggota Tim</p>
|
||||
<ul style="list-style:none;margin:0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:0.5rem;">
|
||||
${a.members.map(m => memberItem(m.nama, m.angkatan ? `Angkatan ${m.angkatan}` : '')).join('')}
|
||||
</ul>
|
||||
</div>` : '';
|
||||
|
||||
renderModal(`
|
||||
<!-- Image header -->
|
||||
<div style="position:relative;border-radius:0.75rem 0.75rem 0 0;background:#0f172a;flex-shrink:0;">
|
||||
<img src="${escHtml(a.image)}" alt="${escHtml(a.title)}" style="width:100%;max-height:450px;object-fit:contain;display:block;"
|
||||
onerror="this.src='https://placehold.co/800x600/0f172a/FDB813?text=Informatika+UNTAN'">
|
||||
<div style="position:absolute;inset:0;background:linear-gradient(to top,rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.1) 40%,transparent 100%);pointer-events:none;"></div>
|
||||
<!-- Close button: white rounded-full -->
|
||||
<button id="acaab-modal-close" aria-label="Tutup"
|
||||
style="position:absolute;top:0.75rem;right:0.75rem;width:2.25rem;height:2.25rem;background:rgba(255,255,255,0.9);backdrop-filter:blur(4px);border:none;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,0.2);">
|
||||
<i class="fas fa-times" style="color:#334155;font-size:0.875rem;"></i>
|
||||
</button>
|
||||
<!-- Two badges bottom-left -->
|
||||
<div style="position:absolute;bottom:1rem;left:1rem;display:flex;gap:0.5rem;flex-wrap:wrap;">
|
||||
<span style="background:#feb401;color:#0f172a;font-size:0.72rem;font-weight:700;padding:0.3rem 0.75rem;border-radius:0.25rem;display:flex;align-items:center;gap:0.375rem;">
|
||||
<i class="fas fa-trophy" style="font-size:0.65rem;"></i>${escHtml(a.rank)}
|
||||
</span>
|
||||
<span style="background:rgba(255,255,255,0.2);backdrop-filter:blur(4px);color:white;font-size:0.72rem;font-weight:700;padding:0.3rem 0.75rem;border-radius:0.25rem;text-transform:uppercase;letter-spacing:0.05em;">
|
||||
${escHtml(a.level)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Content -->
|
||||
<div style="padding:1.5rem;">
|
||||
<span style="color:#1e40af;font-size:0.72rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;">${escHtml(a.category)}</span>
|
||||
<h2 style="font-size:1.125rem;font-weight:700;color:#003150;line-height:1.3;margin:0.25rem 0 1.25rem;font-family:'Roboto Condensed',sans-serif;">${escHtml(a.title)}</h2>
|
||||
<!-- Info grid: slate-50 bg -->
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:1rem;padding:1rem;background:#f8fafc;border-radius:0.5rem;margin-bottom:1.25rem;">
|
||||
${infoRow('users', t('grp_acaab_modal_team'), a.team)}
|
||||
${a.nim ? infoRow('id-card', 'NIM', a.nim) : ''}
|
||||
${infoRow('user-graduate', t('grp_acaab_modal_generation'), a.generation)}
|
||||
${infoRow('calendar-alt', 'Tahun', String(a.year))}
|
||||
${infoRow('award', 'Kompetisi', a.competition)}
|
||||
${infoRow('tag', 'Bidang', a.category)}
|
||||
</div>
|
||||
${membersHtml}
|
||||
<!-- Description -->
|
||||
<div style="border-top:1px solid #f1f5f9;padding-top:1rem;">
|
||||
<p style="font-size:0.6rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin:0 0 0.5rem;">Deskripsi</p>
|
||||
<p style="color:#475569;font-size:0.875rem;line-height:1.65;margin:0;">${escHtml(a.description)}</p>
|
||||
</div>
|
||||
<!-- Close button full-width -->
|
||||
<button id="acaab-modal-close-btn" style="margin-top:1.5rem;width:100%;padding:0.75rem;background:#003150;color:white;font-weight:700;border:none;border-radius:0.5rem;cursor:pointer;font-size:0.875rem;">
|
||||
Tutup
|
||||
</button>
|
||||
</div>
|
||||
`, true);
|
||||
}
|
||||
|
||||
// ─── Projects ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const PROJ_INIT = 6;
|
||||
const PROJ_MORE = 3;
|
||||
|
||||
function initProjects() {
|
||||
buildProjFilterOptions();
|
||||
renderProjects();
|
||||
bindProjEvents();
|
||||
}
|
||||
|
||||
function buildProjFilterOptions() {
|
||||
const catSel = document.getElementById('acaab-proj-cat');
|
||||
const yearSel = document.getElementById('acaab-proj-year');
|
||||
if (!catSel || !yearSel) return;
|
||||
|
||||
const cats = [...new Set(projects.flatMap(p => p.categories))].sort();
|
||||
const years = [...new Set(projects.map(p => String(p.year)))].filter(Boolean).sort((a, b) => b - a);
|
||||
|
||||
catSel.innerHTML = `<option value="">${escHtml(t('grp_acaab_proj_filter_cat'))}</option>` +
|
||||
cats.map(c => `<option value="${escHtml(c)}"${projFilter.cat === c ? ' selected' : ''}>${escHtml(c)}</option>`).join('');
|
||||
yearSel.innerHTML = `<option value="">${escHtml(t('grp_acaab_proj_filter_year'))}</option>` +
|
||||
years.map(y => `<option value="${escHtml(y)}"${projFilter.year === y ? ' selected' : ''}>${escHtml(y)}</option>`).join('');
|
||||
}
|
||||
|
||||
function filterProjects() {
|
||||
const q = projFilter.search.toLowerCase();
|
||||
const result = projects.filter(p => {
|
||||
const matchSearch = !q || [p.title, p.studentName, p.description, ...p.categories]
|
||||
.some(s => (s || '').toLowerCase().includes(q));
|
||||
const matchCat = !projFilter.cat || p.categories.includes(projFilter.cat);
|
||||
const matchYear = !projFilter.year || String(p.year) === projFilter.year;
|
||||
return matchSearch && matchCat && matchYear;
|
||||
});
|
||||
|
||||
// Sort descending by year
|
||||
result.sort((a, b) => (b.year || 0) - (a.year || 0));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function renderProjects() {
|
||||
const track = document.getElementById('acaab-proj-track');
|
||||
const moreBtn = document.getElementById('acaab-proj-more');
|
||||
const resetBtn = document.getElementById('acaab-proj-reset');
|
||||
if (!track) return;
|
||||
|
||||
const filtered = filterProjects();
|
||||
const visible = filtered.slice(0, projVisible);
|
||||
const hasFilter = projFilter.search || projFilter.cat || projFilter.year;
|
||||
|
||||
if (resetBtn) resetBtn.style.display = hasFilter ? 'flex' : 'none';
|
||||
|
||||
if (filtered.length === 0) {
|
||||
track.innerHTML = `<p style="color:#64748b;padding:0.5rem 0;">${escHtml(t('grp_acaab_proj_empty'))}</p>`;
|
||||
if (moreBtn) moreBtn.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
track.innerHTML = visible.map((p, i) => projCardHtml(p, i)).join('');
|
||||
if (moreBtn) moreBtn.style.display = projVisible < filtered.length ? 'inline-block' : 'none';
|
||||
|
||||
// Responsif: Sembunyikan scroll button & center jika cuma 1 data
|
||||
const prevBtn = document.getElementById('acaab-proj-prev');
|
||||
const nextBtn = document.getElementById('acaab-proj-next');
|
||||
if (prevBtn) prevBtn.style.display = filtered.length <= 1 ? 'none' : 'flex';
|
||||
if (nextBtn) nextBtn.style.display = filtered.length <= 1 ? 'none' : 'flex';
|
||||
track.style.justifyContent = filtered.length === 1 ? 'center' : 'flex-start';
|
||||
|
||||
track.querySelectorAll('.acaab-proj-card-wrap').forEach(card => {
|
||||
card.addEventListener('click', (e) => {
|
||||
if (e.target.closest('a') && e.target.closest('a').href) return;
|
||||
const proj = projects.find(p => p.id === card.dataset.id);
|
||||
if (proj) openProjModal(proj);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function projCardHtml(p, idx) {
|
||||
const catBadges = p.categories.map(c => `
|
||||
<span style="display:inline-flex;align-items:center;gap:0.2rem;font-size:0.6rem;font-weight:700;color:#feb401;text-transform:uppercase;letter-spacing:0.05em;background:rgba(0,0,0,0.3);padding:0.2rem 0.45rem;border-radius:0.2rem;backdrop-filter:blur(4px);">
|
||||
<i class="fas fa-tag" style="font-size:0.5rem;"></i>${escHtml(c)}
|
||||
</span>`).join('');
|
||||
|
||||
return `
|
||||
<div class="acaab-proj-card acaab-proj-card-wrap acaab-fade-in" data-id="${escHtml(p.id)}" style="animation-delay:${idx * 0.05}s;cursor:pointer;">
|
||||
<div class="acaab-proj-left-bar"></div>
|
||||
<!-- Image h-52 (208px) dengan title overlay -->
|
||||
<div style="height:208px;overflow:hidden;position:relative;">
|
||||
<img src="${escHtml(p.image)}" alt="${escHtml(p.title)}" loading="lazy" class="acaab-card-img"
|
||||
style="width:100%;height:100%;object-fit:cover;"
|
||||
onerror="this.src='https://placehold.co/800x600/003150/FDB813?text=Informatika+UNTAN'">
|
||||
<!-- Gradient overlay: title + categories di dalam gambar -->
|
||||
<div style="position:absolute;inset:0;background:linear-gradient(to top,rgba(0,49,80,0.85),transparent);padding:1.25rem;display:flex;flex-direction:column;justify-content:flex-end;pointer-events:none;">
|
||||
<h4 style="font-size:1rem;font-weight:700;color:white;line-height:1.25;margin:0 0 0.375rem;font-family:'Roboto Condensed',sans-serif;">${escHtml(p.title)}</h4>
|
||||
<div style="display:flex;flex-wrap:wrap;gap:0.3rem;">${catBadges}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Body p-5 -->
|
||||
<div style="padding:1.25rem;display:flex;flex-direction:column;flex-grow:1;">
|
||||
<!-- Meta: student + year -->
|
||||
<div style="display:flex;flex-wrap:wrap;align-items:center;gap:0.625rem;margin-bottom:0.75rem;font-size:0.72rem;color:#64748b;font-weight:500;">
|
||||
${p.studentName ? `<span style="display:flex;align-items:center;gap:0.25rem;"><i class="fas fa-user" style="color:#94a3b8;font-size:0.6rem;"></i>${escHtml(p.studentName)}</span>` : ''}
|
||||
${p.year ? `<span style="display:flex;align-items:center;gap:0.25rem;"><i class="fas fa-calendar-alt" style="color:#94a3b8;font-size:0.6rem;"></i>${escHtml(String(p.year))}</span>` : ''}
|
||||
</div>
|
||||
<!-- Description 3 lines -->
|
||||
<p class="acaab-line-clamp-3" style="color:#475569;font-size:0.875rem;line-height:1.6;margin:0 0 1.25rem;flex-grow:1;">${escHtml(p.description)}</p>
|
||||
<!-- Actions -->
|
||||
<div style="display:flex;align-items:center;gap:0.625rem;margin-top:auto;">
|
||||
<button class="acaab-proj-readmore" data-id="${escHtml(p.id)}"
|
||||
style="color:#003150;font-weight:700;font-size:0.875rem;background:none;border:none;cursor:pointer;display:flex;align-items:center;gap:0.375rem;min-height:44px;">
|
||||
${escHtml(t('grp_acaab_modal_read_more'))} <i class="fas fa-arrow-right" style="font-size:0.7rem;"></i>
|
||||
</button>
|
||||
${p.link ? `
|
||||
<a href="${escHtml(p.link)}" target="_blank" rel="noopener noreferrer"
|
||||
style="margin-left:auto;display:flex;align-items:center;gap:0.375rem;font-size:0.72rem;font-weight:700;color:#64748b;border:1px solid #e2e8f0;border-radius:0.375rem;padding:0.375rem 0.625rem;text-decoration:none;min-height:44px;transition:color 0.2s,border-color 0.2s;">
|
||||
<i class="fas fa-external-link-alt" style="font-size:0.65rem;"></i>${escHtml(t('grp_acaab_modal_visit'))}
|
||||
</a>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function bindProjEvents() {
|
||||
const search = document.getElementById('acaab-proj-search');
|
||||
const cat = document.getElementById('acaab-proj-cat');
|
||||
const year = document.getElementById('acaab-proj-year');
|
||||
const reset = document.getElementById('acaab-proj-reset');
|
||||
const moreBtn = document.getElementById('acaab-proj-more');
|
||||
const prevBtn = document.getElementById('acaab-proj-prev');
|
||||
const nextBtn = document.getElementById('acaab-proj-next');
|
||||
|
||||
const onChange = () => {
|
||||
projFilter.search = search ? search.value.trim() : '';
|
||||
projFilter.cat = cat ? cat.value : '';
|
||||
projFilter.year = year ? year.value : '';
|
||||
projVisible = PROJ_INIT;
|
||||
renderProjects();
|
||||
};
|
||||
|
||||
if (search) search.addEventListener('input', onChange);
|
||||
if (cat) cat.addEventListener('change', onChange);
|
||||
if (year) year.addEventListener('change', onChange);
|
||||
|
||||
if (reset) reset.addEventListener('click', () => {
|
||||
projFilter = { search: '', cat: '', year: '' };
|
||||
if (search) search.value = '';
|
||||
if (cat) cat.value = '';
|
||||
if (year) year.value = '';
|
||||
projVisible = PROJ_INIT;
|
||||
renderProjects();
|
||||
});
|
||||
|
||||
if (moreBtn) moreBtn.addEventListener('click', () => { projVisible += PROJ_MORE; renderProjects(); });
|
||||
|
||||
const track = document.getElementById('acaab-proj-track');
|
||||
if (prevBtn && track) prevBtn.addEventListener('click', () => {
|
||||
const cardW = (track.firstElementChild ? track.firstElementChild.offsetWidth : 300) + 20;
|
||||
track.scrollBy({ left: -cardW, behavior: 'smooth' });
|
||||
});
|
||||
if (nextBtn && track) nextBtn.addEventListener('click', () => {
|
||||
const cardW = (track.firstElementChild ? track.firstElementChild.offsetWidth : 300) + 20;
|
||||
track.scrollBy({ left: cardW, behavior: 'smooth' });
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Project Modal ────────────────────────────────────────────────────────────
|
||||
|
||||
function openProjModal(p) {
|
||||
const membersHtml = p.members && p.members.length > 0 ? `
|
||||
<div style="border-top:1px solid #f1f5f9;padding-top:1rem;margin-bottom:1rem;">
|
||||
<p style="font-size:0.6rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin:0 0 0.5rem;">Anggota Tim</p>
|
||||
<ul style="list-style:none;margin:0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:0.5rem;">
|
||||
${p.members.map(m => memberItem(m.nama, m.nim || '')).join('')}
|
||||
</ul>
|
||||
</div>` : '';
|
||||
|
||||
const catBadgesImg = p.categories.map(c => `
|
||||
<span style="background:#feb401;color:#0f172a;font-size:0.72rem;font-weight:700;padding:0.3rem 0.75rem;border-radius:0.25rem;display:inline-flex;align-items:center;gap:0.375rem;text-transform:uppercase;letter-spacing:0.05em;">
|
||||
<i class="fas fa-tag" style="font-size:0.6rem;"></i>${escHtml(c)}
|
||||
</span>`).join('');
|
||||
|
||||
const linkSection = p.link
|
||||
? `<a href="${escHtml(p.link)}" target="_blank" rel="noopener noreferrer"
|
||||
style="display:flex;align-items:center;justify-content:center;gap:0.5rem;width:100%;padding:0.75rem;background:#003150;color:white;font-weight:700;border-radius:0.5rem;font-size:0.875rem;text-decoration:none;margin-bottom:0.625rem;">
|
||||
<i class="fas fa-external-link-alt" style="font-size:0.8rem;"></i>${escHtml(t('grp_acaab_modal_visit'))}
|
||||
</a>`
|
||||
: `<div style="display:flex;align-items:center;justify-content:center;gap:0.5rem;width:100%;padding:0.75rem;background:#f1f5f9;color:#94a3b8;font-weight:700;border-radius:0.5rem;font-size:0.875rem;margin-bottom:0.625rem;cursor:not-allowed;">
|
||||
<i class="fas fa-file-alt" style="font-size:0.8rem;"></i>${escHtml(t('grp_acaab_modal_no_link'))}
|
||||
</div>`;
|
||||
|
||||
renderModal(`
|
||||
<!-- Image header -->
|
||||
<div style="position:relative;border-radius:0.75rem 0.75rem 0 0;background:#0f172a;flex-shrink:0;">
|
||||
<img src="${escHtml(p.image)}" alt="${escHtml(p.title)}" style="width:100%;max-height:450px;object-fit:contain;display:block;"
|
||||
onerror="this.src='https://placehold.co/800x600/0f172a/FDB813?text=Informatika+UNTAN'">
|
||||
<div style="position:absolute;inset:0;background:linear-gradient(to top,rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.1) 40%,transparent 100%);pointer-events:none;"></div>
|
||||
<!-- Close button -->
|
||||
<button id="acaab-modal-close" aria-label="Tutup"
|
||||
style="position:absolute;top:0.75rem;right:0.75rem;width:2.25rem;height:2.25rem;background:rgba(255,255,255,0.9);backdrop-filter:blur(4px);border:none;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,0.2);">
|
||||
<i class="fas fa-times" style="color:#334155;font-size:0.875rem;"></i>
|
||||
</button>
|
||||
<!-- Category badges bottom-left -->
|
||||
<div style="position:absolute;bottom:1rem;left:1rem;display:flex;flex-wrap:wrap;gap:0.375rem;">${catBadgesImg}</div>
|
||||
</div>
|
||||
<!-- Content -->
|
||||
<div style="padding:1.5rem;">
|
||||
<h2 style="font-size:1.125rem;font-weight:700;color:#003150;line-height:1.3;margin:0 0 1.25rem;font-family:'Roboto Condensed',sans-serif;">${escHtml(p.title)}</h2>
|
||||
<!-- Info grid -->
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:1rem;padding:1rem;background:#f8fafc;border-radius:0.5rem;margin-bottom:1.25rem;">
|
||||
${p.studentName ? infoRow('users', t('grp_acaab_modal_team'), p.studentName) : ''}
|
||||
${p.nim ? infoRow('id-card', 'NIM', p.nim) : ''}
|
||||
${infoRow('calendar-alt', 'Tahun', String(p.year))}
|
||||
${infoRow('tag', 'Bidang', p.categories.join(', '))}
|
||||
</div>
|
||||
${membersHtml}
|
||||
<!-- Description -->
|
||||
<div style="border-top:1px solid #f1f5f9;padding-top:1rem;margin-bottom:1.25rem;">
|
||||
<p style="font-size:0.6rem;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin:0 0 0.5rem;">Deskripsi</p>
|
||||
<p style="color:#475569;font-size:0.875rem;line-height:1.65;margin:0;">${escHtml(p.description)}</p>
|
||||
${p.catatan ? `
|
||||
<div style="margin-top:1rem;padding:0.75rem;background:rgba(239,246,255,0.5);border:1px solid #bfdbfe;border-radius:0.5rem;">
|
||||
<p style="font-size:0.6rem;font-weight:700;text-transform:uppercase;color:#93c5fd;margin:0 0 0.25rem;">Catatan Tambahan</p>
|
||||
<p style="font-size:0.875rem;color:#475569;font-style:italic;margin:0;">${escHtml(p.catatan)}</p>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
<!-- Link + close buttons -->
|
||||
${linkSection}
|
||||
<button id="acaab-modal-close-btn" style="width:100%;padding:0.625rem;border:2px solid #e2e8f0;color:#475569;font-weight:700;background:white;border-radius:0.5rem;cursor:pointer;font-size:0.875rem;transition:border-color 0.2s,background 0.2s;">
|
||||
Tutup
|
||||
</button>
|
||||
</div>
|
||||
`, true);
|
||||
}
|
||||
|
||||
// ─── Modal shared ─────────────────────────────────────────────────────────────
|
||||
|
||||
function renderModal(innerHtml, hasCloseBtn = false) {
|
||||
const container = document.getElementById('acaab-modal');
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="acaab-modal-backdrop" id="acaab-modal-bd">
|
||||
<div style="background:white;border-radius:0.75rem;max-width:672px;width:100%;max-height:90vh;overflow-y:auto;box-shadow:0 20px 60px rgba(0,0,0,0.35);">
|
||||
${innerHtml}
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
document.body.classList.add('acaab-modal-open');
|
||||
|
||||
document.getElementById('acaab-modal-close')?.addEventListener('click', closeModal);
|
||||
if (hasCloseBtn) {
|
||||
document.getElementById('acaab-modal-close-btn')?.addEventListener('click', closeModal);
|
||||
}
|
||||
document.getElementById('acaab-modal-bd').addEventListener('click', e => {
|
||||
if (e.target === e.currentTarget) closeModal();
|
||||
});
|
||||
document.addEventListener('keydown', onEsc);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
const c = document.getElementById('acaab-modal');
|
||||
if (c) c.innerHTML = '';
|
||||
document.body.classList.remove('acaab-modal-open');
|
||||
document.removeEventListener('keydown', onEsc);
|
||||
}
|
||||
|
||||
function onEsc(e) { if (e.key === 'Escape') closeModal(); }
|
||||
|
||||
// ─── CTA / WhatsApp ───────────────────────────────────────────────────────────
|
||||
|
||||
const WA_NUMBER = '6285177655161';
|
||||
|
||||
function initWaButton() { updateWaButton(); }
|
||||
|
||||
function updateWaButton() {
|
||||
const btn = document.getElementById('acaab-cta-wa');
|
||||
if (!btn) return;
|
||||
const msg = getLang() === 'en'
|
||||
? 'Hello! I would like to know more about Informatika UNTAN student achievements and projects.'
|
||||
: 'Halo! Saya ingin mengetahui lebih lanjut tentang prestasi dan karya mahasiswa Informatika UNTAN.';
|
||||
btn.href = `https://wa.me/${WA_NUMBER}?text=${encodeURIComponent(msg)}`;
|
||||
}
|
||||
|
||||
// ─── Placeholder sync ─────────────────────────────────────────────────────────
|
||||
|
||||
function updateSearchPlaceholders() {
|
||||
const s1 = document.getElementById('acaab-ach-search');
|
||||
const s2 = document.getElementById('acaab-proj-search');
|
||||
if (s1) s1.placeholder = t('grp_acaab_ach_search');
|
||||
if (s2) s2.placeholder = t('grp_acaab_proj_search');
|
||||
}
|
||||
+212
-38
@@ -1,48 +1,222 @@
|
||||
:root {
|
||||
--brand-navy: #003150;
|
||||
--brand-yellow: #feb401;
|
||||
--text-main: #1e293b;
|
||||
--text-soft: #64748b;
|
||||
--bg-soft: #f8fafc;
|
||||
--line: #e2e8f0;
|
||||
/* =====================================================
|
||||
ACAAB – Prestasi & Karya Mahasiswa
|
||||
Custom styles yang tidak dicakup output.css
|
||||
===================================================== */
|
||||
|
||||
/* Cegah horizontal scroll tanpa clip full-bleed */
|
||||
body { overflow-x: hidden; }
|
||||
|
||||
/* --- Full-bleed: section keluar dari container prose --- */
|
||||
.acaab-full-bleed {
|
||||
width: 100vw;
|
||||
margin-left: calc(50% - 50vw);
|
||||
margin-right: calc(50% - 50vw);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body { font-family: "Roboto", Arial, sans-serif; color: var(--text-main); background: #fff; line-height: 1.6; }
|
||||
.container { width: min(1100px, 92%); margin-inline: auto; }
|
||||
/* --- Sembunyikan scrollbar carousel tapi tetap scrollable --- */
|
||||
.acaab-hide-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.acaab-hide-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav { background: var(--brand-navy); color: #fff; border-bottom: 4px solid var(--brand-yellow); padding: 14px 0; }
|
||||
.brand { font-size: 1.1rem; font-weight: 700; letter-spacing: .02em; }
|
||||
/* --- Card ukuran responsif di carousel --- */
|
||||
.acaab-proj-card {
|
||||
width: 80vw;
|
||||
flex-shrink: 0;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
@media (min-width: 768px) { .acaab-proj-card { width: 44vw; } }
|
||||
@media (min-width: 1024px) { .acaab-proj-card { width: 30vw; } }
|
||||
|
||||
.hero { position: relative; color: #fff; min-height: 220px; display: flex; align-items: flex-end; overflow: hidden; }
|
||||
.hero-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: brightness(0.45); }
|
||||
.hero-inner { position: relative; z-index: 1; padding: 36px 0; }
|
||||
.badge { display: inline-block; background: var(--brand-yellow); color: #111827; font-size: .68rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; padding: .2rem .45rem; margin-bottom: 12px; }
|
||||
.hero h1 { margin: 0; font-size: clamp(1.6rem, 3.2vw, 2.8rem); line-height: 1.2; }
|
||||
/* --- Snap scroll carousel --- */
|
||||
.acaab-carousel-track {
|
||||
scroll-snap-type: x mandatory;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.layout { display: grid; grid-template-columns: 1fr; gap: 2rem; padding: 2rem 0 4rem; }
|
||||
@media (min-width: 1024px) { .layout { grid-template-columns: minmax(0, 3fr) minmax(260px, 1fr); } }
|
||||
/* --- Animasi fade-in untuk cards --- */
|
||||
@keyframes acaab-fade-in {
|
||||
from { opacity: 0; transform: translateY(14px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.acaab-fade-in {
|
||||
animation: acaab-fade-in 0.35s ease both;
|
||||
}
|
||||
|
||||
.meta { font-size: .78rem; text-transform: uppercase; color: #475569; display: flex; flex-wrap: wrap; gap: .75rem 1rem; margin-bottom: 1rem; }
|
||||
.cover { background: var(--bg-soft); border: 1px solid var(--line); margin-bottom: 1.5rem; }
|
||||
.cover img { width: 100%; height: auto; display: block; }
|
||||
/* --- Badge level warna --- */
|
||||
.acaab-badge-intl { background-color: #ca8a04; color: #fff; }
|
||||
.acaab-badge-nasional { background-color: #1d4ed8; color: #fff; }
|
||||
.acaab-badge-regional { background-color: #64748b; color: #fff; }
|
||||
|
||||
.article-body > * + * { margin-top: 1.1em; }
|
||||
.article-body h2 { font-size: 1.35rem; margin: 1.6em 0 .5em; }
|
||||
.article-body h3 { font-size: 1.1rem; margin: 1.4em 0 .4em; }
|
||||
.article-body p { margin: 0 0 1em; }
|
||||
.article-body ul, .article-body ol { padding-left: 1.4rem; }
|
||||
.article-body blockquote { border-left: 4px solid #005eb8; background: #eef6ff; padding: .8rem 1rem; color: #334155; }
|
||||
.article-body a { color: #005eb8; }
|
||||
.article-body img { max-width: 100%; border-radius: 8px; }
|
||||
.article-body code { background: #f1f5f9; padding: .1em .35em; border-radius: 4px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
||||
/* --- Skeleton loading --- */
|
||||
.acaab-skeleton {
|
||||
background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: acaab-skeleton-pulse 1.5s infinite;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
@keyframes acaab-skeleton-pulse {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
.note { border: 1px solid var(--line); background: var(--bg-soft); padding: 1rem; }
|
||||
.note h3 { margin: 0 0 .5rem; font-size: .76rem; text-transform: uppercase; letter-spacing: .12em; color: #475569; }
|
||||
/* --- Modal backdrop --- */
|
||||
.acaab-modal-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.65);
|
||||
backdrop-filter: blur(4px);
|
||||
-webkit-backdrop-filter: blur(4px);
|
||||
z-index: 200;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.footer { margin-top: 2rem; background: var(--brand-navy); color: #fff; border-top: 4px solid var(--brand-yellow); }
|
||||
.footer-inner { display: flex; align-items: center; justify-content: center; gap: .75rem; padding: 1rem 0; }
|
||||
.footer-logo { height: 28px; width: auto; }
|
||||
.footer-ornament { width: 100%; display: block; opacity: .9; }
|
||||
/* --- Scroll lock saat modal terbuka --- */
|
||||
body.acaab-modal-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* --- Stats grid: divider vertikal di desktop --- */
|
||||
@media (min-width: 768px) {
|
||||
.acaab-stats-grid {
|
||||
grid-template-columns: 1fr 1px 1fr 1px 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Line clamp (browser lama) --- */
|
||||
.acaab-line-clamp-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.acaab-line-clamp-3 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* --- Achievement card --- */
|
||||
.acaab-ach-card {
|
||||
position: relative;
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);
|
||||
border: 1px solid #e2e8f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
.acaab-ach-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.12), 0 4px 10px rgba(0,0,0,0.08);
|
||||
}
|
||||
.acaab-ach-top-bar {
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 3px;
|
||||
background: #003150;
|
||||
z-index: 10;
|
||||
transition: background 0.25s ease;
|
||||
}
|
||||
.acaab-ach-card:hover .acaab-ach-top-bar { background: #feb401; }
|
||||
.acaab-ach-card:hover .acaab-card-title { color: #1e40af; }
|
||||
.acaab-card-title { transition: color 0.2s ease; }
|
||||
.acaab-ach-read-btn:hover { background: #003150 !important; color: white !important; }
|
||||
|
||||
/* --- Project card wrapper --- */
|
||||
.acaab-proj-card-wrap {
|
||||
position: relative;
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);
|
||||
border: 1px solid #e2e8f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
.acaab-proj-card-wrap:hover { box-shadow: 0 10px 25px rgba(0,0,0,0.12); }
|
||||
.acaab-proj-left-bar {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 3px; height: 100%;
|
||||
background: #feb401;
|
||||
z-index: 10;
|
||||
transform-origin: bottom;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.acaab-proj-card-wrap:hover .acaab-proj-left-bar { transform: scaleY(1.08); }
|
||||
.acaab-proj-card-wrap:hover .acaab-card-img { transform: scale(1.05); }
|
||||
|
||||
/* --- Card image zoom --- */
|
||||
.acaab-card-img {
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
/* --- Stats grid dividers responsive --- */
|
||||
.acaab-stat-vdivider { display: none; }
|
||||
@media (min-width: 768px) {
|
||||
.acaab-stat-vdivider { display: flex; }
|
||||
.acaab-stat-hdivider { display: none; }
|
||||
}
|
||||
|
||||
/* --- Filter focus --- */
|
||||
#acaab-ach-filters input:focus,
|
||||
#acaab-ach-filters select:focus,
|
||||
#acaab-proj-filters input:focus,
|
||||
#acaab-proj-filters select:focus {
|
||||
outline: 2px solid #003150;
|
||||
outline-offset: 1px;
|
||||
border-color: #003150;
|
||||
}
|
||||
|
||||
/* --- CTA inner layout: stacked mobile → row desktop --- */
|
||||
.acaab-cta-inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.acaab-cta-inner {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
text-align: left;
|
||||
gap: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Reduced motion --- */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
}
|
||||
|
||||
/* --- Modal Responsiveness Overrides --- */
|
||||
.acaab-modal-achievement {
|
||||
max-width: 500px !important;
|
||||
}
|
||||
|
||||
.acaab-modal-project {
|
||||
max-width: 700px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 639px) {
|
||||
.acaab-modal-achievement, .acaab-modal-project {
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
border-radius: 1rem 1rem 0 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user