agenda
Seminar Hasil Penelitian an. Adinda Nur'aida Ascada
| Hari, Tanggal | : Selasa, 24 Juni 2025 |
| Waktu | : 08.00 - 09.30 WIB |
| Tempat | : Ruang Seminar FMIPA |
Berita Terbaru Lainnya
116 Total
#1 agenda
Seminar Hasil Penelitian an. Glentino Puraya
30 Nov 2025
#2 agenda
Seminar Hasil Penelitian an. Eltika
30 Nov 2025
#3 agenda
Seminar Hasil Penelitian an. Nopita Tamara Sari
30 Nov 2025
#4 agenda
Sidang Akhir Sarjana an. Emy Rahayu
30 Nov 2025
#5 agenda
Sidang Akhir Sarjana an. Yuli Wulan Sari
30 Nov 2025
#6 agenda
Sidang Akhir Sarjana an. Glentino Puraya
30 Nov 2025
#7 agenda
Seminar Hasil Penelitian an. Hadijah
30 Nov 2025
#8 agenda
Seminar Hasil Penelitian an. Nabila Aprilianti
30 Nov 2025
#9 agenda
Ujian Akhir Semester
30 Nov 2025
#10 agenda
Seminar Hasil Penelitian an. Krishna Ananka Reza Guevara
30 Nov 2025
#11 agenda
Seminar Hasil Penelitian an. Eunike Livia Pomantow
30 Nov 2025
#12 agenda
Seminar Hasil Penelitian an. Xaverius Vowell Manalu
30 Nov 2025
#13 agenda
Sidang Akhir Sarjana an. Tio Pinta Agustina Tamba
30 Nov 2025
#14 agenda
Seminar Hasil Penelitian an. Jini
30 Nov 2025
#15 agenda
Seminar Hasil Penelitian an. Richad
30 Nov 2025
#16 agenda
Sidang Akhir Sarjana an. Tiara Putri Maharani
30 Nov 2025
#17 agenda
Seminar Proposal an. Aprilita Pitriani
30 Nov 2025
#18 agenda
Seminar Hasil Penelitian an. Fauzan Fikri
30 Nov 2025
#19 agenda
Seminar Hasil Penelitian an. Sindi Kristia
30 Nov 2025
#20 agenda
Seminar Hasil Penelitian an. Efrayando
30 Nov 2025
#21 agenda
Sidang Akhir Sarjana an. Jini
30 Nov 2025
#22 agenda
Sidang Akhir Sarjana an. Eunike Livia Pomantow
30 Nov 2025
#23 agenda
Sidang Akhir Sarjana an. Xaverius Vowell Manalu
30 Nov 2025
#24 agenda
Sidang Akhir Sarjana an. Richad
30 Nov 2025
#25 agenda
Sidang Akhir Sarjana an. Fauzan Fikri
30 Nov 2025
#26 agenda
Sidang Akhir Sarjana an. Sindi Kristia
30 Nov 2025
#27 agenda
Seminar Hasil Penelitian an. Roni Valentino
30 Nov 2025
#28 agenda
Sidang Akhir Sarjana an. Adinda Nur’aida Ascada
30 Nov 2025
#29 agenda
Seminar Hasil Penelitian an. Arisa Grace Yuli Lubis
30 Nov 2025
#30 agenda
Seminar Hasil Penelitian an. Agustina Putri Maharati
30 Nov 2025
#31 agenda
Sidang Akhir Sarjana an. Efrayando
30 Nov 2025
#32 agenda
Seminar Hasil Penelitian an. Salsabila Devana Putri
30 Nov 2025
#33 agenda
Seminar Hasil Penelitian an. Fadtra Jaya
30 Nov 2025
#34 agenda
Seminar Proposal an. Amelia Safitri
30 Nov 2025
#35 agenda
Seminar Hasil Penelitian an. Nadila Franciska
30 Nov 2025
#36 agenda
Sidang Akhir Sarjana an. Salsabila Devana Putri
30 Nov 2025
#37 agenda
Sidang Akhir Sarjana an. Agustina Putri Maharati
30 Nov 2025
#38 agenda
Sidang Akhir Sarjana an. Arisa Grace Yuli Lubis
30 Nov 2025
#39 agenda
Seminar Hasil Penelitian an. Yuli Wulan Sari
30 Nov 2025
#40 berita
Penerimaan Mahasiswa Baru UPR Tahun 2021
30 Nov 2025
#41 berita
UPR dan UNSIKA Tandatangani MOU
30 Nov 2025
#42 berita
Kelompok Studi Herpetologi
30 Nov 2025
#43 berita
Kuliah Tamu Pengendalian Hama Terpadu
30 Nov 2025
#44 berita
Kuliah Tamu Fitopatologi
30 Nov 2025
#45 berita
Kegiatan Pengabdian Masyarakat
30 Nov 2025
#46 berita
Kegiatan Seminar Nasional
30 Nov 2025
#47 berita
Benchmarking Revisi Kurikulum Program Studi Biologi Fakultas Matematika dan Ilmu Pengetahuan Alam UPR ke Program Studi Biologi Fakultas Biologi UNSOED
30 Nov 2025
#48 berita
Benchmarking Revisi Kurikulum Program Studi Biologi FMIPA UPR ke Program Studi Biologi FMIPA ULM
30 Nov 2025
#49 berita
Penandatanganan Perjanjian Kerjasama Program Studi Biologi FMIPA UPR dan Borneo Nature Foundation
30 Nov 2025
#50 berita
Wisuda Periode Agustus 2022 Universitas Palangka Raya
30 Nov 2025
#51 berita
Mahasiswa Biologi FMIPA UPR Berhasil Meraih Juara I dan III Olimpiade Biologi Pada Pekan Ilmiah FKIP UPR
30 Nov 2025
#52 berita
Pelatihan Karakterisasi Morfologi Bakteri dan Fungi Sebagai Pengayaan Praktikum Biologi Bagi Guru dan Siswa Sekolah Menengah Atas di Kota Palangka Raya
30 Nov 2025
#53 berita
Rayakan Dies Natalis ke-5
30 Nov 2025
#54 berita
Rayakan Dies Natalis ke-5
30 Nov 2025
#55 berita
Yudisium Periode Desember 2022 FMIPA Universitas Palangka Raya
30 Nov 2025
#56 berita
Pameran Herbarium Biologi
30 Nov 2025
#57 berita
Kuliah Tamu “Khamir Asal Lada (Pipper nigrum L.) Sebagai Agens Pengendali Hayati Phytophthora capsici”
30 Nov 2025
#58 berita
Workshop Penyusunan Rencana Pembelajaran Semester (RPS) Dosen Program Studi Biologi FMIPA Universitas Palangka Raya
30 Nov 2025
#59 berita
Seminar dan Workshop Osteo-Staining Bone: Pengenalan Metode Sidik Perkembangan Hewan Vertebrata
30 Nov 2025
#60 berita
Sosialisasi Tugas Akhir Prodi Biologi FMIPA Universitas Palangka Raya
30 Nov 2025
#61 berita
Biologi FMIPA UPR menggelar Workshop “Analisa Bioakustik Satwa Liar” dengan pembicara dari University of Georgia
30 Nov 2025
#62 berita
BOSF menggelar kuliah umum “Orang Utan Goes to School” bekerjasama dengan Biologi FMIPA UPR
30 Nov 2025
#63 berita
Prodi Biologi FMIPA UPR Berkolaborasi dengan STIFERA
30 Nov 2025
#64 berita
“Pelatihan Teknik Herbarium” dari Prodi Biologi FMIPA UPR untuk Guru-Guru Biologi se-Kota Palangka Raya
30 Nov 2025
#65 berita
Pelatihan Budidaya Sayuran Menggunakan Sistem Hidroponik Bagi Warga Kompleks Perumahan di Kota Palangka Raya
30 Nov 2025
#66 berita
Mahasiswa Biologi Bersama dengan Mahasiswa Fisika FMIPA Universitas Palangka Raya Melaksanakan Kunjungan Lapangan ke Stasiun Meteorologi Kelas I Tjilik Riwut
30 Nov 2025
#67 berita
Penandatanganan Perjanjian Kerja Sama Prodi Biologi dengan Borneo Orangutan Survival Foundation (BOSF)
30 Nov 2025
#68 berita
Sosialisasi Visi - Misi dan Review Kurikulum Merdeka Belajar Kampus Merdeka Program Studi S-1 Biologi FMIPA Universitas Palangka Raya
30 Nov 2025
#69 berita
Sosialisasi Visi - Misi dan Review Kurikulum Merdeka Belajar Kampus Merdeka Program Studi S-1 Biologi FMIPA Universitas Palangka Raya
30 Nov 2025
#70 berita
Prodi Biologi FMIPA Universitas Palangka Raya Gelar Pelatihan Peningkatan Pengetahuan Guru Biologi SMA terhadap Pediculus humanus capitis (pengenalan
30 Nov 2025
#71 berita
Kuliah Tamu "Biosistematika Tumbuhan
30 Nov 2025
#72 berita
Kuliah Tamu "Virologi Hewan
30 Nov 2025
#73 berita
Pelatihan Oshibana
30 Nov 2025
#74 berita
Penandatanganan Perjanjian Kerja Sama FMIPA UPR dan FST UT
30 Nov 2025
#75 berita
Dosen Universitas Palangka Raya berikan “Penguatan Edukasi terkait Penanganan dan Pencegahan Konflik Monyet Ekor Panjang di Pemukiman”
30 Nov 2025
#76 berita
Dosen Biologi FMIPA Universitas Palangka Raya Berikan Pelatihan Pembuatan Karbol Serai sebagai Upaya Pencegahan Vektor dan Zoonosis di Kelurahan Pahandut
30 Nov 2025
#77 berita
Kuliah Tamu Morfologi Tumbuhan
30 Nov 2025
#78 berita
Dosen Program Studi Biologi FMIPA Universitas Palangka Raya Menggelar Pelatihan Kepada Guru-Guru Biologi SMA se-Palangka Raya dalam meningkatkan Keterampilan Handling Hewan Coba dan Pembuatan Preparat Histologi Jaringan
30 Nov 2025
#79 berita
Mahasiswa Biologi Raih Prestasi Student Exchange ke Osaka University Tahun 2024
30 Nov 2025
#80 pengumuman
Kalender Akademik Semester Ganjil Tahun Ajaran 2020/2021
30 Nov 2025
#81 pengumuman
Masa Pembayaran UKT/SPP Semester Genap Tahun Akademik 2020/2021
30 Nov 2025
#82 pengumuman
Informasi Hasil Evaluasi Keringanan dan Penerima Bantuan UKT Semester Genap Tahun Akademik 2020-2021
30 Nov 2025
#83 pengumuman
Alur Heregistrasi dan Pengisian KRS Semester Genap Tahun Akademik 2020-2021 FMIPA UPR
30 Nov 2025
#84 pengumuman
KERINGANAN PEMBAYARAN UANG KULIAH TUNGGAL (UKT) PERIODE GANJIL 2021/2022
30 Nov 2025
#85 pengumuman
Bantuan Uang Kuliah Tunggal Semester Gasal Ta. 2021/2022 UPR
30 Nov 2025
#86 pengumuman
PENGUMUMAN : Jadwal Her-Registrasi Mahasiswa Lama Semester Ganjil T.A. 2021/2022
30 Nov 2025
#87 pengumuman
PKKMB UNIVERSITAS PALANGKA RAYA TAHUN 2021
30 Nov 2025
#88 pengumuman
PENERIMA BANTUAN UKT SEMENTARA PROGRAM INDONESIA PINTAR TA 2021/2022 GANJIL
30 Nov 2025
#89 pengumuman
Dies Natalis Universitas Palangka Raya ke-58
30 Nov 2025
#90 pengumuman
Hasil Evaluasi Pengajuan Keringanan Pembayaran Uang Kuliah Tunggal (UKT) bagi Mahasiswa Universitas Palangka Raya Semester Genap Tahun Akademik 2021/2022
30 Nov 2025
#91 pengumuman
Daftar Indeks Prestasi Komulatif (IPK) Mahasiswa Biologi Kurang Dari 2
30 Nov 2025
#92 pengumuman
Pembukaan Program Beasiswa Yayasan Karya Salemba Empat Tahun Akademik 2022/2023
30 Nov 2025
#93 pengumuman
Perubahan Jadwal Proses Penetapan dan Pembayaran UKT Mahasiswa Baru Universitas Palangkaraya Jalur SNMPTN Tahun 2022
30 Nov 2025
#94 pengumuman
Alur Her Registrasi Mahasiswa Fakultas MIPA Semester Ganjil Tahun Akademik 2022/2023
30 Nov 2025
#95 pengumuman
Seleksi Program Djarum Beasiswa Plus 2022/2023
30 Nov 2025
#96 pengumuman
Lomba Karya Tulis Ilmiah Mahasiswa (LKTIM) Bidang Kemaritiman Tingkat Nasional Tahun 2022
30 Nov 2025
#97 pengumuman
Keringanan Pembayaran Uang Kuliah Tunggal Bagi Mahasiswa UPR Semester Ganjil Tahun Akademik 2022/2023 di Masa Pandemi Covid-19
30 Nov 2025
#98 pengumuman
Keringanan Pembayaran Uang Kuliah Tunggal Bagi Mahasiswa Eks Bidikmisi Angakatan 2018 dan Afirmasi Dikti Angkatan 2017 yang Telah Melampaui Batas Akhir Pemberian Bantuan Biaya Pendidikan/Beasiswa UPR Semester Ganjil Tahun Akademik 2022/2023 di Masa P
30 Nov 2025
#99 pengumuman
Perpanjangan Jadwal Proses Penyiapan Dokumen dan Pengisian Borang Program Pemberian Keringanan Pembayaran UKT Mahasiswa Lama Semester Ganjil Tahun Akademik 2022/2023
30 Nov 2025
#100 pengumuman
Wisuda Periode Agustus 2022 Universitas Palangka Raya
30 Nov 2025
#101 pengumuman
Her-Registrasi Mahasiswa Lama FMIPA Universitas Palangka Raya Semester Ganjil TA. 2022/2023
30 Nov 2025
#102 pengumuman
Perpanjangan Jadwal Pendaftaran Ulang Mahasiswa Lama (Her-Registrasi) Semester Ganjil Tahun Akademik 2022-2023
30 Nov 2025
#103 pengumuman
Pendaftaran Yudisium Periode Agustus 2022 Fakultas Matematika dan Ilmu Pengetahuan Alam Universitas Palangka Raya
30 Nov 2025
#104 pengumuman
National Youth Competition 2022
30 Nov 2025
#105 pengumuman
Pelatihan Penulisan Tugas Akhir
30 Nov 2025
#106 pengumuman
Webinar Strategi Pencegahan Plagiarisme dan Penggunaan Parafrase dalam Penelitian
30 Nov 2025
#107 pengumuman
Pendaftaran Yudisium Periode Desember 2022 Fakultas Matematika dan Ilmu Pengetahuan Alam Universitas Palangka Raya
30 Nov 2025
#108 pengumuman
Pendaftaran Wisuda Periode Desember 2022
30 Nov 2025
#109 pengumuman
Pengumuman Pemenang Olimpiade dan Essay Biologi Tingkat SMA sederajat se-Kota Palangka Raya dalam rangka Dies Natalis ke-5 Program Studi Biologi FMIPA Universitas Palangka Raya (UPR)
30 Nov 2025
#110 pengumuman
Perpanjangan Pendaftaran Ulang Mahasiswa Lama (Herregistrasi) Semester Genap Tahun Akademik 2022/2023 Universitas Palangka Raya
30 Nov 2025
#111 pengumuman
Pendaftaran Wisuda Periode April Tahun 2023
30 Nov 2025
#112 pengumuman
Pendaftaran Yudisium Periode April 2023 Fakultas Matematika dan Ilmu Pengetahuan Alam Universitas Palangka Raya
30 Nov 2025
#113 pengumuman
Mahasiswa Baru Jalur SNBP 2023
30 Nov 2025
#114 pengumuman
Registrasi Mahasiswa Baru Fakultas Matematika Dan Ilmu Pengetahuan Alam Universitas Palangka Raya
30 Nov 2025
#115 pengumuman
Seminar Nasional Sains dan Teknologi (SNST) KE-5 Tahun 2023 FMIPA Universitas Palangka Raya
30 Nov 2025
#116 pengumuman
Program Studi Biologi FMIPA Universitas Palangka Raya
30 Nov 2025Menu Aksesibilitas
Penyesuaian kenyamanan membaca & navigasi
Ukuran Teks
Keterbacaan Teks
Warna & Kontras
Alat Bantu Fokus & Navigasi
Bantuan Suara (Text to Speech)
Pilih/sorot teks mana saja di website lalu klik tombol di bawah untuk mendengarkan suara pembaca.
c + c).join('');
const num = parseInt(clean, 16);
return { r: (num >> 16) & 255, g: (num >> 8) & 255, b: num & 255 };
},
rgbToHex(r, g, b) {
const clamp = v => Math.max(0, Math.min(255, Math.round(v)));
return '#' + [clamp(r), clamp(g), clamp(b)].map(x => x.toString(16).padStart(2, '0')).join('');
},
rgbToHsl(r, g, b) {
r /= 255; g /= 255; b /= 255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
let h = 0, s = 0, l = (max + min) / 2;
if (max !== min) {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = ((g - b) / d + (g < b ? 6 : 0)); break;
case g: h = ((b - r) / d + 2); break;
case b: h = ((r - g) / d + 4); break;
}
h *= 60;
}
return { h: Math.round(h), s: Math.round(s * 100), l: Math.round(l * 100) };
},
hslToHex(h, s, l) {
h = ((h % 360) + 360) % 360;
s /= 100; l /= 100;
const k = n => (n + h / 30) % 12;
const a = s * Math.min(l, 1 - l);
const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
return this.rgbToHex(Math.round(f(0) * 255), Math.round(f(8) * 255), Math.round(f(4) * 255));
},
init() {
this.darkMode = document.documentElement.classList.contains('dark');
window.addEventListener('dark-mode-toggled', (e) => {
if (e.detail && typeof e.detail.darkMode !== 'undefined') {
this.darkMode = e.detail.darkMode;
}
});
const userCustomized = localStorage.getItem('theme_user_customized') === 'true';
const savedOrgCode = localStorage.getItem('theme_org_code');
if (userCustomized && savedOrgCode === this.orgCode) {
const savedWheel = localStorage.getItem('theme_color_wheel_palette');
if (savedWheel) {
try {
const parsed = JSON.parse(savedWheel);
if (parsed.primaryHex && /^#[0-9A-Fa-f]{3,8}$/.test(parsed.primaryHex)) this.primaryHex = parsed.primaryHex;
if (parsed.secondaryHex && /^#[0-9A-Fa-f]{3,8}$/.test(parsed.secondaryHex)) this.secondaryHex = parsed.secondaryHex;
if (parsed.harmonyType) this.harmonyType = parsed.harmonyType;
if (parsed.secondaryMode) this.secondaryMode = parsed.secondaryMode;
if (parsed.currentTheme) this.currentTheme = parsed.currentTheme;
} catch (e) {}
} else if (localStorage.getItem('customAccentColor')) {
this.primaryHex = localStorage.getItem('customAccentColor');
this.currentTheme = localStorage.getItem('currentTheme') || 'theme-custom';
}
} else {
this.primaryHex = this.defaultColor;
this.harmonyType = 'complementary';
this.secondaryMode = 'harmony';
this.currentTheme = 'theme-custom';
}
const rgb = this.hexToRgb(this.primaryHex);
const hsl = this.rgbToHsl(rgb.r, rgb.g, rgb.b);
this.primaryHue = hsl.h;
this.primarySat = hsl.s;
this.primaryLit = hsl.l;
this.applyAll(userCustomized && savedOrgCode === this.orgCode);
window.addEventListener('open-theme-customizer', () => {
this.open = true;
this.$nextTick(() => this.drawWheel());
});
this.$watch('open', value => {
if (value) {
this.$nextTick(() => this.drawWheel());
}
});
},
toggleDarkMode() {
this.darkMode = !this.darkMode;
if (this.darkMode) {
document.documentElement.classList.add('dark');
localStorage.setItem('darkMode', 'true');
} else {
document.documentElement.classList.remove('dark');
localStorage.setItem('darkMode', 'false');
}
localStorage.setItem('theme_user_customized', 'true');
localStorage.setItem('theme_org_code', this.orgCode);
window.dispatchEvent(new CustomEvent('dark-mode-toggled', { detail: { darkMode: this.darkMode } }));
},
// Canva Color Wheel Canvas Drawing
drawWheel() {
const canvas = document.getElementById('canvaColorWheel');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const cx = canvas.width / 2;
const cy = canvas.height / 2;
const radius = canvas.width / 2 - 10;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 1. Draw Hue Spectrum (Conic Gradient)
for (let angle = 0; angle < 360; angle += 1) {
const startAngle = (angle - 1.5) * Math.PI / 180;
const endAngle = (angle + 1.5) * Math.PI / 180;
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, startAngle, endAngle);
ctx.closePath();
ctx.fillStyle = `hsl(${angle}, 100%, 50%)`;
ctx.fill();
}
// 2. Center Radial Gradient (White in center to full saturation on edge)
const radGrad = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);
radGrad.addColorStop(0, 'rgba(255, 255, 255, 0.85)');
radGrad.addColorStop(0.65, 'rgba(255, 255, 255, 0.15)');
radGrad.addColorStop(1, 'rgba(255, 255, 255, 0)');
ctx.fillStyle = radGrad;
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
ctx.fill();
// 3. Wheel Outline Border
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
ctx.stroke();
const dist = radius * 0.76;
// 4. Draw Harmony Points (Circles on wheel)
const harmonyHues = this.getHarmonyHues();
harmonyHues.forEach(h => {
const hRad = h * Math.PI / 180;
const hx = cx + dist * Math.cos(hRad);
const hy = cy + dist * Math.sin(hRad);
ctx.beginPath();
ctx.arc(hx, hy, 8, 0, Math.PI * 2);
ctx.fillStyle = this.hslToHex(h, 90, 50);
ctx.fill();
ctx.strokeStyle = '#FFFFFF';
ctx.lineWidth = 3;
ctx.stroke();
});
// 5. Draw Primary Pointer Marker (Large ring with white stroke, like Canva)
const primaryRad = this.primaryHue * Math.PI / 180;
const px = cx + dist * Math.cos(primaryRad);
const py = cy + dist * Math.sin(primaryRad);
ctx.beginPath();
ctx.arc(px, py, 11, 0, Math.PI * 2);
ctx.fillStyle = this.primaryHex;
ctx.fill();
ctx.strokeStyle = '#FFFFFF';
ctx.lineWidth = 4;
ctx.stroke();
// Shadow for primary marker
ctx.beginPath();
ctx.arc(px, py, 13, 0, Math.PI * 2);
ctx.strokeStyle = 'rgba(0, 0, 0, 0.25)';
ctx.lineWidth = 1.5;
ctx.stroke();
},
getHarmonyHues() {
const h = this.primaryHue;
switch (this.harmonyType) {
case 'complementary':
return [(h + 180) % 360];
case 'analogous':
return [(h - 35 + 360) % 360, (h + 35) % 360];
case 'triadic':
return [(h + 120) % 360, (h + 240) % 360];
case 'tetradic':
return [(h + 60) % 360, (h + 180) % 360, (h + 240) % 360];
case 'monochromatic':
return [h];
default:
return [];
}
},
handleWheelEvent(e) {
const canvas = document.getElementById('canvaColorWheel');
if (!canvas) return;
const rect = canvas.getBoundingClientRect();
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
const x = clientX - rect.left - canvas.width / 2;
const y = clientY - rect.top - canvas.height / 2;
let angle = Math.atan2(y, x) * (180 / Math.PI);
if (angle < 0) angle += 360;
this.primaryHue = Math.round(angle);
this.primaryHex = this.hslToHex(this.primaryHue, 88, 48);
this.currentTheme = 'theme-custom';
this.applyAll(true);
this.drawWheel();
},
onWheelMouseDown(e) {
this.isDraggingWheel = true;
this.handleWheelEvent(e);
},
onWheelMouseMove(e) {
if (!this.isDraggingWheel) return;
this.handleWheelEvent(e);
},
onWheelMouseUp() {
this.isDraggingWheel = false;
},
setPrimaryFromHex(hex) {
if (!/^#[0-9A-Fa-f]{6}$/.test(hex)) return;
this.primaryHex = hex;
const rgb = this.hexToRgb(hex);
const hsl = this.rgbToHsl(rgb.r, rgb.g, rgb.b);
this.primaryHue = hsl.h;
this.primarySat = hsl.s;
this.primaryLit = hsl.l;
this.currentTheme = 'theme-custom';
this.applyAll(true);
this.drawWheel();
},
setHarmony(type) {
this.harmonyType = type;
this.applyAll(true);
this.drawWheel();
},
setSecondaryMode(mode) {
this.secondaryMode = mode;
this.applyAll(true);
this.drawWheel();
},
selectPreset(p) {
this.primaryHex = p.hex;
this.currentTheme = p.theme;
const rgb = this.hexToRgb(p.hex);
const hsl = this.rgbToHsl(rgb.r, rgb.g, rgb.b);
this.primaryHue = hsl.h;
this.primarySat = hsl.s;
this.primaryLit = hsl.l;
const isDefaultPreset = (p.hex.toLowerCase() === this.defaultColor.toLowerCase());
this.applyAll(!isDefaultPreset);
if (isDefaultPreset) {
localStorage.removeItem('theme_user_customized');
localStorage.removeItem('theme_color_wheel_palette');
localStorage.removeItem('customAccentColor');
localStorage.setItem('theme_org_code', this.orgCode);
}
this.drawWheel();
},
applyAll(isUserAction = true) {
const pRgb = this.hexToRgb(this.primaryHex);
const pHsl = this.rgbToHsl(pRgb.r, pRgb.g, pRgb.b);
// Hitung warna sekunder
if (this.secondaryMode === 'harmony') {
if (this.harmonyType === 'complementary') {
this.secondaryHex = this.hslToHex((pHsl.h + 180) % 360, Math.min(Math.max(pHsl.s, 65), 90), Math.min(Math.max(pHsl.l, 46), 54));
} else if (this.harmonyType === 'analogous') {
this.secondaryHex = this.hslToHex((pHsl.h + 35) % 360, pHsl.s, pHsl.l);
} else if (this.harmonyType === 'triadic') {
this.secondaryHex = this.hslToHex((pHsl.h + 120) % 360, Math.min(Math.max(pHsl.s, 60), 90), Math.min(Math.max(pHsl.l, 46), 54));
} else if (this.harmonyType === 'tetradic') {
this.secondaryHex = this.hslToHex((pHsl.h + 180) % 360, Math.min(Math.max(pHsl.s, 60), 90), Math.min(Math.max(pHsl.l, 46), 54));
} else if (this.harmonyType === 'monochromatic') {
this.secondaryHex = this.hslToHex(pHsl.h, Math.max(30, pHsl.s - 15), pHsl.l > 50 ? Math.max(25, pHsl.l - 25) : Math.min(75, pHsl.l + 25));
} else {
this.secondaryHex = this.hslToHex((pHsl.h + 180) % 360, 85, 50);
}
} else {
this.secondaryHex = '#EA580C'; // Fixed pekat orange
}
const sRgb = this.hexToRgb(this.secondaryHex);
const pHoverHex = this.rgbToHex(pRgb.r * 0.85, pRgb.g * 0.85, pRgb.b * 0.85);
const sHoverHex = this.rgbToHex(sRgb.r * 0.85, sRgb.g * 0.85, sRgb.b * 0.85);
const sDarkHex = this.rgbToHex(sRgb.r * 0.65, sRgb.g * 0.65, sRgb.b * 0.65);
// Dynamic Themed Topbar & Footer Tokens
const isGrayScale = pHsl.s < 20;
let surfaceDark, cardDark, cardAltDark, borderDark;
let topbarBg, footerBg, footerCard, footerCardAlt, footerBorder, footerInput;
if (isGrayScale) {
surfaceDark = '#0B0F17';
cardDark = '#111827';
cardAltDark = '#1E293B';
borderDark = '#1E293B';
topbarBg = '#1E293B';
footerBg = '#0F172A';
footerCard = '#1E293B';
footerCardAlt = '#334155';
footerBorder = 'rgba(255, 255, 255, 0.12)';
footerInput = '#1E293B';
} else {
surfaceDark = this.hslToHex(pHsl.h, Math.min(25, Math.round(pHsl.s * 0.25)), 6);
cardDark = this.hslToHex(pHsl.h, Math.min(22, Math.round(pHsl.s * 0.2)), 10);
cardAltDark = this.hslToHex(pHsl.h, Math.min(22, Math.round(pHsl.s * 0.2)), 15);
borderDark = this.hslToHex(pHsl.h, Math.min(22, Math.round(pHsl.s * 0.2)), 20);
// Dynamic rich tones for topbar and footer reflecting theme
topbarBg = this.hslToHex(pHsl.h, Math.min(Math.max(pHsl.s, 45), 75), 18);
footerBg = this.hslToHex(pHsl.h, Math.min(Math.max(pHsl.s * 0.5, 30), 55), 10);
footerCard = this.hslToHex(pHsl.h, Math.min(Math.max(pHsl.s * 0.45, 25), 45), 15);
footerCardAlt = this.hslToHex(pHsl.h, Math.min(Math.max(pHsl.s * 0.4, 25), 45), 20);
footerBorder = this.hslToHex(pHsl.h, Math.min(Math.max(pHsl.s * 0.5, 35), 60), 26);
footerInput = this.hslToHex(pHsl.h, Math.min(Math.max(pHsl.s * 0.45, 25), 45), 13);
}
const topbarRgb = this.hexToRgb(topbarBg);
const footerRgb = this.hexToRgb(footerBg);
const footerCardRgb = this.hexToRgb(footerCard);
const footerCardAltRgb = this.hexToRgb(footerCardAlt);
const footerBorderRgb = this.hexToRgb(footerBorder.startsWith('#') ? footerBorder : '#1E293B');
const footerInputRgb = this.hexToRgb(footerInput);
const surfaceDarkRgb = this.hexToRgb(surfaceDark);
const cardDarkRgb = this.hexToRgb(cardDark);
const cardAltDarkRgb = this.hexToRgb(cardAltDark);
const borderDarkRgb = this.hexToRgb(borderDark);
// Terapkan ke DOM (:root dan document.body)
const targets = [document.documentElement, document.body].filter(Boolean);
targets.forEach(target => {
target.style.setProperty('--color-primary', this.primaryHex);
target.style.setProperty('--color-primary-rgb', `${pRgb.r} ${pRgb.g} ${pRgb.b}`);
target.style.setProperty('--color-primary-hover', pHoverHex);
target.style.setProperty('--color-primary-hover-rgb', `${Math.round(pRgb.r * 0.85)} ${Math.round(pRgb.g * 0.85)} ${Math.round(pRgb.b * 0.85)}`);
target.style.setProperty('--color-primary-glow', `rgba(${pRgb.r}, ${pRgb.g}, ${pRgb.b}, 0.38)`);
target.style.setProperty('--color-primary-subtle', `rgba(${pRgb.r}, ${pRgb.g}, ${pRgb.b}, 0.12)`);
target.style.setProperty('--color-secondary', this.secondaryHex);
target.style.setProperty('--color-secondary-rgb', `${sRgb.r} ${sRgb.g} ${sRgb.b}`);
target.style.setProperty('--color-secondary-hover', sHoverHex);
target.style.setProperty('--color-secondary-hover-rgb', `${Math.round(sRgb.r * 0.85)} ${Math.round(sRgb.g * 0.85)} ${Math.round(sRgb.b * 0.85)}`);
target.style.setProperty('--color-secondary-dark', sDarkHex);
target.style.setProperty('--color-secondary-dark-rgb', `${Math.round(sRgb.r * 0.65)} ${Math.round(sRgb.g * 0.65)} ${Math.round(sRgb.b * 0.65)}`);
target.style.setProperty('--color-secondary-glow', `rgba(${sRgb.r}, ${sRgb.g}, ${sRgb.b}, 0.35)`);
target.style.setProperty('--color-secondary-subtle', `rgba(${sRgb.r}, ${sRgb.g}, ${sRgb.b}, 0.12)`);
target.style.setProperty('--color-accent', this.primaryHex);
target.style.setProperty('--color-accent-rgb', `${pRgb.r} ${pRgb.g} ${pRgb.b}`);
target.style.setProperty('--color-accent-hover', pHoverHex);
target.style.setProperty('--color-accent-hover-rgb', `${Math.round(pRgb.r * 0.85)} ${Math.round(pRgb.g * 0.85)} ${Math.round(pRgb.b * 0.85)}`);
target.style.setProperty('--color-accent-glow', `rgba(${pRgb.r}, ${pRgb.g}, ${pRgb.b}, 0.38)`);
target.style.setProperty('--color-accent-subtle', `rgba(${pRgb.r}, ${pRgb.g}, ${pRgb.b}, 0.12)`);
target.style.setProperty('--color-surface-dark', surfaceDark);
target.style.setProperty('--color-surface-dark-rgb', `${surfaceDarkRgb.r} ${surfaceDarkRgb.g} ${surfaceDarkRgb.b}`);
target.style.setProperty('--color-card-dark', cardDark);
target.style.setProperty('--color-card-dark-rgb', `${cardDarkRgb.r} ${cardDarkRgb.g} ${cardDarkRgb.b}`);
target.style.setProperty('--color-card-alt-dark', cardAltDark);
target.style.setProperty('--color-card-alt-dark-rgb', `${cardAltDarkRgb.r} ${cardAltDarkRgb.g} ${cardAltDarkRgb.b}`);
target.style.setProperty('--color-border-dark', borderDark);
target.style.setProperty('--color-border-dark-rgb', `${borderDarkRgb.r} ${borderDarkRgb.g} ${borderDarkRgb.b}`);
target.style.setProperty('--color-topbar-bg', topbarBg);
target.style.setProperty('--color-topbar-bg-rgb', `${topbarRgb.r} ${topbarRgb.g} ${topbarRgb.b}`);
target.style.setProperty('--color-footer-bg', footerBg);
target.style.setProperty('--color-footer-bg-rgb', `${footerRgb.r} ${footerRgb.g} ${footerRgb.b}`);
target.style.setProperty('--color-footer-card', footerCard);
target.style.setProperty('--color-footer-card-rgb', `${footerCardRgb.r} ${footerCardRgb.g} ${footerCardRgb.b}`);
target.style.setProperty('--color-footer-card-alt', footerCardAlt);
target.style.setProperty('--color-footer-card-alt-rgb', `${footerCardAltRgb.r} ${footerCardAltRgb.g} ${footerCardAltRgb.b}`);
target.style.setProperty('--color-footer-border', footerBorder);
target.style.setProperty('--color-footer-border-rgb', `${footerBorderRgb.r} ${footerBorderRgb.g} ${footerBorderRgb.b}`);
target.style.setProperty('--color-footer-input', footerInput);
target.style.setProperty('--color-footer-input-rgb', `${footerInputRgb.r} ${footerInputRgb.g} ${footerInputRgb.b}`);
});
// Update tema class pada document.documentElement dan body
const themeClassList = ['theme-eduma', 'theme-emerald', 'theme-neon', 'theme-blue', 'theme-sapphire', 'theme-purple', 'theme-orange', 'theme-crimson', 'theme-rose', 'theme-gold', 'theme-teal', 'theme-gray', 'theme-dark', 'theme-custom'];
themeClassList.forEach(cls => {
document.documentElement.classList.remove(cls);
if (document.body) document.body.classList.remove(cls);
});
if (this.currentTheme) {
document.documentElement.classList.add(this.currentTheme);
if (document.body) document.body.classList.add(this.currentTheme);
}
// Simpan ke localStorage jika user mengubah tema secara manual
if (isUserAction) {
localStorage.setItem('theme_user_customized', 'true');
localStorage.setItem('theme_org_code', this.orgCode);
localStorage.setItem('theme_color_wheel_palette', JSON.stringify({
primaryHex: this.primaryHex,
secondaryHex: this.secondaryHex,
harmonyType: this.harmonyType,
secondaryMode: this.secondaryMode,
currentTheme: this.currentTheme
}));
localStorage.setItem('customAccentColor', this.primaryHex);
localStorage.setItem('currentTheme', this.currentTheme);
}
// Event global
window.dispatchEvent(new CustomEvent('theme-changed', {
detail: {
primaryHex: this.primaryHex,
secondaryHex: this.secondaryHex,
harmonyType: this.harmonyType,
themeName: this.currentTheme
}
}));
},
resetToDefault() {
this.primaryHex = this.defaultColor;
this.secondaryHex = '#EA580C';
this.harmonyType = 'complementary';
this.secondaryMode = 'harmony';
this.currentTheme = 'theme-custom';
const rgb = this.hexToRgb(this.primaryHex);
const hsl = this.rgbToHsl(rgb.r, rgb.g, rgb.b);
this.primaryHue = hsl.h;
this.primarySat = hsl.s;
this.primaryLit = hsl.l;
const targetDark = (this.defaultMode === 'dark');
this.darkMode = targetDark;
if (targetDark) {
document.documentElement.classList.add('dark');
localStorage.setItem('darkMode', 'true');
} else {
document.documentElement.classList.remove('dark');
localStorage.setItem('darkMode', 'false');
}
window.dispatchEvent(new CustomEvent('dark-mode-toggled', { detail: { darkMode: targetDark } }));
localStorage.removeItem('theme_user_customized');
localStorage.removeItem('theme_color_wheel_palette');
localStorage.removeItem('customAccentColor');
localStorage.setItem('theme_org_code', this.orgCode);
this.applyAll(false);
this.drawWheel();
},
copyHex(hex) {
navigator.clipboard.writeText(hex).then(() => {
this.copied = true;
this.copiedText = hex;
setTimeout(() => { this.copied = false; }, 2000);
});
}
}"
@keydown.escape.window="open = false"
@keydown.alt.t.window.prevent="open = !open">