Merge pull request 'feature/multilanguage' (#7) from feature/multilanguage into main

Reviewed-on: tisto/student-web-if-development-kit#7
Reviewed-by: requestha <d1041231091@student.untan.ac.id>
Reviewed-by: pancaa <d1041231077@student.untan.ac.id>
This commit is contained in:
2026-06-05 05:17:21 +00:00
3 changed files with 623 additions and 1829 deletions
+4 -4
View File
@@ -604,14 +604,14 @@ const translations = {
grp_habisiniseminar_meta_group: 'Kelompok 02', grp_habisiniseminar_meta_group: 'Kelompok 02',
grp_habisiniseminar_about_title: 'Seleksi Program Sarjana', grp_habisiniseminar_about_title: 'Seleksi Program Sarjana',
grp_habisiniseminar_about_desc: 'Program Studi Informatika Universitas Tanjungpura membuka kesempatan bagi putra-putri terbaik bangsa untuk bergabung melalui berbagai jalur seleksi. Kami mencari talenta yang siap menjadi inovator teknologi masa depan.', grp_habisiniseminar_about_desc: 'Program Studi Informatika Universitas Tanjungpura membuka kesempatan bagi putra-putri terbaik bangsa untuk bergabung melalui berbagai jalur seleksi. Kami mencari talenta yang siap menjadi inovator teknologi masa depan.',
// ── Pathways ───────────────────────────────────────────────────────── // ── Pathways ─────────────────────────────────────────────────────────
grp_habisiniseminar_path_snbp_desc: 'Seleksi Nasional Berdasarkan Prestasi', grp_habisiniseminar_path_snbp_desc: 'Seleksi Nasional Berdasarkan Prestasi',
grp_habisiniseminar_path_snbt_desc: 'Seleksi Nasional Berdasarkan Tes', grp_habisiniseminar_path_snbt_desc: 'Seleksi Nasional Berdasarkan Tes',
grp_habisiniseminar_path_smmptn_desc: 'Seleksi Mandiri Wilayah Barat', grp_habisiniseminar_path_smmptn_desc: 'Seleksi Mandiri Wilayah Barat',
grp_habisiniseminar_path_mandiri_desc: 'Seleksi Mandiri Universitas Tanjungpura', grp_habisiniseminar_path_mandiri_desc: 'Seleksi Mandiri Universitas Tanjungpura',
grp_habisiniseminar_info_jalur_title: 'Informasi Jalur Seleksi', grp_habisiniseminar_info_jalur_title: 'Informasi Jalur Seleksi',
// ── Sidebar ────────────────────────────────────────────────────────── // ── Sidebar ──────────────────────────────────────────────────────────
grp_habisiniseminar_sidebar_heading: 'Pilih Jalur', grp_habisiniseminar_sidebar_heading: 'Pilih Jalur',
grp_habisiniseminar_sidebar_data_date: '*Data yang digunakan per tanggal Mei 2026', grp_habisiniseminar_sidebar_data_date: '*Data yang digunakan per tanggal Mei 2026',
@@ -1377,14 +1377,14 @@ const translations = {
grp_habisiniseminar_meta_group: 'Group 02', grp_habisiniseminar_meta_group: 'Group 02',
grp_habisiniseminar_about_title: 'Undergraduate Program Selection', grp_habisiniseminar_about_title: 'Undergraduate Program Selection',
grp_habisiniseminar_about_desc: 'The Informatics Study Program at Tanjungpura University opens opportunities for the nation\'s best students to join through various selection pathways. We seek talented individuals ready to become future technology innovators.', grp_habisiniseminar_about_desc: 'The Informatics Study Program at Tanjungpura University opens opportunities for the nation\'s best students to join through various selection pathways. We seek talented individuals ready to become future technology innovators.',
// ── Pathways ───────────────────────────────────────────────────────── // ── Pathways ─────────────────────────────────────────────────────────
grp_habisiniseminar_path_snbp_desc: 'National Selection Based on Achievement', grp_habisiniseminar_path_snbp_desc: 'National Selection Based on Achievement',
grp_habisiniseminar_path_snbt_desc: 'National Selection Based on Test', grp_habisiniseminar_path_snbt_desc: 'National Selection Based on Test',
grp_habisiniseminar_path_smmptn_desc: 'Western Region Joint Independent Selection', grp_habisiniseminar_path_smmptn_desc: 'Western Region Joint Independent Selection',
grp_habisiniseminar_path_mandiri_desc: 'Tanjungpura University Independent Selection', grp_habisiniseminar_path_mandiri_desc: 'Tanjungpura University Independent Selection',
grp_habisiniseminar_info_jalur_title: 'Selection Pathway Information', grp_habisiniseminar_info_jalur_title: 'Selection Pathway Information',
// ── Sidebar ────────────────────────────────────────────────────────── // ── Sidebar ──────────────────────────────────────────────────────────
grp_habisiniseminar_sidebar_heading: 'Choose Pathway', grp_habisiniseminar_sidebar_heading: 'Choose Pathway',
grp_habisiniseminar_sidebar_data_date: '*Data used as of May 2026', grp_habisiniseminar_sidebar_data_date: '*Data used as of May 2026',
+349 -91
View File
@@ -5,31 +5,6 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Group 03 &ndash; HarusSelesaiKP | Informatika UNTAN</title> <title>Group 03 &ndash; HarusSelesaiKP | Informatika UNTAN</title>
<!--
Anti-flicker safety net: body.lang-pending is hidden via style.css
until localization.js (loaded sync below) applies the correct
language on DOMContentLoaded and removes the class.
This inline fallback ensures the rule exists even if style.css
hasn't parsed yet.
-->
<style id="lang-pending-style">
body.lang-pending {
visibility: hidden
}
</style>
<!--
localization.js MUST be loaded synchronously (no defer/async)
so the IIFE inside it can set window.__currentLang before
the browser renders any text. This is the ONLY intentional
render-blocking script.
-->
<script src="localization.js"></script>
<!-- Preload hero image — eliminates LCP delay -->
<link rel="preload" href="images/hero.webp" as="image" type="image/webp" />
<link rel="stylesheet" href="../../assets/global/output.css" /> <link rel="stylesheet" href="../../assets/global/output.css" />
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
@@ -37,17 +12,297 @@
<link <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" 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" /> rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
<style>
/* ===== MOBILE NAV STABILITY FIX =====
Prevents logo bar from collapsing/shifting on Android when
address bar hides/shows and triggers viewport reflow.
===================================== */
#nav-wrapper {
position: fixed !important;
top: 0;
left: 0;
right: 0;
z-index: 50;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
will-change: box-shadow;
}
<!-- Font Awesome loaded async — non-render-blocking --> #nav-wrapper>div:first-child {
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" transform: translateZ(0);
media="print" onload="this.media='all'" /> -webkit-transform: translateZ(0);
<noscript> }
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
</noscript> @media (max-width: 1023px) {
#nav-wrapper>div:first-child {
min-height: 0 !important;
max-height: none;
}
}
#pengumuman-bar {
z-index: 40;
}
#pengumuman-bar.is-stuck {
position: fixed;
left: 0;
right: 0;
z-index: 40;
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Skip Link Styling */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #003150;
color: white;
padding: 8px 16px;
z-index: 100;
transition: top 0.3s;
}
.skip-link:focus {
top: 0;
}
/* Focus visible for better keyboard navigation */
:focus-visible {
outline: 3px solid #feb401;
outline-offset: 2px;
}
/* Mega Menu Styles */
.hero-pagination .swiper-pagination-bullet {
width: 8px;
height: 8px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
display: inline-block;
margin: 0 4px;
cursor: pointer;
transition: all 0.3s ease;
}
.hero-pagination .swiper-pagination-bullet-active {
background: rgba(255, 255, 255, 1);
width: 24px;
border-radius: 4px;
}
.mega-panel {
opacity: 0;
visibility: hidden;
transition:
opacity 0.2s ease,
visibility 0.2s ease;
position: absolute;
top: 100%;
left: 0;
right: 0;
}
.mega-panel.active {
opacity: 1;
visibility: visible;
}
/* Overlay transition */
#mega-overlay {
opacity: 0;
visibility: hidden;
transition:
opacity 0.2s ease,
visibility 0.2s ease;
}
#mega-overlay.active {
opacity: 1;
visibility: visible;
}
.mega-link-card {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 1rem;
border-radius: 0.75rem;
border: 1px solid #e2e8f0;
background: white;
transition: all 0.2s ease;
}
.mega-link-card:hover {
border-color: #3b82f6;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
transform: translateY(-2px);
}
.mega-link-icon {
width: 2.5rem;
height: 2.5rem;
border-radius: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 0.2s ease;
}
.nav-menu-btn.active {
background: rgba(255, 255, 255, 0.9);
color: #1e40af;
}
.nav-menu-btn:hover {
background: rgba(255, 255, 255, 0.8);
}
/* Mega menu positioning - no gap */
#main-nav {
position: relative;
}
#mega-menu-container {
position: absolute;
top: 100%;
left: 0;
right: 0;
pointer-events: none;
}
#mega-menu-container .mega-panel {
pointer-events: auto;
}
/* Keep pointer bridge under nav to prevent hover loss */
.nav-menu-item {
position: relative;
}
.nav-menu-item::after {
content: "";
position: absolute;
bottom: -12px;
left: 0;
right: 0;
height: 12px;
}
/* ===== Luco Chatbot Animations ===== */
@keyframes slideInRight {
from {
transform: translateX(100px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes fadeInUp {
from {
transform: translateY(10px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes lucoPulse {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
#luco-container {
animation: slideInRight 0.5s ease-out forwards;
}
#luco-bubble {
animation: fadeInUp 0.3s ease-out forwards;
width: min(18rem, calc(100vw - 2rem));
}
#luco-btn {
animation: lucoPulse 2s ease-in-out infinite;
}
#luco-btn:hover {
animation: none;
}
/* Typing indicator */
.typing-indicator span {
display: inline-block;
animation: bounce 1.4s infinite ease-in-out;
}
.typing-indicator span:nth-child(1) {
animation-delay: 0s;
}
.typing-indicator span:nth-child(2) {
animation-delay: 0.2s;
}
.typing-indicator span:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes bounce {
0%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-6px);
}
}
/* Luco speech bubble arrow */
#luco-bubble .bubble-arrow {
position: absolute;
right: 24px;
bottom: -6px;
width: 12px;
height: 12px;
background: white;
transform: rotate(45deg);
border-right: 1px solid #e2e8f0;
border-bottom: 1px solid #e2e8f0;
}
</style>
</head> </head>
<body class="text-slate-800 antialiased bg-white selection:bg-untan-yellow selection:text-black">
<body class="lang-pending 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> <a href="#main-content" class="skip-link" data-i18n="skip_to_content">Langsung ke Konten Utama</a>
<div id="nav-wrapper" <div id="nav-wrapper"
@@ -96,9 +351,8 @@
<div class="pl-5 border-l border-white/20 flex items-center gap-3"> <div class="pl-5 border-l border-white/20 flex items-center gap-3">
<button <button
class="language-toggle-btn text-xs hover:text-untan-yellow transition-colors flex items-center gap-1"> class="language-toggle-btn text-xs hover:text-untan-yellow transition-colors flex items-center gap-1">
<span class="lang-id font-bold">ID</span> <span class="font-bold">ID</span>
<span class="text-white/40">|</span> <span class="text-white/40">|</span> EN
<span class="lang-en opacity-50 font-normal">EN</span>
</button> </button>
<button <button
class="w-8 h-8 flex items-center justify-center rounded-sm hover:bg-white/10 transition-colors" class="w-8 h-8 flex items-center justify-center rounded-sm hover:bg-white/10 transition-colors"
@@ -879,9 +1133,9 @@
<button <button
class="language-toggle-btn px-2 py-1 rounded-sm border border-white/20 text-xs text-white hover:bg-white/10 transition-colors flex items-center gap-2" class="language-toggle-btn px-2 py-1 rounded-sm border border-white/20 text-xs text-white hover:bg-white/10 transition-colors flex items-center gap-2"
aria-label="Ganti bahasa"> aria-label="Ganti bahasa">
<span class="lang-id font-bold">ID</span> <span class="font-bold">ID</span>
<span class="text-white/40" aria-hidden="true">|</span> <span class="text-white/40" aria-hidden="true">|</span>
<span class="lang-en opacity-50 font-normal">EN</span> EN
</button> </button>
<button <button
class="w-8 h-8 rounded-sm bg-white/10 hover:bg-white/20 flex items-center justify-center text-white transition-colors" class="w-8 h-8 rounded-sm bg-white/10 hover:bg-white/20 flex items-center justify-center text-white transition-colors"
@@ -1027,7 +1281,10 @@
<span class="highlight-text">Universitas Tanjungpura</span> Pontianak <span class="highlight-text">Universitas Tanjungpura</span> Pontianak
</h1> </h1>
<p class="hero-description" data-i18n="skp_hero_desc"> <p class="hero-description" data-skp-i18n="skp_hero_desc">
=======
<p class="hero-description" data-skp-i18n="skp_hero_desc">
>>>>>>> origin/main
Kuliah di kampus unggulan Kalimantan Barat dengan fasilitas lengkap, Kuliah di kampus unggulan Kalimantan Barat dengan fasilitas lengkap,
lingkungan nyaman dan kehidupan mahasiswa yang terjangkau lingkungan nyaman dan kehidupan mahasiswa yang terjangkau
</p> </p>
@@ -1041,30 +1298,30 @@
</div> </div>
<div class="about-content"> <div class="about-content">
<span class="eyebrow-component" data-i18n="skp_about_eyebrow">Tentang Untan</span> <span class="eyebrow-component" data-skp-i18n="skp_about_eyebrow">Tentang Untan</span>
<h2 class="about-title" data-i18n="skp_about_title"> <h2 class="about-title" data-skp-i18n="skp_about_title">
Kampus Unggul di Kalimantan Barat Kampus Unggul di Kalimantan Barat
</h2> </h2>
<div class="about-description"> <div class="about-description">
<p data-i18n="skp_about_desc_1"> <p data-skp-i18n="skp_about_desc_1">
Universitas Tanjungpura merupakan perguruan tinggi negeri Universitas Tanjungpura merupakan perguruan tinggi negeri
terkemuka di Kalimantan Barat yang berkomitmen menghadirkan terkemuka di Kalimantan Barat yang berkomitmen menghadirkan
pendidikan berkualitas. pendidikan berkualitas.
</p> </p>
<p data-i18n="skp_about_desc_2"> <p data-skp-i18n="skp_about_desc_2">
UNTAN terus mendorong pengembangan riset, inovasi, dan kolaborasi UNTAN terus mendorong pengembangan riset, inovasi, dan kolaborasi
di berbagai bidang. di berbagai bidang.
</p> </p>
<p data-i18n="skp_about_desc_3"> <p data-skp-i18n="skp_about_desc_3">
Didukung lingkungan belajar yang nyaman, mahasiswa memiliki ruang Didukung lingkungan belajar yang nyaman, mahasiswa memiliki ruang
untuk berkembang secara akademik maupun nonakademik. untuk berkembang secara akademik maupun nonakademik.
</p> </p>
</div> </div>
<a href="https://www.untan.ac.id/" target="_blank" rel="noopener noreferrer" class="about-link"> <a href="https://www.untan.ac.id/" target="_blank" rel="noopener noreferrer" class="about-link">
<span data-i18n="skp_about_link_text">Kunjungi Website Resmi</span> <span data-skp-i18n="skp_about_link_text">Kunjungi Website Resmi</span>
<svg xmlns="http://www.w3.org/2000/svg" class="link-icon" viewBox="0 0 24 24"> <svg xmlns="http://www.w3.org/2000/svg" class="link-icon" viewBox="0 0 24 24">
<path fill="currentColor" fill-rule="evenodd" <path fill="currentColor" fill-rule="evenodd"
d="M12 5.714a1 1 0 0 1 1 1v12.5a1 1 0 0 1-2 0v-12.5a1 1 0 0 1 1-1" clip-rule="evenodd"> d="M12 5.714a1 1 0 0 1 1 1v12.5a1 1 0 0 1-2 0v-12.5a1 1 0 0 1 1-1" clip-rule="evenodd">
@@ -1079,9 +1336,9 @@
<!-- FACILITIES SECTION --> <!-- FACILITIES SECTION -->
<section class="facilities-section"> <section class="facilities-section">
<span class="eyebrow-component" data-i18n="skp_fac_eyebrow">Fasilitas Kampus</span> <span class="eyebrow-component" data-skp-i18n="skp_fac_eyebrow">Fasilitas Kampus</span>
<h2 class="facilities-title" data-i18n="skp_fac_main_title"> <h2 class="facilities-title" data-skp-i18n="skp_fac_main_title">
Fasilitas Kampus untuk Pengalaman Belajar yang Nyaman Fasilitas Kampus untuk Pengalaman Belajar yang Nyaman
</h2> </h2>
@@ -1090,12 +1347,12 @@
<!-- CAMPUS SECTION --> <!-- CAMPUS SECTION -->
<section class="campus-section"> <section class="campus-section">
<span class="eyebrow-component" data-i18n="skp_campus_eyebrow">Kehidupan Kampus</span> <span class="eyebrow-component" data-skp-i18n="skp_campus_eyebrow">Kehidupan Kampus</span>
<h2 class="campus-title" data-i18n="skp_campus_title"> <h2 class="campus-title" data-skp-i18n="skp_campus_title">
Aktivitas Mahasiswa & Organisasi Kampus Aktivitas Mahasiswa & Organisasi Kampus
</h2> </h2>
<p class="campus-subtitle" data-i18n="skp_campus_subtitle"> <p class="campus-subtitle" data-skp-i18n="skp_campus_subtitle">
Mahasiswa UNTAN memiliki berbagai kesempatan untuk berkembang melalui Mahasiswa UNTAN memiliki berbagai kesempatan untuk berkembang melalui
organisasi, UKM, komunitas, dan kegiatan ekstrakurikuler. organisasi, UKM, komunitas, dan kegiatan ekstrakurikuler.
</p> </p>
@@ -1112,12 +1369,12 @@
<div class="pontianak-overlay"></div> <div class="pontianak-overlay"></div>
<div class="pontianak-content"> <div class="pontianak-content">
<span class="eyebrow-component" data-i18n="skp_pontianak_eyebrow">Kota Pontianak</span> <span class="eyebrow-component" data-skp-i18n="skp_pontianak_eyebrow">Kota Pontianak</span>
<h2 class="pontianak-title" data-i18n="skp_pontianak_title"> <h2 class="pontianak-title" data-skp-i18n="skp_pontianak_title">
Live In Pontianak Live In Pontianak
</h2> </h2>
<p class="pontianak-desc" data-i18n="skp_pontianak_desc"> <p class="pontianak-desc" data-skp-i18n="skp_pontianak_desc">
Pontianak bukan sekadar ibu kota Kalimantan Barat, tetapi tempat Pontianak bukan sekadar ibu kota Kalimantan Barat, tetapi tempat
yang nyaman untuk tinggal, ramah bagi mahasiswa, dan bersahabat di yang nyaman untuk tinggal, ramah bagi mahasiswa, dan bersahabat di
kantong. Kota ini menawarkan akses fasilitas umum yang lengkap, kantong. Kota ini menawarkan akses fasilitas umum yang lengkap,
@@ -1129,9 +1386,9 @@
<!-- DESTINATION SECTION --> <!-- DESTINATION SECTION -->
<section class="destination-section"> <section class="destination-section">
<span class="eyebrow-component" data-i18n="skp_dest_eyebrow">Wisata & Destinasi</span> <span class="eyebrow-component" data-skp-i18n="skp_dest_eyebrow">Wisata & Destinasi</span>
<h2 class="destination-title" data-i18n="skp_dest_title"> <h2 class="destination-title" data-skp-i18n="skp_dest_title">
Tempat Menarik di Pontianak Tempat Menarik di Pontianak
</h2> </h2>
@@ -1142,9 +1399,9 @@
<!-- CULINARY SECTION --> <!-- CULINARY SECTION -->
<section class="culinary-section"> <section class="culinary-section">
<span class="eyebrow-component" data-i18n="skp_cul_eyebrow">Cafe & Kuliner</span> <span class="eyebrow-component" data-skp-i18n="skp_cul_eyebrow">Cafe & Kuliner</span>
<h2 class="culinary-title" data-i18n="skp_cul_title"> <h2 class="culinary-title" data-skp-i18n="skp_cul_title">
Kuliner dan Coffee Shop Favorit Mahasiswa Kuliner dan Coffee Shop Favorit Mahasiswa
</h2> </h2>
<hr class="culinary-divider" /> <hr class="culinary-divider" />
@@ -1157,24 +1414,23 @@
<!-- LIVING COST SECTION --> <!-- LIVING COST SECTION -->
<section class="living-cost-section"> <section class="living-cost-section">
<div class="cost-banner-wrapper"> <div class="cost-banner-wrapper">
<img src="images/biaya-hidup.jpg" alt="Ilustrasi biaya hidup mahasiswa di Pontianak" <img src="images/biaya-hidup.jpg" alt="biaya hidup" class="cost-banner-img" />
class="cost-banner-img" loading="lazy" decoding="async" width="1200" height="800" />
<div class="cost-banner-overlay"></div> <div class="cost-banner-overlay"></div>
</div> </div>
<div class="cost-info-panel"> <div class="cost-info-panel">
<span class="eyebrow-component" data-i18n="skp_cost_eyebrow">Biaya Hidup Mahasiswa</span> <span class="eyebrow-component" data-skp-i18n="skp_cost_eyebrow">Biaya Hidup Mahasiswa</span>
<h2 class="cost-title" data-i18n="skp_cost_title"> <h2 class="cost-title" data-skp-i18n="skp_cost_title">
Perkiraan Biaya Hidup Mahasiswa di Pontianak Perkiraan Biaya Hidup Mahasiswa di Pontianak
</h2> </h2>
<p class="cost-desc" data-i18n="skp_cost_desc"> <p class="cost-desc" data-skp-i18n="skp_cost_desc">
Perencanaan keuangan yang baik membantu mahasiswa menjalani masa Perencanaan keuangan yang baik membantu mahasiswa menjalani masa
studi dengan lebih nyaman di Pontianak. studi dengan lebih nyaman di Pontianak.
</p> </p>
<span class="cost-note" data-i18n="skp_cost_note"> <span class="cost-note" data-skp-i18n="skp_cost_note">
*Data yang didapat bersumber dari survey internal *Data yang didapat bersumber dari survey internal
</span> </span>
@@ -1211,7 +1467,7 @@
<div class="flex flex-col sm:flex-row items-center justify-center gap-4 sm:gap-6 mb-8 text-left"> <div class="flex flex-col sm:flex-row items-center justify-center gap-4 sm:gap-6 mb-8 text-left">
<img src="https://upload.wikimedia.org/wikipedia/id/0/03/Lambang_Universitas_Tanjungpura.png" <img src="https://upload.wikimedia.org/wikipedia/id/0/03/Lambang_Universitas_Tanjungpura.png"
class="h-16 sm:h-20 shrink-0" alt="Logo UNTAN" loading="lazy" decoding="async" /> class="h-16 sm:h-20 shrink-0" alt="Logo UNTAN" />
<div <div
class="border-t sm:border-t-0 sm:border-l-2 border-white/30 pt-4 sm:pt-0 sm:pl-5 py-1 flex flex-col justify-center leading-tight"> class="border-t sm:border-t-0 sm:border-l-2 border-white/30 pt-4 sm:pt-0 sm:pl-5 py-1 flex flex-col justify-center leading-tight">
<h2 class="text-2xl sm:text-3xl font-bold font-sans tracking-widest uppercase mb-1"> <h2 class="text-2xl sm:text-3xl font-bold font-sans tracking-widest uppercase mb-1">
@@ -1246,8 +1502,7 @@
<div class="w-full relative z-0 mt-4 pointer-events-none flex justify-center"> <div class="w-full relative z-0 mt-4 pointer-events-none flex justify-center">
<img src="../../assets/global/footer.png" alt="Footer Illustration" <img src="../../assets/global/footer.png" alt="Footer Illustration"
class="w-full h-auto object-cover object-bottom" style="object-position: bottom" loading="lazy" class="w-full h-auto object-cover object-bottom" style="object-position: bottom" />
decoding="async" />
</div> </div>
</footer> </footer>
@@ -1364,8 +1619,11 @@
})(); })();
</script> </script>
<!-- localization.js is now loaded in <head> synchronously for anti-flicker --> <script src="../../assets/global/localization.js"></script>
<!-- See the <head> section for its <script> tag --> <script src="localization.js"></script>
<script>
if (typeof applySkp === 'function') applySkp();
</script>
<!-- JavaScript Kelompok HarusSelesaiKP --> <!-- JavaScript Kelompok HarusSelesaiKP -->
<!-- JavaScript Facilities Section --> <!-- JavaScript Facilities Section -->
@@ -1436,7 +1694,7 @@
desc: "Fasilitas laboratorium modern UNTAN yang mendukung riset, praktikum, dan inovasi mahasiswa.", desc: "Fasilitas laboratorium modern UNTAN yang mendukung riset, praktikum, dan inovasi mahasiswa.",
}, },
{ {
imgSrc: "images/audit-untan.webp", imgSrc: "images/audit-untan.png",
icon: "icons/building-home.svg", icon: "icons/building-home.svg",
titleKey: "skp_fac_title_audit", titleKey: "skp_fac_title_audit",
descKey: "skp_fac_desc_audit", descKey: "skp_fac_desc_audit",
@@ -1453,9 +1711,9 @@
facilitiesData.forEach((item) => { facilitiesData.forEach((item) => {
const displayTitle = const displayTitle =
typeof t === "function" ? t(item.titleKey) : item.titleKey; typeof skpT === "function" ? skpT(item.titleKey) : item.titleKey;
const displayDesc = const displayDesc =
typeof t === "function" ? t(item.descKey) : item.descKey; typeof skpT === "function" ? skpT(item.descKey) : item.descKey;
cardsHtmlHTML += ` cardsHtmlHTML += `
<div class="facility-card"> <div class="facility-card">
@@ -1508,7 +1766,7 @@
const directoriesData = [ const directoriesData = [
{ {
category: "Organisasi", category: "Organisasi",
image: "images/bem-untan.webp", image: "images/bem-untan.png",
titleKey: "skp_campus_dir_bem_title", titleKey: "skp_campus_dir_bem_title",
descKey: "skp_campus_dir_bem_desc", descKey: "skp_campus_dir_bem_desc",
}, },
@@ -1520,25 +1778,25 @@
}, },
{ {
category: "Organisasi", category: "Organisasi",
image: "images/hmif-untan.webp", image: "images/hmif-untan.png",
titleKey: "skp_campus_dir_hmif_title", titleKey: "skp_campus_dir_hmif_title",
descKey: "skp_campus_dir_hmif_desc", descKey: "skp_campus_dir_hmif_desc",
}, },
{ {
category: "Organisasi", category: "Organisasi",
image: "images/cafatifa-untan.webp", image: "images/cafatifa-untan.png",
titleKey: "skp_campus_dir_cafa_title", titleKey: "skp_campus_dir_cafa_title",
descKey: "skp_campus_dir_cafa_desc", descKey: "skp_campus_dir_cafa_desc",
}, },
{ {
category: "UKM", category: "UKM",
image: "images/mapala-untan.webp", image: "images/mapala-untan.png",
titleKey: "skp_campus_dir_mapala_title", titleKey: "skp_campus_dir_mapala_title",
descKey: "skp_campus_dir_mapala_desc", descKey: "skp_campus_dir_mapala_desc",
}, },
{ {
category: "UKM", category: "UKM",
image: "images/lisma-untan.webp", image: "images/lisma-untan.png",
titleKey: "skp_campus_dir_lisma_title", titleKey: "skp_campus_dir_lisma_title",
descKey: "skp_campus_dir_lisma_desc", descKey: "skp_campus_dir_lisma_desc",
}, },
@@ -1573,7 +1831,7 @@
const isActiveClass = const isActiveClass =
cat.id === currentActiveCategory ? "active" : ""; cat.id === currentActiveCategory ? "active" : "";
const displayCategoryText = const displayCategoryText =
typeof t === "function" ? t(cat.textKey) : cat.id; typeof skpT === "function" ? skpT(cat.textKey) : cat.id;
return ` return `
<button class="category-btn ${isActiveClass}" onclick="handleCategoryChange('${cat.id}')"> <button class="category-btn ${isActiveClass}" onclick="handleCategoryChange('${cat.id}')">
@@ -1593,9 +1851,9 @@
cardsRoot.innerHTML = filteredData cardsRoot.innerHTML = filteredData
.map((dir) => { .map((dir) => {
const displayTitle = const displayTitle =
typeof t === "function" ? t(dir.titleKey) : dir.titleKey; typeof skpT === "function" ? skpT(dir.titleKey) : dir.titleKey;
const displayDesc = const displayDesc =
typeof t === "function" ? t(dir.descKey) : dir.descKey; typeof skpT === "function" ? skpT(dir.descKey) : dir.descKey;
return ` return `
<div class="directory-card"> <div class="directory-card">
@@ -1657,7 +1915,7 @@
`; `;
const buttonText = const buttonText =
typeof t === "function" ? t("skp_dest_open_maps") : "Open Maps"; typeof skpT === "function" ? skpT("skp_dest_open_maps") : "Open Maps";
return ` return `
<a class="map-button-component" href="${href}" target="_blank" rel="noopener noreferrer"> <a class="map-button-component" href="${href}" target="_blank" rel="noopener noreferrer">
@@ -1669,13 +1927,13 @@
const destinationsData = [ const destinationsData = [
{ {
image: "images/khatulistiwa.webp", image: "images/khatulistiwa.png",
nameKey: "skp_dest_khatulistiwa_name", nameKey: "skp_dest_khatulistiwa_name",
descKey: "skp_dest_khatulistiwa_desc", descKey: "skp_dest_khatulistiwa_desc",
href: "https://maps.app.goo.gl/BUw4GWfSSDxvMCKA6", href: "https://maps.app.goo.gl/BUw4GWfSSDxvMCKA6",
}, },
{ {
image: "images/waterfront.webp", image: "images/waterfront.jpg",
nameKey: "skp_dest_waterfront_name", nameKey: "skp_dest_waterfront_name",
descKey: "skp_dest_waterfront_desc", descKey: "skp_dest_waterfront_desc",
href: "https://maps.app.goo.gl/2uo4jwNZtGTsvogU6", href: "https://maps.app.goo.gl/2uo4jwNZtGTsvogU6",
@@ -1687,7 +1945,7 @@
href: "https://maps.app.goo.gl/dfLJPdFJMK9ifja66", href: "https://maps.app.goo.gl/dfLJPdFJMK9ifja66",
}, },
{ {
image: "images/rumah-radank.webp", image: "images/rumah-radank.png",
nameKey: "skp_dest_radank_name", nameKey: "skp_dest_radank_name",
descKey: "skp_dest_radank_desc", descKey: "skp_dest_radank_desc",
href: "https://maps.app.goo.gl/UqBchR3zimQSdTqW6", href: "https://maps.app.goo.gl/UqBchR3zimQSdTqW6",
@@ -1729,9 +1987,9 @@
// Menerjemahkan nama dan deskripsi destinasi secara dinamis // Menerjemahkan nama dan deskripsi destinasi secara dinamis
const displayName = const displayName =
typeof t === "function" ? t(dest.nameKey) : dest.nameKey; typeof skpT === "function" ? skpT(dest.nameKey) : dest.nameKey;
const displayDesc = const displayDesc =
typeof t === "function" ? t(dest.descKey) : dest.descKey; typeof skpT === "function" ? skpT(dest.descKey) : dest.descKey;
return ` return `
<div class="destination-card" style="background-image: url('${dest.image}')"> <div class="destination-card" style="background-image: url('${dest.image}')">
@@ -1764,14 +2022,14 @@
const cuisinesData = [ const cuisinesData = [
{ {
category: "RM", category: "RM",
image: "images/gebuk-sambalado.webp", image: "images/gebuk-sambalado.png",
name: "Gebuk Sambalado", name: "Gebuk Sambalado",
descKey: "skp_cul_gebuk_desc", descKey: "skp_cul_gebuk_desc",
href: "https://maps.app.goo.gl/J1xCUCqVyTqPStG6A", href: "https://maps.app.goo.gl/J1xCUCqVyTqPStG6A",
}, },
{ {
category: "RM", category: "RM",
image: "images/kota-sari.webp", image: "images/kota-sari.png",
name: "Kota Sari", name: "Kota Sari",
descKey: "skp_cul_sari_desc", descKey: "skp_cul_sari_desc",
href: "https://maps.app.goo.gl/Tx5Rbt6TxCtFuiGdA", href: "https://maps.app.goo.gl/Tx5Rbt6TxCtFuiGdA",
@@ -1860,7 +2118,7 @@
.map((cat) => { .map((cat) => {
const isActive = cat.id === activeCulinaryCategory ? "active" : ""; const isActive = cat.id === activeCulinaryCategory ? "active" : "";
const displayTabText = const displayTabText =
typeof t === "function" ? t(cat.textKey) : cat.id; typeof skpT === "function" ? skpT(cat.textKey) : cat.id;
return ` return `
<button class="culinary-tab-btn ${isActive}" onclick="handleCulinaryCategoryChange('${cat.id}')"> <button class="culinary-tab-btn ${isActive}" onclick="handleCulinaryCategoryChange('${cat.id}')">
@@ -1884,7 +2142,7 @@
: `<a href="${item.href}">Maps</a>`; : `<a href="${item.href}">Maps</a>`;
const displayDesc = const displayDesc =
typeof t === "function" ? t(item.descKey) : item.descKey; typeof skpT === "function" ? skpT(item.descKey) : item.descKey;
return ` return `
<div class="culinary-card"> <div class="culinary-card">
@@ -1947,9 +2205,9 @@
costCardsRoot.innerHTML = livingCostDetailsData costCardsRoot.innerHTML = livingCostDetailsData
.map((detail) => { .map((detail) => {
const displayType = const displayType =
typeof t === "function" ? t(detail.typeKey) : detail.typeKey; typeof skpT === "function" ? skpT(detail.typeKey) : detail.typeKey;
const displayPeriod = const displayPeriod =
typeof t === "function" ? t("skp_cost_period") : "per bulan"; typeof skpT === "function" ? skpT("skp_cost_period") : "per bulan";
return ` return `
<div class="cost-item-card"> <div class="cost-item-card">
File diff suppressed because it is too large Load Diff