1/* axoi. studio â slide page content between nav items; nav stays fixed */ 2(function () { 3 const ORDER = ['index.html', 'services.html', 'work.html', 'about.html', 'contact.html', 'launch.html', 'thank-you.html']; 4 const DURATION = 220; 5 const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; 6 7 function pageKey(href) { 8 try { 9 const u = new URL(href, location.href); 10 if (u.origin !== location.origin) return null; 11 let path = u.pathname.split('/').pop() || 'index.html'; 12 if (path === '' || path === '/') path = 'index.html'; 13 if (!/\.html?$/i.test(path)) return null; 14 return path; 15 } catch (_) { 16 return null; 17 } 18 } 19 20 function currentKey() { 21 return pageKey(location.href) || 'index.html'; 22 } 23 24 function direction(from, to) { 25 const a = ORDER.indexOf(from); 26 const b = ORDER.indexOf(to); 27 if (a === -1 || b === -1 || a === b) return 'forward'; 28 return b > a ? 'forward' : 'back'; 29 } 30 31 /* Wrap everything except the fixed nav (and scripts) so transforms never move the bar. */ 32 function ensureShell() { 33 let shell = document.querySelector('.page-shell'); 34 if (shell) return shell; 35 shell = document.createElement('div'); 36 shell.className = 'page-shell'; 37 const nav = document.querySelector('body > .nav'); 38 const keep = new Set([nav]); 39 document.querySelectorAll('body > script').forEach((el) => keep.add(el)); 40 [...document.body.children] 41 .filter((el) => !keep.has(el)) 42 .forEach((el) => shell.appendChild(el)); 43 if (nav) nav.after(shell); 44 else document.body.prepend(shell); 45 return shell; 46 } 47 48 const shell = ensureShell(); 49 50 function clearTransition() { 51 document.documentElement.classList.remove('nav-pending'); 52 document.body.classList.remove('is-paging'); 53 shell.classList.remove('page-leave', 'page-leave-back', 'page-enter', 'page-enter-back'); 54 } 55 56 function go(href, dir) { 57 try { sessionStorage.setItem('axoi-nav-dir', dir); } catch (_) {} 58 if (reduce) { 59 location.href = href; 60 return; 61 } 62 document.body.classList.add('is-paging'); 63 shell.classList.remove('page-enter', 'page-enter-back'); 64 shell.classList.add(dir === 'back' ? 'page-leave-back' : 'page-leave'); 65 window.setTimeout(() => { location.href = href; }, DURATION); 66 } 67 68 /* Enter only when arriving via our leave transition. 69 Add enter class before clearing nav-pending so opacity stays 0 (no flash). */ 70 if (!reduce) { 71 let dir = null; 72 try { 73 dir = sessionStorage.getItem('axoi-nav-dir'); 74 sessionStorage.removeItem('axoi-nav-dir'); 75 } catch (_) {} 76 if (dir) { 77 const enterClass = dir === 'back' ? 'page-enter-back' : 'page-enter'; 78 shell.classList.add(enterClass); 79 shell.addEventListener('animationend', () => { 80 shell.classList.remove('page-enter', 'page-enter-back'); 81 }, { once: true }); 82 } 83 } 84 document.documentElement.classList.remove('nav-pending'); 85 86 /* Back-forward cache can restore a page mid-leave (opacity 0). */ 87 window.addEventListener('pageshow', (e) => { 88 if (e.persisted) clearTransition(); 89 }); 90 91 document.addEventListener('click', (e) => { 92 if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return; 93 const a = e.target.closest('a[href]'); 94 if (!a) return; 95 if (a.target === '_blank' || a.hasAttribute('download')) return; 96 97 const href = a.getAttribute('href'); 98 if (!href || href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:')) return; 99 100 const to = pageKey(href); 101 if (!to) return; 102 103 const from = currentKey(); 104 if (to === from) return; 105 106 e.preventDefault(); 107 const nav = document.querySelector('.nav'); 108 if (nav) nav.classList.remove('mobile-open'); 109 go(a.href, direction(from, to)); 110 }); 111})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.