/** * Tracks scroll depth milestones (25 / 50 / 75 / 100 %) on each page. * Also intercepts external link clicks and tracks them. * * Usage: call once in default.vue layout. */ export function useScrollTracking() { const route = useRoute() const { trackScrollDepth, trackExternalLink } = useTracking() // ── Scroll depth ──────────────────────────────────────────────────────── const fired = new Set() function onScroll() { const el = document.documentElement const scrolled = el.scrollTop + el.clientHeight const total = el.scrollHeight if (total <= el.clientHeight) return const pct = (scrolled / total) * 100 for (const milestone of [25, 50, 75, 100] as const) { if (pct >= milestone && !fired.has(milestone)) { fired.add(milestone) trackScrollDepth(route.path, milestone) } } } // Reset fired milestones on route change watch(() => route.path, () => fired.clear()) // ── External link tracking ─────────────────────────────────────────────── function onLinkClick(e: MouseEvent) { const target = (e.target as HTMLElement).closest('a') if (!target) return const href = target.getAttribute('href') || '' if (!href.startsWith('http') && !href.startsWith('//')) return try { const url = new URL(href) if (url.hostname === 'librodrome.org') return trackExternalLink(href, target.textContent?.trim() || '') } catch { /* invalid URL, ignore */ } } onMounted(() => { window.addEventListener('scroll', onScroll, { passive: true }) document.addEventListener('click', onLinkClick) }) onUnmounted(() => { window.removeEventListener('scroll', onScroll) document.removeEventListener('click', onLinkClick) }) }