From 73964fe87492b59501689ef2a3d07ef4cbfc241d Mon Sep 17 00:00:00 2001 From: muthianura Date: Thu, 4 Jun 2026 20:46:39 +0700 Subject: [PATCH] feat(alumni): integrasi data dinamis skill alumni dari google sheets --- groups/M4N1FEST/index.html | 165 +++++++++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 26 deletions(-) diff --git a/groups/M4N1FEST/index.html b/groups/M4N1FEST/index.html index eb62733..cebea77 100644 --- a/groups/M4N1FEST/index.html +++ b/groups/M4N1FEST/index.html @@ -50,6 +50,11 @@ z-index: 40; } + @keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } + } + @media (prefers-reduced-motion: reduce) { *, @@ -1521,50 +1526,66 @@
- -
+ +
+ +
Web Development -
-
-
- 78% +
+
+
Python / Data Science -
-
-
- 65% +
+
+
Mobile Development -
-
-
- 54% +
+
+
UI/UX Design -
-
-
- 48% +
+
+
Networking / DevOps -
-
-
- 38% +
+
+
Cybersecurity -
-
-
- 25% +
+
+ +
+ Machine Learning / AI +
+ +
+ +
+ Database +
+ +
+ + +

+ + + + Memuat data skill alumni... +

@@ -2758,6 +2779,98 @@ } } + /* ── SKILL DISTRIBUTION — Live fetch from Google Sheets (approved rows only) ── */ + (function fetchSkillData() { + const SHEET_ID = '1mtVB1vLev-OWz6aTuuddGKPS8tCv8MJcGpzws8irpxk'; + // Col I=Skill1, J=Skill2, K=Skill3, L=Approved (admin status) + const query = encodeURIComponent("select I,J,K where lower(L)='approved'"); + const url = `https://docs.google.com/spreadsheets/d/${SHEET_ID}/gviz/tq?tqx=out:json&tq=${query}`; + + // Map: skill label → bar id prefix (must match id="bar-XXX" and id="pct-XXX" in HTML) + const SKILL_MAP = { + 'Web Development' : 'web-development', + 'Mobile Development' : 'mobile-development', + 'Python / Data Science': 'python-data-science', + 'UI/UX Design' : 'uiux-design', + 'Networking / DevOps' : 'networking-devops', + 'Cybersecurity' : 'cybersecurity', + 'Machine Learning / AI': 'machine-learning-ai', + 'Database' : 'database', + }; + + const spinner = document.getElementById('skill-note-spinner'); + const noteText = document.getElementById('skill-note-text'); + + function setNote(text, spin, isCta) { + if (spinner) spinner.style.animation = spin ? 'spin 1s linear infinite' : 'none'; + if (!noteText) return; + if (isCta) { + noteText.innerHTML = text + ' Isi form kontribusi'; + } else { + noteText.textContent = text; + } + } + + function normalizeSkill(val) { + if (!val) return null; + const s = val.toLowerCase().trim(); + if (s.includes('web')) return 'Web Development'; + if (s.includes('mobile')) return 'Mobile Development'; + if (s.includes('python') || s.includes('data science') || s.includes('data science')) return 'Python / Data Science'; + if (s.includes('ui') || s.includes('ux')) return 'UI/UX Design'; + if (s.includes('network') || s.includes('devops')) return 'Networking / DevOps'; + if (s.includes('cyber')) return 'Cybersecurity'; + if (s.includes('machine') || s.includes('ai') || s.includes('artificial')) return 'Machine Learning / AI'; + if (s.includes('database') || s.includes('db')) return 'Database'; + return null; + } + + fetch(url) + .then(res => res.text()) + .then(raw => { + const json = JSON.parse(raw.replace(/^[^{]+/, '').replace(/[);]+$/, '')); + const rows = (json.table && json.table.rows) ? json.table.rows : []; + + if (rows.length === 0) { + setNote('Data skill masih kosong, bantu kami lengkapi data ini!', false, false); + return; + } + + // Count normalized skill mentions + const counts = {}; + rows.forEach(row => { + [0, 1, 2].forEach(colIdx => { + const cell = row.c && row.c[colIdx]; + const val = cell && cell.v ? String(cell.v).trim() : ''; + const normalized = normalizeSkill(val); + if (normalized) { + counts[normalized] = (counts[normalized] || 0) + 1; + } + }); + }); + + const totalMentions = Object.values(counts).reduce((s, c) => s + c, 0); + const maxCount = Math.max(...Object.values(counts), 0); + + // Update bars for predefined skills + Object.entries(SKILL_MAP).forEach(([label, idKey]) => { + const count = counts[label] || 0; + const pct = totalMentions > 0 ? Math.round((count / totalMentions) * 100) : 0; + const barPct = maxCount > 0 ? Math.round((count / maxCount) * 100) : 0; + + const barEl = document.getElementById('bar-' + idKey); + const pctEl = document.getElementById('pct-' + idKey); + if (barEl) barEl.style.width = barPct + '%'; + if (pctEl) pctEl.textContent = count > 0 ? pct + '%' : '—'; + }); + + setNote(`Data dari ${rows.length} alumni yang diverifikasi.`, false, false); + }) + .catch(() => { + setNote('Data skill masih kosong, bantu kami lengkapi data ini!', false, false); + }); + })(); + /* ── REVEAL ON SCROLL ── */ const ro = new IntersectionObserver( (entries) => { -- 2.52.0