/** * Utility Functions * 유틸리티 함수 모음 */ /** * 가격 포맷팅 (한국 원화) */ export function formatPrice(price) { return '₩' + price.toLocaleString('ko-KR'); } /** * 탭 전환 (n8n/Terraform) */ export function switchTab(tab) { const btnN8n = document.getElementById('btn-n8n'); const btnTf = document.getElementById('btn-tf'); const panelN8n = document.getElementById('panel-n8n'); const panelTf = document.getElementById('panel-tf'); // Null checks for DOM elements if (!btnN8n || !btnTf || !panelN8n || !panelTf) return; if (tab === 'n8n') { // Update ARIA states for n8n tab btnN8n.setAttribute('aria-selected', 'true'); btnN8n.setAttribute('tabindex', '0'); btnTf.setAttribute('aria-selected', 'false'); btnTf.setAttribute('tabindex', '-1'); // Update classes btnN8n.className = 'px-4 py-2 rounded-lg bg-purple-600 text-white text-sm font-bold transition shadow-lg shadow-purple-500/20'; btnTf.className = 'px-4 py-2 rounded-lg bg-slate-800 text-slate-400 text-sm font-bold border border-slate-700 hover:text-white transition'; panelN8n.classList.remove('hidden'); panelTf.classList.add('hidden'); } else { // Update ARIA states for Terraform tab btnTf.setAttribute('aria-selected', 'true'); btnTf.setAttribute('tabindex', '0'); btnN8n.setAttribute('aria-selected', 'false'); btnN8n.setAttribute('tabindex', '-1'); // Update classes btnN8n.className = 'px-4 py-2 rounded-lg bg-slate-800 text-slate-400 text-sm font-bold border border-slate-700 hover:text-white transition'; btnTf.className = 'px-4 py-2 rounded-lg bg-blue-600 text-white text-sm font-bold transition shadow-lg shadow-blue-500/20'; panelN8n.classList.add('hidden'); panelTf.classList.remove('hidden'); } } /** * 실시간 Ping 시뮬레이션 */ export function updatePing() { const regions = [ { id: 'ping-kr', base: 2, variance: 2 }, { id: 'ping-jp', base: 35, variance: 5 }, { id: 'ping-hk', base: 45, variance: 8 }, { id: 'ping-sg', base: 65, variance: 10 } ]; regions.forEach(region => { const el = document.getElementById(region.id); if (el) { const jitter = Math.floor(Math.random() * region.variance) - (region.variance / 2); let val = Math.max(1, Math.floor(region.base + jitter)); el.innerText = val; } }); } // Ping 업데이트 시작 (visibility-aware) let pingInterval; export function startPingUpdates() { if (!pingInterval) { pingInterval = setInterval(updatePing, 2000); } } export function stopPingUpdates() { if (pingInterval) { clearInterval(pingInterval); pingInterval = null; } } // Visibility change handler document.addEventListener('visibilitychange', () => { if (document.hidden) { stopPingUpdates(); } else { startPingUpdates(); } }); // Initial start startPingUpdates(); // Tab switching with event listeners and keyboard navigation document.addEventListener('DOMContentLoaded', () => { const btnN8n = document.getElementById('btn-n8n'); const btnTf = document.getElementById('btn-tf'); if (btnN8n && btnTf) { // Click event listeners btnN8n.addEventListener('click', () => switchTab('n8n')); btnTf.addEventListener('click', () => switchTab('tf')); // Keyboard navigation (Arrow keys) [btnN8n, btnTf].forEach(btn => { btn.addEventListener('keydown', (e) => { const currentTab = btn.getAttribute('data-tab'); if (e.key === 'ArrowRight') { e.preventDefault(); if (currentTab === 'n8n') { btnTf.focus(); switchTab('tf'); } } else if (e.key === 'ArrowLeft') { e.preventDefault(); if (currentTab === 'tf') { btnN8n.focus(); switchTab('n8n'); } } }); }); } });