1// Instant anchor scroll - no smooth scrolling for better UX on long pages
2export function initAnchorScroll() {
3 document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
4 anchor.addEventListener("click", (e) => {
5 e.preventDefault();
6 const target = document.querySelector(anchor.getAttribute("href"));
7 if (target) {
8 // Instant jump with small offset for visual breathing room
9 const offset = 40;
10 const targetPosition = target.getBoundingClientRect().top + window.scrollY - offset;
11 window.scrollTo({ top: targetPosition, behavior: 'auto' });
12 }
13 });
14 });
15}
16
17export function initHashTracking() {
18 const sections = document.querySelectorAll('section[id]');
19 if (!sections.length) return;
20
21 let currentHash = window.location.hash.slice(1) || '';
22 let ticking = false;
23
24 function updateHash() {
25 // Don't override command deep links while user is in the commands section
26 if (currentHash.startsWith('cmd-')) {
27 const cmdEl = document.getElementById(currentHash);
28 if (cmdEl) {
29 const rect = cmdEl.getBoundingClientRect();
30 // Only clear the cmd hash if user scrolled well away from commands section
31 if (rect.top > window.innerHeight * 2 || rect.bottom < -window.innerHeight) {
32 currentHash = '';
33 } else {
34 ticking = false;
35 return;
36 }
37 }
38 }
39
40 const scrollY = window.scrollY;
41 const viewportHeight = window.innerHeight;
42 const triggerPoint = scrollY + viewportHeight * 0.3;
43
44 let activeSection = '';
45
46 sections.forEach(section => {
47 const rect = section.getBoundingClientRect();
48 const sectionTop = scrollY + rect.top;
49 const sectionBottom = sectionTop + rect.height;
50
51 if (triggerPoint >= sectionTop && triggerPoint < sectionBottom) {
52 activeSection = section.id;
53 }
54 });
55
56 // Don't set #hero — it's the default state, no hash needed
57 if (activeSection === 'hero') activeSection = '';
58
59 if (activeSection !== currentHash) {
60 currentHash = activeSection;
61 if (activeSection) {
62 history.replaceState(null, '', `#${activeSection}`);
63 } else {
64 history.replaceState(null, '', window.location.pathname);
65 }
66 }
67
68 ticking = false;
69 }
70
71 window.addEventListener('scroll', () => {
72 if (!ticking) {
73 requestAnimationFrame(updateHash);
74 ticking = true;
75 }
76 }, { passive: true });
77
78 // Handle initial hash on page load - instant jump
79 if (window.location.hash) {
80 const hash = window.location.hash.slice(1);
81 const target = document.getElementById(hash);
82 if (target) {
83 currentHash = hash;
84 setTimeout(() => {
85 const offset = 40;
86 const targetPosition = target.getBoundingClientRect().top + window.scrollY - offset;
87 window.scrollTo({ top: targetPosition, behavior: 'auto' });
88
89 // If it's a command deep link, activate it
90 if (hash.startsWith('cmd-') && target.classList.contains('manual-entry')) {
91 target.click();
92 }
93 }, 100);
94 }
95 } else {
96 // No hash — don't set one on initial load
97 }
98}
99