readysite / hosting / views / static / js / home.js
4.1 KB
home.js
// Scroll Reveal — IntersectionObserver adds .visible to .reveal elements
(function () {
    var reveals = document.querySelectorAll('.reveal');
    if (!reveals.length) return;

    var observer = new IntersectionObserver(function (entries) {
        entries.forEach(function (entry) {
            if (!entry.isIntersecting) return;

            var el = entry.target;
            var delay = parseInt(el.getAttribute('data-delay') || '0', 10);

            setTimeout(function () {
                el.classList.add('visible');
            }, delay);

            observer.unobserve(el);
        });
    }, { threshold: 0.15 });

    reveals.forEach(function (el) {
        observer.observe(el);
    });
})();

// Terminal Typing — sequentially reveal lines when terminal enters viewport
(function () {
    var terminal = document.querySelector('.terminal-body');
    if (!terminal) return;

    var lines = terminal.querySelectorAll('.terminal-line');
    var cursor = terminal.querySelector('.terminal-cursor');
    var triggered = false;

    var observer = new IntersectionObserver(function (entries) {
        entries.forEach(function (entry) {
            if (!entry.isIntersecting || triggered) return;
            triggered = true;
            observer.unobserve(entry.target);

            lines.forEach(function (line, i) {
                setTimeout(function () {
                    line.classList.add('visible');
                    // Move cursor after last visible line
                    if (cursor && i === lines.length - 1) {
                        setTimeout(function () {
                            cursor.style.display = 'none';
                        }, 1500);
                    }
                }, i * 600);
            });
        });
    }, { threshold: 0.3 });

    observer.observe(terminal);
})();

// Particle Emitter — ember-like pixels off accent borders
(function () {
    var websiteNode = document.getElementById('website-node');
    var salesforceNode = document.getElementById('salesforce-node');

    var violetColors = ['#8b5cf6', '#a78bfa', '#c4b5fd', '#22d3ee', '#7c3aed', '#818cf8'];
    var emeraldColors = ['#10b981', '#34d399', '#6ee7b7', '#22d3ee', '#059669', '#a7f3d0'];

    function spawnParticle(emitter, colors, side) {
        var isMobile = window.innerWidth < 768;
        var el = document.createElement('div');
        el.className = 'accent-particle accent-particle-' + side;
        if (isMobile) el.classList.add('accent-particle-v');

        // Pick random color
        var color = colors[Math.floor(Math.random() * colors.length)];
        el.style.background = color;
        var glowSize = side === 'left' ? '8px' : '6px';
        el.style.boxShadow = '0 0 ' + glowSize + ' ' + color;

        var dist, px, py;
        if (isMobile) {
            // Mobile: position along horizontal edge, vertical drift
            el.style.left = (5 + Math.random() * 90) + '%';
            dist = 14 + Math.random() * 34;
            // Salesforce (left): converge from above into top border
            // Website (right): drift downward from bottom border
            py = (side === 'left' ? -dist : dist) + 'px';
            px = (Math.random() - 0.5) * 40 + 'px';
        } else {
            // Desktop: position along vertical edge, horizontal drift
            el.style.top = (5 + Math.random() * 90) + '%';
            dist = side === 'left' ? (14 + Math.random() * 34) : (14 + Math.random() * 32);
            px = (side === 'left' ? -dist : dist) + 'px';
            py = (Math.random() - 0.5) * 40 + 'px';
        }

        el.style.setProperty('--px', px);
        el.style.setProperty('--py', py);
        el.style.setProperty('--duration', (1.2 + Math.random() * 1.3) + 's');

        emitter.appendChild(el);

        // Clean up after animation
        setTimeout(function () {
            if (el.parentNode) el.parentNode.removeChild(el);
        }, 2600);
    }

    if (websiteNode) {
        setInterval(function () { spawnParticle(websiteNode, violetColors, 'right'); }, 70);
    }
    if (salesforceNode) {
        setInterval(function () { spawnParticle(salesforceNode, emeraldColors, 'left'); }, 150);
    }
})();
← Back