|
|
|
|
@ -7,24 +7,27 @@
|
|
|
|
|
const href = link.getAttribute('href'); |
|
|
|
|
if (!href) return; |
|
|
|
|
|
|
|
|
|
// Create minimal tooltip with just the link
|
|
|
|
|
// Create tooltip
|
|
|
|
|
const tooltip = document.createElement('div'); |
|
|
|
|
tooltip.className = 'audio-tooltip'; |
|
|
|
|
tooltip.innerHTML = `<a href="${href}" class="audio-tooltip-link">Go to page →</a>`; |
|
|
|
|
document.body.appendChild(tooltip); |
|
|
|
|
|
|
|
|
|
let cleanup = null; |
|
|
|
|
let hideTimeout = null; |
|
|
|
|
const HIDE_DELAY_MS = 250; // Adjust if needed (higher = more forgiving)
|
|
|
|
|
|
|
|
|
|
const showTooltip = () => { |
|
|
|
|
clearTimeout(hideTimeout); |
|
|
|
|
tooltip.style.display = 'block'; |
|
|
|
|
|
|
|
|
|
// Dynamically import Floating UI (works if in core or via build/CDN)
|
|
|
|
|
// Floating UI dynamic import + positioning
|
|
|
|
|
import('@floating-ui/dom').then(({ computePosition, autoUpdate, offset, flip, shift }) => { |
|
|
|
|
cleanup = autoUpdate(link, tooltip, () => { |
|
|
|
|
computePosition(link, tooltip, { |
|
|
|
|
placement: 'top', |
|
|
|
|
middleware: [ |
|
|
|
|
offset(10), // distance from link
|
|
|
|
|
offset(10), |
|
|
|
|
flip(), |
|
|
|
|
shift({ padding: 8 }) |
|
|
|
|
] |
|
|
|
|
@ -36,7 +39,7 @@
|
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
}).catch(() => { |
|
|
|
|
// Fallback positioning if Floating UI import fails
|
|
|
|
|
// Fallback centering above
|
|
|
|
|
const rect = link.getBoundingClientRect(); |
|
|
|
|
tooltip.style.left = `${rect.left + window.scrollX + rect.width / 2}px`; |
|
|
|
|
tooltip.style.top = `${rect.top + window.scrollY - tooltip.offsetHeight - 10}px`; |
|
|
|
|
@ -44,20 +47,34 @@
|
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const hideTooltip = () => { |
|
|
|
|
tooltip.style.display = 'none'; |
|
|
|
|
if (cleanup) { |
|
|
|
|
cleanup(); |
|
|
|
|
cleanup = null; |
|
|
|
|
} |
|
|
|
|
const scheduleHide = () => { |
|
|
|
|
clearTimeout(hideTimeout); |
|
|
|
|
hideTimeout = setTimeout(() => { |
|
|
|
|
tooltip.style.display = 'none'; |
|
|
|
|
if (cleanup) { |
|
|
|
|
cleanup(); |
|
|
|
|
cleanup = null; |
|
|
|
|
} |
|
|
|
|
}, HIDE_DELAY_MS); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Trigger events
|
|
|
|
|
link.addEventListener('mouseenter', showTooltip); |
|
|
|
|
link.addEventListener('mouseleave', hideTooltip); |
|
|
|
|
link.addEventListener('mouseleave', scheduleHide); |
|
|
|
|
|
|
|
|
|
// Keep open when hovering tooltip
|
|
|
|
|
tooltip.addEventListener('mouseenter', () => { |
|
|
|
|
clearTimeout(hideTimeout); |
|
|
|
|
tooltip.style.display = 'block'; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// Optional: keep visible on hover of tooltip itself (so user can click)
|
|
|
|
|
tooltip.addEventListener('mouseenter', showTooltip); |
|
|
|
|
tooltip.addEventListener('mouseleave', hideTooltip); |
|
|
|
|
tooltip.addEventListener('mouseleave', scheduleHide); |
|
|
|
|
|
|
|
|
|
// Optional: Clean up on click (prevents stuck tooltips)
|
|
|
|
|
tooltip.querySelector('a').addEventListener('click', () => { |
|
|
|
|
tooltip.style.display = 'none'; |
|
|
|
|
if (cleanup) cleanup(); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|