|
| 1 | +// Lito Graph Landing Page Scripts |
| 2 | +(function () { |
| 3 | + // ---- Theme: respect system preference on first visit ---- |
| 4 | + var stored = localStorage.getItem('theme'); |
| 5 | + if (!stored) { |
| 6 | + var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; |
| 7 | + document.documentElement.classList.toggle('dark', prefersDark); |
| 8 | + document.documentElement.classList.toggle('light', !prefersDark); |
| 9 | + } |
| 10 | + |
| 11 | + // ---- Navbar scroll ---- |
| 12 | + var nav = document.getElementById('ln'); |
| 13 | + var hero = document.querySelector('.hero'); |
| 14 | + |
| 15 | + function updateNav() { |
| 16 | + if (!hero || !nav) return; |
| 17 | + nav.classList.toggle('scrolled', window.scrollY > hero.offsetHeight - 80); |
| 18 | + } |
| 19 | + |
| 20 | + window.addEventListener('scroll', updateNav, { passive: true }); |
| 21 | + updateNav(); |
| 22 | + |
| 23 | + // ---- Mobile menu ---- |
| 24 | + var menuBtn = document.getElementById('menuToggle'); |
| 25 | + var mobileMenu = document.getElementById('mobileMenu'); |
| 26 | + |
| 27 | + if (menuBtn && mobileMenu) { |
| 28 | + menuBtn.addEventListener('click', function () { |
| 29 | + var open = mobileMenu.classList.toggle('open'); |
| 30 | + menuBtn.classList.toggle('active', open); |
| 31 | + menuBtn.setAttribute('aria-expanded', open); |
| 32 | + }); |
| 33 | + } |
| 34 | + |
| 35 | + // ---- Theme toggle ---- |
| 36 | + var themeBtn = document.getElementById('themeToggle'); |
| 37 | + if (themeBtn) { |
| 38 | + themeBtn.addEventListener('click', function () { |
| 39 | + var isDark = document.documentElement.classList.toggle('dark'); |
| 40 | + document.documentElement.classList.toggle('light', !isDark); |
| 41 | + localStorage.setItem('theme', isDark ? 'dark' : 'light'); |
| 42 | + }); |
| 43 | + } |
| 44 | + |
| 45 | + // ---- Scroll reveals ---- |
| 46 | + var els = document.querySelectorAll('[data-reveal]'); |
| 47 | + var revealEls = []; |
| 48 | + for (var i = 0; i < els.length; i++) { |
| 49 | + if (!els[i].closest('.hero')) revealEls.push(els[i]); |
| 50 | + } |
| 51 | + |
| 52 | + if (revealEls.length && 'IntersectionObserver' in window) { |
| 53 | + var obs = new IntersectionObserver(function (entries) { |
| 54 | + entries.forEach(function (e) { |
| 55 | + if (!e.isIntersecting) return; |
| 56 | + var el = e.target; |
| 57 | + var parent = el.parentElement; |
| 58 | + var siblings = parent |
| 59 | + ? Array.prototype.filter.call(parent.children, function (c) { return c.hasAttribute('data-reveal'); }) |
| 60 | + : [el]; |
| 61 | + var idx = siblings.indexOf(el); |
| 62 | + setTimeout(function () { el.classList.add('revealed'); }, idx * 80); |
| 63 | + obs.unobserve(el); |
| 64 | + }); |
| 65 | + }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' }); |
| 66 | + |
| 67 | + revealEls.forEach(function (el) { obs.observe(el); }); |
| 68 | + } else { |
| 69 | + for (var j = 0; j < els.length; j++) els[j].classList.add('revealed'); |
| 70 | + } |
| 71 | + |
| 72 | + // ---- Showcase tabs ---- |
| 73 | + var tabs = document.querySelectorAll('.sc-tab'); |
| 74 | + var panels = document.querySelectorAll('.sc-panel'); |
| 75 | + |
| 76 | + tabs.forEach(function (tab) { |
| 77 | + tab.addEventListener('click', function () { |
| 78 | + var target = tab.getAttribute('data-tab'); |
| 79 | + tabs.forEach(function (t) { t.classList.remove('active'); }); |
| 80 | + panels.forEach(function (p) { p.classList.remove('active'); }); |
| 81 | + tab.classList.add('active'); |
| 82 | + var panel = document.querySelector('[data-panel="' + target + '"]'); |
| 83 | + if (panel) panel.classList.add('active'); |
| 84 | + }); |
| 85 | + }); |
| 86 | + |
| 87 | + // ---- Terminal typing (left panel) ---- |
| 88 | + var cmd = 'npx @litodocs/graph https://docs.example.com/graph.json'; |
| 89 | + var typedEl = document.getElementById('typed'); |
| 90 | + var cursorEl = document.getElementById('cursor'); |
| 91 | + var ci = 0; |
| 92 | + |
| 93 | + function typeNext() { |
| 94 | + if (!typedEl) return; |
| 95 | + if (ci < cmd.length) { |
| 96 | + typedEl.textContent += cmd[ci]; |
| 97 | + ci++; |
| 98 | + setTimeout(typeNext, 40 + Math.random() * 30); |
| 99 | + } else { |
| 100 | + setTimeout(function () { |
| 101 | + if (cursorEl) cursorEl.style.display = 'none'; |
| 102 | + showOut(); |
| 103 | + }, 500); |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + function showOut() { |
| 108 | + ['o1', 'o2', 'o3'].forEach(function (id, i) { |
| 109 | + setTimeout(function () { |
| 110 | + var el = document.getElementById(id); |
| 111 | + if (!el) return; |
| 112 | + el.style.display = 'flex'; |
| 113 | + void el.offsetHeight; |
| 114 | + el.classList.add('show'); |
| 115 | + }, i * 600); |
| 116 | + }); |
| 117 | + // Show right panel agent output after left finishes |
| 118 | + setTimeout(showAgent, 2200); |
| 119 | + } |
| 120 | + |
| 121 | + // ---- Agent panel typing ---- |
| 122 | + function showAgent() { |
| 123 | + ['a1', 'a2', 'a3', 'a4', 'a5', 'a6'].forEach(function (id, i) { |
| 124 | + setTimeout(function () { |
| 125 | + var el = document.getElementById(id); |
| 126 | + if (!el) return; |
| 127 | + el.style.display = 'block'; |
| 128 | + void el.offsetHeight; |
| 129 | + el.classList.add('show'); |
| 130 | + }, i * 300); |
| 131 | + }); |
| 132 | + } |
| 133 | + |
| 134 | + setTimeout(typeNext, 900); |
| 135 | +})(); |
0 commit comments