Skip to content

Commit 454b782

Browse files
authored
Update script.js
1 parent 59f7d13 commit 454b782

1 file changed

Lines changed: 82 additions & 2 deletions

File tree

script.js

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ const scene = document.getElementById('scene-container');
44
const motionBtn = document.getElementById('toggle-motion');
55
const searchInput = document.getElementById('search-input');
66

7+
// --- Preview Pane Elements ---
8+
const previewSidebar = document.getElementById('preview-sidebar');
9+
const previewFrame = document.getElementById('preview-frame');
10+
const previewTitle = document.getElementById('preview-title');
11+
const previewLink = document.getElementById('preview-link');
12+
const closePreviewBtn = document.getElementById('close-preview');
13+
let previewDebounceTimer = null;
14+
715
// --- Configuration ---
816
const config = {
917
sphereRadius: 280,
@@ -57,24 +65,39 @@ class Point {
5765
this.element = document.createElement('a');
5866
this.element.href = data.url;
5967
this.element.className = 'node-link';
60-
this.element.target = "_blank";
68+
// We remove target="_blank" behavior in JS, but keep it in HTML for fallback
69+
this.element.target = "_blank";
6170
this.element.setAttribute('aria-label', `Visit ${data.text}`);
6271

6372
this.element.innerHTML = `
6473
<div class="node-dot"></div>
6574
<span class="node-text">${data.text}</span>
6675
`;
6776

77+
// --- Event Listeners ---
78+
79+
// CLICK: Open immediately
80+
this.element.addEventListener('click', (e) => {
81+
e.preventDefault(); // Stop normal navigation
82+
focusedPoint = this;
83+
config.isPaused = true;
84+
loadPreviewNow(this.data);
85+
});
86+
87+
// FOCUS: Open with delay (Debounce) to prevent lag while tabbing
6888
this.element.addEventListener('focus', () => {
6989
focusedPoint = this;
7090
config.isPaused = true;
91+
schedulePreview(this.data);
7192
});
7293

7394
this.element.addEventListener('blur', () => {
7495
focusedPoint = null;
7596
if (!mediaQuery.matches && motionBtn.innerText === "PAUSE MOTION") {
7697
config.isPaused = false;
7798
}
99+
// Cancel any pending preview load if user tabs away quickly
100+
clearTimeout(previewDebounceTimer);
78101
});
79102

80103
scene.appendChild(this.element);
@@ -157,6 +180,61 @@ function drawConnections() {
157180
ctx.restore();
158181
}
159182

183+
// --- Preview Logic ---
184+
185+
function schedulePreview(data) {
186+
// Cancel any existing timer
187+
clearTimeout(previewDebounceTimer);
188+
// Wait 800ms before loading. If user tabs away, 'blur' will clear this.
189+
previewDebounceTimer = setTimeout(() => {
190+
loadPreviewNow(data);
191+
}, 800);
192+
}
193+
194+
function loadPreviewNow(data) {
195+
clearTimeout(previewDebounceTimer);
196+
197+
// Update Sidebar UI
198+
previewTitle.textContent = data.text;
199+
previewLink.href = data.url;
200+
previewSidebar.classList.add('active');
201+
202+
// Only load if it's a new URL (prevents reloading on repeated clicks)
203+
if (previewFrame.getAttribute('src') !== data.url) {
204+
previewFrame.classList.remove('loaded'); // Hide until loaded
205+
previewFrame.src = data.url;
206+
207+
previewFrame.onload = () => {
208+
previewFrame.classList.add('loaded');
209+
};
210+
}
211+
}
212+
213+
function closePreview() {
214+
previewSidebar.classList.remove('active');
215+
216+
// Clear iframe source after animation to free memory/CPU
217+
setTimeout(() => {
218+
previewFrame.src = '';
219+
previewFrame.classList.remove('loaded');
220+
}, 500);
221+
}
222+
223+
// Close preview when clicking X
224+
closePreviewBtn.addEventListener('click', closePreview);
225+
226+
// Close preview when clicking outside sidebar and nodes
227+
window.addEventListener('click', (e) => {
228+
const isNode = e.target.closest('.node-link');
229+
const isSidebar = e.target.closest('#preview-sidebar');
230+
if (!isNode && !isSidebar) {
231+
closePreview();
232+
}
233+
});
234+
235+
236+
// --- Existing Event Listeners ---
237+
160238
searchInput.addEventListener('mouseenter', () => { isSearchHovering = true; });
161239
searchInput.addEventListener('mouseleave', () => { isSearchHovering = false; });
162240
searchInput.addEventListener('touchstart', () => { isSearchHovering = true; }, {passive: true});
@@ -242,5 +320,7 @@ window.addEventListener('keydown', (e) => {
242320
} else {
243321
if (document.activeElement === last) { e.preventDefault(); first.focus(); }
244322
}
323+
} else if (e.key === 'Escape') {
324+
closePreview();
245325
}
246-
});
326+
});

0 commit comments

Comments
 (0)