// Focus dot animation const dot = document.querySelector('.dot-point'); function updateDotState() { const isActive = document.visibilityState === 'visible' && document.hasFocus(); dot.classList.toggle('is-active', isActive); } document.addEventListener('visibilitychange', updateDotState); window.addEventListener('focus', updateDotState); window.addEventListener('blur', updateDotState); // 졜초 μ‹€ν–‰ updateDotState(); // ping async function checkStatus() { const cards = document.querySelectorAll(".card"); cards.forEach(async (card) => { const url = card.getAttribute("data-url"); const dot = card.querySelector(".card__decor.card__decor--tr"); try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); await fetch(url, { mode: "no-cors", cache: "no-cache", signal: controller.signal, }); dot.classList.remove("status-offline"); dot.classList.add("status-online"); clearTimeout(timeoutId); } catch (e) { dot.classList.remove("status-online"); dot.classList.add("status-offline"); } }); } checkStatus(); setInterval(checkStatus, 300000); // πŸ”΄ ν…ŒμŠ€νŠΈ ON // const TEST_ONLY_SECOND_CARD = true; // 🟒 ν…ŒμŠ€νŠΈ OFF const TEST_ONLY_SECOND_CARD = false; // bolt animation function startBoltAction() { let allBolts = []; if (TEST_ONLY_SECOND_CARD) { // πŸ”§ 2번째 μΉ΄λ“œλ§Œ 선택 (0-based index) const secondCard = document.querySelectorAll(".card")[1]; if (!secondCard) return; allBolts = secondCard.querySelectorAll(".card__decor"); } else { // πŸ”Ή 전체 μΉ΄λ“œ λŒ€μƒ allBolts = document.querySelectorAll(".card__decor"); } if (allBolts.length === 0) return; const availableBolts = Array.from(allBolts).filter( (bolt) => !bolt.classList.contains("card__decor-acting") ); if (availableBolts.length > 0) { const randomBolt = availableBolts[Math.floor(Math.random() * availableBolts.length)]; const baseRot = randomBolt.style.getPropertyValue("--r") || "0deg"; randomBolt.style.setProperty("--r", baseRot); const BOLT_ANIMATION_DURATION = 16000; // CSS와 λ°˜λ“œμ‹œ 일치 randomBolt.classList.add("card__decor-acting"); setTimeout(() => { randomBolt.classList.remove("card__decor-acting"); }, BOLT_ANIMATION_DURATION); } const nextInterval = Math.random() * 4000 + 3000; setTimeout(startBoltAction, nextInterval); } window.addEventListener("load", () => { setTimeout(startBoltAction, 2000); }); // λ‚˜μ‚¬ 랜덀 각도 λΆ€μ—°` document.querySelectorAll('.card').forEach((card, cardIndex) => { card.querySelectorAll('.card__decor').forEach((decor, decorIndex) => { // -30 ~ 150 정도가 λ‚˜μ‚¬ λŠλ‚Œ 제일 μ•ˆμ •μ  const angle = Math.floor(Math.random() * 180) - 30; decor.style.setProperty('--r', `${angle}deg`); }); }); // 1. μ‚¬μš©ν•  ν…Œλ§ˆ 리슀트 const themes = ['semi-nova', 'nova', 'semi-solaris', 'solaris']; const STORAGE_KEY = 'selected-theme'; // 2. 초기 λ‘œλ“œ μ‹œ ν…Œλ§ˆ 적용 (κΈ°λ³Έκ°’: semi-nova) const savedTheme = localStorage.getItem(STORAGE_KEY) || themes[0]; document.body.classList.add(savedTheme); window.addEventListener('keydown', (e) => { // OS별 μˆ˜μ • ν‚€ νŒλ³„ (Mac: Command, Win: Control) const isMac = navigator.platform.toUpperCase().includes('MAC'); const isModifierPressed = isMac ? e.metaKey : e.ctrlKey; // λ°©ν–₯ν‚€ 쒌/우 확인 const isLeft = e.code === 'ArrowLeft'; const isRight = e.code === 'ArrowRight'; if ( isModifierPressed && (isLeft || isRight) && // μž…λ ₯μ°½ μ•ˆμ—μ„œ μ»€μ„œ 이동을 λ°©ν•΄ν•˜μ§€ μ•Šλ„λ‘ 체크 !['INPUT', 'TEXTAREA'].includes(document.activeElement?.tagName) && !document.activeElement?.isContentEditable // 에디터 μ˜μ—­ λŒ€μ‘ ) { e.preventDefault(); // ν˜„μž¬ 인덱슀 μ°ΎκΈ° let currentIndex = themes.findIndex(t => document.body.classList.contains(t)); if (currentIndex === -1) currentIndex = 0; // 3. 쒌/우 λ°©ν–₯에 λ”°λ₯Έ 인덱슀 μˆœν™˜ if (isRight) { // 였λ₯Έμͺ½ ν™”μ‚΄ν‘œ: λ‹€μŒ ν…Œλ§ˆ currentIndex = (currentIndex + 1) % themes.length; } else if (isLeft) { // μ™Όμͺ½ ν™”μ‚΄ν‘œ: 이전 ν…Œλ§ˆ currentIndex = (currentIndex - 1 + themes.length) % themes.length; } const nextTheme = themes[currentIndex]; // 4. 클래슀 ꡐ체 및 μ €μž₯ themes.forEach(t => document.body.classList.remove(t)); document.body.classList.add(nextTheme); localStorage.setItem(STORAGE_KEY, nextTheme); console.log(`Current Theme: ${nextTheme}`); } }); const logo = document.querySelector('header h1'); // const themes = ['semi-nova', 'nova', 'semi-solaris', 'solaris']; // const STORAGE_KEY = 'selected-theme'; let startX = 0; let isDragging = false; const SWIPE_THRESHOLD = 40; // px function getCurrentThemeIndex() { return themes.findIndex(t => document.body.classList.contains(t)); } function applyTheme(index) { themes.forEach(t => document.body.classList.remove(t)); document.body.classList.add(themes[index]); localStorage.setItem(STORAGE_KEY, themes[index]); const dot = document.querySelector('.dot-point'); if (dot) { dot.classList.remove('blink-alert'); void dot.offsetWidth; // μ• λ‹ˆλ©”μ΄μ…˜ 리셋 dot.classList.add('blink-alert'); } } logo.addEventListener('pointerdown', (e) => { startX = e.clientX; isDragging = true; logo.classList.add('is-sliding'); }); logo.addEventListener('pointerup', (e) => { if (!isDragging) return; const deltaX = e.clientX - startX; if (Math.abs(deltaX) > SWIPE_THRESHOLD) { let index = getCurrentThemeIndex(); if (index === -1) index = 0; if (deltaX > 0) { // πŸ‘‰ 였λ₯Έμͺ½ index = (index + 1) % themes.length; } else { // πŸ‘ˆ μ™Όμͺ½ index = (index - 1 + themes.length) % themes.length; } applyTheme(index); } reset(); }); logo.addEventListener('pointerleave', reset); logo.addEventListener('pointercancel', reset); function reset() { isDragging = false; logo.classList.remove('is-sliding'); } // Focus dot animation function updateDotState() { const isActive = document.visibilityState === 'visible' && document.hasFocus(); dot.classList.toggle('is-active', isActive); } document.addEventListener('visibilitychange', updateDotState); window.addEventListener('focus', updateDotState); window.addEventListener('blur', updateDotState); // 졜초 μ‹€ν–‰ updateDotState();