Files
web-if-dev/index.html
2026-01-15 12:25:47 +00:00

1437 lines
79 KiB
HTML

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Informatika UNTAN - Universitas Tanjungpura</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Google Fonts: Poppins & Playfair Display -->
<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=Poppins:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,700;1,700&display=swap" rel="stylesheet">
<!-- Font Awesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Swiper.js CSS -->
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css" />
<style>
/* Custom Styles - Poppins & Palette (UNTAN Blue/Yellow accents can be applied here) */
:root {
--primary-blue: #005eb8; /* Approximate UNTAN Blue */
--secondary-blue: #004a94;
--accent-yellow: #fdb913; /* UNTAN Yellow */
}
body {
font-family: 'Poppins', sans-serif;
background-color: #ffffff;
color: #111827;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Poppins', sans-serif;
font-weight: 700;
}
.font-quote {
font-family: 'Playfair Display', serif;
}
/* Accessibility Styles */
.high-contrast { background-color: #000; color: #fff; }
.high-contrast header, .high-contrast footer, .high-contrast .card, .high-contrast #accessibility-panel { background-color: #1a1a1a; border: 1px solid #555; }
.high-contrast a { color: #fdb913; }
.links-underlined a { text-decoration: underline !important; }
.font-readable { font-family: 'Georgia', serif; }
.card { transition: transform 0.3s ease, box-shadow 0.3s ease; }
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
}
#accessibility-panel { transition: transform 0.3s ease-in-out; }
#accessibility-panel.is-open { transform: translateX(0); }
#mobile-menu { transition: transform 0.3s ease-in-out; }
/* Section Title Accent */
.section-title h2::after {
content: '';
display: block;
width: 60px;
height: 4px;
background-color: var(--primary-blue);
margin-top: 8px;
border-radius: 2px;
}
/* Centered title accent for mobile if text-center is used */
.text-center .section-title h2::after {
margin-left: auto;
margin-right: auto;
}
/* Custom Header Styles */
/* Top Bar - Darker & Shorter */
.header-top-bar {
background-color: var(--secondary-blue);
font-size: 0.75rem; /* Text lebih kecil */
}
/* Main Nav - Sticky & Logo Inline */
.header-main-nav {
background-color: var(--primary-blue);
border-top: 3px solid var(--accent-yellow);
position: sticky; /* Kunci Sticky */
top: 0;
z-index: 50; /* Pastikan di atas elemen lain */
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.nav-item {
position: relative;
}
.nav-item > a {
transition: all 0.3s ease;
border-bottom: 3px solid transparent;
}
.nav-item:hover > a {
background-color: rgba(0,0,0,0.1);
border-bottom-color: var(--accent-yellow);
}
/* Mega Menu Styles */
.mega-menu {
opacity: 0;
transform: translateY(15px);
transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s;
visibility: hidden;
pointer-events: none;
}
.group:hover .mega-menu {
opacity: 1;
transform: translateY(0);
visibility: visible;
pointer-events: auto;
}
/* Hero Slider Styles */
.hero-swiper {
width: 100%;
height: 100%;
}
.hero-slide {
position: relative;
background-size: cover;
background-position: center;
color: white;
display: flex;
align-items: flex-end;
}
.hero-slide::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.6) 30%, rgba(0, 0, 0, 0.1) 100%);
}
.hero-slide-content {
position: relative;
z-index: 10;
width: 100%;
padding: 1.5rem 1.5rem;
text-shadow: 0 1px 4px rgba(0,0,0,0.5);
}
@media (min-width: 768px) {
.hero-slide-content {
padding: 2rem 2.5rem;
}
}
.hero-swiper .swiper-button-next, .hero-swiper .swiper-button-prev {
color: #ffffff;
}
.hero-swiper .swiper-pagination-bullet {
background: rgba(255, 255, 255, 0.7);
width: 10px;
height: 10px;
opacity: 1;
}
.hero-swiper .swiper-pagination-bullet-active {
background: var(--accent-yellow);
}
/* Dosen Swiper Customization (Marquee Effect) */
.dosen-swiper {
padding: 20px 10px 30px 10px !important;
-webkit-mask-image: linear-gradient(to right, transparent, black 5%, black 95%, transparent);
mask-image: linear-gradient(to right, transparent, black 5%, black 95%, transparent);
}
.dosen-swiper .swiper-wrapper {
transition-timing-function: linear;
}
/* Scroll Animation Styles */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
will-change: opacity, transform;
}
.reveal-visible {
opacity: 1;
transform: translateY(0);
}
/* Marquee Styles */
#marquee-text {
animation: marquee 40s linear infinite;
}
@keyframes marquee {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
/* Custom Scrollbar for Agenda */
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: #f1f1f1;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 4px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #999;
}
/* DEBUG STYLES */
#api-error-message {
display: none;
background-color: #fee2e2;
border: 1px solid #ef4444;
color: #b91c1c;
padding: 1rem;
margin: 1rem;
border-radius: 0.5rem;
text-align: center;
font-size: 0.875rem;
}
</style>
</head>
<body class="text-gray-900 flex flex-col min-h-screen">
<!-- REVISED HEADER STRUCTURE -->
<!-- Top Bar (Short & Dark Blue) -->
<div class="header-top-bar text-white relative z-50">
<div class="container mx-auto px-4 flex justify-between items-center py-1"> <!-- py-1 makes it short -->
<!-- Left: Contact Info (Hidden on mobile) -->
<div class="hidden md:flex items-center space-x-4 opacity-90">
<span><i class="fas fa-envelope mr-1"></i> informatika@untan.ac.id</span>
<span><i class="fas fa-phone mr-1"></i> +62 561 739630</span>
</div>
<!-- Right: Quick Links -->
<div class="flex items-center space-x-4 ml-auto font-medium">
<a href="https://satu.untan.ac.id/" class="hover:text-yellow-400">SATU UNTAN</a>
<span class="opacity-50">|</span>
<a href="#" class="hover:text-yellow-400">E-Learning</a>
<span class="opacity-50">|</span>
<a href="#" class="hover:text-yellow-400">Jurnal</a>
<span class="opacity-50">|</span>
<a href="#" class="flex items-center hover:text-yellow-400">
<img src="https://upload.wikimedia.org/wikipedia/commons/9/9f/Flag_of_Indonesia.svg" alt="ID Flag" class="h-3 w-4 object-cover mr-1 border border-white/50"> ID
</a>
</div>
</div>
</div>
<!-- Main Navigation (Sticky, Logo Inline with Menu) -->
<nav class="header-main-nav text-white w-full">
<div class="container mx-auto px-4">
<div class="flex justify-between items-center h-20"> <!-- Fixed height ensures consistency -->
<!-- Logo Section (Moved Here) -->
<a href="#" class="flex items-center space-x-3 group">
<img src="https://upload.wikimedia.org/wikipedia/id/0/03/Lambang_Universitas_Tanjungpura.png" alt="Logo UNTAN" class="h-12 w-auto object-contain bg-white/10 rounded p-1 transition-transform group-hover:scale-105">
<div class="flex flex-col">
<span class="text-xl font-bold leading-none tracking-tight">INFORMATIKA</span>
<span class="text-xs font-light tracking-[0.2em] text-yellow-300">UNIVERSITAS TANJUNGPURA</span>
</div>
</a>
<!-- Desktop Menu (Right Aligned) -->
<div class="hidden lg:flex items-center h-full">
<div class="nav-item h-full flex items-center">
<a href="#" class="px-5 h-full flex items-center font-semibold">Beranda</a>
</div>
<!-- Profil -->
<div class="nav-item group h-full flex items-center">
<a href="#" class="px-5 h-full flex items-center font-semibold cursor-pointer">Profil <i class="fas fa-chevron-down text-xs ml-2 opacity-70"></i></a>
<!-- Mega Menu -->
<div class="mega-menu absolute top-full left-auto right-0 w-64 bg-white text-gray-700 shadow-xl rounded-b-lg border-t-4 border-[#fdb913]">
<ul class="py-2 text-sm">
<li><a href="#" class="block px-6 py-3 hover:bg-gray-50 hover:text-[#005eb8] border-b border-gray-50">Sejarah Jurusan</a></li>
<li><a href="#" class="block px-6 py-3 hover:bg-gray-50 hover:text-[#005eb8] border-b border-gray-50">Visi & Misi</a></li>
<li><a href="#" class="block px-6 py-3 hover:bg-gray-50 hover:text-[#005eb8] border-b border-gray-50">Struktur Organisasi</a></li>
<li><a href="#" class="block px-6 py-3 hover:bg-gray-50 hover:text-[#005eb8]">Dosen & Staf</a></li>
</ul>
</div>
</div>
<!-- Akademik -->
<div class="nav-item group h-full flex items-center">
<a href="#" class="px-5 h-full flex items-center font-semibold cursor-pointer">Akademik <i class="fas fa-chevron-down text-xs ml-2 opacity-70"></i></a>
<div class="mega-menu absolute top-full right-0 w-[500px] p-6 bg-white text-gray-700 shadow-xl rounded-b-lg border-t-4 border-[#fdb913]">
<div class="grid grid-cols-2 gap-8">
<div>
<h4 class="font-bold mb-3 text-base text-[#005eb8] border-b pb-2">Program Studi</h4>
<ul class="space-y-2 text-sm">
<li><a href="#" class="hover:text-[#fdb913] transition-colors flex items-center"><i class="fas fa-angle-right mr-2 text-gray-400"></i>S1 Informatika</a></li>
<li><a href="#" class="hover:text-[#fdb913] transition-colors flex items-center"><i class="fas fa-angle-right mr-2 text-gray-400"></i>S1 Sistem Informasi</a></li>
<li><a href="#" class="hover:text-[#fdb913] transition-colors flex items-center"><i class="fas fa-angle-right mr-2 text-gray-400"></i>S2 Teknik Informatika</a></li>
</ul>
</div>
<div>
<h4 class="font-bold mb-3 text-base text-[#005eb8] border-b pb-2">Informasi</h4>
<ul class="space-y-2 text-sm">
<li><a href="#" class="hover:text-[#fdb913] transition-colors">Kurikulum & Silabus</a></li>
<li><a href="#" class="hover:text-[#fdb913] transition-colors">Kalender Akademik</a></li>
<li><a href="#" class="hover:text-[#fdb913] transition-colors">Panduan Skripsi</a></li>
<li><a href="#" class="hover:text-[#fdb913] transition-colors">Program MBKM</a></li>
</ul>
</div>
</div>
</div>
</div>
<!-- Riset & Lab -->
<div class="nav-item group h-full flex items-center">
<a href="#" class="px-5 h-full flex items-center font-semibold cursor-pointer">Riset <i class="fas fa-chevron-down text-xs ml-2 opacity-70"></i></a>
<div class="mega-menu absolute top-full right-0 w-64 bg-white text-gray-700 shadow-xl rounded-b-lg border-t-4 border-[#fdb913]">
<ul class="py-2 text-sm">
<li><a href="#" class="block px-6 py-3 hover:bg-gray-50 hover:text-[#005eb8] border-b border-gray-50">Laboratorium</a></li>
<li><a href="#" class="block px-6 py-3 hover:bg-gray-50 hover:text-[#005eb8] border-b border-gray-50">Grup Riset (RG)</a></li>
<li><a href="#" class="block px-6 py-3 hover:bg-gray-50 hover:text-[#005eb8]">Publikasi & Jurnal</a></li>
</ul>
</div>
</div>
<div class="nav-item h-full flex items-center">
<a href="#" class="px-5 h-full flex items-center font-semibold">Kemahasiswaan</a>
</div>
<!-- Search Icon Button -->
<div class="ml-4 pl-4 border-l border-white/20 h-8 flex items-center">
<button class="text-white hover:text-yellow-300 transition-colors">
<i class="fas fa-search text-lg"></i>
</button>
</div>
</div>
<!-- Mobile Menu Button -->
<div class="lg:hidden flex items-center">
<button id="mobile-menu-button" class="text-white hover:text-yellow-400 text-2xl p-2">
<i class="fas fa-bars"></i>
</button>
</div>
</div>
</div>
</nav>
<!-- END REVISED HEADER -->
<!-- Mobile Menu (Side Drawer) -->
<div id="mobile-menu" class="fixed top-0 left-0 w-[300px] max-w-[85%] h-full bg-white z-[60] transform -translate-x-full lg:hidden transition-transform duration-300 flex flex-col shadow-2xl">
<div class="flex justify-between items-center p-4 border-b bg-[#005eb8] text-white flex-shrink-0">
<div class="flex items-center space-x-2">
<img src="https://upload.wikimedia.org/wikipedia/id/0/03/Lambang_Universitas_Tanjungpura.png" class="h-8 bg-white/20 rounded p-1">
<span class="font-bold">INFORMATIKA</span>
</div>
<button id="close-mobile-menu" class="text-2xl text-white w-10 h-10 flex items-center justify-center hover:bg-white/20 rounded-full transition-colors">&times;</button>
</div>
<nav class="flex-1 flex flex-col p-6 overflow-y-auto space-y-1">
<a href="#" class="block py-3 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] font-bold border-l-4 border-transparent hover:border-[#fdb913]">Beranda</a>
<div class="py-2">
<span class="block px-3 text-xs font-bold text-gray-400 uppercase tracking-wider mb-2 mt-2">Profil</span>
<a href="#" class="block py-2 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] ml-2">Sejarah & Visi Misi</a>
<a href="#" class="block py-2 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] ml-2">Struktur Organisasi</a>
<a href="#" class="block py-2 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] ml-2">Dosen & Staf</a>
</div>
<div class="py-2 border-t border-gray-100">
<span class="block px-3 text-xs font-bold text-gray-400 uppercase tracking-wider mb-2 mt-2">Akademik</span>
<a href="#" class="block py-2 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] ml-2">Program Studi</a>
<a href="#" class="block py-2 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] ml-2">Kurikulum</a>
<a href="#" class="block py-2 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] ml-2">Skripsi & Kerja Praktik</a>
</div>
<div class="py-2 border-t border-gray-100">
<a href="#" class="block py-3 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] font-semibold">Riset & Lab</a>
<a href="#" class="block py-3 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] font-semibold">Kemahasiswaan</a>
<a href="#" class="block py-3 px-3 rounded-lg text-gray-700 hover:bg-blue-50 hover:text-[#005eb8] font-semibold">Kontak</a>
</div>
<div class="mt-4 pt-6 border-t border-gray-200 grid grid-cols-2 gap-3 text-center text-sm pb-10">
<a href="#" class="p-3 bg-gray-50 rounded border border-gray-200 hover:bg-[#005eb8] hover:text-white hover:border-[#005eb8] transition-all font-semibold">SIAKAD</a>
<a href="#" class="p-3 bg-gray-50 rounded border border-gray-200 hover:bg-[#005eb8] hover:text-white hover:border-[#005eb8] transition-all font-semibold">E-Learning</a>
</div>
</nav>
</div>
<!-- Main Content -->
<main class="flex-grow">
<!-- ERROR MESSAGE CONTAINER -->
<div id="api-error-message" class="container mx-auto mt-4 hidden">
<!-- Pesan error akan muncul di sini jika fetch gagal -->
</div>
<!-- Running Text Announcement -->
<div class="bg-gray-100 py-2 border-b border-t border-gray-200">
<div class="container mx-auto px-4 flex items-center overflow-hidden h-8">
<span class="bg-[#fdb913] text-black text-[10px] md:text-xs font-bold px-2 md:px-3 py-1 rounded mr-3 md:mr-4 flex-shrink-0 uppercase tracking-wide">PENGUMUMAN</span>
<div class="relative flex-auto h-full overflow-hidden">
<p id="marquee-text" class="absolute whitespace-nowrap leading-8 text-xs md:text-sm font-medium pt-1.5">
</p>
</div>
</div>
</div>
<!-- Hero Slideshow & Agenda Section -->
<section class="mb-10 md:mb-16 mt-4 md:mt-6">
<div class="container mx-auto px-4">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 md:gap-8 h-auto lg:h-[450px]">
<!-- Slider (Left - 2/3) -->
<div class="lg:col-span-2 w-full h-[280px] sm:h-[350px] lg:h-full rounded-2xl overflow-hidden shadow-2xl relative order-1">
<div class="swiper-container hero-swiper h-full">
<div class="swiper-wrapper" id="hero-slides">
<!-- Slides will be injected by JS -->
</div>
<div class="swiper-pagination"></div>
<div class="swiper-button-next hidden md:flex"></div>
<div class="swiper-button-prev hidden md:flex"></div>
</div>
</div>
<!-- Agenda (Right - 1/3) -->
<div class="lg:col-span-1 order-2 h-auto lg:h-full flex flex-col relative z-30">
<div class="bg-white border border-gray-100 rounded-2xl shadow-lg h-full overflow-hidden flex flex-col">
<div class="flex border-b border-gray-100">
<button onclick="openTab('agenda')" id="btn-tab-agenda" class="flex-1 py-3 text-sm font-bold text-[#005eb8] border-b-2 border-[#005eb8] hover:bg-gray-50 transition-colors focus:outline-none">
<i class="far fa-calendar-alt mr-2"></i> Agenda
</button>
<button onclick="openTab('dokumen')" id="btn-tab-dokumen" class="flex-1 py-3 text-sm font-bold text-gray-400 border-b-2 border-transparent hover:text-[#005eb8] hover:bg-gray-50 transition-colors focus:outline-none">
<i class="far fa-file-alt mr-2"></i> Berkas
</button>
</div>
<div id="content-agenda" class="flex-grow flex flex-col p-5 overflow-hidden h-full">
<div class="flex justify-between items-center mb-2">
<h3 class="text-xs font-bold text-gray-400 uppercase tracking-wider">Jadwal Terdekat</h3>
<a href="#" class="text-[10px] font-bold text-[#005eb8] hover:underline">Semua Agenda &rarr;</a>
</div>
<ul class="space-y-4 overflow-y-auto pr-2 custom-scrollbar flex-grow max-h-[300px] lg:max-h-none agenda-list-container">
<li class="text-center py-10 text-gray-400 text-xs">Memuat agenda...</li>
</ul>
</div>
<div id="content-dokumen" class="hidden flex-grow flex-col p-5 overflow-hidden h-full">
<div class="flex justify-between items-center mb-2">
<h3 class="text-xs font-bold text-gray-400 uppercase tracking-wider">File Akademik</h3>
<a href="#" class="text-[10px] font-bold text-[#005eb8] hover:underline">Arsip Dokumen &rarr;</a>
</div>
<ul id="dokumen-list" class="space-y-2 overflow-y-auto pr-2 custom-scrollbar flex-grow max-h-[300px] lg:max-h-none">
<li class="text-center py-10 text-gray-400 text-xs">Memuat file...</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="container mx-auto px-4">
<!-- Latest News -->
<section class="mb-10 md:mb-16">
<div class="section-title mb-6 md:mb-8 flex flex-col md:flex-row justify-between items-baseline gap-2">
<h2 class="text-2xl md:text-3xl md:text-4xl text-[#005eb8]">Berita Terkini</h2>
<a href="#" class="text-xs md:text-sm font-semibold text-gray-500 hover:text-[#005eb8] transition-colors">
Arsip Berita <i class="fas fa-arrow-right ml-1"></i>
</a>
</div>
<div id="terkini-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 md:gap-8">
<!-- Initial content is empty, will be loaded by JS -->
<div class="col-span-full text-center py-10 bg-gray-50 rounded-lg animate-pulse">
<i class="fas fa-spinner fa-spin text-3xl text-gray-400 mb-2"></i>
<p class="text-gray-500">Memuat berita dari server...</p>
</div>
</div>
</section>
<!-- Other Categories Grid -->
<section class="mb-10 md:mb-16 grid grid-cols-1 lg:grid-cols-3 gap-6 md:gap-10">
<!-- Akademik -->
<div id="category-akademik" class="bg-gray-50 p-6 rounded-xl border border-gray-100">
<div class="section-title mb-6">
<h2 class="text-xl md:text-2xl text-[#004a94]">Info Akademik</h2>
</div>
<div id="akademik-list" class="space-y-6">
<!-- Akademik news list will be inserted here -->
<div class="animate-pulse flex space-x-4">
<div class="rounded-full bg-gray-200 h-10 w-10"></div>
<div class="flex-1 space-y-2 py-1">
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
<div class="h-4 bg-gray-200 rounded w-1/2"></div>
</div>
</div>
</div>
<div class="mt-8 text-right">
<a href="#" class="text-sm font-bold text-[#005eb8] hover:underline">Selengkapnya &rarr;</a>
</div>
</div>
<!-- Riset -->
<div id="category-riset" class="bg-gray-50 p-6 rounded-xl border border-gray-100">
<div class="section-title mb-6">
<h2 class="text-xl md:text-2xl text-[#004a94]">Riset & Teknologi</h2>
</div>
<div id="riset-list" class="space-y-6">
<!-- Riset news list will be inserted here -->
</div>
<div class="mt-8 text-right">
<a href="#" class="text-sm font-bold text-[#005eb8] hover:underline">Selengkapnya &rarr;</a>
</div>
</div>
<!-- Mahasiswa -->
<div id="category-mahasiswa" class="bg-gray-50 p-6 rounded-xl border border-gray-100">
<div class="section-title mb-6">
<h2 class="text-xl md:text-2xl text-[#004a94]">Kemahasiswaan</h2>
</div>
<div id="mahasiswa-list" class="space-y-6">
<!-- Mahasiswa news list will be inserted here -->
</div>
<div class="mt-8 text-right">
<a href="#" class="text-sm font-bold text-[#005eb8] hover:underline">Selengkapnya &rarr;</a>
</div>
</div>
</section>
<!-- Dosen & Peneliti Section -->
<section class="mb-10 md:mb-16">
<div class="section-title mb-4 flex justify-between items-end border-b border-gray-100 pb-2">
<div>
<h2 class="text-2xl md:text-3xl text-[#005eb8]">Dosen & Peneliti</h2>
</div>
<a href="#" class="text-xs md:text-sm font-semibold text-gray-500 hover:text-[#005eb8] transition-colors mb-1">
Lihat Direktori Lengkap <i class="fas fa-arrow-right ml-1"></i>
</a>
</div>
<div class="mb-6 bg-gray-50 p-3 md:p-4 rounded-xl border border-gray-200 flex flex-col md:flex-row gap-3 md:items-center">
<div class="flex items-center text-gray-500 text-sm font-semibold min-w-fit">
<i class="fas fa-filter mr-2 text-[#fdb913]"></i> Filter Data:
</div>
<div class="flex flex-wrap gap-2 w-full">
<select id="filter-kbk" class="bg-white border border-gray-300 text-gray-700 text-sm rounded-lg focus:ring-[#005eb8] focus:border-[#005eb8] block p-2.5 outline-none cursor-pointer hover:border-[#005eb8] transition-colors flex-grow md:flex-grow-0 md:min-w-[200px]">
<option value="all">Semua Keahlian (KBK)</option>
</select>
<select id="filter-jabatan" class="bg-white border border-gray-300 text-gray-700 text-sm rounded-lg focus:ring-[#005eb8] focus:border-[#005eb8] block p-2.5 outline-none cursor-pointer hover:border-[#005eb8] transition-colors flex-grow md:flex-grow-0 md:min-w-[180px]">
<option value="all">Semua Jabatan</option>
</select>
<button id="reset-filter" class="flex items-center justify-center px-4 py-2 text-sm font-medium text-red-600 bg-white border border-red-200 rounded-lg hover:bg-red-50 hover:text-red-700 transition-colors ml-auto md:ml-0" title="Reset Filter">
<i class="fas fa-sync-alt mr-1 md:mr-0"></i> <span class="md:hidden ml-1">Reset</span>
</button>
</div>
</div>
<div class="swiper-container dosen-swiper">
<div class="swiper-wrapper" id="dosen-wrapper">
<div class="text-center w-full py-10 text-gray-400">Memuat data dosen...</div>
</div>
</div>
<div id="dosen-empty-state" class="hidden text-center py-12 bg-white rounded-xl border-2 border-dashed border-gray-200 mt-4">
<div class="bg-gray-50 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-3">
<i class="fas fa-search text-gray-400 text-xl"></i>
</div>
<h4 class="text-gray-800 font-bold">Data tidak ditemukan</h4>
<p class="text-gray-500 text-sm mb-3">Coba ganti filter pencarian Anda.</p>
<button onclick="document.getElementById('reset-filter').click()" class="text-[#005eb8] font-bold text-sm hover:underline">Reset Semua Filter</button>
</div>
</section>
<!-- Rubrik Tulisan Dosen & Pengabdian Section -->
<section class="mb-10 md:mb-16">
<div class="section-title mb-6 md:mb-8 flex justify-between items-baseline">
<h2 class="text-2xl md:text-3xl text-[#005eb8]">Informatika Berdampak</h2>
<a href="#" class="text-xs md:text-sm font-semibold text-gray-500 hover:text-[#005eb8] transition-colors">
Lihat Selengkapnya <i class="fas fa-arrow-right ml-1"></i>
</a>
</div>
<div id="rubrik-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-5 md:gap-6">
<!-- Content injected by JS -->
</div>
</section>
<!-- Quote Section -->
<section class="relative bg-[#005eb8] rounded-2xl p-8 md:p-16 my-10 md:my-16 overflow-hidden text-white shadow-xl">
<!-- Background Pattern -->
<div class="absolute top-0 right-0 -mt-10 -mr-10 opacity-10">
<i class="fas fa-code text-9xl"></i>
</div>
<div class="absolute bottom-0 left-0 -mb-10 -ml-10 opacity-10">
<i class="fas fa-network-wired text-9xl"></i>
</div>
<div class="relative max-w-4xl mx-auto text-center z-10">
<i class="fas fa-quote-left text-3xl md:text-4xl text-[#fdb913] mb-4 opacity-80"></i>
<p id="quote-text" class="text-xl md:text-2xl lg:text-3xl font-quote leading-relaxed italic mb-6"></p>
<div class="inline-block border-t border-[#fdb913] pt-4 px-6 md:px-10">
<footer id="quote-author" class="text-base md:text-lg font-bold tracking-wide"></footer>
<span id="quote-role" class="text-xs md:text-sm opacity-80 block mt-1"></span>
</div>
</div>
</section>
<!-- Video Section -->
<section class="mb-12 md:mb-16 mt-8">
<div class="grid grid-cols-1 lg:grid-cols-10 gap-8 lg:gap-12">
<div class="lg:col-span-3 flex flex-col">
<div class="flex justify-between items-end mb-6 border-b border-gray-100 pb-3">
<h3 class="text-2xl md:text-3xl text-[#005eb8] font-bold">Video Profil</h3>
</div>
<div class="w-full aspect-video rounded-xl overflow-hidden shadow-lg mb-6 relative group bg-black cursor-pointer">
<a href="https://www.youtube.com/watch?v=mV0A71z9tuU" target="_blank" class="block w-full h-full relative">
<img src="https://img.youtube.com/vi/mV0A71z9tuU/maxresdefault.jpg"
alt="Thumbnail Video Profil"
class="w-full h-full object-cover opacity-80 group-hover:opacity-60 transition-opacity duration-300">
<div class="absolute inset-0 flex items-center justify-center">
<div class="w-16 h-16 bg-red-600 rounded-full flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform duration-300">
<i class="fas fa-play text-white text-2xl ml-1"></i>
</div>
</div>
<div class="absolute bottom-4 left-0 w-full text-center">
<span class="text-white text-sm font-semibold shadow-black drop-shadow-md">
Tonton di YouTube <i class="fas fa-external-link-alt ml-1 text-xs"></i>
</span>
</div>
</a>
</div>
<p class="text-sm text-gray-500 mb-6 leading-relaxed">
Informatika UNTAN merupakan pusat pendidikan teknologi informasi terdepan. Simak video profil ini untuk mengetahui fasilitas dan keunggulan kami.
</p>
<div class="mt-auto">
<a href="#" class="inline-flex items-center justify-center border-2 border-red-600 text-red-600 font-bold py-3 px-6 rounded-lg hover:bg-red-50 transition-colors w-full md:w-auto text-sm uppercase tracking-wide">
Unduh Profil Jurusan (PDF) <i class="far fa-file-pdf ml-2 text-lg"></i>
</a>
</div>
</div>
<div class="lg:col-span-7">
<div class="flex justify-between items-end mb-6 border-b border-gray-100 pb-3">
<h2 class="text-2xl md:text-3xl text-[#005eb8] font-bold">Galeri Video</h2>
<div class="flex gap-2">
<button class="gallery-prev w-8 h-8 rounded-full border border-gray-300 flex items-center justify-center hover:bg-[#005eb8] hover:text-white transition-colors"><i class="fas fa-chevron-left"></i></button>
<button class="gallery-next w-8 h-8 rounded-full border border-gray-300 flex items-center justify-center hover:bg-[#005eb8] hover:text-white transition-colors"><i class="fas fa-chevron-right"></i></button>
</div>
</div>
<div class="swiper-container gallery-swiper overflow-hidden pb-10">
<div class="swiper-wrapper" id="gallery-wrapper">
<div class="text-center w-full py-10 text-gray-400 italic">Memuat video...</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
</section>
</div>
</main>
<!-- Footer (Optimized: Center on mobile, Left on desktop) -->
<footer class="bg-[#1a1a1a] text-white border-t border-gray-800 mt-auto">
<div class="container mx-auto px-4 py-10 md:py-12">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8 md:gap-10 text-center md:text-left">
<div class="md:col-span-1 flex flex-col items-center md:items-start">
<img src="https://untan.ac.id/wp-content/uploads/2023/01/untan.png" class="h-16 mb-4 bg-white/10 p-2 rounded" alt="Logo Footer">
<h4 class="font-bold text-lg mb-2 text-[#fdb913]">Jurusan Informatika</h4>
<h5 class="font-semibold text-sm mb-4">Universitas Tanjungpura</h5>
<p class="text-sm text-gray-400 leading-relaxed">
Mencetak lulusan yang unggul dalam teknologi informasi, berkarakter, dan mampu bersaing di era digital.
</p>
</div>
<div>
<h4 class="font-bold text-lg mb-4 text-[#fdb913]">Kontak Kami</h4>
<ul class="text-sm space-y-3 text-gray-400 flex flex-col items-center md:items-start">
<li class="flex items-start"><i class="fas fa-map-marker-alt mt-1 mr-3 text-[#005eb8] hidden md:inline"></i>Jl. Prof. Dr. H. Hadari Nawawi, Pontianak</li>
<li class="flex items-center"><a href="mailto:informatika@untan.ac.id" class="hover:text-white transition-colors"><i class="fas fa-envelope mr-3 text-[#005eb8] hidden md:inline"></i>informatika@untan.ac.id</a></li>
<li class="flex items-center"><a href="tel:+62561739630" class="hover:text-white transition-colors"><i class="fas fa-phone mr-3 text-[#005eb8] hidden md:inline"></i>+62 (561) 739630</a></li>
</ul>
</div>
<div>
<h4 class="font-bold text-lg mb-4 text-[#fdb913]">Tautan Cepat</h4>
<ul class="text-sm space-y-2 text-gray-400">
<li><a href="#" class="hover:text-[#fdb913] transition-colors">Sistem Informasi Akademik</a></li>
<li><a href="#" class="hover:text-[#fdb913] transition-colors">Pendaftaran Mahasiswa Baru</a></li>
<li><a href="#" class="hover:text-[#fdb913] transition-colors">Jurnal Informatika</a></li>
<li><a href="#" class="hover:text-[#fdb913] transition-colors">Tracer Study Alumni</a></li>
</ul>
</div>
<div>
<h4 class="font-bold text-lg mb-4 text-[#fdb913]">Sosial Media</h4>
<p class="text-sm text-gray-400 mb-4">Ikuti perkembangan terbaru kami:</p>
<div class="flex justify-center md:justify-start space-x-4">
<a href="#" class="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center hover:bg-[#005eb8] transition-colors"><i class="fab fa-instagram"></i></a>
<a href="#" class="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center hover:bg-[#005eb8] transition-colors"><i class="fab fa-facebook-f"></i></a>
<a href="#" class="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center hover:bg-[#005eb8] transition-colors"><i class="fab fa-youtube"></i></a>
<a href="#" class="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center hover:bg-[#005eb8] transition-colors"><i class="fab fa-linkedin-in"></i></a>
</div>
</div>
</div>
<div class="border-t border-gray-800 mt-10 pt-6 text-center text-sm text-gray-500">
<p>&copy; 2025 Jurusan Informatika, Fakultas Teknik, Universitas Tanjungpura.</p>
</div>
</div>
</footer>
<!-- Accessibility Panel & FAB -->
<div id="accessibility-overlay" class="fixed inset-0 bg-black bg-opacity-50 z-30 hidden"></div>
<div id="accessibility-fab" class="fixed bottom-5 right-5 z-50">
<button id="toggle-panel-btn" class="bg-[#005eb8] text-white rounded-full w-12 h-12 md:w-14 md:h-14 flex items-center justify-center shadow-lg text-xl md:text-2xl transform transition-transform hover:scale-110 border-2 border-white"><i id="fab-icon" class="fa fa-universal-access"></i></button>
</div>
<div id="accessibility-panel" class="fixed top-0 right-0 h-full w-72 bg-white shadow-2xl p-6 z-40 transform translate-x-full">
<h3 class="text-xl font-bold mb-4 text-[#005eb8]">Aksesibilitas</h3>
<div class="space-y-3">
<button onclick="increaseText()" class="w-full text-left p-2 rounded hover:bg-gray-100"><i class="fas fa-search-plus w-6 mr-2"></i>Perbesar Teks</button>
<button onclick="decreaseText()" class="w-full text-left p-2 rounded hover:bg-gray-100"><i class="fas fa-search-minus w-6 mr-2"></i>Perkecil Teks</button>
<button onclick="highContrast()" class="w-full text-left p-2 rounded hover:bg-gray-100"><i class="fas fa-adjust w-6 mr-2"></i>Kontras Tinggi</button>
<button onclick="linksUnderline()" class="w-full text-left p-2 rounded hover:bg-gray-100"><i class="fas fa-underline w-6 mr-2"></i>Garis Bawahi Tautan</button>
<button onclick="readableFont()" class="w-full text-left p-2 rounded hover:bg-gray-100"><i class="fas fa-font w-6 mr-2"></i>Font Mudah Dibaca</button>
<button onclick="resetAkses()" class="w-full text-left mt-4 p-2 rounded bg-red-500 text-white hover:bg-red-600"><i class="fas fa-undo w-6 mr-2"></i>Reset</button>
</div>
</div>
<!-- Swiper JS -->
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
<script>
// --- KONFIGURASI API DIRECTUS ---
// Pastikan URL ini sesuai dengan Coolify Bapak dan protokolnya (HTTP/HTTPS) sama dengan website
const API_BASE_URL = "http://cpanel-webif.203.24.51.230.sslip.io";
document.addEventListener('DOMContentLoaded', async function() {
// -----------------------------------------------------
// 1. FUNGSI AMBIL DATA BERITA (News)
// -----------------------------------------------------
async function getNewsData() {
try {
const response = await fetch(`${API_BASE_URL}/items/berita`);
if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);
const result = await response.json();
return result.data.map(item => ({
id: item.id,
category: (item.category || 'terkini').toLowerCase(),
img: item.img ? `${API_BASE_URL}/assets/${item.img}` : 'https://placehold.co/600x400?text=No+Image',
date: new Date(item.date || item.date_created).toLocaleDateString('id-ID', { day: '2-digit', month: 'short', year: 'numeric' }),
title: item.title || "Tanpa Judul",
excerpt: item.excerpt || ""
}));
} catch (error) {
console.error("Gagal ambil berita:", error);
document.getElementById('api-error-message').style.display = 'block';
document.getElementById('api-error-message').innerHTML = `Gagal memuat data: ${error.message}`;
return [];
}
}
await getAgendaData(); // <--- TAMBAHKAN BARIS INI
// FUNGSI AMBIL DOKUMEN (FIXED CLICK & URL)
async function getDokumenData() {
try {
const response = await fetch(`${API_BASE_URL}/items/dokumen?sort=-date_created&limit=10`);
if (!response.ok) throw new Error("Gagal ambil dokumen");
const result = await response.json();
const docList = document.getElementById('dokumen-list');
if (docList && result.data.length > 0) {
docList.innerHTML = "";
result.data.forEach(item => {
// FIX: Handle ID file baik string maupun object
const fileId = (typeof item.file === 'object' && item.file !== null) ? item.file.id : item.file;
const fileUrl = `${API_BASE_URL}/assets/${fileId}?download`;
let iconClass = "fa-file-pdf text-red-500";
const lowerName = item.nama_file ? item.nama_file.toLowerCase() : "file";
if(lowerName.includes("excel") || lowerName.includes("xls")) iconClass = "fa-file-excel text-green-600";
else if(lowerName.includes("word") || lowerName.includes("doc")) iconClass = "fa-file-word text-blue-600";
// Perhatikan z-20 dan cursor-pointer di sini
docList.innerHTML += `
<li class="pb-2 border-b border-gray-50 last:border-0 last:pb-0">
<a href="${fileUrl}" target="_blank" class="flex items-start p-2 rounded hover:bg-blue-50 transition-colors group relative z-20 w-full cursor-pointer">
<div class="flex-shrink-0 w-8 text-center mr-2">
<i class="far ${iconClass} mt-1 text-lg group-hover:scale-110 transition-transform"></i>
</div>
<div class="flex-grow">
<h5 class="text-xs font-bold text-gray-700 group-hover:text-[#005eb8] leading-tight mb-1">
${item.nama_file}
</h5>
<span class="text-[10px] text-gray-400 bg-gray-100 px-1.5 py-0.5 rounded inline-block group-hover:bg-white border border-gray-200">
<i class="fas fa-download mr-1"></i> Unduh
</span>
</div>
</a>
</li>
`;
});
} else {
if(docList) docList.innerHTML = `<li class="text-center text-xs text-gray-400 italic py-4">Belum ada dokumen.</li>`;
}
} catch (error) {
console.error("Error Dokumen:", error);
}
}
await getDokumenData(); // <--- WAJIB DITAMBAH
// FUNGSI AMBIL KUTIPAN (QUOTE) DINAMIS
async function getQuoteData() {
try {
// Ambil 1 kutipan saja yang statusnya aktif=true, urutkan dari yang paling baru dibuat
const response = await fetch(`${API_BASE_URL}/items/kutipan?filter[aktif][_eq]=true&sort=-date_created&limit=1`);
if (!response.ok) throw new Error("Gagal ambil kutipan");
const result = await response.json();
// Elemen HTML tujuan
const quoteText = document.getElementById('quote-text');
const quoteAuthor = document.getElementById('quote-author');
const quoteRole = document.getElementById('quote-role'); // ID baru tadi
if (result.data.length > 0) {
const data = result.data[0]; // Ambil data pertama
if(quoteText) quoteText.innerHTML = `"${data.isi_kutipan}"`;
if(quoteAuthor) quoteAuthor.innerText = data.penulis;
if(quoteRole) quoteRole.innerText = data.jabatan; // Jabatan dinamis
} else {
// Fallback jika tidak ada yang aktif (Pakai Data Default)
if(quoteText) quoteText.innerHTML = `"Teknologi adalah alat, namun manusialah yang menentukan arah peradaban."`;
if(quoteAuthor) quoteAuthor.innerText = "Admin Informatika";
if(quoteRole) quoteRole.innerText = "Universitas Tanjungpura";
}
} catch (error) {
console.error("Error Quote:", error);
}
}
await getQuoteData();
// FUNGSI PENGUMUMAN DARI DIRECTUS
async function getPengumumanData() {
try {
// Filter: hanya ambil yg aktif=true (jika bapak buat field 'aktif' boolean di directus)
// Kalau tidak ada field 'aktif', hapus bagian: &filter[aktif][_eq]=true
const response = await fetch(`${API_BASE_URL}/items/pengumuman?filter[aktif][_eq]=true&sort=-date_created`);
if (!response.ok) throw new Error("Gagal ambil pengumuman");
const result = await response.json();
const marqueeText = document.getElementById('marquee-text');
if (marqueeText && result.data.length > 0) {
let fullHtml = "";
result.data.forEach(item => {
fullHtml += `<span class="inline-block font-semibold text-black hover:text-red-500 cursor-default transition-colors">${item.teks}</span><span class="mx-8 text-gray-300">|</span>`;
});
// DUPLIKASI KONTEN (Agar running text nyambung/infinite)
marqueeText.innerHTML = fullHtml + fullHtml + fullHtml;
// Trik CSS restart animasi
marqueeText.style.animation = 'none';
marqueeText.offsetHeight;
marqueeText.style.animation = null;
}
} catch (error) {
console.error("Error Pengumuman:", error);
}
}
await getPengumumanData();
// -----------------------------------------------------
// 2. FUNGSI AMBIL DATA DOSEN (Real Data)
// -----------------------------------------------------
async function getDosenData() {
try {
// Ambil data dosen, urutkan by nama
const response = await fetch(`${API_BASE_URL}/items/dosen?sort=nama`);
if (!response.ok) throw new Error("Gagal ambil data dosen");
const result = await response.json();
return result.data.map(item => {
// Handle Tags (Kepakaran) - pastikan jadi array
let tags = item.kepakaran;
if (!Array.isArray(tags)) tags = [];
return {
name: item.nama,
// Jabatan (Badge atas foto)
jabatan: item.jabatan_fungsional,
// KBK (Subtitle di bawah nama)
kelompok_keahlian: item.kelompok_keahlian,
// Tags (Chips di bawah)
tags: tags,
// Foto
img: item.foto ? `${API_BASE_URL}/assets/${item.foto}` : 'https://placehold.co/300x300?text=No+Img',
// Detail Pendidikan (untuk Popup)
s1: item.pendidikan_s1 || '-',
s2: item.pendidikan_s2 || '-',
s3: item.pendidikan_s3 || '-'
};
});
} catch (error) {
console.error("Error Dosen:", error);
return [];
}
}
// --- MULAI COPY DARI SINI ---
// FUNGSI AMBIL DATA AGENDA (DENGAN HITUNG MUNDUR)
async function getAgendaData() {
try {
const todayRaw = new Date();
const todayStr = todayRaw.toISOString().split('T')[0];
// Ambil data dari Directus
const response = await fetch(`${API_BASE_URL}/items/agenda?sort=tanggal&filter[tanggal][_gte]=${todayStr}&limit=5`);
if (!response.ok) throw new Error("Gagal ambil agenda");
const result = await response.json();
// Selector ini mencari <ul> tempat agenda berada
const agendaList = document.querySelector('.space-y-4.overflow-y-auto');
if (agendaList && result.data.length > 0) {
agendaList.innerHTML = ""; // HAPUS DATA DUMMY BAWAAN
result.data.forEach(item => {
const eventDate = new Date(item.tanggal);
// LOGIKA HITUNG MUNDUR
const nowZero = new Date(todayRaw.getFullYear(), todayRaw.getMonth(), todayRaw.getDate());
const eventZero = new Date(eventDate.getFullYear(), eventDate.getMonth(), eventDate.getDate());
const diffTime = eventZero - nowZero;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
// Badge Sisa Hari
let countdownBadge = "";
if (diffDays === 0) {
countdownBadge = `<span class="text-[10px] font-bold text-red-600 bg-red-100 px-2 py-0.5 rounded ml-2 animate-pulse">HARI INI!</span>`;
} else if (diffDays === 1) {
countdownBadge = `<span class="text-[10px] font-bold text-orange-600 bg-orange-100 px-2 py-0.5 rounded ml-2">Besok</span>`;
} else {
countdownBadge = `<span class="text-[10px] font-semibold text-blue-600 bg-blue-50 px-2 py-0.5 rounded ml-2">${diffDays} hari lagi</span>`;
}
// Format Tanggal
const day = eventDate.getDate();
const month = eventDate.toLocaleDateString('id-ID', { month: 'short' });
// Masukkan ke HTML
agendaList.innerHTML += `
<li class="flex gap-4 items-start pb-3 border-b border-gray-100 last:border-0 hover:bg-gray-50 transition-colors rounded p-1 group">
<div class="bg-blue-50 rounded p-2 text-center min-w-[55px] border border-blue-100 group-hover:bg-[#005eb8] group-hover:text-white transition-colors">
<span class="block text-xl font-bold text-[#005eb8] group-hover:text-white">${day}</span>
<span class="block text-[10px] uppercase font-bold text-gray-500 group-hover:text-yellow-300">${month}</span>
</div>
<div class="flex-grow">
<div class="flex justify-between items-start">
<h4 class="font-bold text-sm hover:text-[#fdb913] cursor-pointer text-gray-800 leading-snug mb-1">
${item.Judul}
</h4>
</div>
<div class="mb-1">${countdownBadge}</div>
<div class="flex flex-col gap-1">
<span class="text-xs text-gray-400 flex items-center"><i class="far fa-clock mr-1 w-4 text-center"></i> ${item.waktu || '-'}</span>
<span class="text-xs text-gray-400 flex items-center"><i class="fas fa-map-marker-alt mr-1 w-4 text-center"></i> ${item.lokasi || '-'}</span>
</div>
</div>
</li>
`;
});
} else {
if(agendaList) agendaList.innerHTML = `<div class="text-center text-sm text-gray-400 py-4 italic">Belum ada agenda terdekat.</div>`;
}
} catch (error) {
console.error("Error Agenda:", error);
}
}
// --- SELESAI COPY ---
// --- HELPER: AMBIL ID YOUTUBE ---
function getYoutubeId(url) {
if (!url) return null;
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
const match = url.match(regExp);
return (match && match[2].length === 11) ? match[2] : null;
}
// --- FUNGSI GALERI VIDEO (DENGAN JUDUL) ---
async function getGalleryData() {
try {
// Ambil field youtube_url dan judul
const response = await fetch(`${API_BASE_URL}/items/galeri?sort=-date_created&limit=10`);
if (!response.ok) throw new Error("Gagal ambil galeri");
const result = await response.json();
const galleryWrapper = document.getElementById('gallery-wrapper');
if (galleryWrapper && result.data.length > 0) {
galleryWrapper.innerHTML = "";
result.data.forEach(item => {
const videoId = getYoutubeId(item.youtube_url);
if(!videoId) return; // Skip jika link salah
const thumbnail = `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`;
// AMBIL JUDUL (Default jika kosong)
const judulVideo = item.judul || "Video Kegiatan Informatika";
galleryWrapper.innerHTML += `
<div class="swiper-slide h-auto">
<div class="bg-white rounded-xl overflow-hidden shadow-sm border border-gray-200 group h-full flex flex-col">
<a href="${item.youtube_url}" target="_blank" class="relative aspect-video block overflow-hidden bg-black">
<img src="${thumbnail}" alt="${judulVideo}" class="w-full h-full object-cover opacity-90 group-hover:opacity-100 group-hover:scale-105 transition-all duration-500">
<div class="absolute inset-0 flex items-center justify-center bg-black/20 group-hover:bg-black/10 transition-colors">
<div class="w-10 h-10 bg-red-600 rounded-full flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform">
<i class="fas fa-play text-white text-xs ml-0.5"></i>
</div>
</div>
</a>
<div class="p-4 flex-grow flex flex-col justify-center">
<h4 class="font-bold text-sm text-gray-800 line-clamp-2 leading-snug group-hover:text-[#005eb8] transition-colors" title="${judulVideo}">
${judulVideo}
</h4>
</div>
</div>
</div>
`;
});
// Re-init Swiper Galeri
new Swiper('.gallery-swiper', {
slidesPerView: 2, spaceBetween: 15,
navigation: { nextEl: '.gallery-next', prevEl: '.gallery-prev' },
pagination: { el: '.swiper-pagination', clickable: true, dynamicBullets: true },
breakpoints: {
640: { slidesPerView: 2, spaceBetween: 15 },
1024: { slidesPerView: 3, spaceBetween: 20 },
}
});
} else {
if(galleryWrapper) galleryWrapper.innerHTML = `<div class="text-center w-full py-10 text-gray-400">Belum ada video.</div>`;
}
} catch (error) {
console.error("Error Galeri:", error);
}
}
// -----------------------------------------------------
// EKSEKUSI DATA
// -----------------------------------------------------
const newsData = await getNewsData();
const dosenData = await getDosenData();
await getGalleryData();
// --- RENDER BERITA ---
const terkiniGrid = document.getElementById('terkini-grid');
const heroSlidesContainer = document.getElementById('hero-slides');
// Hero Slider (Ambil 3 Berita 'terkini' atau terbaru)
let heroItems = newsData.filter(i => i.category === 'terkini').slice(0, 3);
if(heroItems.length === 0) heroItems = newsData.slice(0, 3);
if(heroSlidesContainer && heroItems.length > 0) {
heroSlidesContainer.innerHTML = "";
heroItems.forEach(news => {
heroSlidesContainer.innerHTML += `
<div class="swiper-slide hero-slide" style="background-image: url('${news.img}')">
<a href="#" class="hero-slide-content">
<div class="container mx-auto px-4">
<span class="bg-[#fdb913] text-black text-[10px] font-bold px-2 py-1 mb-2 inline-block rounded">TERPOPULER</span>
<h2 class="text-lg md:text-2xl font-bold mb-2 font-serif leading-tight drop-shadow-md text-white">${news.title}</h2>
</div>
</a>
</div>
`;
});
new Swiper('.hero-swiper', { loop: true, autoplay: { delay: 5000 }, pagination: { el: '.swiper-pagination', clickable: true }, navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' } });
}
// Grid Berita Terkini
if(terkiniGrid && newsData.length > 0) {
terkiniGrid.innerHTML = "";
newsData.slice(0, 6).forEach((news, idx) => {
terkiniGrid.innerHTML += `
<div class="card bg-white rounded-xl overflow-hidden shadow-sm border border-gray-100 flex flex-col h-full reveal" style="transition-delay: ${idx * 100}ms">
<div class="h-48 overflow-hidden relative group">
<img src="${news.img}" alt="${news.title}" class="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-500">
<div class="absolute top-0 right-0 bg-[#005eb8] text-white text-xs px-2 py-1 m-2 rounded capitalize">${news.category}</div>
</div>
<div class="p-6 flex flex-col flex-grow">
<span class="text-xs text-gray-400 mb-2"><i class="far fa-calendar-alt mr-1"></i> ${news.date}</span>
<h3 class="font-bold text-lg mb-2 leading-tight hover:text-[#005eb8] line-clamp-2">${news.title}</h3>
<p class="text-sm text-gray-500 line-clamp-3 mb-4">${news.excerpt}</p>
<a href="#" class="mt-auto text-sm font-semibold text-[#005eb8] hover:text-[#fdb913]">Baca Selengkapnya &rarr;</a>
</div>
</div>
`;
});
} else if (terkiniGrid) {
terkiniGrid.innerHTML = `<div class="col-span-full text-center py-10 text-gray-400">Belum ada berita.</div>`;
}
// Render List Kategori (Akademik, Riset, Mahasiswa)
['akademik', 'riset', 'mahasiswa'].forEach(cat => {
const container = document.getElementById(`category-${cat}`);
const listContainer = document.getElementById(`${cat}-list`);
if(listContainer) {
const items = newsData.filter(i => i.category === cat).slice(0, 3);
listContainer.innerHTML = items.length ? "" : "<p class='text-sm text-gray-400 italic'>Belum ada info.</p>";
items.forEach((news, idx) => {
listContainer.innerHTML += `
<a href="#" class="block group reveal">
<div class="flex items-start space-x-4">
<div class="flex-shrink-0 w-8 text-center pt-1"><span class="text-lg font-bold text-gray-300 group-hover:text-[#fdb913]">0${idx+1}</span></div>
<div class="border-b border-gray-100 pb-4 w-full">
<h3 class="font-semibold text-gray-800 group-hover:text-[#005eb8] line-clamp-2 text-sm">${news.title}</h3>
<p class="text-xs text-gray-400 mt-1">${news.date}</p>
</div>
</div>
</a>
`;
});
}
});
// --- RENDER DOSEN (LOGIKA BARU) ---
// ============================================================
// 3. LOGIKA DOSEN & FILTER (ADVANCED)
// ============================================================
// Variabel Global untuk menyimpan data dosen mentah
let allDosenData = [];
let dosenSwiperInstance = null; // Simpan instance swiper biar bisa dihancurkan/re-init
// Fungsi Render Dosen ke HTML
function renderDosenList(data) {
const wrapper = document.getElementById('dosen-wrapper');
const emptyState = document.getElementById('dosen-empty-state');
const swiperContainer = document.querySelector('.dosen-swiper');
if (!wrapper) return;
// 1. Reset Tampilan
wrapper.innerHTML = "";
// 2. Cek jika data kosong setelah filter
if (data.length === 0) {
swiperContainer.classList.add('hidden');
emptyState.classList.remove('hidden');
return;
} else {
swiperContainer.classList.remove('hidden');
emptyState.classList.add('hidden');
}
// 3. Loop Data & Render HTML
data.forEach((dosen) => {
// Generate Tags HTML
let tagsHtml = '';
if(dosen.tags.length > 0) {
dosen.tags.slice(0, 2).forEach(tag => {
tagsHtml += `<span class="inline-block bg-blue-50 text-blue-600 text-[10px] px-2 py-1 rounded mr-1 mb-1 border border-blue-100">${tag}</span>`;
});
if(dosen.tags.length > 2) tagsHtml += `<span class="inline-block text-[10px] text-gray-400 px-1">+${dosen.tags.length - 2}</span>`;
} else {
tagsHtml = `<span class="text-[10px] text-gray-400 italic">Belum set kepakaran</span>`;
}
wrapper.innerHTML += `
<div class="swiper-slide h-auto">
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden hover:shadow-md transition-shadow duration-300 h-full flex flex-col group cursor-pointer"
onclick="alert('Detail ${dosen.name}:\\n\\nS1: ${dosen.s1}\\nS2: ${dosen.s2}\\nS3: ${dosen.s3}\\n\\nKBK: ${dosen.kelompok_keahlian || '-'}\\nKepakaran: ${dosen.tags.join(', ')}')">
<div class="aspect-square overflow-hidden bg-gray-100 relative">
<img src="${dosen.img}" alt="${dosen.name}" class="w-full h-full object-cover object-top group-hover:scale-105 transition-transform duration-500">
<div class="absolute top-0 right-0 m-2">
<span class="bg-[#fdb913] text-black text-[10px] font-bold px-2 py-1 rounded shadow-sm">
${dosen.jabatan || 'Dosen'}
</span>
</div>
</div>
<div class="p-3 flex flex-col flex-grow">
<h3 class="font-bold text-gray-800 text-sm leading-snug mb-1 line-clamp-2">${dosen.name}</h3>
<p class="text-xs text-[#005eb8] font-semibold mb-3 border-b border-gray-100 pb-2">
<i class="fas fa-layer-group mr-1"></i> ${dosen.kelompok_keahlian || '-'}
</p>
<div class="mt-auto flex flex-wrap content-end gap-1">
${tagsHtml}
</div>
</div>
</div>
</div>
`;
});
// 4. Re-Initialize Swiper
// Kita harus hancurkan swiper lama dulu kalau ada, biar gak error/double
if (dosenSwiperInstance) {
dosenSwiperInstance.destroy(true, true);
}
dosenSwiperInstance = new Swiper('.dosen-swiper', {
slidesPerView: 2, spaceBetween: 16,
// Loop hanya aktif jika jumlah dosen lebih banyak dari kolom yg ditampilkan
loop: data.length > 4,
speed: 4000,
autoplay: { delay: 0, disableOnInteraction: false, pauseOnMouseEnter: true },
breakpoints: {
640: { slidesPerView: 3, spaceBetween: 20 },
768: { slidesPerView: 4, spaceBetween: 20 },
1024: { slidesPerView: 6, spaceBetween: 24 },
1280: { slidesPerView: 7, spaceBetween: 24 },
}
});
}
// Fungsi Mengisi Opsi Dropdown secara Otomatis
function populateFilters() {
const kbkSet = new Set();
const jabatanSet = new Set();
// Ambil data unik
allDosenData.forEach(d => {
if(d.kelompok_keahlian) kbkSet.add(d.kelompok_keahlian);
if(d.jabatan) jabatanSet.add(d.jabatan);
});
// Isi Select KBK
const kbkSelect = document.getElementById('filter-kbk');
Array.from(kbkSet).sort().forEach(kbk => {
const option = document.createElement('option');
option.value = kbk;
option.textContent = kbk;
kbkSelect.appendChild(option);
});
// Isi Select Jabatan
const jabatanSelect = document.getElementById('filter-jabatan');
Array.from(jabatanSet).sort().forEach(jab => {
const option = document.createElement('option');
option.value = jab;
option.textContent = jab;
jabatanSelect.appendChild(option);
});
}
// Fungsi Utama Filtering
function applyFilter() {
const selectedKbk = document.getElementById('filter-kbk').value;
const selectedJabatan = document.getElementById('filter-jabatan').value;
const filtered = allDosenData.filter(dosen => {
const matchKbk = (selectedKbk === 'all') || (dosen.kelompok_keahlian === selectedKbk);
const matchJabatan = (selectedJabatan === 'all') || (dosen.jabatan === selectedJabatan);
return matchKbk && matchJabatan;
});
renderDosenList(filtered);
}
// --- EKSEKUSI ---
// 1. Ambil Data
allDosenData = await getDosenData();
// 2. Render Awal (Semua Data)
renderDosenList(allDosenData);
// 3. Isi Opsi Filter
populateFilters();
// 4. Event Listeners (Saat dropdown berubah)
document.getElementById('filter-kbk').addEventListener('change', applyFilter);
document.getElementById('filter-jabatan').addEventListener('change', applyFilter);
// 5. Tombol Reset
document.getElementById('reset-filter').addEventListener('click', () => {
document.getElementById('filter-kbk').value = 'all';
document.getElementById('filter-jabatan').value = 'all';
applyFilter();
});
// --- RUBRIK STATIS (Placeholder) ---
// FUNGSI AMBIL DATA RUBRIK (ARTIKEL & PENGABDIAN)
// FUNGSI AMBIL DATA RUBRIK (REVISI TAMPILAN)
async function getRubrikData() {
try {
const response = await fetch(`${API_BASE_URL}/items/rubrik?sort=-tanggal&limit=4`);
if (!response.ok) throw new Error("Gagal ambil rubrik");
const result = await response.json();
const rubrikGrid = document.getElementById('rubrik-grid');
if (rubrikGrid && result.data.length > 0) {
rubrikGrid.innerHTML = "";
result.data.forEach((item, index) => {
const isPengabdian = item.kategori === 'Pengabdian';
const badgeClass = isPengabdian
? 'bg-green-100 text-green-700 border-green-200'
: 'bg-blue-100 text-blue-700 border-blue-200';
const dateObj = new Date(item.tanggal);
const dateStr = dateObj.toLocaleDateString('id-ID', { day: 'numeric', month: 'short' });
const linkUrl = item.link || '#';
const delay = index * 100;
rubrikGrid.innerHTML += `
<div class="bg-white p-5 rounded-xl shadow-sm border border-gray-100 hover:shadow-lg transition-all duration-300 reveal group cursor-pointer h-full flex flex-col" style="transition-delay: ${delay}ms" onclick="window.location.href='${linkUrl}'">
<div class="mb-3">
<span class="text-[10px] uppercase font-bold px-2 py-1 rounded border ${badgeClass} inline-block tracking-wide">
${item.kategori}
</span>
</div>
<h3 class="font-bold text-gray-800 text-lg leading-snug mb-4 group-hover:text-[#005eb8] transition-colors line-clamp-5">
${item.judul}
</h3>
<div class="mt-auto pt-3 border-t border-gray-50 flex flex-col sm:flex-row sm:items-center justify-between text-xs text-gray-500 gap-2">
<div class="flex items-center">
<i class="fas ${isPengabdian ? 'fa-map-marker-alt' : 'fa-user'} mr-2 text-gray-400"></i>
<span class="font-medium text-gray-600">${item.penulis}</span>
</div>
<div class="flex items-center flex-shrink-0">
<i class="far fa-calendar text-gray-400 mr-1"></i>
<span>${dateStr}</span>
</div>
</div>
</div>
`;
});
// Re-observe animasi
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('reveal-visible');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.1 });
document.querySelectorAll('#rubrik-grid .reveal').forEach(el => observer.observe(el));
} else {
rubrikGrid.innerHTML = `<div class="col-span-full text-center text-gray-400 py-6">Belum ada artikel/pengabdian.</div>`;
}
} catch (error) {
console.error("Error Rubrik:", error);
}
}
await getRubrikData();
// Scroll Animation Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('reveal-visible'); observer.unobserve(entry.target); } });
}, { threshold: 0.1 });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
// Marquee
//document.getElementById('marquee-text').innerHTML = "Pendaftaran Yudisium Periode IV dibuka | Kuliah Umum AI wajib smt 5 | Jadwal UTS tersedia di SIAKAD".repeat(3);
});
// Accessibility & UI Functions
function increaseText() { document.body.style.fontSize = (parseFloat(window.getComputedStyle(document.body).fontSize) * 1.1) + "px"; }
function decreaseText() { document.body.style.fontSize = (parseFloat(window.getComputedStyle(document.body).fontSize) * 0.9) + "px"; }
function resetAkses() { document.body.style.fontSize = ""; document.body.classList.remove("high-contrast"); }
function highContrast() { document.body.classList.toggle("high-contrast"); }
document.getElementById('toggle-panel-btn').addEventListener('click', () => {
document.getElementById('accessibility-panel').classList.toggle('is-open');
document.getElementById('accessibility-overlay').classList.toggle('hidden');
});
document.getElementById('accessibility-overlay').addEventListener('click', () => {
document.getElementById('accessibility-panel').classList.remove('is-open');
document.getElementById('accessibility-overlay').classList.add('hidden');
});
// Mobile Menu
const mobileMenu = document.getElementById('mobile-menu');
document.getElementById('mobile-menu-button').addEventListener('click', () => mobileMenu.classList.remove('-translate-x-full'));
document.getElementById('close-mobile-menu').addEventListener('click', () => mobileMenu.classList.add('-translate-x-full'));
// FUNGSI GANTI TAB (AGENDA <-> DOKUMEN)
window.openTab = function(tabName) {
const contentAgenda = document.getElementById('content-agenda');
const contentDokumen = document.getElementById('content-dokumen');
const btnAgenda = document.getElementById('btn-tab-agenda');
const btnDokumen = document.getElementById('btn-tab-dokumen');
if (tabName === 'agenda') {
contentAgenda.classList.remove('hidden');
contentAgenda.classList.add('flex');
contentDokumen.classList.add('hidden');
contentDokumen.classList.remove('flex');
btnAgenda.className = "flex-1 py-3 text-sm font-bold text-[#005eb8] border-b-2 border-[#005eb8] bg-blue-50/50 transition-colors focus:outline-none";
btnDokumen.className = "flex-1 py-3 text-sm font-bold text-gray-400 border-b-2 border-transparent hover:text-[#005eb8] hover:bg-gray-50 transition-colors focus:outline-none";
} else {
contentDokumen.classList.remove('hidden');
contentDokumen.classList.add('flex');
contentAgenda.classList.add('hidden');
contentAgenda.classList.remove('flex');
btnDokumen.className = "flex-1 py-3 text-sm font-bold text-[#005eb8] border-b-2 border-[#005eb8] bg-blue-50/50 transition-colors focus:outline-none";
btnAgenda.className = "flex-1 py-3 text-sm font-bold text-gray-400 border-b-2 border-transparent hover:text-[#005eb8] hover:bg-gray-50 transition-colors focus:outline-none";
}
}
</script>
</body>
</html>