diff --git a/src/renderer/handlers/image-preview.js b/src/renderer/handlers/image-preview.js index b693a31..cd1ea13 100644 --- a/src/renderer/handlers/image-preview.js +++ b/src/renderer/handlers/image-preview.js @@ -1,18 +1,13 @@ -const SHOW_DELAY = 1000; const HIDE_DELAY = 100; -const SVG_NS = 'http://www.w3.org/2000/svg'; -const RADIUS = 20; -const CIRC = 2 * Math.PI * RADIUS; // ~125.66 - let _el = null; let _imgEl = null; -let _showTimer = null; let _hideTimer = null; let _visible = false; -let _loaderEl = null; let _activeCard = null; +let _hoverCard = null; let _enabled = true; +let _showSeq = 0; export function init() { _el = document.createElement('div'); @@ -26,13 +21,13 @@ export function init() { export function setEnabled(v) { _enabled = v; if (!v) { - clearTimeout(_showTimer); _showTimer = null; clearTimeout(_hideTimer); _hideTimer = null; - _removeLoader(); - _activeCard = null; - _visible = false; - _el.style.display = 'none'; - _el.style.visibility = 'hidden'; + _hideNow(); + return; + } + + if (_hoverCard?.isConnected) { + _showForCard(_hoverCard); } } @@ -42,62 +37,56 @@ export function setupCard(card) { } function _onEnter() { - if (!_enabled) return; const card = this; + _hoverCard = card; + if (!_enabled) return; + _activeCard = card; - // 팝업이 사라지려고 대기 중이면 취소 if (_hideTimer) { clearTimeout(_hideTimer); _hideTimer = null; } if (_visible) { - // 이미 팝업이 열려 있으면 즉시 내용 전환 _switchTo(card); return; } - // 팝업이 닫힌 상태 — 1초 대기 후 표시 - clearTimeout(_showTimer); - _showLoader(card); - _showTimer = setTimeout(async () => { - _showTimer = null; - _removeLoader(); - if (_activeCard !== card) return; - - const src = await _loadSrc(card); - if (!src || _activeCard !== card) return; - - _imgEl.src = src; - _visible = true; - _show(card); - }, SHOW_DELAY); + _showForCard(card); } function _onLeave() { + if (_hoverCard === this) _hoverCard = null; + if (!_visible) { - // 팝업 미표시 상태 — 로더·타이머만 정리 - clearTimeout(_showTimer); - _showTimer = null; - _removeLoader(); return; } - // 팝업 표시 중 — 0.1초 후 닫기 (다른 카드 진입 시 취소됨) _hideTimer = setTimeout(() => { _hideTimer = null; - _visible = false; - _el.style.display = 'none'; - _el.style.visibility = 'hidden'; + _hideNow(); }, HIDE_DELAY); } // ── 팝업 내용 전환 (이미 열린 상태에서 카드 변경) ── -async function _switchTo(card) { +async function _showForCard(card) { + const seq = ++_showSeq; + _activeCard = card; + const src = await _loadSrc(card); - if (!src || _activeCard !== card) return; + if (!src || !_enabled || _activeCard !== card || seq !== _showSeq) return; + + _imgEl.src = src; + _visible = true; + _show(card); +} + +async function _switchTo(card) { + const seq = ++_showSeq; + const src = await _loadSrc(card); + if (!src || !_enabled || _activeCard !== card || seq !== _showSeq) return; _imgEl.src = src; _show(card); @@ -115,41 +104,12 @@ async function _loadSrc(card) { return src; } -// ── 원형 로딩바 ────────────────────────────────── - -function _showLoader(card) { - _removeLoader(); - - const svg = document.createElementNS(SVG_NS, 'svg'); - svg.classList.add('card-hover-loader'); - svg.setAttribute('viewBox', '0 0 48 48'); - - const bg = document.createElementNS(SVG_NS, 'circle'); - bg.classList.add('loader-bg'); - bg.setAttribute('cx', '24'); bg.setAttribute('cy', '24'); bg.setAttribute('r', '24'); - - const track = document.createElementNS(SVG_NS, 'circle'); - track.classList.add('loader-track'); - track.setAttribute('cx', '24'); track.setAttribute('cy', '24'); track.setAttribute('r', String(RADIUS)); - - const progress = document.createElementNS(SVG_NS, 'circle'); - progress.classList.add('loader-progress'); - progress.setAttribute('cx', '24'); progress.setAttribute('cy', '24'); progress.setAttribute('r', String(RADIUS)); - progress.style.strokeDasharray = CIRC; - progress.style.strokeDashoffset = CIRC; - - svg.appendChild(bg); - svg.appendChild(track); - svg.appendChild(progress); - card.appendChild(svg); - _loaderEl = svg; -} - -function _removeLoader() { - if (_loaderEl) { - _loaderEl.remove(); - _loaderEl = null; - } +function _hideNow() { + _showSeq++; + _activeCard = null; + _visible = false; + _el.style.display = 'none'; + _el.style.visibility = 'hidden'; } // ── 이미지 팝업 위치 계산 및 표시 ──────────────── diff --git a/src/renderer/keyboard.js b/src/renderer/keyboard.js index 0b9bfce..1247bc5 100644 --- a/src/renderer/keyboard.js +++ b/src/renderer/keyboard.js @@ -34,7 +34,8 @@ export function initKeyboardShortcuts({ } else if (e.metaKey && e.shiftKey && e.code === 'KeyZ') { e.preventDefault(); performRedo(); - } else if (e.code === 'KeyP') { + } else if (e.code === 'Space') { + e.preventDefault(); btnPreviewToggle.click(); } else if (e.code === 'Backspace' || e.code === 'Delete') { deleteSelected();